TimeTrex/vendor/kigkonsult/icalcreator/test/RecurYearTest.php

638 lines
23 KiB
PHP

<?php
/**
* iCalcreator, the PHP class package managing iCal (rfc2445/rfc5445) calendar information.
*
* This file is a part of iCalcreator.
*
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
* @copyright 2007-2022 Kjell-Inge Gustafsson, kigkonsult, All rights reserved
* @link https://kigkonsult.se
* @license Subject matter of licence is the software iCalcreator.
* The above copyright, link, package and version notices,
* this licence notice and the invariant [rfc5545] PRODID result use
* as implemented and invoked in iCalcreator shall be included in
* all copies or substantial portions of the iCalcreator.
*
* iCalcreator is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* iCalcreator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with iCalcreator. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Kigkonsult\Icalcreator;
use Kigkonsult\Icalcreator\Util\DateTimeFactory;
use Kigkonsult\Icalcreator\Util\RecurFactory2;
use DateTime;
use Exception;
/**
* class RecurTest, testing selectComponents
*
* @since 2.27.20 - 2019-05-20
*/
class RecurYearTest extends RecurBaseTest
{
/**
* recurYearlyTest111x provider
*
* @return mixed[]
* @throws Exception
*/
public function recurYearlyTest111xProvider() : array
{
$dataArr = [];
$dataSetNo = 0;
$DATASET = 'DATASET';
$interval = 1;
$count = 10;
for( $ix = 111; $ix <= 112; $ix++ ) {
$time = microtime( true );
$start = DateTimeFactory::factory( '20190101T0900', 'Europe/Stockholm' );
$year = (int)$start->format( 'Y' );
$month = (int)$start->format( 'm' );
$day = (int)$start->format( 'd' );
$end = ( clone $start )->modify( '20 years' );
$expects = [];
$x = 1;
while( $x < $count ) {
$year += $interval;
$Ymd = sprintf( '%04d%02d%02d', $year, $month, $day );
$expects[] = $Ymd;
++$x;
}
$execTime = microtime( true ) - $time;
$dataArr[] = [
$ix . '-' . $interval,
$start,
$end,
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::INTERVAL => $interval,
IcalInterface::COUNT => $count,
$DATASET => $dataSetNo++
],
$expects,
$execTime
];
++$interval;
}
return $dataArr;
}
/**
* Testing recur2date Yearly simple
*
* @test
* @dataProvider recurYearlyTest111xProvider
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @param float $prepTime
* @throws Exception
*/
public function recurYearlyTest111x(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects,
float $prepTime
) : void
{
$this->recurYearlyTest1X( $case, $start, $end, $recur, $expects, $prepTime );
}
/**
* recurYearlyTest23 provider
*
* @return mixed[]
* @throws Exception
*/
public function recurYearlyTest23Provider() : array
{
$dataArr = [];
$dataSetNo = 0;
$DATASET = 'DATASET';
// rfc example 23 - exact (no interval)
$dataArr[] = [
'19-23-0-0-0',
DateTimeFactory::factory( '19970610T0900', 'Europe/Stockholm' ),
DateTimeFactory::factory( '20040610T0900', 'Europe/Stockholm' ),
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::COUNT => 10,
IcalInterface::BYMONTH => [ 6, 7 ],
$DATASET => $dataSetNo,
'MRANGE' => [ 6, 7 ]
],
[ 19970710, 19980610, 19980710, 19990610, 19990710, 20000610, 20000710, 20010610, 20010710 ],
0,0,
];
// rfc example 23 - with interval for-loop '19-23-...'
$count = 10;
$mRange = [];
for( $ix1 = 1; $ix1 < 5; $ix1++ ) {
$interval = 0;
for( $ix2 = 1; $ix2 <= 10; $ix2++ ) {
++$interval;
$mRange[] = array_rand( array_flip( range( 1, 12 )));
sort( $mRange );
$mRange = array_unique( $mRange, SORT_NUMERIC );
$time = microtime( true );
// $start = DateTimeFactory::factory( '20190101T0900', 'Europe/Stockholm' );
$start = DateTimeFactory::factory( '19970610T0900', 'Europe/Stockholm' );
$startYmd = $start->format( 'Ymd' );
$end = ( clone $start )->setDate(
((int) $start->format( 'Y' ) + ( 10 + $interval )),
(int) $start->format( 'm' ),
(int) $start->format( 'd' )
);
$endYmd = $end->format( 'Ymd' );
$expects = [];
$x = 1;
$wDate = clone $start;
$wDate = $wDate->setDate(
(int) $wDate->format( 'Y' ),
1,
(int) $wDate->format( 'd' )
);
$currYear = (int) $wDate->format( 'Y' );
while( $x < $count ) {
if( $currYear !== (int) $wDate->format( 'Y' )) {
$wDate = $wDate->setDate(
((int) $wDate->format( 'Y' ) + $interval ),
1,
(int) $wDate->format( 'd' )
);
$currYear = (int) $wDate->format( 'Y' );
}
if( $endYmd < $wDate->format( 'Ymd' )) {
break;
}
if( $startYmd < $wDate->format( 'Ymd' )) {
if( in_array( (int)$wDate->format( 'm' ), $mRange, true ) ) {
$expects[] = $wDate->format( 'Ymd' );
++$x;
}
if( 12 === (int) $wDate->format( 'm' )) {
$currYear = -1;
continue;
}
}
$wDate = $wDate->setDate(
(int) $wDate->format( 'Y' ),
((int) $wDate->format( 'm' ) + 1 ),
(int) $wDate->format( 'd' )
);
} // end while
$execTime = microtime( true ) - $time;
$dataArr[] = [
'19-23-' . $ix1 . '-' . $ix2 . '-' . $interval,
$start,
$end,
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::INTERVAL => $interval,
IcalInterface::COUNT => $count,
IcalInterface::BYMONTH => $mRange,
$DATASET => $dataSetNo++,
'MRANGE' => implode( ',', $mRange )
],
$expects,
$execTime,
];
} // end for... $x2
} // end for... $x1
return $dataArr;
}
/**
* Testing recur2date Yearly , rfc example 23 - with interval for-loop '19-23-...'
*
* Test RecurFactory::recurYearly1
*
* @test
* @dataProvider recurYearlyTest23Provider
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @param float $prepTime
* @throws Exception
*/
public function recurYearlyTest23(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects,
float $prepTime
) : void
{
$this->recurYearlyTest1X( $case, $start, $end, $recur, $expects, $prepTime );
}
/**
* recurYearlyTest23e provider, rfc example 23 -Extended, both byMonth and byMonthDay
*
* @return mixed[]
* @throws Exception
*/
public function recurYearlyTest23eProvider() : array
{
$dataArr = [];
$dataSetNo = 0;
$DATASET = 'DATASET';
// rfc example 23 -Extended, both byMonth and byMonthDay
$start = DateTimeFactory::factory( '20190101T0900', 'Europe/Stockholm' );
$end = ( clone $start )->modify('+10 years' );
$count = 20;
$mRange = [ 1 ]; // month
$dRange = []; // days in month
$baseDays = [ 4, 8, 12, 16, -16, -12, -8, -4 ];
for( $ix1 = 1; $ix1 < 5; $ix1++ ) {
$interval = 1;
for( $ix2 = 1; $ix2 <= 2; $ix2++ ) {
$mRange[] = array_rand( array_flip( range( 4, 12 )));
sort( $mRange );
$mRange = array_values( array_unique( $mRange ));
$dKey = array_rand( $baseDays );
$dRange[] = $baseDays[$dKey];
sort( $dRange );
$dRange = array_values( array_unique( $dRange ));
$time = microtime( true );
$startYmd = $start->format( 'Ymd' );
$startYm = $start->format( 'Ym' );
$endYmd = $end->format( 'Ymd' );
$expects = [];
$x = 1;
$wDate = clone $start;
$currYear = $year = (int) $wDate->format( 'Y' );
$mx = 0;
$month = $mRange[$mx];
$day = (int) $wDate->format( 'd' );
$wDate->setDate( $year, $month, $day );
$currMonth = $month;
while(( $x < $count ) && ( $endYmd > $wDate->format( 'Ymd' ))) {
// if( 4000 < ++$y ) break;
if( $currYear !== (int) $wDate->format( 'Y' )) {
$year += $interval;
$currYear = $year;
$mx = 0;
$currMonth = $month = $mRange[$mx];
} // end if
if( $currMonth !== $month ) {
++$mx;
if( ! isset( $mRange[$mx] )) {
$currYear = -1;
continue;
}
$currMonth = $month = $mRange[$mx];
} // end if
$wDate->setDate( $year, $month, $day );
if( $endYmd < $wDate->format( 'Ymd' )) {
break;
}
if( $startYm > $wDate->format( 'Ym' )) {
$currMonth = -1;
continue;
}
if( in_array( $month, $mRange, true ) ) { // bort ??
$xDate = clone $wDate;
foreach( RecurFactory2::getMonthDaysFromByMonthDayList(
(int) $wDate->format( 't' ),
$dRange
) as $monthDay ) {
if( $x >= $count ) {
break 2;
}
$xDate->setDate(
(int) $wDate->format( 'Y' ),
(int) $wDate->format( 'm' ),
$monthDay
);
$Ymd = $xDate->format( 'Ymd' );
if( $startYmd >= $Ymd ) {
continue;
}
if( $endYmd < $Ymd ) {
break 2;
}
$expects[] = $Ymd;
++$x;
} // end foreach
} // end if ... in mRange
$currMonth = -1;
} // end while
$execTime = microtime( true ) - $time;
$dataArr[] = [
'19-23e' . $ix1 . '-' . $ix2 . '-' . $interval,
$start,
$end,
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::INTERVAL => $interval,
IcalInterface::COUNT => $count,
IcalInterface::BYMONTH => $mRange,
IcalInterface::BYMONTHDAY => $dRange,
$DATASET => $dataSetNo++,
'MRANGE' => implode( ',', $mRange )
],
$expects,
$execTime,
];
} // end for... $x2
} // end for... $x1
return $dataArr;
}
/**
* Testing recur2date Yearly , rfc example 23 -Extended, both byMonth and byMonthDay
*
* @test
* @dataProvider recurYearlyTest23eProvider
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @param float $prepTime
* @throws Exception
*/
public function recurYearlyTest23e(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects,
float $prepTime
) : void
{
$this->recurYearlyTest1X( $case, $start, $end, $recur, $expects, $prepTime );
}
/**
* recurYearlyTest23l provider, rfc example 23 changed date and limited by INTERVAL 2 and byMonthDay [ -20, -10 ]
*
* @return mixed[]
* @throws Exception
*/
public function recurYearlyTest23lProvider() : array
{
$dataArr = [];
$dataSetNo = 0;
$DATASET = 'DATASET';
// rfc example 23 changed date and limited by INTERVAL 2 and byMonthDay [ -20, -10 ]
$start = DateTimeFactory::factory( '20200801T0900', 'Europe/Stockholm' );
$end = ( clone $start )->modify('+12 years' );
$dataArr[] = [
'19-23l',
$start,
$end,
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::INTERVAL => 2,
IcalInterface::COUNT => 10,
IcalInterface::BYMONTHDAY => [ -15, -2 ],
$DATASET => $dataSetNo++,
],
[ 20200817, 20200830, 20220817, 20220830, 20240817, 20240830, 20260817, 20260830, 20280817 ],
0.0,
];
return $dataArr;
}
/**
* Testing recur2date Yearly, rfc example 23 changed date and limited by INTERVAL 2 and byMonthDay [ -20, -10 ]
*
* @test
* @dataProvider recurYearlyTest23lProvider
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @param float $prepTime
* @throws Exception
*/
public function recurYearlyTest23l(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects,
float $prepTime
) : void
{
$this->recurYearlyTest1X( $case, $start, $end, $recur, $expects, $prepTime );
}
/**
* Testing recur2date Yearly
*
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @param float $prepTime
* @throws Exception
*/
public function recurYearlyTest1X(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects,
float $prepTime
) : void
{
$saveStartDate = clone $start;
if( ! isset( $recur[IcalInterface::INTERVAL] )) {
$recur[IcalInterface::INTERVAL] = 1;
}
// error_log('' ); // test ###
// error_log( __FUNCTION__ . ' start ' . $case ); // test ###
$strCase = str_pad( $case, 12 );
if( '19-23l' === $case ) {
$result = array_flip( $expects );
if( defined( 'DISPRECUR' ) && ( '1' === DISPRECUR )) {
echo $strCase . 'expects : ' .
implode( ' - ', array_keys( $result ) ) . PHP_EOL; // test ###
}
}
else {
$result = $this->recur2dateTest( // return old
$case,
$start,
$end,
$recur,
$expects,
$prepTime
);
}
$recurDisp = str_replace( [PHP_EOL, ' ' ], '', var_export( $recur, true ));
if( ! RecurFactory2::isRecurYearly1( $recur )) {
if( defined( 'DISPRECUR' ) && ( '1' === DISPRECUR )) {
echo $strCase . ' NOT isRecurYearly1 ' . $recurDisp . PHP_EOL;
}
$this->fail();
}
$time = microtime( true );
$resultX = RecurFactory2::recurYearly1( $recur, $start, clone $start, $end );
$execTime = microtime( true ) - $time;
if( defined( 'DISPRECUR' ) && ( '1' === DISPRECUR )) {
echo $strCase . 'year smpl1 time:' . number_format( $execTime, 6 ) . ' : ' .
implode( ' - ', array_keys( $resultX ) ) . PHP_EOL; // test ###
echo $recurDisp . ' start ' . $start->format( 'Ymd' ) . ' end ' . $end->format( 'Ymd' ) . PHP_EOL; // test ###
}
$endFormat = is_array( $end )
? implode( '-', $end )
: $end->format( 'Ymd' );
$this->assertEquals(
array_keys( $result ), // exp, old
array_keys( $resultX ), // new, actual
sprintf(
self::$ERRFMT,
__FUNCTION__,
$case . ' old -> new ',
$saveStartDate->format( 'Ymd' ),
$endFormat,
$recurDisp
)
);
}
/**
* recurYearlyTest2X provider
*
* @return mixed[]
* @throws Exception
*/
public function recurYearlyTest2XProvider() : array
{
$dataArr = [];
$dataSetNo = 0;
$DATASET = 'DATASET';
// yearly in june, third TU/WE/TH in month, forever
$start = DateTimeFactory::factory( '20200101T090000', 'Europe/Stockholm');
$wDate = clone $start;
$dataArr[] = [
'2001',
$start,
$wDate->modify( 10 . ' year' ), // end
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::BYMONTH => 6,
IcalInterface::BYDAY => [
[ IcalInterface::DAY => IcalInterface::TU ],
[ IcalInterface::DAY => IcalInterface::WE ],
[ IcalInterface::DAY => IcalInterface::TH ],
],
IcalInterface::BYSETPOS => -3,
$DATASET => $dataSetNo++
],
[ 20200624,20210624,20220628,20230627,20240625,20250624,20260624,20270624,20280627,20290626 ]
];
// neotsn Thanksgiving event - 4th Thursday of every November - Yearly - same in recurMonthly2Test by MONTHLY
$start = DateTimeFactory::factory( '20201126T113000', 'America/Chicago');
$wDate = clone $start;
$dataArr[] = [
'neotsn',
$start,
$wDate->modify( 10 . ' year' ), // end
[
IcalInterface::FREQ => IcalInterface::YEARLY,
IcalInterface::BYMONTH => 11,
IcalInterface::BYDAY => [
[ IcalInterface::DAY => IcalInterface::TH ],
],
IcalInterface::BYSETPOS => 4,
$DATASET => $dataSetNo++
],
[ 20211125,20221124,20231123,20241128,20251127,20261126,20271125,20281123,20291122 ]
];
return $dataArr;
}
/**
* Testing recurMonthlyYearly3 - YEARLY + BYMONTH + BYDAY
*
* @test
* @dataProvider recurYearlyTest2XProvider
* @param string $case
* @param DateTime $start
* @param DateTime|mixed[] $end
* @param mixed[] $recur
* @param mixed[] $expects
* @throws Exception
*/
public function recurYearly2XTest(
string $case,
DateTime $start,
DateTime | array $end,
array $recur,
array $expects
) : void
{
$saveStartDate = clone $start;
if( ! isset( $recur[IcalInterface::INTERVAL] )) {
$recur[IcalInterface::INTERVAL] = 1;
}
$strCase = str_pad( $case, 12 );
$recurDisp = str_replace( [PHP_EOL, ' ' ], '', var_export( $recur, true ));
if( ! RecurFactory2::isRecurYearly2( $recur )) {
if( defined( 'DISPRECUR' ) && ( '1' === DISPRECUR )) {
echo $strCase . ' NOT isRecurYearly2 ' . $recurDisp . PHP_EOL;
}
$this->fail();
} // end if
$time = microtime( true );
$resultX = RecurFactory2::recurMonthlyYearly3( $recur, $start, clone $start, $end );
$execTime = microtime( true ) - $time;
if( defined( 'DISPRECUR' ) && ( '1' === DISPRECUR )) {
echo $strCase . 'year smpl2 time:' . number_format( $execTime, 6 ) . ' : ' .
implode( ' - ', array_keys( $resultX ) ) . PHP_EOL; // test ###
echo $recurDisp . PHP_EOL; // test ###
}
$this->assertEquals(
$expects,
array_keys( $resultX ),
sprintf( self::$ERRFMT, __FUNCTION__, $case . '-21',
$saveStartDate->format( 'Ymd' ),
$end->format( 'Ymd' ),
PHP_EOL . $recurDisp .
PHP_EOL . 'exp : ' . implode( ',', $expects ) .
PHP_EOL . 'got : ' . implode( ',', array_keys( $resultX ))
)
);
}
}