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, ['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 [
  72. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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, ['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 [
  154. ['PT0S', 0, 0, '0s', '0s'],
  155. ['PT0S', 0.1, 0, $withMs ? '+ 00:00:00.100' : '0s', '%is'],
  156. ['PT1S', 0, 0, '+ 00:00:01'.$ms, '%is'],
  157. ['PT2M', 0, 0, '+ 00:02:00'.$ms, '%is'],
  158. ['PT3H', 0, 0, '+ 03:00:00'.$ms, '%ss'],
  159. ['P4D', 0, 0, '+ 4d', '%ss'],
  160. ['P5M', 0, 0, '+ 5m', null],
  161. ['P6Y', 0, 0, '+ 6y', null],
  162. ['P1Y2M3DT4H5M6S', 0, 0, '+ 1y 2m 3d 04:05:06'.$ms, null],
  163. ['PT1M60S', 0, 0, '+ 00:02:00'.$ms, null],
  164. ['PT1H60M', 0, 0, '+ 02:00:00'.$ms, null],
  165. ['P1DT24H', 0, 0, '+ 2d', null],
  166. ['P1M32D', 0, 0, '+ 1m 32d', null],
  167. ['PT0S', 0, 1, '0s', '0s'],
  168. ['PT0S', 0.1, 1, $withMs ? '- 00:00:00.100' : '0s', '%is'],
  169. ['PT1S', 0, 1, '- 00:00:01'.$ms, '%is'],
  170. ['PT2M', 0, 1, '- 00:02:00'.$ms, '%is'],
  171. ['PT3H', 0, 1, '- 03:00:00'.$ms, '%ss'],
  172. ['P4D', 0, 1, '- 4d', '%ss'],
  173. ['P5M', 0, 1, '- 5m', null],
  174. ['P6Y', 0, 1, '- 6y', null],
  175. ['P1Y2M3DT4H5M6S', 0, 1, '- 1y 2m 3d 04:05:06'.$ms, null],
  176. ['PT1M60S', 0, 1, '- 00:02:00'.$ms, null],
  177. ['PT1H60M', 0, 1, '- 02:00:00'.$ms, null],
  178. ['P1DT24H', 0, 1, '- 2d', null],
  179. ['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, ['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 [
  249. // type 1 (UTC offset)
  250. ['-12:00', '-12:00', ''],
  251. ['+00:00', '+00:00', ''],
  252. ['+14:00', '+14:00', ''],
  253. // type 2 (timezone abbreviation)
  254. ['GMT', '+00:00', ''],
  255. ['a', '+01:00', ''],
  256. ['b', '+02:00', ''],
  257. ['z', '+00:00', ''],
  258. // type 3 (timezone identifier)
  259. ['Africa/Tunis', 'Africa/Tunis (%s:00)', $xRegion],
  260. ['America/Panama', 'America/Panama (%s:00)', $xRegion],
  261. ['Asia/Jerusalem', 'Asia/Jerusalem (%s:00)', $xRegion],
  262. ['Atlantic/Canary', 'Atlantic/Canary (%s:00)', $xRegion],
  263. ['Australia/Perth', 'Australia/Perth (%s:00)', $xRegion],
  264. ['Europe/Zurich', 'Europe/Zurich (%s:00)', $xRegion],
  265. ['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, [], $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 = [
  320. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. ['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. }