MacroTest.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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\CarbonPeriod;
  12. use BadMethodCallException;
  13. use Carbon\Carbon;
  14. use Carbon\CarbonPeriod;
  15. use Carbon\CarbonPeriodImmutable;
  16. use ReflectionClass;
  17. use Tests\AbstractTestCase;
  18. use Tests\CarbonPeriod\Fixtures\MacroableClass;
  19. use Tests\CarbonPeriod\Fixtures\Mixin;
  20. use Tests\CarbonPeriod\Fixtures\MixinTrait;
  21. class MacroTest extends AbstractTestCase
  22. {
  23. private function setStaticProperty(string $class, string $property, $value): void
  24. {
  25. $reflection = new ReflectionClass($class);
  26. if (PHP_VERSION >= 7.4) {
  27. $reflection->setStaticPropertyValue($property, $value);
  28. return;
  29. }
  30. $property = $reflection->getProperty($property);
  31. $property->setAccessible(true);
  32. $property->setValue($value);
  33. }
  34. protected function tearDown(): void
  35. {
  36. $this->setStaticProperty($this->periodClass, 'macros', []);
  37. parent::tearDown();
  38. }
  39. public function testCallMacro()
  40. {
  41. $periodClass = $this->periodClass;
  42. $periodClass::macro('onlyWeekdays', function () {
  43. /** @var CarbonPeriod $period */
  44. $period = $this;
  45. return $period->addFilter(function ($date) {
  46. return !\in_array($date->dayOfWeek, [Carbon::SATURDAY, Carbon::SUNDAY], true);
  47. });
  48. });
  49. /** @var mixed $period */
  50. $period = $periodClass::create('2018-05-10', '2018-05-14');
  51. $result = $period->onlyWeekdays();
  52. $this->assertSame(
  53. $periodClass === CarbonPeriod::class,
  54. $period === $result,
  55. 'Must be same object if mutable'
  56. );
  57. $this->assertSame(
  58. $this->standardizeDates(['2018-05-10', '2018-05-11', '2018-05-14']),
  59. $this->standardizeDates($result)
  60. );
  61. }
  62. public function testParameterOtherThanSelfIsNotGivenPeriodInstance()
  63. {
  64. $periodClass = $this->periodClass;
  65. $periodClass::macro('foobar', function ($param = 123) {
  66. return $param;
  67. });
  68. /** @var mixed $period */
  69. $period = $periodClass::create();
  70. $this->assertSame(123, $period->foobar());
  71. }
  72. public function testPassPeriodInstanceAfterOptionalParameters()
  73. {
  74. $periodClass = $this->periodClass;
  75. $periodClass::macro('formatStartDate', function ($format = 'l, j F Y') {
  76. /** @var CarbonPeriod $period */
  77. $period = $this;
  78. return $period->getStartDate()->format($format);
  79. });
  80. /** @var mixed $period */
  81. $period = $periodClass::start('2016-09-11');
  82. $this->assertSame(
  83. 'Sunday, 11 September 2016',
  84. $period->formatStartDate()
  85. );
  86. }
  87. public function testMacroIsBindedToDatePeriodInstance()
  88. {
  89. $periodClass = $this->periodClass;
  90. $periodClass::macro('myself', function () {
  91. return $this;
  92. });
  93. /** @var mixed $period */
  94. $period = new $periodClass();
  95. $this->assertInstanceOf($periodClass, $period->myself());
  96. $this->assertSame($period, $period->myself());
  97. }
  98. public function testCallMacroStatically()
  99. {
  100. $periodClass = $this->periodClass;
  101. $periodClass::macro('countWeekdaysBetween', function ($from, $to) use ($periodClass) {
  102. return $periodClass::create($from, $to)
  103. ->addFilter(function ($date) {
  104. return !\in_array($date->dayOfWeek, [Carbon::SATURDAY, Carbon::SUNDAY], true);
  105. })
  106. ->count();
  107. });
  108. $this->assertSame(
  109. 3,
  110. $periodClass::countWeekdaysBetween('2018-05-10', '2018-05-14')
  111. );
  112. }
  113. public function testMacroIsBoundToDatePeriodClass()
  114. {
  115. $periodClass = $this->periodClass;
  116. $periodClass::macro('newMyself', function () {
  117. return new static();
  118. });
  119. $this->assertInstanceOf($periodClass, $periodClass::newMyself());
  120. }
  121. public function testRegisterNonClosureMacro()
  122. {
  123. $periodClass = $this->periodClass;
  124. $periodClass::macro('lower', 'strtolower');
  125. /** @var mixed $period */
  126. $period = new $periodClass();
  127. $this->assertSame('abc', $period->lower('ABC'));
  128. $this->assertSame('abc', $periodClass::lower('ABC'));
  129. }
  130. public function testRegisterMixin()
  131. {
  132. $periodClass = $this->periodClass;
  133. $periodClass::mixin(new Mixin());
  134. $this->assertNull($periodClass::getFoo());
  135. $periodClass::setFoo('bar');
  136. $this->assertSame('bar', $periodClass::getFoo());
  137. }
  138. public function testCallNonExistingMacro()
  139. {
  140. $this->expectExceptionObject(new BadMethodCallException(
  141. 'Method nonExistingMacro does not exist.'
  142. ));
  143. $periodClass = $this->periodClass;
  144. /** @var mixed $period */
  145. $period = $periodClass::create();
  146. $period->nonExistingMacro();
  147. }
  148. public function testCallNonExistingMacroStatically()
  149. {
  150. $this->expectExceptionObject(new BadMethodCallException(
  151. 'Method nonExistingMacro does not exist.'
  152. ));
  153. $periodClass = $this->periodClass;
  154. $periodClass::nonExistingMacro();
  155. }
  156. public function testOverrideAlias()
  157. {
  158. $periodClass = $this->periodClass;
  159. $periodClass::macro('recurrences', function () {
  160. return 'foo';
  161. });
  162. $this->assertSame('foo', $periodClass::recurrences());
  163. }
  164. public function testInstatiateViaStaticMacroCall()
  165. {
  166. $periodClass = $this->periodClass;
  167. $periodClass::macro('fromTomorrow', function () {
  168. /** @var CarbonPeriod $period */
  169. $period = $this;
  170. return $period->setStartDate(Carbon::tomorrow());
  171. });
  172. $period = $periodClass::fromTomorrow();
  173. $this->assertEquals(Carbon::tomorrow(), $period->getStartDate());
  174. }
  175. public function testMixinInstance()
  176. {
  177. require_once __DIR__.'/Fixtures/MixinTrait.php';
  178. require_once __DIR__.'/Fixtures/MacroableClass.php';
  179. $periodClass = $this->periodClass;
  180. $periodClass::mixin(MixinTrait::class);
  181. $period = $periodClass::create('2023-06-10', '2023-06-12');
  182. $copy = $period->copyOneMoreDay();
  183. $this->assertSame('Every 1 day from 2023-06-10 to 2023-06-12', (string) $period);
  184. $this->assertSame('Every 1 day from 2023-06-10 to 2023-06-13', (string) $copy);
  185. $mutated = $period->oneMoreDay();
  186. $immutable = ($this->periodClass === CarbonPeriodImmutable::class);
  187. $expectedEnd = $immutable ? '2023-06-12' : '2023-06-13';
  188. $this->assertSame('Every 1 day from 2023-06-10 to 2023-06-13', (string) $mutated);
  189. $this->assertSame("Every 1 day from 2023-06-10 to $expectedEnd", (string) $period);
  190. $expectedResult = $immutable ? 'a new instance' : 'the same instance';
  191. $this->assertSame(
  192. $immutable,
  193. ($mutated !== $period),
  194. "{$this->periodClass}::oneMoreDay() should return $expectedResult"
  195. );
  196. $this->assertNotSame($copy, $period);
  197. $this->assertSame('2023-06-14', $mutated->endNextDay()->format('Y-m-d'));
  198. $this->assertSame($this->periodClass === CarbonPeriodImmutable::class
  199. ? '2023-06-13'
  200. : '2023-06-14', $period->endNextDay()->format('Y-m-d'));
  201. MacroableClass::mixin(MixinTrait::class);
  202. $obj = new MacroableClass();
  203. $result = $obj
  204. ->setEndDate(Carbon::parse('2023-06-01'))
  205. ->oneMoreDay();
  206. $endDate = $result->getEndDate();
  207. $this->assertInstanceOf(MacroableClass::class, $result);
  208. $this->assertNotSame(MacroableClass::class, \get_class($result));
  209. $this->assertSame(Carbon::class, \get_class($endDate));
  210. $this->assertSame('2023-06-02', $endDate->format('Y-m-d'));
  211. }
  212. }