Security update for Core, with self-updated composer
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Datetime / DateTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Datetime;
4
5 use Drupal\Core\Cache\CacheableMetadata;
6 use Drupal\Core\Datetime\DateFormatter;
7 use Drupal\Core\Datetime\FormattedDateDiff;
8 use Drupal\Core\DependencyInjection\ContainerBuilder;
9 use Drupal\Tests\UnitTestCase;
10 use Symfony\Component\HttpFoundation\Request;
11 use Drupal\Core\StringTranslation\TranslatableMarkup;
12
13 /**
14  * @coversDefaultClass \Drupal\Core\Datetime\DateFormatter
15  * @group Datetime
16  */
17 class DateTest extends UnitTestCase {
18
19   /**
20    * The mocked entity manager.
21    *
22    * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
23    */
24   protected $entityManager;
25
26   /**
27    * The mocked language manager.
28    *
29    * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
30    */
31   protected $languageManager;
32
33   /**
34    * The mocked string translation.
35    *
36    * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
37    */
38   protected $stringTranslation;
39
40   /**
41    * The mocked string translation.
42    *
43    * @var \Symfony\Component\HttpFoundation\RequestStack|\PHPUnit_Framework_MockObject_MockObject
44    */
45   protected $requestStack;
46
47   /**
48    * The mocked date formatter class.
49    *
50    * @var \Drupal\Core\Datetime\DateFormatter
51    */
52   protected $dateFormatter;
53
54   /**
55    * The date formatter class where methods can be stubbed.
56    *
57    * @var \Drupal\Core\Datetime\DateFormatter|\PHPUnit_Framework_MockObject_MockObject
58    */
59   protected $dateFormatterStub;
60
61   protected function setUp() {
62     parent::setUp();
63
64     $entity_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
65
66     $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
67     $this->entityManager->expects($this->any())->method('getStorage')->with('date_format')->willReturn($entity_storage);
68
69     $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
70     $this->stringTranslation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
71     $this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack');
72
73     $config_factory = $this->getConfigFactoryStub(['system.date' => ['country' => ['default' => 'GB']]]);
74     $container = new ContainerBuilder();
75     $container->set('config.factory', $config_factory);
76     $container->set('string_translation', $this->getStringTranslationStub());
77     \Drupal::setContainer($container);
78
79     $this->dateFormatter = new DateFormatter($this->entityManager, $this->languageManager, $this->stringTranslation, $this->getConfigFactoryStub(), $this->requestStack);
80
81     $this->dateFormatterStub = $this->getMockBuilder('\Drupal\Core\Datetime\DateFormatter')
82       ->setConstructorArgs([$this->entityManager, $this->languageManager, $this->stringTranslation, $this->getConfigFactoryStub(), $this->requestStack])
83       ->setMethods(['formatDiff'])
84       ->getMock();
85   }
86
87   /**
88    * Tests the formatInterval method.
89    *
90    * @dataProvider providerTestFormatInterval
91    *
92    * @covers ::formatInterval
93    */
94   public function testFormatInterval($interval, $granularity, $expected, $langcode = NULL) {
95     // Mocks a simple formatPlural implementation.
96     $this->stringTranslation->expects($this->any())
97       ->method('translateString')
98       ->willReturnCallback(function (TranslatableMarkup $arg) {
99         return $arg->getUntranslatedString();
100       });
101
102     // Check if the granularity is specified.
103     if ($granularity) {
104       $result = $this->dateFormatter->formatInterval($interval, $granularity, $langcode);
105     }
106     else {
107       $result = $this->dateFormatter->formatInterval($interval);
108     }
109
110     $this->assertEquals(new TranslatableMarkup($expected, [], ['langcode' => $langcode], $this->stringTranslation), $result);
111   }
112
113   /**
114    * Provides some test data for the format interval test.
115    */
116   public function providerTestFormatInterval() {
117     $data = [
118       // Checks for basic seconds.
119       [1, 1, '1 sec'],
120       [1, 2, '1 sec'],
121       [2, 1, '2 sec'],
122       [2, 2, '2 sec'],
123       // Checks for minutes with seconds.
124       [61, 1, '1 min'],
125       [61, 2, '1 min 1 sec'],
126       [62, 2, '1 min 2 sec'],
127       [121, 1, '2 min'],
128       [121, 2, '2 min 1 sec'],
129       // Check for hours with minutes and seconds.
130       [3601, 1, '1 hour'],
131       [3601, 2, '1 hour'],
132       // Check for higher units.
133       [86401, 1, '1 day'],
134       [604800, 1, '1 week'],
135       [2592000 * 2, 1, '2 months'],
136       [31536000 * 2, 1, '2 years'],
137       // Check for a complicated one with months weeks and days.
138       [2592000 * 2 + 604800 * 3 + 86400 * 4, 3, '2 months 3 weeks 4 days'],
139       // Check for the langcode.
140       [61, 1, '1 min', 'xxx-lolspeak'],
141       // Check with an unspecified granularity.
142       [61, NULL, '1 min 1 sec'],
143     ];
144
145     return $data;
146   }
147
148   /**
149    * Tests the formatInterval method for 0 second.
150    */
151   public function testFormatIntervalZeroSecond() {
152     $result = $this->dateFormatter->formatInterval(0, 1, 'xxx-lolspeak');
153     $this->assertEquals(new TranslatableMarkup('0 sec', [], ['langcode' => 'xxx-lolspeak'], $this->stringTranslation), $result);
154   }
155
156   /**
157    * Tests the getSampleDateFormats method.
158    *
159    * @covers \Drupal\Core\Datetime\DateFormatter::getSampleDateFormats
160    */
161   public function testGetSampleDateFormats() {
162     $timestamp = strtotime('2015-03-22 14:23:00');
163     $expected = $this->dateFormatter->getSampleDateFormats('en', $timestamp, 'Australia/Sydney');
164
165     // Removed characters related to timezone 'e' and 'T', as test does not have
166     // timezone set.
167     $date_characters = 'dDjlNSwzWFmMntLoYyaABgGhHisuIOPZcrU';
168     $date_chars = str_split($date_characters);
169
170     foreach ($date_chars as $val) {
171       $this->assertEquals($expected[$val], date($val, $timestamp));
172     }
173   }
174
175   /**
176    * Tests the formatTimeDiffUntil method.
177    *
178    * @covers ::formatTimeDiffUntil
179    */
180   public function testFormatTimeDiffUntil() {
181     $expected = '1 second';
182     $request_time = $this->createTimestamp('2013-12-11 10:09:08');
183     $timestamp = $this->createTimestamp('2013-12-11 10:09:09');
184     $options = [];
185
186     // Mocks the formatDiff function of the dateformatter object.
187     $this->dateFormatterStub
188       ->expects($this->at(0))
189       ->method('formatDiff')
190       ->with($timestamp, $request_time, $options)
191       ->will($this->returnValue($expected));
192
193     $this->dateFormatterStub
194       ->expects($this->at(1))
195       ->method('formatDiff')
196       ->with($timestamp, $request_time, $options + ['return_as_object' => TRUE])
197       ->will($this->returnValue(new FormattedDateDiff('1 second', 1)));
198
199     $request = Request::createFromGlobals();
200     $request->server->set('REQUEST_TIME', $request_time);
201     // Mocks a the request stack getting the current request.
202     $this->requestStack->expects($this->any())
203       ->method('getCurrentRequest')
204       ->willReturn($request);
205
206     $this->assertEquals($expected, $this->dateFormatterStub->formatTimeDiffSince($timestamp, $options));
207     $options['return_as_object'] = TRUE;
208     $expected_object = new FormattedDateDiff('1 second', 1);
209     $this->assertEquals($expected_object, $this->dateFormatterStub->formatTimeDiffSince($timestamp, $options));
210   }
211
212   /**
213    * Tests the formatTimeDiffSince method.
214    *
215    * @covers ::formatTimeDiffSince
216    */
217   public function testFormatTimeDiffSince() {
218     $expected = '1 second';
219     $timestamp = $this->createTimestamp('2013-12-11 10:09:07');
220     $request_time = $this->createTimestamp('2013-12-11 10:09:08');
221     $options = [];
222
223     // Mocks the formatDiff function of the dateformatter object.
224     $this->dateFormatterStub
225       ->expects($this->at(0))
226       ->method('formatDiff')
227       ->with($request_time, $timestamp, $options)
228       ->will($this->returnValue($expected));
229
230     $this->dateFormatterStub
231       ->expects($this->at(1))
232       ->method('formatDiff')
233       ->with($request_time, $timestamp, $options + ['return_as_object' => TRUE])
234       ->will($this->returnValue(new FormattedDateDiff('1 second', 1)));
235
236     $request = Request::createFromGlobals();
237     $request->server->set('REQUEST_TIME', $request_time);
238     // Mocks a the request stack getting the current request.
239     $this->requestStack->expects($this->any())
240       ->method('getCurrentRequest')
241       ->willReturn($request);
242
243     $this->assertEquals($expected, $this->dateFormatterStub->formatTimeDiffUntil($timestamp, $options));
244     $options['return_as_object'] = TRUE;
245     $expected_object = new FormattedDateDiff('1 second', 1);
246     $this->assertEquals($expected_object, $this->dateFormatterStub->formatTimeDiffUntil($timestamp, $options));
247   }
248
249   /**
250    * Tests the formatDiff method.
251    *
252    * @dataProvider providerTestFormatDiff
253    *
254    * @covers ::formatDiff
255    */
256   public function testformatDiff($expected, $max_age, $timestamp1, $timestamp2, $options = []) {
257     // Mocks a simple translateString implementation.
258     $this->stringTranslation->expects($this->any())
259       ->method('translateString')
260       ->willReturnCallback(function (TranslatableMarkup $arg) {
261         return $arg->getUntranslatedString();
262       });
263
264     if (isset($options['langcode'])) {
265       $expected_markup = new TranslatableMarkup($expected, [], ['langcode' => $options['langcode']], $this->stringTranslation);
266     }
267     else {
268       $expected_markup = new TranslatableMarkup($expected, [], [], $this->stringTranslation);
269     }
270     $this->assertEquals($expected_markup, $this->dateFormatter->formatDiff($timestamp1, $timestamp2, $options));
271
272     $options['return_as_object'] = TRUE;
273     $expected_object = new FormattedDateDiff($expected, $max_age);
274     $this->assertEquals($expected_object, $this->dateFormatter->formatDiff($timestamp1, $timestamp2, $options));
275   }
276
277   /**
278    * Data provider for testformatDiff().
279    */
280   public function providerTestFormatDiff() {
281     // This is the fixed request time in the test.
282     $request_time = $this->createTimestamp('2013-12-11 10:09:08');
283
284     $granularity_3 = ['granularity' => 3];
285     $granularity_4 = ['granularity' => 4];
286
287     $langcode_en = ['langcode' => 'en'];
288     $langcode_lolspeak = ['langcode' => 'xxx-lolspeak'];
289
290     $non_strict = ['strict' => FALSE];
291
292     $data = [
293       // Checks for equal timestamps.
294       ['0 seconds', 0, $request_time, $request_time],
295
296       // Checks for seconds only.
297       ['1 second', 1, $this->createTimestamp('2013-12-11 10:09:07'), $request_time],
298       ['1 second', 1, $this->createTimestamp('2013-12-11 10:09:07'), $request_time],
299       ['1 second', 1, $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $granularity_3 + $langcode_en],
300       ['1 second', 1, $this->createTimestamp('2013-12-11 10:09:07'), $request_time, $granularity_4 + $langcode_lolspeak],
301       ['2 seconds', 1, $this->createTimestamp('2013-12-11 10:09:06'), $request_time],
302       ['59 seconds', 1, $this->createTimestamp('2013-12-11 10:08:09'), $request_time],
303       ['59 seconds', 1, $this->createTimestamp('2013-12-11 10:08:09'), $request_time],
304
305       // Checks for minutes and possibly seconds.
306       ['1 minute', 60, $this->createTimestamp('2013-12-11 10:08:08'), $request_time],
307       ['1 minute', 60, $this->createTimestamp('2013-12-11 10:08:08'), $request_time],
308       ['1 minute 1 second', 1, $this->createTimestamp('2013-12-11 10:08:07'), $request_time],
309       ['1 minute 59 seconds', 1, $this->createTimestamp('2013-12-11 10:07:09'), $request_time],
310       ['2 minutes', 60, $this->createTimestamp('2013-12-11 10:07:08'), $request_time],
311       ['2 minutes 1 second', 1, $this->createTimestamp('2013-12-11 10:07:07'), $request_time],
312       ['2 minutes 2 seconds', 1, $this->createTimestamp('2013-12-11 10:07:06'), $request_time],
313       ['2 minutes 2 seconds', 1, $this->createTimestamp('2013-12-11 10:07:06'), $request_time, $granularity_3],
314       ['2 minutes 2 seconds', 1, $this->createTimestamp('2013-12-11 10:07:06'), $request_time, $granularity_4],
315       ['30 minutes', 60, $this->createTimestamp('2013-12-11 09:39:08'), $request_time],
316       ['59 minutes 59 seconds', 1, $this->createTimestamp('2013-12-11 09:09:09'), $request_time],
317       ['59 minutes 59 seconds', 1, $this->createTimestamp('2013-12-11 09:09:09'), $request_time],
318
319       // Checks for hours and possibly minutes or seconds.
320       ['1 hour', 3600, $this->createTimestamp('2013-12-11 09:09:08'), $request_time],
321       ['1 hour', 3600, $this->createTimestamp('2013-12-11 09:09:08'), $request_time],
322       ['1 hour', 3600, $this->createTimestamp('2013-12-11 09:09:07'), $request_time],
323       ['1 hour', 3600, $this->createTimestamp('2013-12-11 09:09:06'), $request_time],
324       ['1 hour 1 minute', 60, $this->createTimestamp('2013-12-11 09:08:08'), $request_time],
325       ['1 hour 1 minute 1 second', 1, $this->createTimestamp('2013-12-11 09:08:07'), $request_time, $granularity_3],
326       ['1 hour 1 minute 2 seconds', 1, $this->createTimestamp('2013-12-11 09:08:06'), $request_time, $granularity_4],
327       ['1 hour 30 minutes', 60, $this->createTimestamp('2013-12-11 08:39:08'), $request_time],
328       ['2 hours', 3600, $this->createTimestamp('2013-12-11 08:09:08'), $request_time],
329       ['23 hours 59 minutes', 60, $this->createTimestamp('2013-12-10 10:10:08'), $request_time],
330
331       // Checks for days and possibly hours, minutes or seconds.
332       ['1 day', 86400, $this->createTimestamp('2013-12-10 10:09:08'), $request_time],
333       ['1 day', 86400, $this->createTimestamp('2013-12-10 10:09:07'), $request_time],
334       ['1 day 1 hour', 3600, $this->createTimestamp('2013-12-10 09:09:08'), $request_time],
335       ['1 day 1 hour 1 minute', 60, $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_3 + $langcode_en],
336       ['1 day 1 hour 1 minute 1 second', 1, $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_4 + $langcode_lolspeak],
337       ['1 day 2 hours 2 minutes 2 seconds', 1, $this->createTimestamp('2013-12-10 08:07:06'), $request_time, $granularity_4],
338       ['2 days', 86400, $this->createTimestamp('2013-12-09 10:09:08'), $request_time],
339       ['2 days', 86400, $this->createTimestamp('2013-12-09 10:07:08'), $request_time],
340       ['2 days 2 hours', 3600, $this->createTimestamp('2013-12-09 08:09:08'), $request_time],
341       ['2 days 2 hours 2 minutes', 60, $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_3 + $langcode_en],
342       ['2 days 2 hours 2 minutes 2 seconds', 1, $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_4 + $langcode_lolspeak],
343
344       // Checks for weeks and possibly days, hours, minutes or seconds.
345       ['1 week', 7 * 86400, $this->createTimestamp('2013-12-04 10:09:08'), $request_time],
346       ['1 week 1 day', 86400, $this->createTimestamp('2013-12-03 10:09:08'), $request_time],
347       ['2 weeks', 7 * 86400, $this->createTimestamp('2013-11-27 10:09:08'), $request_time],
348       ['2 weeks 2 days', 86400, $this->createTimestamp('2013-11-25 08:07:08'), $request_time],
349       ['2 weeks 2 days 2 hours 2 minutes', 60, $this->createTimestamp('2013-11-25 08:07:08'), $request_time, $granularity_4],
350       ['4 weeks', 7 * 86400, $this->createTimestamp('2013-11-13 10:09:08'), $request_time],
351       ['4 weeks 1 day', 86400, $this->createTimestamp('2013-11-12 10:09:08'), $request_time],
352
353       // Checks for months and possibly days, hours, minutes or seconds.
354       ['1 month', 30 * 86400, $this->createTimestamp('2013-11-11 10:09:08'), $request_time],
355       ['1 month', 30 * 86400, $this->createTimestamp('2013-11-11 10:09:07'), $request_time],
356       ['1 month', 30 * 86400, $this->createTimestamp('2013-11-11 09:09:08'), $request_time],
357       ['1 month', 30 * 86400, $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_3],
358       ['1 month', 30 * 86400, $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_4],
359       ['1 month 4 weeks', 7 * 86400, $this->createTimestamp('2013-10-13 10:09:08'), $request_time],
360       ['1 month 4 weeks 1 day', 86400, $this->createTimestamp('2013-10-13 10:09:08'), $request_time, $granularity_3],
361       ['1 month 4 weeks', 7 * 86400, $this->createTimestamp('2013-10-12 10:09:08'), $request_time],
362       ['1 month 4 weeks 2 days', 86400, $this->createTimestamp('2013-10-12 10:09:08'), $request_time, $granularity_3],
363       ['2 months', 30 * 86400, $this->createTimestamp('2013-10-11 10:09:08'), $request_time],
364       ['2 months', 30 * 86400, $this->createTimestamp('2013-10-10 10:09:08'), $request_time],
365       ['2 months', 30 * 86400, $this->createTimestamp('2013-10-09 08:07:06'), $request_time],
366       ['2 months', 30 * 86400, $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_3],
367       ['2 months', 30 * 86400, $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_4],
368       ['6 months', 30 * 86400, $this->createTimestamp('2013-06-09 10:09:08'), $request_time],
369       ['11 months', 30 * 86400, $this->createTimestamp('2013-01-11 07:09:08'), $request_time],
370       ['11 months 4 weeks', 7 * 86400, $this->createTimestamp('2012-12-12 10:09:08'), $request_time],
371       ['11 months 4 weeks 2 days', 86400, $this->createTimestamp('2012-12-12 10:09:08'), $request_time, $granularity_3],
372
373       // Checks for years and possibly months, days, hours, minutes or seconds.
374       ['1 year', 365 * 86400, $this->createTimestamp('2012-12-11 10:09:08'), $request_time],
375       ['1 year', 365 * 86400, $this->createTimestamp('2012-12-11 10:08:08'), $request_time],
376       ['1 year', 365 * 86400, $this->createTimestamp('2012-12-10 10:09:08'), $request_time],
377       ['2 years', 365 * 86400, $this->createTimestamp('2011-12-11 10:09:08'), $request_time],
378       ['2 years', 365 * 86400, $this->createTimestamp('2011-12-11 10:07:08'), $request_time],
379       ['2 years', 365 * 86400, $this->createTimestamp('2011-12-09 10:09:08'), $request_time],
380       ['2 years 2 months', 30 * 86400, $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_3],
381       ['2 years 2 months', 30 * 86400, $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_4],
382       ['10 years', 365 * 86400, $this->createTimestamp('2003-12-11 10:09:08'), $request_time],
383       ['100 years', 365 * 86400, $this->createTimestamp('1913-12-11 10:09:08'), $request_time],
384
385       // Checks the non-strict option vs. strict (default).
386       ['1 second', 1, $this->createTimestamp('2013-12-11 10:09:08'), $this->createTimestamp('2013-12-11 10:09:07'), $non_strict],
387       ['0 seconds', 0, $this->createTimestamp('2013-12-11 10:09:08'), $this->createTimestamp('2013-12-11 10:09:07')],
388
389       // Checks granularity limit.
390       ['2 years 3 months 1 week', 7 * 86400, $this->createTimestamp('2011-08-30 11:15:57'), $request_time, $granularity_3],
391     ];
392
393     return $data;
394   }
395
396   /**
397    * Tests FormattedDateDiff.
398    *
399    * @covers \Drupal\Core\Datetime\FormattedDateDiff::toRenderable
400    * @covers \Drupal\Core\Datetime\FormattedDateDiff::getString
401    * @covers \Drupal\Core\Datetime\FormattedDateDiff::getCacheMaxAge
402    */
403   public function testFormattedDateDiff() {
404     $string = '10 minutes';
405     $max_age = 60;
406     $object = new FormattedDateDiff($string, $max_age);
407
408     // Test conversion to a render array.
409     $expected = [
410       '#markup' => $string,
411       '#cache' => [
412         'max-age' => $max_age,
413       ],
414     ];
415     $this->assertArrayEquals($expected, $object->toRenderable());
416
417     // Test retrieving the formatted time difference string.
418     $this->assertEquals($string, $object->getString());
419
420     // Test applying cacheability data to an existing build.
421     $build = [];
422     CacheableMetadata::createFromObject($object)->applyTo($build);
423     $this->assertEquals($max_age, $build['#cache']['max-age']);
424     // Test the BC layer.
425     $this->assertSame($object->getCacheMaxAge(), $object->getMaxAge());
426   }
427
428   /**
429    * Creates a UNIX timestamp given a date and time string in the format
430    * year-month-day hour:minute:seconds (e.g. 2013-12-11 10:09:08).
431    *
432    * @param string $dateTimeString
433    *   The formatted date and time string.
434    *
435    * @return int
436    *   The UNIX timestamp.
437    */
438   private function createTimestamp($dateTimeString) {
439     return \DateTime::createFromFormat('Y-m-d G:i:s', $dateTimeString)->getTimestamp();
440   }
441
442 }