SerializationTest.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of the Carbon package.
  5. *
  6. * (c) Brian Nesbitt <brian@nesbot.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Tests\Carbon;
  12. use Carbon\Carbon;
  13. use DateTime;
  14. use Generator;
  15. use InvalidArgumentException;
  16. use ReflectionClass;
  17. use ReflectionObject;
  18. use ReflectionProperty;
  19. use Tests\AbstractTestCase;
  20. use Throwable;
  21. class SerializationTest extends AbstractTestCase
  22. {
  23. /**
  24. * @var string
  25. */
  26. protected $serialized;
  27. protected function setUp(): void
  28. {
  29. parent::setUp();
  30. $this->serialized = \extension_loaded('msgpack')
  31. ? [
  32. "O:13:\"Carbon\Carbon\":4:{s:4:\"date\";s:26:\"2016-02-01 13:20:25.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:15:\"America/Toronto\";s:18:\"dumpDateProperties\";a:2:{s:4:\"date\";s:26:\"2016-02-01 13:20:25.000000\";s:8:\"timezone\";s:96:\"O:21:\"Carbon\CarbonTimeZone\":2:{s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:15:\"America/Toronto\";}\";}}",
  33. "O:13:\"Carbon\Carbon\":4:{s:4:\"date\";s:26:\"2016-02-01 13:20:25.000000\";s:13:\"timezone_type\";i:3;s:8:\"timezone\";s:15:\"America/Toronto\";s:18:\"dumpDateProperties\";a:2:{s:4:\"date\";s:26:\"2016-02-01 13:20:25.000000\";s:8:\"timezone\";s:23:\"s:15:\"America/Toronto\";\";}}",
  34. ]
  35. : ['O:13:"Carbon\Carbon":3:{s:4:"date";s:26:"2016-02-01 13:20:25.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:15:"America/Toronto";}'];
  36. }
  37. protected function cleanSerialization(string $serialization): string
  38. {
  39. return preg_replace('/s:\d+:\"[^"]*dumpDateProperties\"/', 's:18:"dumpDateProperties"', $serialization);
  40. }
  41. public function testSerialize()
  42. {
  43. $dt = Carbon::create(2016, 2, 1, 13, 20, 25);
  44. $message = "not in:\n".implode("\n", $this->serialized);
  45. $this->assertContains($this->cleanSerialization($dt->serialize()), $this->serialized, $message);
  46. $this->assertContains($this->cleanSerialization(serialize($dt)), $this->serialized, $message);
  47. }
  48. public function testFromUnserialized()
  49. {
  50. $dt = Carbon::fromSerialized($this->serialized[0]);
  51. $this->assertCarbon($dt, 2016, 2, 1, 13, 20, 25);
  52. $dt = unserialize($this->serialized[0]);
  53. $this->assertCarbon($dt, 2016, 2, 1, 13, 20, 25);
  54. }
  55. public function testSerialization()
  56. {
  57. $this->assertEquals(Carbon::now(), unserialize(serialize(Carbon::now())));
  58. $dt = Carbon::parse('2018-07-11 18:30:11.654321', 'Europe/Paris')->locale('fr_FR');
  59. $copy = unserialize(serialize($dt));
  60. $this->assertSame('fr_FR', $copy->locale);
  61. $this->assertSame('mercredi 18:30:11.654321', $copy->tz('Europe/Paris')->isoFormat('dddd HH:mm:ss.SSSSSS'));
  62. }
  63. public static function dataForTestFromUnserializedWithInvalidValue(): Generator
  64. {
  65. yield [null];
  66. yield [true];
  67. yield [false];
  68. yield [123];
  69. yield ['foobar'];
  70. }
  71. /**
  72. * @param mixed $value
  73. *
  74. * @dataProvider \Tests\Carbon\SerializationTest::dataForTestFromUnserializedWithInvalidValue
  75. */
  76. public function testFromUnserializedWithInvalidValue($value)
  77. {
  78. $this->expectExceptionObject(new InvalidArgumentException(
  79. "Invalid serialized value: $value"
  80. ));
  81. Carbon::fromSerialized($value);
  82. }
  83. public function testDateSerializationReflectionCompatibility()
  84. {
  85. $tz = $this->firstValidTimezoneAmong(['America/Los_Angeles', 'US/Pacific'])->getName();
  86. try {
  87. $reflection = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor();
  88. @$reflection->date = '1990-01-17 10:28:07';
  89. @$reflection->timezone_type = 3;
  90. @$reflection->timezone = $tz;
  91. $date = unserialize(serialize($reflection));
  92. } catch (Throwable $exception) {
  93. $this->markTestSkipped(
  94. "It fails on DateTime so Carbon can't support it, error was:\n".$exception->getMessage()
  95. );
  96. }
  97. $this->assertSame('1990-01-17 10:28:07', $date->format('Y-m-d h:i:s'));
  98. $reflection = (new ReflectionClass(Carbon::class))->newInstanceWithoutConstructor();
  99. @$reflection->date = '1990-01-17 10:28:07';
  100. @$reflection->timezone_type = 3;
  101. @$reflection->timezone = $tz;
  102. $date = unserialize(serialize($reflection));
  103. $this->assertSame('1990-01-17 10:28:07', $date->format('Y-m-d h:i:s'));
  104. $reflection = new ReflectionObject(Carbon::parse('1990-01-17 10:28:07'));
  105. $target = (new ReflectionClass(Carbon::class))->newInstanceWithoutConstructor();
  106. /** @var ReflectionProperty[] $properties */
  107. $properties = [];
  108. foreach ($reflection->getProperties() as $property) {
  109. $property->setAccessible(true);
  110. $properties[$property->getName()] = $property;
  111. }
  112. $setValue = function ($key, $value) use (&$properties, &$target) {
  113. if (isset($properties[$key])) {
  114. $properties[$key]->setValue($target, $value);
  115. return;
  116. }
  117. @$target->$key = $value;
  118. };
  119. $setValue('date', '1990-01-17 10:28:07');
  120. $setValue('timezone_type', 3);
  121. $setValue('timezone', $tz);
  122. $date = unserialize(serialize($target));
  123. $this->assertSame('1990-01-17 10:28:07', $date->format('Y-m-d h:i:s'));
  124. }
  125. public function testMsgPackExtension(): void
  126. {
  127. if (!\extension_loaded('msgpack')) {
  128. $this->markTestSkipped('This test needs msgpack extension to be enabled.');
  129. }
  130. $string = '2018-06-01 21:25:13.321654 Europe/Vilnius';
  131. $date = Carbon::parse('2018-06-01 21:25:13.321654 Europe/Vilnius');
  132. $message = @msgpack_pack($date);
  133. $copy = msgpack_unpack($message);
  134. $this->assertSame($string, $copy->format('Y-m-d H:i:s.u e'));
  135. }
  136. }