Pull merge.
[yaffs-website] / web / core / tests / Drupal / Tests / UnitTestCase.php
1 <?php
2
3 namespace Drupal\Tests;
4
5 use Drupal\Component\FileCache\FileCacheFactory;
6 use Drupal\Component\Utility\NestedArray;
7 use Drupal\Component\Utility\Random;
8 use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
9 use Drupal\Core\DependencyInjection\ContainerBuilder;
10 use Drupal\Core\StringTranslation\TranslatableMarkup;
11 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
12 use PHPUnit\Framework\TestCase;
13
14 /**
15  * Provides a base class and helpers for Drupal unit tests.
16  *
17  * @ingroup testing
18  */
19 abstract class UnitTestCase extends TestCase {
20
21   use PhpunitCompatibilityTrait;
22
23   /**
24    * The random generator.
25    *
26    * @var \Drupal\Component\Utility\Random
27    */
28   protected $randomGenerator;
29
30   /**
31    * The app root.
32    *
33    * @var string
34    */
35   protected $root;
36
37   /**
38    * {@inheritdoc}
39    */
40   protected function setUp() {
41     parent::setUp();
42     // Ensure that an instantiated container in the global state of \Drupal from
43     // a previous test does not leak into this test.
44     \Drupal::unsetContainer();
45
46     // Ensure that the NullFileCache implementation is used for the FileCache as
47     // unit tests should not be relying on caches implicitly.
48     FileCacheFactory::setConfiguration([FileCacheFactory::DISABLE_CACHE => TRUE]);
49     // Ensure that FileCacheFactory has a prefix.
50     FileCacheFactory::setPrefix('prefix');
51
52     $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
53   }
54
55   /**
56    * Generates a unique random string containing letters and numbers.
57    *
58    * @param int $length
59    *   Length of random string to generate.
60    *
61    * @return string
62    *   Randomly generated unique string.
63    *
64    * @see \Drupal\Component\Utility\Random::name()
65    */
66   public function randomMachineName($length = 8) {
67     return $this->getRandomGenerator()->name($length, TRUE);
68   }
69
70   /**
71    * Gets the random generator for the utility methods.
72    *
73    * @return \Drupal\Component\Utility\Random
74    *   The random generator
75    */
76   protected function getRandomGenerator() {
77     if (!is_object($this->randomGenerator)) {
78       $this->randomGenerator = new Random();
79     }
80     return $this->randomGenerator;
81   }
82
83   /**
84    * Asserts if two arrays are equal by sorting them first.
85    *
86    * @param array $expected
87    * @param array $actual
88    * @param string $message
89    */
90   protected function assertArrayEquals(array $expected, array $actual, $message = NULL) {
91     ksort($expected);
92     ksort($actual);
93     $this->assertEquals($expected, $actual, $message);
94   }
95
96   /**
97    * Returns a stub config factory that behaves according to the passed array.
98    *
99    * Use this to generate a config factory that will return the desired values
100    * for the given config names.
101    *
102    * @param array $configs
103    *   An associative array of configuration settings whose keys are
104    *   configuration object names and whose values are key => value arrays for
105    *   the configuration object in question. Defaults to an empty array.
106    *
107    * @return \PHPUnit_Framework_MockObject_MockBuilder
108    *   A MockBuilder object for the ConfigFactory with the desired return
109    *   values.
110    */
111   public function getConfigFactoryStub(array $configs = []) {
112     $config_get_map = [];
113     $config_editable_map = [];
114     // Construct the desired configuration object stubs, each with its own
115     // desired return map.
116     foreach ($configs as $config_name => $config_values) {
117       // Define a closure over the $config_values, which will be used as a
118       // returnCallback below. This function will mimic
119       // \Drupal\Core\Config\Config::get and allow using dotted keys.
120       $config_get = function ($key = '') use ($config_values) {
121         // Allow to pass in no argument.
122         if (empty($key)) {
123           return $config_values;
124         }
125         // See if we have the key as is.
126         if (isset($config_values[$key])) {
127           return $config_values[$key];
128         }
129         $parts = explode('.', $key);
130         $value = NestedArray::getValue($config_values, $parts, $key_exists);
131         return $key_exists ? $value : NULL;
132       };
133
134       $immutable_config_object = $this->getMockBuilder('Drupal\Core\Config\ImmutableConfig')
135         ->disableOriginalConstructor()
136         ->getMock();
137       $immutable_config_object->expects($this->any())
138         ->method('get')
139         ->will($this->returnCallback($config_get));
140       $config_get_map[] = [$config_name, $immutable_config_object];
141
142       $mutable_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
143         ->disableOriginalConstructor()
144         ->getMock();
145       $mutable_config_object->expects($this->any())
146         ->method('get')
147         ->will($this->returnCallback($config_get));
148       $config_editable_map[] = [$config_name, $mutable_config_object];
149     }
150     // Construct a config factory with the array of configuration object stubs
151     // as its return map.
152     $config_factory = $this->createMock('Drupal\Core\Config\ConfigFactoryInterface');
153     $config_factory->expects($this->any())
154       ->method('get')
155       ->will($this->returnValueMap($config_get_map));
156     $config_factory->expects($this->any())
157       ->method('getEditable')
158       ->will($this->returnValueMap($config_editable_map));
159     return $config_factory;
160   }
161
162   /**
163    * Returns a stub config storage that returns the supplied configuration.
164    *
165    * @param array $configs
166    *   An associative array of configuration settings whose keys are
167    *   configuration object names and whose values are key => value arrays
168    *   for the configuration object in question.
169    *
170    * @return \Drupal\Core\Config\StorageInterface
171    *   A mocked config storage.
172    */
173   public function getConfigStorageStub(array $configs) {
174     $config_storage = $this->createMock('Drupal\Core\Config\NullStorage');
175     $config_storage->expects($this->any())
176       ->method('listAll')
177       ->will($this->returnValue(array_keys($configs)));
178
179     foreach ($configs as $name => $config) {
180       $config_storage->expects($this->any())
181         ->method('read')
182         ->with($this->equalTo($name))
183         ->will($this->returnValue($config));
184     }
185     return $config_storage;
186   }
187
188   /**
189    * Mocks a block with a block plugin.
190    *
191    * @param string $machine_name
192    *   The machine name of the block plugin.
193    *
194    * @return \Drupal\block\BlockInterface|\PHPUnit_Framework_MockObject_MockObject
195    *   The mocked block.
196    *
197    * @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Unit test
198    *   base classes should not have dependencies on extensions. Set up mocks in
199    *   individual tests.
200    *
201    * @see https://www.drupal.org/node/2896072
202    */
203   protected function getBlockMockWithMachineName($machine_name) {
204     $plugin = $this->getMockBuilder('Drupal\Core\Block\BlockBase')
205       ->disableOriginalConstructor()
206       ->getMock();
207     $plugin->expects($this->any())
208       ->method('getMachineNameSuggestion')
209       ->will($this->returnValue($machine_name));
210
211     $block = $this->getMockBuilder('Drupal\block\Entity\Block')
212       ->disableOriginalConstructor()
213       ->getMock();
214     $block->expects($this->any())
215       ->method('getPlugin')
216       ->will($this->returnValue($plugin));
217     @trigger_error(__METHOD__ . ' is deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Unit test base classes should not have dependencies on extensions. Set up mocks in individual tests.', E_USER_DEPRECATED);
218     return $block;
219   }
220
221   /**
222    * Returns a stub translation manager that just returns the passed string.
223    *
224    * @return \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\StringTranslation\TranslationInterface
225    *   A mock translation object.
226    */
227   public function getStringTranslationStub() {
228     $translation = $this->createMock('Drupal\Core\StringTranslation\TranslationInterface');
229     $translation->expects($this->any())
230       ->method('translate')
231       ->willReturnCallback(function ($string, array $args = [], array $options = []) use ($translation) {
232         return new TranslatableMarkup($string, $args, $options, $translation);
233       });
234     $translation->expects($this->any())
235       ->method('translateString')
236       ->willReturnCallback(function (TranslatableMarkup $wrapper) {
237         return $wrapper->getUntranslatedString();
238       });
239     $translation->expects($this->any())
240       ->method('formatPlural')
241       ->willReturnCallback(function ($count, $singular, $plural, array $args = [], array $options = []) use ($translation) {
242         $wrapper = new PluralTranslatableMarkup($count, $singular, $plural, $args, $options, $translation);
243         return $wrapper;
244       });
245     return $translation;
246   }
247
248   /**
249    * Sets up a container with a cache tags invalidator.
250    *
251    * @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_validator
252    *   The cache tags invalidator.
253    *
254    * @return \Symfony\Component\DependencyInjection\ContainerInterface|\PHPUnit_Framework_MockObject_MockObject
255    *   The container with the cache tags invalidator service.
256    */
257   protected function getContainerWithCacheTagsInvalidator(CacheTagsInvalidatorInterface $cache_tags_validator) {
258     $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerInterface');
259     $container->expects($this->any())
260       ->method('get')
261       ->with('cache_tags.invalidator')
262       ->will($this->returnValue($cache_tags_validator));
263
264     \Drupal::setContainer($container);
265     return $container;
266   }
267
268   /**
269    * Returns a stub class resolver.
270    *
271    * @return \Drupal\Core\DependencyInjection\ClassResolverInterface|\PHPUnit_Framework_MockObject_MockObject
272    *   The class resolver stub.
273    */
274   protected function getClassResolverStub() {
275     $class_resolver = $this->createMock('Drupal\Core\DependencyInjection\ClassResolverInterface');
276     $class_resolver->expects($this->any())
277       ->method('getInstanceFromDefinition')
278       ->will($this->returnCallback(function ($class) {
279         if (is_subclass_of($class, 'Drupal\Core\DependencyInjection\ContainerInjectionInterface')) {
280           return $class::create(new ContainerBuilder());
281         }
282         else {
283           return new $class();
284         }
285       }));
286     return $class_resolver;
287   }
288
289 }