p2 project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

563 lines
17 KiB

<?php
declare(strict_types=1);
/**
* This file is part of the Carbon package.
*
* (c) Brian Nesbitt <brian@nesbot.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tests\CarbonPeriod;
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Carbon\CarbonPeriod;
use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\AbstractTestCase;
use Tests\CarbonPeriod\Fixtures\CarbonPeriodFactory;
class IteratorTest extends AbstractTestCase
{
protected $iterationLimit = 100;
public function testKeyAndCurrentAreCorrectlyInstantiated()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$this->assertSame(0, $period->key());
$this->assertInstanceOfCarbon($period->current());
$this->assertSame('2012-07-04 00:00:00', $period->current()->format('Y-m-d H:i:s'));
$this->assertTrue($period->valid());
}
public function testValidIsCorrectlyInstantiated()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$this->assertTrue($period->valid());
}
public function testCurrentIsAlwaysCarbonInstance()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
foreach ($period as $current) {
$this->assertInstanceOfCarbon($current);
$this->assertEquals($current, $period->current());
if (PHP_VERSION < 8.2) {
$this->assertEquals($current, $period->current);
}
}
}
public function testKeysAreSequential()
{
$keys = [];
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
foreach ($period as $key => $current) {
$this->assertIsInt($keys[] = $key);
$this->assertSame($key, $period->key());
}
$this->assertSame(array_keys($keys), $keys);
}
public function testElementsInLoopAreAlwaysValid()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
foreach ($period as $key => $current) {
$this->assertTrue($period->valid());
}
}
public function testKeyAndCurrentAreCorrectlyIterated()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$period->next();
$this->assertSame(1, $period->key());
$this->assertSame('2012-07-10 00:00:00', $period->current()->format('Y-m-d H:i:s'));
$this->assertTrue($period->valid());
}
public function testKeyAndCurrentAreCorrectlyRewound()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$period->next();
$period->rewind();
$this->assertSame(0, $period->key());
$this->assertSame('2012-07-04 00:00:00', $period->current()->format('Y-m-d H:i:s'));
$this->assertTrue($period->valid());
}
public function testKeyAndCurrentAreNullAfterIteration()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
foreach ($period as $key => $current) {
//
}
$this->assertNull($period->key());
$this->assertNull($period->current());
$this->assertFalse($period->valid());
}
#[DataProvider('dataForIterateBackwardsArguments')]
public function testIterateBackwards(array $arguments, array $expected)
{
$periodClass = static::$periodClass;
$period = $periodClass::create(...$arguments);
$interval = new CarbonInterval('P3D');
$interval->invert = 1;
$period = $period->setDateInterval($interval);
$this->assertSame(
$this->standardizeDates($expected),
$this->standardizeDates($period),
);
}
public static function dataForIterateBackwardsArguments(): Generator
{
yield [
['2015-10-15', '2015-10-06'],
['2015-10-15', '2015-10-12', '2015-10-09', '2015-10-06'],
];
yield [
['2015-10-15', '2015-10-06', CarbonPeriod::EXCLUDE_START_DATE],
['2015-10-12', '2015-10-09', '2015-10-06'],
];
yield [
['2015-10-15', '2015-10-06', CarbonPeriod::EXCLUDE_END_DATE],
['2015-10-15', '2015-10-12', '2015-10-09'],
];
yield [
['2015-10-15', '2015-10-06', CarbonPeriod::EXCLUDE_START_DATE | CarbonPeriod::EXCLUDE_END_DATE],
['2015-10-12', '2015-10-09'],
];
yield [
['2015-10-15', 3],
['2015-10-15', '2015-10-12', '2015-10-09'],
];
}
public function testChangingParametersShouldNotCauseInfiniteLoop()
{
$periodClass = static::$periodClass;
$period = $periodClass::create()
->setStartDate($start = '2012-07-01')
->setEndDate($end = '2012-07-20')
->setDateInterval($interval = 'P1D')
->setRecurrences($recurrences = 10)
->setOptions($options = $periodClass::EXCLUDE_START_DATE | $periodClass::EXCLUDE_END_DATE)
->addFilter($filter = function () {
return true;
});
$counter = 0;
foreach ($period as $current) {
if (++$counter >= $this->iterationLimit) {
break;
}
$period->removeFilter($filter)
->prependFilter($filter)
->setFilters([])
->setStartDate($start)
->setEndDate($end)
->invertDateInterval()
->setDateInterval($interval)
->setRecurrences($recurrences)
->setOptions($options)
->resetFilters()
->addFilter($filter);
}
$this->assertLessThan($this->iterationLimit, $counter, 'Changing parameters during the iteration caused an infinite loop.');
}
public function testChangeEndDateDuringIteration()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$results = [];
foreach ($period as $key => $current) {
$results[] = \sprintf('%s => %s', $key, $current->toDateString());
if ($current->toDateString() === '2012-07-16') {
$period = $period->setEndDate($current);
// Note: Current is no longer valid, because it is now equal to end, which is excluded.
$this->assertNull($period->key());
$this->assertNull($period->current());
$this->assertFalse($period->valid());
}
if (\count($results) >= $this->iterationLimit) {
$this->fail('Infinite loop detected when traversing the period.');
}
}
$this->assertSame(
['0 => 2012-07-04', '1 => 2012-07-10', '2 => 2012-07-16'],
$results,
);
}
public function testKeepIncreasingRecurrencesDuringIteration()
{
$period = new CarbonPeriod('2012-07-01', $recurrences = 1);
$results = [];
foreach ($period as $key => $current) {
$results[] = \sprintf('%s => %s', $key, $current->toDateString());
if ($recurrences < 4) {
$period->setRecurrences(++$recurrences);
// Note: Current is still valid, because we simply extended the period.
$this->assertSame($key, $period->key());
$this->assertEquals($current, $period->current());
$this->assertTrue($period->valid());
}
if (\count($results) >= $this->iterationLimit) {
$this->fail('Infinite loop detected when traversing the period.');
}
}
$this->assertSame(
['0 => 2012-07-01', '1 => 2012-07-02', '2 => 2012-07-03', '3 => 2012-07-04'],
$results,
);
}
public function testChangeStartDateDuringIteration()
{
$period = new CarbonPeriod('2012-07-01', '2012-07-04');
$results = [];
$newStart = new Carbon('2012-07-03');
foreach ($period as $key => $current) {
$results[] = \sprintf('%s => %s', $key, $current->toDateString());
if ($current < $newStart) {
$period->setStartDate($newStart);
// Note: Current is still valid, because start date is used only for initialization.
$this->assertEquals($key, $period->key());
$this->assertEquals($current, $period->current());
$this->assertTrue($period->valid());
}
if (\count($results) >= $this->iterationLimit) {
$this->fail('Infinite loop detected when traversing the period.');
}
}
$this->assertSame(
// Note: Results are not affected, because start date is used only for initialization.
['0 => 2012-07-01', '1 => 2012-07-02', '2 => 2012-07-03', '3 => 2012-07-04'],
$results,
);
}
public function testChangeDateIntervalDuringIteration()
{
$period = new CarbonPeriod('2012-07-01', 3);
$results = [];
foreach ($period as $key => $current) {
$results[] = \sprintf('%s => %s', $key, $current->toDateString());
$period->setDateInterval('P3D');
// Note: Current is still valid, because changed interval changes only subsequent items.
$this->assertSame($key, $period->key());
$this->assertEquals($current, $period->current());
$this->assertTrue($period->valid());
if (\count($results) >= $this->iterationLimit) {
$this->fail('Infinite loop detected when traversing the period.');
}
}
$this->assertSame(
['0 => 2012-07-01', '1 => 2012-07-04', '2 => 2012-07-07'],
$results,
);
}
public function testValidateOncePerIteration()
{
$period = CarbonPeriodFactory::withCounter(static::$periodClass, $counter);
$period->key();
$period->current();
$period->valid();
$this->assertSame(1, $counter);
$period->next();
$this->assertSame(2, $counter);
$period->key();
$period->current();
$period->valid();
$this->assertSame(2, $counter);
}
public function testInvalidateCurrentAfterChangingParameters()
{
$periodClass = static::$periodClass;
$period = $periodClass::create('2012-10-01');
$this->assertInstanceOfCarbon($period->current());
$period = $period->addFilter($periodClass::END_ITERATION);
$this->assertNull($period->current());
}
public function testTraversePeriodDynamically()
{
$period = CarbonPeriodFactory::withEvenDaysFilter(static::$periodClass);
$results = [];
while ($current = $period->current()) {
$results[] = $current;
$period->next();
if (\count($results) >= $this->iterationLimit) {
$this->fail('Infinite loop detected when traversing the period.');
}
}
$this->assertSame(
$this->standardizeDates(['2012-07-04', '2012-07-10', '2012-07-16']),
$this->standardizeDates($results),
);
}
public function testExtendCompletedIteration()
{
$periodClass = static::$periodClass;
$period = $periodClass::create('2018-10-10', '2018-10-11');
$results = [];
while ($period->valid()) {
$results[] = $period->current();
$period->next();
}
$period = $period->setEndDate('2018-10-13');
while ($period->valid()) {
$results[] = $period->current();
$period->next();
}
$this->assertSame(
$this->standardizeDates(['2018-10-10', '2018-10-11', '2018-10-12', '2018-10-13']),
$this->standardizeDates($results),
);
}
public function testRevalidateCurrentAfterChangeOfParameters()
{
$periodClass = static::$periodClass;
$period = $periodClass::create()->setStartDate($start = new Carbon('2018-10-28'));
$this->assertEquals($start, $period->current());
$this->assertNotSame($start, $period->current());
$period = $period->addFilter($excludeStart = function ($date) use ($start) {
return $date != $start;
});
$this->assertNull($period->current());
$period = $period->removeFilter($excludeStart);
$this->assertEquals($start, $period->current());
$this->assertNotSame($start, $period->current());
}
public function testRevalidateCurrentAfterEndOfIteration()
{
$periodClass = static::$periodClass;
$period = $periodClass::create()->setStartDate($start = new Carbon('2018-10-28'));
$this->assertEquals($start, $period->current());
$this->assertNotSame($start, $period->current());
$period = $period->addFilter($periodClass::END_ITERATION);
$this->assertNull($period->current());
$period = $period->removeFilter($periodClass::END_ITERATION);
$this->assertEquals($start, $period->current());
$this->assertNotSame($start, $period->current());
}
public function testChangeStartDateBeforeIteration()
{
$periodClass = static::$periodClass;
$period = $periodClass::create(new Carbon('2018-10-05'), 3)
->setStartDate(new Carbon('2018-10-13'))
->toggleOptions($periodClass::EXCLUDE_START_DATE, true);
$this->assertEquals(new Carbon('2018-10-14'), $period->current());
}
public function testChangeStartDateAfterStartedIteration()
{
$periodClass = static::$periodClass;
$period = $periodClass::create(new Carbon('2018-10-05'), 3);
$current = $period->current();
$period->toggleOptions($periodClass::EXCLUDE_START_DATE, true);
$period->setStartDate(new Carbon('2018-10-13'));
$this->assertEquals($current, $period->current());
}
public function testInvertDateIntervalDuringIteration()
{
$periodClass = static::$periodClass;
$period = new $periodClass('2018-04-11', 5);
$results = [];
foreach ($period as $key => $date) {
$results[] = $date;
if ($key === 2) {
$period->invertDateInterval();
}
}
$this->assertSame(
$this->standardizeDates(['2018-04-11', '2018-04-12', '2018-04-13', '2018-04-12', '2018-04-11']),
$this->standardizeDates($results),
);
}
public function testManualIteration()
{
$period = CarbonPeriodFactory::withStackFilter(static::$periodClass);
$period->rewind();
$str = '';
while ($period->valid()) {
if ($period->key()) {
$str .= ', ';
}
$str .= $period->current()->format('m-d');
$period->next();
}
$this->assertSame('01-01, 01-03', $str);
}
public function testSkip()
{
$periodClass = static::$periodClass;
$period = $periodClass::create('2018-05-30', '2018-07-13');
$output = [];
foreach ($period as $day) {
/* @var Carbon $day */
$output[] = $day->format('Y-m-d');
if ($day->isSunday()) {
$this->assertTrue($period->skip(7));
$output[] = '...';
}
}
$this->assertSame([
'2018-05-30',
'2018-05-31',
'2018-06-01',
'2018-06-02',
'2018-06-03',
'...',
'2018-06-11',
'2018-06-12',
'2018-06-13',
'2018-06-14',
'2018-06-15',
'2018-06-16',
'2018-06-17',
'...',
'2018-06-25',
'2018-06-26',
'2018-06-27',
'2018-06-28',
'2018-06-29',
'2018-06-30',
'2018-07-01',
'...',
'2018-07-09',
'2018-07-10',
'2018-07-11',
'2018-07-12',
'2018-07-13',
], $output);
$this->assertFalse($period->skip());
$this->assertFalse($period->skip(7));
}
public function testLocale()
{
/** @var CarbonPeriod $period */
$period = CarbonPeriodFactory::withStackFilter(static::$periodClass)->locale('de');
$str = '';
foreach ($period as $key => $date) {
if ($key) {
$str .= ', ';
}
$str .= $date->isoFormat('MMMM dddd');
}
$this->assertSame('Januar Montag, Januar Mittwoch', $str);
}
public function testTimezone()
{
$period = CarbonPeriodFactory::withStackFilter(static::$periodClass)->shiftTimezone('America/Toronto');
$str = null;
foreach ($period as $key => $date) {
$str = $date->format('H e');
break;
}
$this->assertSame('00 America/Toronto', $str);
}
}