More updates to stop using dev or alpha or beta versions.
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Cache / Context / CacheContextsManagerTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\Cache\Context\CacheContextsManagerTest.
6  */
7
8 namespace Drupal\Tests\Core\Cache\Context;
9
10 use Drupal\Core\Cache\CacheableMetadata;
11 use Drupal\Core\Cache\Context\CacheContextsManager;
12 use Drupal\Core\Cache\Context\CacheContextInterface;
13 use Drupal\Core\Cache\Context\CalculatedCacheContextInterface;
14 use Drupal\Core\DependencyInjection\ContainerBuilder;
15 use Drupal\Tests\UnitTestCase;
16 use Symfony\Component\DependencyInjection\Container;
17
18 /**
19  * @coversDefaultClass \Drupal\Core\Cache\Context\CacheContextsManager
20  * @group Cache
21  */
22 class CacheContextsManagerTest extends UnitTestCase {
23
24   /**
25    * @covers ::optimizeTokens
26    *
27    * @dataProvider providerTestOptimizeTokens
28    */
29   public function testOptimizeTokens(array $context_tokens, array $optimized_context_tokens) {
30     $container = $this->getMockBuilder('Drupal\Core\DependencyInjection\Container')
31       ->disableOriginalConstructor()
32       ->getMock();
33     $container->expects($this->any())
34       ->method('get')
35       ->will($this->returnValueMap([
36         ['cache_context.a', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
37         ['cache_context.a.b', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
38         ['cache_context.a.b.c', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
39         ['cache_context.x', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
40         ['cache_context.a.b.no-optimize', Container::EXCEPTION_ON_INVALID_REFERENCE, new NoOptimizeCacheContext()],
41       ]));
42     $cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
43
44     $this->assertSame($optimized_context_tokens, $cache_contexts_manager->optimizeTokens($context_tokens));
45   }
46
47   /**
48    * Provides a list of context token sets.
49    */
50   public function providerTestOptimizeTokens() {
51     return [
52       [['a', 'x'], ['a', 'x']],
53       [['a.b', 'x'], ['a.b', 'x']],
54
55       // Direct ancestor, single-level hierarchy.
56       [['a', 'a.b'], ['a']],
57       [['a.b', 'a'], ['a']],
58
59       // Direct ancestor, multi-level hierarchy.
60       [['a.b', 'a.b.c'], ['a.b']],
61       [['a.b.c', 'a.b'], ['a.b']],
62
63       // Indirect ancestor.
64       [['a', 'a.b.c'], ['a']],
65       [['a.b.c', 'a'], ['a']],
66
67       // Direct & indirect ancestors.
68       [['a', 'a.b', 'a.b.c'], ['a']],
69       [['a', 'a.b.c', 'a.b'], ['a']],
70       [['a.b', 'a', 'a.b.c'], ['a']],
71       [['a.b', 'a.b.c', 'a'], ['a']],
72       [['a.b.c', 'a.b', 'a'], ['a']],
73       [['a.b.c', 'a', 'a.b'], ['a']],
74
75       // Using parameters.
76       [['a', 'a.b.c:foo'], ['a']],
77       [['a.b.c:foo', 'a'], ['a']],
78       [['a.b.c:foo', 'a.b.c'], ['a.b.c']],
79
80       // max-age 0 is treated as non-optimizable.
81       [['a.b.no-optimize', 'a.b', 'a'], ['a.b.no-optimize', 'a']],
82     ];
83   }
84
85   /**
86    * @covers ::convertTokensToKeys
87    */
88   public function testConvertTokensToKeys() {
89     $container = $this->getMockContainer();
90     $cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
91
92     $new_keys = $cache_contexts_manager->convertTokensToKeys([
93       'foo',
94       'baz:parameterA',
95       'baz:parameterB',
96     ]);
97
98     $expected = [
99       '[baz:parameterA]=cnenzrgreN',
100       '[baz:parameterB]=cnenzrgreO',
101       '[foo]=bar',
102     ];
103     $this->assertEquals($expected, $new_keys->getKeys());
104   }
105
106   /**
107    * @covers ::convertTokensToKeys
108    */
109   public function testInvalidContext() {
110     $container = $this->getMockContainer();
111     $cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
112
113     $this->setExpectedException(\AssertionError::class);
114     $cache_contexts_manager->convertTokensToKeys(["non-cache-context"]);
115   }
116
117   /**
118    * @covers ::convertTokensToKeys
119    *
120    * @dataProvider providerTestInvalidCalculatedContext
121    */
122   public function testInvalidCalculatedContext($context_token) {
123     $container = $this->getMockContainer();
124     $cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
125
126     $this->setExpectedException(\Exception::class);
127     $cache_contexts_manager->convertTokensToKeys([$context_token]);
128   }
129
130   /**
131    * Provides a list of invalid 'baz' cache contexts: the parameter is missing.
132    */
133   public function providerTestInvalidCalculatedContext() {
134     return [
135       ['baz'],
136       ['baz:'],
137     ];
138   }
139
140   public function testAvailableContextStrings() {
141     $cache_contexts_manager = new CacheContextsManager($this->getMockContainer(), $this->getContextsFixture());
142     $contexts = $cache_contexts_manager->getAll();
143     $this->assertEquals(["foo", "baz"], $contexts);
144   }
145
146   public function testAvailableContextLabels() {
147     $container = $this->getMockContainer();
148     $cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
149     $labels = $cache_contexts_manager->getLabels();
150     $expected = ["foo" => "Foo"];
151     $this->assertEquals($expected, $labels);
152   }
153
154   protected function getContextsFixture() {
155     return ['foo', 'baz'];
156   }
157
158   protected function getMockContainer() {
159     $container = $this->getMockBuilder('Drupal\Core\DependencyInjection\Container')
160       ->disableOriginalConstructor()
161       ->getMock();
162     $container->expects($this->any())
163       ->method('get')
164       ->will($this->returnValueMap([
165         ['cache_context.foo', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
166         ['cache_context.baz', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
167       ]));
168     return $container;
169   }
170
171   /**
172    * Provides a list of cache context token arrays.
173    *
174    * @return array
175    */
176   public function validateTokensProvider() {
177     return [
178       [[], FALSE],
179       [['foo'], FALSE],
180       [['foo', 'foo.bar'], FALSE],
181       [['foo', 'baz:llama'], FALSE],
182       // Invalid.
183       [[FALSE], 'Cache contexts must be strings, boolean given.'],
184       [[TRUE], 'Cache contexts must be strings, boolean given.'],
185       [['foo', FALSE], 'Cache contexts must be strings, boolean given.'],
186       [[NULL], 'Cache contexts must be strings, NULL given.'],
187       [['foo', NULL], 'Cache contexts must be strings, NULL given.'],
188       [[1337], 'Cache contexts must be strings, integer given.'],
189       [['foo', 1337], 'Cache contexts must be strings, integer given.'],
190       [[3.14], 'Cache contexts must be strings, double given.'],
191       [['foo', 3.14], 'Cache contexts must be strings, double given.'],
192       [[[]], 'Cache contexts must be strings, array given.'],
193       [['foo', []], 'Cache contexts must be strings, array given.'],
194       [['foo', ['bar']], 'Cache contexts must be strings, array given.'],
195       [[new \stdClass()], 'Cache contexts must be strings, object given.'],
196       [['foo', new \stdClass()], 'Cache contexts must be strings, object given.'],
197       // Non-existing.
198       [['foo.bar', 'qux'], '"qux" is not a valid cache context ID.'],
199       [['qux', 'baz'], '"qux" is not a valid cache context ID.'],
200     ];
201   }
202
203   /**
204    * @covers ::validateTokens
205    *
206    * @dataProvider validateTokensProvider
207    */
208   public function testValidateContexts(array $contexts, $expected_exception_message) {
209     $container = new ContainerBuilder();
210     $cache_contexts_manager = new CacheContextsManager($container, ['foo', 'foo.bar', 'baz']);
211     if ($expected_exception_message !== FALSE) {
212       $this->setExpectedException('LogicException', $expected_exception_message);
213     }
214     // If it doesn't throw an exception, validateTokens() returns NULL.
215     $this->assertNull($cache_contexts_manager->validateTokens($contexts));
216   }
217
218 }
219
220 /**
221  * Fake cache context class.
222  */
223 class FooCacheContext implements CacheContextInterface {
224
225   /**
226    * {@inheritdoc}
227    */
228   public static function getLabel() {
229     return 'Foo';
230   }
231
232   /**
233    * {@inheritdoc}
234    */
235   public function getContext() {
236     return 'bar';
237   }
238
239   /**
240    * {@inheritdoc}
241    */
242   public function getCacheableMetadata() {
243     return new CacheableMetadata();
244   }
245
246 }
247
248 /**
249  * Fake calculated cache context class.
250  */
251 class BazCacheContext implements CalculatedCacheContextInterface {
252
253   /**
254    * {@inheritdoc}
255    */
256   public static function getLabel() {
257     return 'Baz';
258   }
259
260   /**
261    * {@inheritdoc}
262    */
263   public function getContext($parameter = NULL) {
264     if (!is_string($parameter) || strlen($parameter) === 0) {
265       throw new \Exception();
266     }
267     return str_rot13($parameter);
268   }
269
270   /**
271    * {@inheritdoc}
272    */
273   public function getCacheableMetadata($parameter = NULL) {
274     return new CacheableMetadata();
275   }
276
277 }
278
279 /**
280  * Non-optimizable context class.
281  */
282 class NoOptimizeCacheContext implements CacheContextInterface {
283
284   /**
285    * {@inheritdoc}
286    */
287   public static function getLabel() {
288     return 'Foo';
289   }
290
291   /**
292    * {@inheritdoc}
293    */
294   public function getContext() {
295     return 'bar';
296   }
297
298   /**
299    * {@inheritdoc}
300    */
301   public function getCacheableMetadata() {
302     $cacheable_metadata = new CacheableMetadata();
303     return $cacheable_metadata->setCacheMaxAge(0);
304   }
305
306 }