DateCasterTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\VarDumper\Tests\Caster;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\VarDumper\Caster\Caster;
  13. use Symfony\Component\VarDumper\Caster\DateCaster;
  14. use Symfony\Component\VarDumper\Cloner\Stub;
  15. use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
  16. /**
  17. * @author Dany Maillard <danymaillard93b@gmail.com>
  18. */
  19. class DateCasterTest extends TestCase
  20. {
  21. use VarDumperTestTrait;
  22. /**
  23. * @dataProvider provideDateTimes
  24. */
  25. public function testDumpDateTime($time, $timezone, $xDate, $xTimestamp)
  26. {
  27. if ((\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) && preg_match('/[-+]\d{2}:\d{2}/', $timezone)) {
  28. $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
  29. }
  30. $date = new \DateTime($time, new \DateTimeZone($timezone));
  31. $xDump = <<<EODUMP
  32. DateTime @$xTimestamp {
  33. date: $xDate
  34. }
  35. EODUMP;
  36. $this->assertDumpEquals($xDump, $date);
  37. }
  38. /**
  39. * @dataProvider provideDateTimes
  40. */
  41. public function testCastDateTime($time, $timezone, $xDate, $xTimestamp, $xInfos)
  42. {
  43. if ((\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) && preg_match('/[-+]\d{2}:\d{2}/', $timezone)) {
  44. $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
  45. }
  46. $stub = new Stub();
  47. $date = new \DateTime($time, new \DateTimeZone($timezone));
  48. $cast = DateCaster::castDateTime($date, array('foo' => 'bar'), $stub, false, 0);
  49. $xDump = <<<EODUMP
  50. array:1 [
  51. "\\x00~\\x00date" => $xDate
  52. ]
  53. EODUMP;
  54. $this->assertDumpEquals($xDump, $cast);
  55. $xDump = <<<EODUMP
  56. Symfony\Component\VarDumper\Caster\ConstStub {
  57. +type: 1
  58. +class: "$xDate"
  59. +value: "%A$xInfos%A"
  60. +cut: 0
  61. +handle: 0
  62. +refCount: 0
  63. +position: 0
  64. +attr: []
  65. }
  66. EODUMP;
  67. $this->assertDumpMatchesFormat($xDump, $cast["\0~\0date"]);
  68. }
  69. public function provideDateTimes()
  70. {
  71. return array(
  72. array('2017-04-30 00:00:00.000000', 'Europe/Zurich', '2017-04-30 00:00:00.0 Europe/Zurich (+02:00)', 1493503200, 'Sunday, April 30, 2017%Afrom now%ADST On'),
  73. array('2017-12-31 00:00:00.000000', 'Europe/Zurich', '2017-12-31 00:00:00.0 Europe/Zurich (+01:00)', 1514674800, 'Sunday, December 31, 2017%Afrom now%ADST Off'),
  74. array('2017-04-30 00:00:00.000000', '+02:00', '2017-04-30 00:00:00.0 +02:00', 1493503200, 'Sunday, April 30, 2017%Afrom now'),
  75. array('2017-04-30 00:00:00.100000', '+00:00', '2017-04-30 00:00:00.100 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  76. array('2017-04-30 00:00:00.120000', '+00:00', '2017-04-30 00:00:00.120 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  77. array('2017-04-30 00:00:00.123000', '+00:00', '2017-04-30 00:00:00.123 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  78. array('2017-04-30 00:00:00.123400', '+00:00', '2017-04-30 00:00:00.123400 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  79. array('2017-04-30 00:00:00.123450', '+00:00', '2017-04-30 00:00:00.123450 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  80. array('2017-04-30 00:00:00.123456', '+00:00', '2017-04-30 00:00:00.123456 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
  81. );
  82. }
  83. /**
  84. * @dataProvider provideIntervals
  85. */
  86. public function testDumpInterval($intervalSpec, $ms, $invert, $expected)
  87. {
  88. if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
  89. $this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
  90. }
  91. $interval = $this->createInterval($intervalSpec, $ms, $invert);
  92. $xDump = <<<EODUMP
  93. DateInterval {
  94. interval: $expected
  95. %A}
  96. EODUMP;
  97. $this->assertDumpMatchesFormat($xDump, $interval);
  98. }
  99. /**
  100. * @dataProvider provideIntervals
  101. */
  102. public function testDumpIntervalExcludingVerbosity($intervalSpec, $ms, $invert, $expected)
  103. {
  104. if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
  105. $this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
  106. }
  107. $interval = $this->createInterval($intervalSpec, $ms, $invert);
  108. $xDump = <<<EODUMP
  109. DateInterval {
  110. interval: $expected
  111. }
  112. EODUMP;
  113. $this->assertDumpEquals($xDump, $interval, Caster::EXCLUDE_VERBOSE);
  114. }
  115. /**
  116. * @dataProvider provideIntervals
  117. */
  118. public function testCastInterval($intervalSpec, $ms, $invert, $xInterval, $xSeconds)
  119. {
  120. if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
  121. $this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
  122. }
  123. $interval = $this->createInterval($intervalSpec, $ms, $invert);
  124. $stub = new Stub();
  125. $cast = DateCaster::castInterval($interval, array('foo' => 'bar'), $stub, false, Caster::EXCLUDE_VERBOSE);
  126. $xDump = <<<EODUMP
  127. array:1 [
  128. "\\x00~\\x00interval" => $xInterval
  129. ]
  130. EODUMP;
  131. $this->assertDumpEquals($xDump, $cast);
  132. if (null === $xSeconds) {
  133. return;
  134. }
  135. $xDump = <<<EODUMP
  136. Symfony\Component\VarDumper\Caster\ConstStub {
  137. +type: 1
  138. +class: "$xInterval"
  139. +value: "$xSeconds"
  140. +cut: 0
  141. +handle: 0
  142. +refCount: 0
  143. +position: 0
  144. +attr: []
  145. }
  146. EODUMP;
  147. $this->assertDumpMatchesFormat($xDump, $cast["\0~\0interval"]);
  148. }
  149. public function provideIntervals()
  150. {
  151. $i = new \DateInterval('PT0S');
  152. $ms = ($withMs = \PHP_VERSION_ID >= 70100 && isset($i->f)) ? '.0' : '';
  153. return array(
  154. array('PT0S', 0, 0, '0s', '0s'),
  155. array('PT0S', 0.1, 0, $withMs ? '+ 00:00:00.100' : '0s', '%is'),
  156. array('PT1S', 0, 0, '+ 00:00:01'.$ms, '%is'),
  157. array('PT2M', 0, 0, '+ 00:02:00'.$ms, '%is'),
  158. array('PT3H', 0, 0, '+ 03:00:00'.$ms, '%ss'),
  159. array('P4D', 0, 0, '+ 4d', '%ss'),
  160. array('P5M', 0, 0, '+ 5m', null),
  161. array('P6Y', 0, 0, '+ 6y', null),
  162. array('P1Y2M3DT4H5M6S', 0, 0, '+ 1y 2m 3d 04:05:06'.$ms, null),
  163. array('PT1M60S', 0, 0, '+ 00:02:00'.$ms, null),
  164. array('PT1H60M', 0, 0, '+ 02:00:00'.$ms, null),
  165. array('P1DT24H', 0, 0, '+ 2d', null),
  166. array('P1M32D', 0, 0, '+ 1m 32d', null),
  167. array('PT0S', 0, 1, '0s', '0s'),
  168. array('PT0S', 0.1, 1, $withMs ? '- 00:00:00.100' : '0s', '%is'),
  169. array('PT1S', 0, 1, '- 00:00:01'.$ms, '%is'),
  170. array('PT2M', 0, 1, '- 00:02:00'.$ms, '%is'),
  171. array('PT3H', 0, 1, '- 03:00:00'.$ms, '%ss'),
  172. array('P4D', 0, 1, '- 4d', '%ss'),
  173. array('P5M', 0, 1, '- 5m', null),
  174. array('P6Y', 0, 1, '- 6y', null),
  175. array('P1Y2M3DT4H5M6S', 0, 1, '- 1y 2m 3d 04:05:06'.$ms, null),
  176. array('PT1M60S', 0, 1, '- 00:02:00'.$ms, null),
  177. array('PT1H60M', 0, 1, '- 02:00:00'.$ms, null),
  178. array('P1DT24H', 0, 1, '- 2d', null),
  179. array('P1M32D', 0, 1, '- 1m 32d', null),
  180. );
  181. }
  182. /**
  183. * @dataProvider provideTimeZones
  184. */
  185. public function testDumpTimeZone($timezone, $expected)
  186. {
  187. if ((\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) && !preg_match('/\w+\/\w+/', $timezone)) {
  188. $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
  189. }
  190. $timezone = new \DateTimeZone($timezone);
  191. $xDump = <<<EODUMP
  192. DateTimeZone {
  193. timezone: $expected
  194. %A}
  195. EODUMP;
  196. $this->assertDumpMatchesFormat($xDump, $timezone);
  197. }
  198. /**
  199. * @dataProvider provideTimeZones
  200. */
  201. public function testDumpTimeZoneExcludingVerbosity($timezone, $expected)
  202. {
  203. if ((\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) && !preg_match('/\w+\/\w+/', $timezone)) {
  204. $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
  205. }
  206. $timezone = new \DateTimeZone($timezone);
  207. $xDump = <<<EODUMP
  208. DateTimeZone {
  209. timezone: $expected
  210. }
  211. EODUMP;
  212. $this->assertDumpMatchesFormat($xDump, $timezone, Caster::EXCLUDE_VERBOSE);
  213. }
  214. /**
  215. * @dataProvider provideTimeZones
  216. */
  217. public function testCastTimeZone($timezone, $xTimezone, $xRegion)
  218. {
  219. if ((\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID <= 50509) && !preg_match('/\w+\/\w+/', $timezone)) {
  220. $this->markTestSkipped('DateTimeZone GMT offsets are supported since 5.5.10. See https://github.com/facebook/hhvm/issues/5875 for HHVM.');
  221. }
  222. $timezone = new \DateTimeZone($timezone);
  223. $stub = new Stub();
  224. $cast = DateCaster::castTimeZone($timezone, array('foo' => 'bar'), $stub, false, Caster::EXCLUDE_VERBOSE);
  225. $xDump = <<<EODUMP
  226. array:1 [
  227. "\\x00~\\x00timezone" => $xTimezone
  228. ]
  229. EODUMP;
  230. $this->assertDumpMatchesFormat($xDump, $cast);
  231. $xDump = <<<EODUMP
  232. Symfony\Component\VarDumper\Caster\ConstStub {
  233. +type: 1
  234. +class: "$xTimezone"
  235. +value: "$xRegion"
  236. +cut: 0
  237. +handle: 0
  238. +refCount: 0
  239. +position: 0
  240. +attr: []
  241. }
  242. EODUMP;
  243. $this->assertDumpMatchesFormat($xDump, $cast["\0~\0timezone"]);
  244. }
  245. public function provideTimeZones()
  246. {
  247. $xRegion = \extension_loaded('intl') ? '%s' : '';
  248. return array(
  249. // type 1 (UTC offset)
  250. array('-12:00', '-12:00', ''),
  251. array('+00:00', '+00:00', ''),
  252. array('+14:00', '+14:00', ''),
  253. // type 2 (timezone abbreviation)
  254. array('GMT', '+00:00', ''),
  255. array('a', '+01:00', ''),
  256. array('b', '+02:00', ''),
  257. array('z', '+00:00', ''),
  258. // type 3 (timezone identifier)
  259. array('Africa/Tunis', 'Africa/Tunis (%s:00)', $xRegion),
  260. array('America/Panama', 'America/Panama (%s:00)', $xRegion),
  261. array('Asia/Jerusalem', 'Asia/Jerusalem (%s:00)', $xRegion),
  262. array('Atlantic/Canary', 'Atlantic/Canary (%s:00)', $xRegion),
  263. array('Australia/Perth', 'Australia/Perth (%s:00)', $xRegion),
  264. array('Europe/Zurich', 'Europe/Zurich (%s:00)', $xRegion),
  265. array('Pacific/Tahiti', 'Pacific/Tahiti (%s:00)', $xRegion),
  266. );
  267. }
  268. /**
  269. * @dataProvider providePeriods
  270. */
  271. public function testDumpPeriod($start, $interval, $end, $options, $expected)
  272. {
  273. if (\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID < 50620 || (\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70005)) {
  274. $this->markTestSkipped();
  275. }
  276. $p = new \DatePeriod(new \DateTime($start), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end), $options);
  277. $xDump = <<<EODUMP
  278. DatePeriod {
  279. period: $expected
  280. %A}
  281. EODUMP;
  282. $this->assertDumpMatchesFormat($xDump, $p);
  283. }
  284. /**
  285. * @dataProvider providePeriods
  286. */
  287. public function testCastPeriod($start, $interval, $end, $options, $xPeriod, $xDates)
  288. {
  289. if (\defined('HHVM_VERSION_ID') || \PHP_VERSION_ID < 50620 || (\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70005)) {
  290. $this->markTestSkipped();
  291. }
  292. $p = new \DatePeriod(new \DateTime($start), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end), $options);
  293. $stub = new Stub();
  294. $cast = DateCaster::castPeriod($p, array(), $stub, false, 0);
  295. $xDump = <<<EODUMP
  296. array:1 [
  297. "\\x00~\\x00period" => $xPeriod
  298. ]
  299. EODUMP;
  300. $this->assertDumpEquals($xDump, $cast);
  301. $xDump = <<<EODUMP
  302. Symfony\Component\VarDumper\Caster\ConstStub {
  303. +type: 1
  304. +class: "$xPeriod"
  305. +value: "%A$xDates%A"
  306. +cut: 0
  307. +handle: 0
  308. +refCount: 0
  309. +position: 0
  310. +attr: []
  311. }
  312. EODUMP;
  313. $this->assertDumpMatchesFormat($xDump, $cast["\0~\0period"]);
  314. }
  315. public function providePeriods()
  316. {
  317. $i = new \DateInterval('PT0S');
  318. $ms = \PHP_VERSION_ID >= 70100 && isset($i->f) ? '.0' : '';
  319. $periods = array(
  320. array('2017-01-01', 'P1D', '2017-01-03', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-03 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02'),
  321. array('2017-01-01', 'P1D', 1, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 2 time/s', '1) 2017-01-01%a2) 2017-01-02'),
  322. array('2017-01-01', 'P1D', '2017-01-04', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-04 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03'),
  323. array('2017-01-01', 'P1D', 2, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 3 time/s', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03'),
  324. array('2017-01-01', 'P1D', '2017-01-05', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-05 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02%a1 more'),
  325. array('2017-01-01', 'P1D', 3, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 4 time/s', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03%a1 more'),
  326. array('2017-01-01', 'P1D', '2017-01-21', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-21 00:00:00.0', '1) 2017-01-01%a17 more'),
  327. array('2017-01-01', 'P1D', 19, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 20 time/s', '1) 2017-01-01%a17 more'),
  328. array('2017-01-01 01:00:00', 'P1D', '2017-01-03 01:00:00', 0, 'every + 1d, from 2017-01-01 01:00:00.0 (included) to 2017-01-03 01:00:00.0', '1) 2017-01-01 01:00:00.0%a2) 2017-01-02 01:00:00.0'),
  329. array('2017-01-01 01:00:00', 'P1D', 1, 0, 'every + 1d, from 2017-01-01 01:00:00.0 (included) recurring 2 time/s', '1) 2017-01-01 01:00:00.0%a2) 2017-01-02 01:00:00.0'),
  330. array('2017-01-01', 'P1DT1H', '2017-01-03', 0, "every + 1d 01:00:00$ms, from 2017-01-01 00:00:00.0 (included) to 2017-01-03 00:00:00.0", '1) 2017-01-01 00:00:00.0%a2) 2017-01-02 01:00:00.0'),
  331. array('2017-01-01', 'P1DT1H', 1, 0, "every + 1d 01:00:00$ms, from 2017-01-01 00:00:00.0 (included) recurring 2 time/s", '1) 2017-01-01 00:00:00.0%a2) 2017-01-02 01:00:00.0'),
  332. array('2017-01-01', 'P1D', '2017-01-04', \DatePeriod::EXCLUDE_START_DATE, 'every + 1d, from 2017-01-01 00:00:00.0 (excluded) to 2017-01-04 00:00:00.0', '1) 2017-01-02%a2) 2017-01-03'),
  333. array('2017-01-01', 'P1D', 2, \DatePeriod::EXCLUDE_START_DATE, 'every + 1d, from 2017-01-01 00:00:00.0 (excluded) recurring 2 time/s', '1) 2017-01-02%a2) 2017-01-03'),
  334. );
  335. if (\PHP_VERSION_ID < 70107) {
  336. array_walk($periods, function (&$i) { $i[5] = ''; });
  337. }
  338. return $periods;
  339. }
  340. private function createInterval($intervalSpec, $ms, $invert)
  341. {
  342. $interval = new \DateInterval($intervalSpec);
  343. if (\PHP_VERSION_ID >= 70100 && isset($interval->f)) {
  344. $interval->f = $ms;
  345. }
  346. $interval->invert = $invert;
  347. return $interval;
  348. }
  349. }