Passed
Pull Request — master (#251)
by Gabriel
10:21
created

BaseFileCacheTest   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 14
c 0
b 0
f 0
lcom 1
cbo 4
dl 0
loc 138
rs 10
1
<?php
2
3
namespace Doctrine\Tests\Common\Cache;
4
5
use Doctrine\Common\Cache\FileCache;
6
use RecursiveDirectoryIterator;
7
use RecursiveIteratorIterator;
8
use const DIRECTORY_SEPARATOR;
9
use function bin2hex;
10
use function file_exists;
11
use function floor;
12
use function get_class;
13
use function hash;
14
use function is_dir;
15
use function rmdir;
16
use function str_repeat;
17
use function strlen;
18
use function substr;
19
use function sys_get_temp_dir;
20
use function uniqid;
21
use function unlink;
22
23
abstract class BaseFileCacheTest extends CacheTest
24
{
25
    protected $directory;
26
27
    protected function setUp() : void
28
    {
29
        do {
30
            $this->directory = sys_get_temp_dir() . '/doctrine_cache_' . uniqid();
31
        } while (file_exists($this->directory));
32
    }
33
34
    protected function tearDown() : void
35
    {
36
        if (! is_dir($this->directory)) {
37
            return;
38
        }
39
40
        $iterator = new RecursiveDirectoryIterator($this->directory);
41
42
        foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
43
            if ($file->isFile()) {
44
                @unlink($file->getRealPath());
45
            } elseif ($file->isDir()) {
46
                @rmdir($file->getRealPath());
47
            }
48
        }
49
50
        @rmdir($this->directory);
51
    }
52
53
    public function testFlushAllRemovesBalancingDirectories() : void
54
    {
55
        $cache = $this->_getCacheDriver();
56
57
        self::assertTrue($cache->save('key1', 1));
58
        self::assertTrue($cache->save('key2', 2));
59
        self::assertTrue($cache->flushAll());
60
61
        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST);
62
63
        self::assertCount(0, $iterator);
64
    }
65
66
    protected function isSharedStorage() : bool
67
    {
68
        return false;
69
    }
70
71
    public function getPathLengthsToTest() : array
72
    {
73
        // Windows officially supports 260 bytes including null terminator
74
        // 258 bytes available to use due to php bug #70943
75
        // Windows officially supports 260 bytes including null terminator
76
        // 259 characters is too large due to PHP bug (https://bugs.php.net/bug.php?id=70943)
77
        // 260 characters is too large - null terminator is included in allowable length
78
        return [
79
            [257, false],
80
            [258, false],
81
            [259, true],
82
            [260, true],
83
        ];
84
    }
85
86
    private static function getBasePathForWindowsPathLengthTests(int $pathLength) : string
87
    {
88
        return FileCacheTest::getBasePathForWindowsPathLengthTests($pathLength);
89
    }
90
91
    private static function getKeyAndPathFittingLength(int $length, string $basePath) : array
92
    {
93
        $baseDirLength             = strlen($basePath);
94
        $extensionLength           = strlen('.doctrine.cache');
95
        $directoryLength           = strlen(DIRECTORY_SEPARATOR . 'aa' . DIRECTORY_SEPARATOR);
96
        $namespaceAndBracketLength = strlen(bin2hex('[][1]'));
97
        $keyLength                 = $length
98
            - ($baseDirLength
99
                + $extensionLength
100
                + $directoryLength
101
                + $namespaceAndBracketLength);
102
103
        $key           = str_repeat('a', floor($keyLength / 2));
104
        $namespacedKey = '[' . $key . '][1]';
105
106
        $keyHash = hash('sha256', $namespacedKey);
107
108
        $keyPath = $basePath
109
            . DIRECTORY_SEPARATOR
110
            . substr($keyHash, 0, 2)
111
            . DIRECTORY_SEPARATOR
112
            . bin2hex($namespacedKey)
113
            . '.doctrine.cache';
114
115
        $hashedKeyPath = $basePath
116
            . DIRECTORY_SEPARATOR
117
            . substr($keyHash, 0, 2)
118
            . DIRECTORY_SEPARATOR
119
            . '_' . $keyHash
120
            . '.doctrine.cache';
121
122
        return [$key, $keyPath, $hashedKeyPath];
123
    }
124
125
    /**
126
     * @dataProvider getPathLengthsToTest
127
     */
128
    public function testWindowsPathLengthLimitIsCorrectlyHandled(int $length, bool $pathShouldBeHashed) : void
129
    {
130
        $this->directory = self::getBasePathForWindowsPathLengthTests($length);
131
132
        list($key, $keyPath, $hashedKeyPath) = self::getKeyAndPathFittingLength($length, $this->directory);
133
134
        self::assertEquals($length, strlen($keyPath), 'Unhashed path should be of correct length.');
135
136
        $cacheClass = get_class($this->_getCacheDriver());
137
        /* @var $cache \Doctrine\Common\Cache\FileCache */
138
        $cache = new $cacheClass($this->directory, '.doctrine.cache');
139
140
        // Trick it into thinking this is windows.
141
        $reflClass = new \ReflectionClass(FileCache::class);
142
        $reflProp  = $reflClass->getProperty('isRunningOnWindows');
143
        $reflProp->setAccessible(true);
144
        $reflProp->setValue($cache, true);
145
        $reflProp->setAccessible(false);
146
147
        $value = uniqid('value', true);
148
149
        $cache->save($key, $value);
150
        self::assertEquals($value, $cache->fetch($key));
151
152
        if ($pathShouldBeHashed) {
153
            self::assertFileExists($hashedKeyPath, 'Path generated for key should be hashed.');
154
            unlink($hashedKeyPath);
155
        } else {
156
            self::assertFileExists($keyPath, 'Path generated for key should not be hashed.');
157
            unlink($keyPath);
158
        }
159
    }
160
}
161