EventReaderTest.php 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\Tests\unit\CalDAV;
  8. use DateTimeZone;
  9. use OCA\DAV\CalDAV\EventReader;
  10. use Sabre\VObject\Component\VCalendar;
  11. use Test\TestCase;
  12. class EventReaderTest extends TestCase {
  13. /** @var VCalendar*/
  14. private $vCalendar1a;
  15. /** @var VCalendar*/
  16. private $vCalendar1b;
  17. /** @var VCalendar*/
  18. private $vCalendar1c;
  19. /** @var VCalendar*/
  20. private $vCalendar1d;
  21. /** @var VCalendar*/
  22. private $vCalendar2;
  23. /** @var VCalendar*/
  24. private $vCalendar3;
  25. protected function setUp(): void {
  26. parent::setUp();
  27. // construct calendar with a 1 hour event and same start/end time zones
  28. $this->vCalendar1a = new VCalendar();
  29. $vEvent = $this->vCalendar1a->add('VEVENT', []);
  30. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  31. $vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']);
  32. $vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Toronto']);
  33. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  34. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  35. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  36. 'CN' => 'Attendee One',
  37. 'CUTYPE' => 'INDIVIDUAL',
  38. 'PARTSTAT' => 'NEEDS-ACTION',
  39. 'ROLE' => 'REQ-PARTICIPANT',
  40. 'RSVP' => 'TRUE'
  41. ]);
  42. // construct calendar with a 1 hour event and different start/end time zones
  43. $this->vCalendar1b = new VCalendar();
  44. $vEvent = $this->vCalendar1b->add('VEVENT', []);
  45. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  46. $vEvent->add('DTSTART', '20240701T080000', ['TZID' => 'America/Toronto']);
  47. $vEvent->add('DTEND', '20240701T090000', ['TZID' => 'America/Vancouver']);
  48. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  49. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  50. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  51. 'CN' => 'Attendee One',
  52. 'CUTYPE' => 'INDIVIDUAL',
  53. 'PARTSTAT' => 'NEEDS-ACTION',
  54. 'ROLE' => 'REQ-PARTICIPANT',
  55. 'RSVP' => 'TRUE'
  56. ]);
  57. // construct calendar with a 1 hour event and global time zone
  58. $this->vCalendar1c = new VCalendar();
  59. // time zone component
  60. $vTimeZone = $this->vCalendar1c->add('VTIMEZONE');
  61. $vTimeZone->add('TZID', 'America/Toronto');
  62. // event component
  63. $vEvent = $this->vCalendar1c->add('VEVENT', []);
  64. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  65. $vEvent->add('DTSTART', '20240701T080000');
  66. $vEvent->add('DTEND', '20240701T090000');
  67. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  68. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  69. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  70. 'CN' => 'Attendee One',
  71. 'CUTYPE' => 'INDIVIDUAL',
  72. 'PARTSTAT' => 'NEEDS-ACTION',
  73. 'ROLE' => 'REQ-PARTICIPANT',
  74. 'RSVP' => 'TRUE'
  75. ]);
  76. // construct calendar with a 1 hour event and no time zone
  77. $this->vCalendar1d = new VCalendar();
  78. $vEvent = $this->vCalendar1d->add('VEVENT', []);
  79. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  80. $vEvent->add('DTSTART', '20240701T080000');
  81. $vEvent->add('DTEND', '20240701T090000');
  82. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  83. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  84. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  85. 'CN' => 'Attendee One',
  86. 'CUTYPE' => 'INDIVIDUAL',
  87. 'PARTSTAT' => 'NEEDS-ACTION',
  88. 'ROLE' => 'REQ-PARTICIPANT',
  89. 'RSVP' => 'TRUE'
  90. ]);
  91. // construct calendar with a full day event
  92. $this->vCalendar2 = new VCalendar();
  93. // time zone component
  94. $vTimeZone = $this->vCalendar2->add('VTIMEZONE');
  95. $vTimeZone->add('TZID', 'America/Toronto');
  96. // event component
  97. $vEvent = $this->vCalendar2->add('VEVENT', []);
  98. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  99. $vEvent->add('DTSTART', '20240701');
  100. $vEvent->add('DTEND', '20240702');
  101. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  102. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  103. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  104. 'CN' => 'Attendee One',
  105. 'CUTYPE' => 'INDIVIDUAL',
  106. 'PARTSTAT' => 'NEEDS-ACTION',
  107. 'ROLE' => 'REQ-PARTICIPANT',
  108. 'RSVP' => 'TRUE'
  109. ]);
  110. // construct calendar with a multi day event
  111. $this->vCalendar3 = new VCalendar();
  112. // time zone component
  113. $vTimeZone = $this->vCalendar3->add('VTIMEZONE');
  114. $vTimeZone->add('TZID', 'America/Toronto');
  115. // event component
  116. $vEvent = $this->vCalendar3->add('VEVENT', []);
  117. $vEvent->UID->setValue('96a0e6b1-d886-4a55-a60d-152b31401dcc');
  118. $vEvent->add('DTSTART', '20240701');
  119. $vEvent->add('DTEND', '20240706');
  120. $vEvent->add('SUMMARY', 'Test Recurrance Event');
  121. $vEvent->add('ORGANIZER', 'mailto:organizer@testing.com', ['CN' => 'Organizer']);
  122. $vEvent->add('ATTENDEE', 'mailto:attendee1@testing.com', [
  123. 'CN' => 'Attendee One',
  124. 'CUTYPE' => 'INDIVIDUAL',
  125. 'PARTSTAT' => 'NEEDS-ACTION',
  126. 'ROLE' => 'REQ-PARTICIPANT',
  127. 'RSVP' => 'TRUE'
  128. ]);
  129. }
  130. public function testConstructFromCalendarString(): void {
  131. // construct event reader
  132. $er = new EventReader($this->vCalendar1a->serialize(), '96a0e6b1-d886-4a55-a60d-152b31401dcc');
  133. // test object creation
  134. $this->assertInstanceOf(EventReader::class, $er);
  135. }
  136. public function testConstructFromCalendarObject(): void {
  137. // construct event reader
  138. $er = new EventReader($this->vCalendar1a, '96a0e6b1-d886-4a55-a60d-152b31401dcc');
  139. // test object creation
  140. $this->assertInstanceOf(EventReader::class, $er);
  141. }
  142. public function testConstructFromEventObject(): void {
  143. // construct event reader
  144. $er = new EventReader($this->vCalendar1a->VEVENT[0]);
  145. // test object creation
  146. $this->assertInstanceOf(EventReader::class, $er);
  147. }
  148. public function testStartDateTime(): void {
  149. /** test day part event with same start/end time zone */
  150. // construct event reader
  151. $er = new EventReader($this->vCalendar1a, $this->vCalendar1a->VEVENT[0]->UID->getValue());
  152. // test set by constructor
  153. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->startDateTime());
  154. /** test day part event with different start/end time zone */
  155. // construct event reader
  156. $er = new EventReader($this->vCalendar1b, $this->vCalendar1b->VEVENT[0]->UID->getValue());
  157. // test set by constructor
  158. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->startDateTime());
  159. /** test day part event with global time zone */
  160. // construct event reader
  161. $er = new EventReader($this->vCalendar1c, $this->vCalendar1c->VEVENT[0]->UID->getValue());
  162. // test set by constructor
  163. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->startDateTime());
  164. /** test day part event with no time zone */
  165. // construct event reader
  166. $er = new EventReader($this->vCalendar1d, $this->vCalendar1d->VEVENT[0]->UID->getValue());
  167. // test set by constructor
  168. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('UTC')))), $er->startDateTime());
  169. /** test full day event */
  170. // construct event reader
  171. $er = new EventReader($this->vCalendar2, $this->vCalendar2->VEVENT[0]->UID->getValue());
  172. // test set by constructor
  173. $this->assertEquals((new \DateTime('20240701T000000', (new DateTimeZone('America/Toronto')))), $er->startDateTime());
  174. /** test multi day event */
  175. // construct event reader
  176. $er = new EventReader($this->vCalendar3, $this->vCalendar3->VEVENT[0]->UID->getValue());
  177. // test set by constructor
  178. $this->assertEquals((new \DateTime('20240701T000000', (new DateTimeZone('America/Toronto')))), $er->startDateTime());
  179. }
  180. public function testStartTimeZone(): void {
  181. /** test day part event with same start/end time zone */
  182. // construct event reader
  183. $er = new EventReader($this->vCalendar1a, $this->vCalendar1a->VEVENT[0]->UID->getValue());
  184. // test set by constructor
  185. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->startTimeZone());
  186. /** test day part event with different start/end time zone */
  187. // construct event reader
  188. $er = new EventReader($this->vCalendar1b, $this->vCalendar1b->VEVENT[0]->UID->getValue());
  189. // test set by constructor
  190. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->startTimeZone());
  191. /** test day part event with global time zone */
  192. // construct event reader
  193. $er = new EventReader($this->vCalendar1c, $this->vCalendar1c->VEVENT[0]->UID->getValue());
  194. // test set by constructor
  195. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->startTimeZone());
  196. /** test day part event with no time zone */
  197. // construct event reader
  198. $er = new EventReader($this->vCalendar1d, $this->vCalendar1d->VEVENT[0]->UID->getValue());
  199. // test set by constructor
  200. $this->assertEquals((new DateTimeZone('UTC')), $er->startTimeZone());
  201. /** test full day event */
  202. // construct event reader
  203. $er = new EventReader($this->vCalendar2, $this->vCalendar2->VEVENT[0]->UID->getValue());
  204. // test set by constructor
  205. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->startTimeZone());
  206. /** test multi day event */
  207. // construct event reader
  208. $er = new EventReader($this->vCalendar3, $this->vCalendar3->VEVENT[0]->UID->getValue());
  209. // test set by constructor
  210. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->startTimeZone());
  211. }
  212. public function testEndDate(): void {
  213. /** test day part event with same start/end time zone */
  214. // construct event reader
  215. $er = new EventReader($this->vCalendar1a, $this->vCalendar1a->VEVENT[0]->UID->getValue());
  216. // test set by constructor
  217. $this->assertEquals((new \DateTime('20240701T090000', (new DateTimeZone('America/Toronto')))), $er->endDateTime());
  218. /** test day part event with different start/end time zone */
  219. // construct event reader
  220. $er = new EventReader($this->vCalendar1b, $this->vCalendar1b->VEVENT[0]->UID->getValue());
  221. // test set by constructor
  222. $this->assertEquals((new \DateTime('20240701T090000', (new DateTimeZone('America/Vancouver')))), $er->endDateTime());
  223. /** test day part event with global time zone */
  224. // construct event reader
  225. $er = new EventReader($this->vCalendar1c, $this->vCalendar1c->VEVENT[0]->UID->getValue());
  226. // test set by constructor
  227. $this->assertEquals((new \DateTime('20240701T090000', (new DateTimeZone('America/Toronto')))), $er->endDateTime());
  228. /** test day part event with no time zone */
  229. // construct event reader
  230. $er = new EventReader($this->vCalendar1d, $this->vCalendar1d->VEVENT[0]->UID->getValue());
  231. // test set by constructor
  232. $this->assertEquals((new \DateTime('20240701T090000', (new DateTimeZone('UTC')))), $er->endDateTime());
  233. /** test full day event */
  234. // construct event reader
  235. $er = new EventReader($this->vCalendar2, $this->vCalendar2->VEVENT[0]->UID->getValue());
  236. // test set by constructor
  237. $this->assertEquals((new \DateTime('20240702T000000', (new DateTimeZone('America/Toronto')))), $er->endDateTime());
  238. /** test multi day event */
  239. // construct event reader
  240. $er = new EventReader($this->vCalendar3, $this->vCalendar3->VEVENT[0]->UID->getValue());
  241. // test set by constructor
  242. $this->assertEquals((new \DateTime('20240706T000000', (new DateTimeZone('America/Toronto')))), $er->endDateTime());
  243. }
  244. public function testEndTimeZone(): void {
  245. /** test day part event with same start/end time zone */
  246. // construct event reader
  247. $er = new EventReader($this->vCalendar1a, $this->vCalendar1a->VEVENT[0]->UID->getValue());
  248. // test set by constructor
  249. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->endTimeZone());
  250. /** test day part event with different start/end time zone */
  251. // construct event reader
  252. $er = new EventReader($this->vCalendar1b, $this->vCalendar1b->VEVENT[0]->UID->getValue());
  253. // test set by constructor
  254. $this->assertEquals((new DateTimeZone('America/Vancouver')), $er->endTimeZone());
  255. /** test day part event with global time zone */
  256. // construct event reader
  257. $er = new EventReader($this->vCalendar1c, $this->vCalendar1c->VEVENT[0]->UID->getValue());
  258. // test set by constructor
  259. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->endTimeZone());
  260. /** test day part event with no time zone */
  261. // construct event reader
  262. $er = new EventReader($this->vCalendar1d, $this->vCalendar1d->VEVENT[0]->UID->getValue());
  263. // test set by constructor
  264. $this->assertEquals((new DateTimeZone('UTC')), $er->endTimeZone());
  265. /** test full day event */
  266. // construct event reader
  267. $er = new EventReader($this->vCalendar2, $this->vCalendar2->VEVENT[0]->UID->getValue());
  268. // test set by constructor
  269. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->endTimeZone());
  270. /** test multi day event */
  271. // construct event reader
  272. $er = new EventReader($this->vCalendar3, $this->vCalendar3->VEVENT[0]->UID->getValue());
  273. // test set by constructor
  274. $this->assertEquals((new DateTimeZone('America/Toronto')), $er->endTimeZone());
  275. }
  276. public function testEntireDay(): void {
  277. /** test day part event with same start/end time zone */
  278. // construct event reader
  279. $er = new EventReader($this->vCalendar1a, $this->vCalendar1a->VEVENT[0]->UID->getValue());
  280. // test set by constructor
  281. $this->assertFalse($er->entireDay());
  282. /** test full day event */
  283. // construct event reader
  284. $er = new EventReader($this->vCalendar2, $this->vCalendar2->VEVENT[0]->UID->getValue());
  285. // test set by constructor
  286. $this->assertTrue($er->entireDay());
  287. /** test multi day event */
  288. // construct event reader
  289. $er = new EventReader($this->vCalendar3, $this->vCalendar3->VEVENT[0]->UID->getValue());
  290. // test set by constructor
  291. $this->assertTrue($er->entireDay());
  292. }
  293. public function testRecurs(): void {
  294. /** test no recurrance */
  295. $vCalendar = clone $this->vCalendar1a;
  296. // construct event reader
  297. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  298. // test set by constructor
  299. $this->assertFalse($er->recurs());
  300. /** test rrule recurrance */
  301. $vCalendar = clone $this->vCalendar1a;
  302. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  303. // construct event reader
  304. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  305. // test set by constructor
  306. $this->assertTrue($er->recurs());
  307. /** test rdate recurrance */
  308. $vCalendar = clone $this->vCalendar1a;
  309. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  310. // construct event reader
  311. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  312. // test set by constructor
  313. $this->assertTrue($er->recurs());
  314. }
  315. public function testRecurringPattern(): void {
  316. /** test no recurrance */
  317. $vCalendar = clone $this->vCalendar1a;
  318. // construct event reader
  319. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  320. // test set by constructor
  321. $this->assertNull($er->recurringPattern());
  322. /** test absolute rrule recurrance */
  323. $vCalendar = clone $this->vCalendar1a;
  324. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  325. // construct event reader
  326. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  327. // test set by constructor
  328. $this->assertEquals('A', $er->recurringPattern());
  329. /** test relative rrule recurrance */
  330. $vCalendar = clone $this->vCalendar1a;
  331. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYDAY=MO;BYSETPOS=1');
  332. // construct event reader
  333. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  334. // test set by constructor
  335. $this->assertEquals('R', $er->recurringPattern());
  336. /** test rdate recurrance */
  337. $vCalendar = clone $this->vCalendar1a;
  338. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  339. // construct event reader
  340. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  341. // test set by constructor
  342. $this->assertEquals('A', $er->recurringPattern());
  343. }
  344. public function testRecurringPrecision(): void {
  345. /** test no recurrance */
  346. $vCalendar = clone $this->vCalendar1a;
  347. // construct event reader
  348. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  349. // test set by constructor
  350. $this->assertNull($er->recurringPrecision());
  351. /** test daily rrule recurrance */
  352. $vCalendar = clone $this->vCalendar1a;
  353. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=DAILY');
  354. // construct event reader
  355. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  356. // test set by constructor
  357. $this->assertEquals('daily', $er->recurringPrecision());
  358. /** test weekly rrule recurrance */
  359. $vCalendar = clone $this->vCalendar1a;
  360. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR');
  361. // construct event reader
  362. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  363. // test set by constructor
  364. $this->assertEquals('weekly', $er->recurringPrecision());
  365. /** test monthly rrule recurrance */
  366. $vCalendar = clone $this->vCalendar1a;
  367. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYMONTHDAY=1,8,15');
  368. // construct event reader
  369. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  370. // test set by constructor
  371. $this->assertEquals('monthly', $er->recurringPrecision());
  372. /** test yearly rrule recurrance */
  373. $vCalendar = clone $this->vCalendar1a;
  374. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;BYMONTH=7;BYMONTHDAY=1');
  375. // construct event reader
  376. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  377. // test set by constructor
  378. $this->assertEquals('yearly', $er->recurringPrecision());
  379. /** test rdate recurrance */
  380. $vCalendar = clone $this->vCalendar1a;
  381. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  382. // construct event reader
  383. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  384. // test set by constructor
  385. $this->assertEquals('fixed', $er->recurringPrecision());
  386. }
  387. public function testRecurringInterval(): void {
  388. /** test no recurrance */
  389. $vCalendar = clone $this->vCalendar1a;
  390. // construct event reader
  391. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  392. // test set by constructor
  393. $this->assertNull($er->recurringInterval());
  394. /** test daily rrule recurrance */
  395. $vCalendar = clone $this->vCalendar1a;
  396. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=DAILY;INTERVAL=2');
  397. // construct event reader
  398. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  399. // test set by constructor
  400. $this->assertEquals(2, $er->recurringInterval());
  401. /** test rdate recurrance */
  402. $vCalendar = clone $this->vCalendar1a;
  403. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  404. // construct event reader
  405. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  406. // test set by constructor
  407. $this->assertNull($er->recurringInterval());
  408. }
  409. public function testRecurringConcludes(): void {
  410. /** test no recurrance */
  411. $vCalendar = clone $this->vCalendar1a;
  412. // construct event reader
  413. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  414. // test set by constructor
  415. $this->assertFalse($er->recurringConcludes());
  416. /** test rrule recurrance with no end */
  417. $vCalendar = clone $this->vCalendar1a;
  418. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR');
  419. // construct event reader
  420. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  421. // test set by constructor
  422. $this->assertFalse($er->recurringConcludes());
  423. /** test rrule recurrance with until date end */
  424. $vCalendar = clone $this->vCalendar1a;
  425. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  426. // construct event reader
  427. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  428. // test set by constructor
  429. $this->assertTrue($er->recurringConcludes());
  430. /** test rrule recurrance with iteration end */
  431. $vCalendar = clone $this->vCalendar1a;
  432. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  433. // construct event reader
  434. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  435. // test set by constructor
  436. $this->assertTrue($er->recurringConcludes());
  437. /** test rdate recurrance */
  438. $vCalendar = clone $this->vCalendar1a;
  439. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  440. // construct event reader
  441. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  442. // test set by constructor
  443. $this->assertTrue($er->recurringConcludes());
  444. /** test rrule and rdate recurrance with rdate as last date */
  445. $vCalendar = clone $this->vCalendar1a;
  446. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  447. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  448. // construct event reader
  449. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  450. // test set by constructor
  451. $this->assertTrue($er->recurringConcludes());
  452. /** test rrule and rdate recurrance with rrule as last date */
  453. $vCalendar = clone $this->vCalendar1a;
  454. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=7;BYDAY=MO,WE,FR');
  455. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240713');
  456. // construct event reader
  457. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  458. // test set by constructor
  459. $this->assertTrue($er->recurringConcludes());
  460. }
  461. public function testRecurringConcludesAfter(): void {
  462. /** test no recurrance */
  463. $vCalendar = clone $this->vCalendar1a;
  464. // construct event reader
  465. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  466. // test set by constructor
  467. $this->assertNull($er->recurringConcludesAfter());
  468. /** test rrule recurrance with count */
  469. $vCalendar = clone $this->vCalendar1a;
  470. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  471. // construct event reader
  472. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  473. // test set by constructor
  474. $this->assertEquals(6, $er->recurringConcludesAfter());
  475. /** test rdate recurrance */
  476. $vCalendar = clone $this->vCalendar1a;
  477. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  478. // construct event reader
  479. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  480. // test set by constructor
  481. $this->assertEquals(2, $er->recurringConcludesAfter());
  482. /** test rrule and rdate recurrance */
  483. $vCalendar = clone $this->vCalendar1a;
  484. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  485. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  486. // construct event reader
  487. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  488. // test set by constructor
  489. $this->assertEquals(8, $er->recurringConcludesAfter());
  490. }
  491. public function testRecurringConcludesOn(): void {
  492. /** test no recurrance */
  493. $vCalendar = clone $this->vCalendar1a;
  494. // construct event reader
  495. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  496. // test set by constructor
  497. $this->assertNull($er->recurringConcludesOn());
  498. /** test rrule recurrance with no end */
  499. $vCalendar = clone $this->vCalendar1a;
  500. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR');
  501. // construct event reader
  502. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  503. // test set by constructor
  504. $this->assertNull($er->recurringConcludesOn());
  505. /** test rrule recurrance with until date end */
  506. $vCalendar = clone $this->vCalendar1a;
  507. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  508. // construct event reader
  509. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  510. // test set by constructor
  511. // TODO: Fix until time zone
  512. //$this->assertEquals((new \DateTime('20240712T080000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  513. /** test rdate recurrance */
  514. $vCalendar = clone $this->vCalendar1a;
  515. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  516. // construct event reader
  517. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  518. // test set by constructor
  519. $this->assertEquals((new \DateTime('20240705T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  520. /** test rrule and rdate recurrance with rdate as last date */
  521. $vCalendar = clone $this->vCalendar1a;
  522. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  523. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  524. // construct event reader
  525. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  526. // test set by constructor
  527. $this->assertEquals((new \DateTime('20240715T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  528. /** test rrule and rdate recurrance with rrule as last date */
  529. $vCalendar = clone $this->vCalendar1a;
  530. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=7;BYDAY=MO,WE,FR');
  531. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240713');
  532. // construct event reader
  533. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  534. // test set by constructor
  535. $this->assertEquals((new \DateTime('20240715T080000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  536. }
  537. public function testRecurringDaysOfWeek(): void {
  538. /** test no recurrance */
  539. $vCalendar = clone $this->vCalendar1a;
  540. // construct event reader
  541. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  542. // test set by constructor
  543. $this->assertEquals([], $er->recurringDaysOfWeek());
  544. /** test rrule recurrance with weekly days*/
  545. $vCalendar = clone $this->vCalendar1a;
  546. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  547. // construct event reader
  548. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  549. // test set by constructor
  550. $this->assertEquals(['MO','WE','FR'], $er->recurringDaysOfWeek());
  551. }
  552. public function testRecurringDaysOfWeekNamed(): void {
  553. /** test no recurrance */
  554. $vCalendar = clone $this->vCalendar1a;
  555. // construct event reader
  556. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  557. // test set by constructor
  558. $this->assertEquals([], $er->recurringDaysOfWeekNamed());
  559. /** test rrule recurrance with weekly days*/
  560. $vCalendar = clone $this->vCalendar1a;
  561. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  562. // construct event reader
  563. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  564. // test set by constructor
  565. $this->assertEquals(['Monday','Wednesday','Friday'], $er->recurringDaysOfWeekNamed());
  566. }
  567. public function testRecurringDaysOfMonth(): void {
  568. /** test no recurrance */
  569. $vCalendar = clone $this->vCalendar1a;
  570. // construct event reader
  571. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  572. // test set by constructor
  573. $this->assertEquals([], $er->recurringDaysOfMonth());
  574. /** test rrule recurrance with monthly absolute dates*/
  575. $vCalendar = clone $this->vCalendar1a;
  576. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYMONTHDAY=6,13,20,27');
  577. // construct event reader
  578. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  579. // test set by constructor
  580. $this->assertEquals([6,13,20,27], $er->recurringDaysOfMonth());
  581. }
  582. public function testRecurringDaysOfYear(): void {
  583. /** test no recurrance */
  584. $vCalendar = clone $this->vCalendar1a;
  585. // construct event reader
  586. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  587. // test set by constructor
  588. $this->assertEquals([], $er->recurringDaysOfYear());
  589. /** test rrule recurrance with monthly absolute dates*/
  590. $vCalendar = clone $this->vCalendar1a;
  591. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;BYYEARDAY=1,30,180,365');
  592. // construct event reader
  593. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  594. // test set by constructor
  595. $this->assertEquals([1,30,180,365], $er->recurringDaysOfYear());
  596. }
  597. public function testRecurringWeeksOfMonth(): void {
  598. /** test no recurrance */
  599. $vCalendar = clone $this->vCalendar1a;
  600. // construct event reader
  601. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  602. // test set by constructor
  603. $this->assertEquals([], $er->recurringWeeksOfMonth());
  604. /** test rrule recurrance with monthly days*/
  605. $vCalendar = clone $this->vCalendar1a;
  606. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYDAY=MO;BYSETPOS=1');
  607. // construct event reader
  608. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  609. // test set by constructor
  610. $this->assertEquals([1], $er->recurringWeeksOfMonth());
  611. }
  612. public function testRecurringWeeksOfMonthNamed(): void {
  613. /** test no recurrance */
  614. $vCalendar = clone $this->vCalendar1a;
  615. // construct event reader
  616. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  617. // test set by constructor
  618. $this->assertEquals([], $er->recurringWeeksOfMonthNamed());
  619. /** test rrule recurrance with weekly days*/
  620. $vCalendar = clone $this->vCalendar1a;
  621. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYDAY=MO;BYSETPOS=1');
  622. // construct event reader
  623. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  624. // test set by constructor
  625. $this->assertEquals(['First'], $er->recurringWeeksOfMonthNamed());
  626. }
  627. public function testRecurringWeeksOfYear(): void {
  628. /** test no recurrance */
  629. $vCalendar = clone $this->vCalendar1a;
  630. // construct event reader
  631. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  632. // test set by constructor
  633. $this->assertEquals([], $er->recurringWeeksOfYear());
  634. /** test rrule recurrance with monthly days*/
  635. $vCalendar = clone $this->vCalendar1a;
  636. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYWEEKNO=35,42;BYDAY=TU');
  637. // construct event reader
  638. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  639. // test set by constructor
  640. $this->assertEquals([35,42], $er->recurringWeeksOfYear());
  641. }
  642. public function testRecurringMonthsOfYear(): void {
  643. /** test no recurrance */
  644. $vCalendar = clone $this->vCalendar1a;
  645. // construct event reader
  646. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  647. // test set by constructor
  648. $this->assertEquals([], $er->recurringMonthsOfYear());
  649. /** test rrule recurrance with monthly days*/
  650. $vCalendar = clone $this->vCalendar1a;
  651. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYMONTH=7;BYMONTHDAY=1');
  652. // construct event reader
  653. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  654. // test set by constructor
  655. $this->assertEquals([7], $er->recurringMonthsOfYear());
  656. }
  657. public function testRecurringMonthsOfYearNamed(): void {
  658. /** test no recurrance */
  659. $vCalendar = clone $this->vCalendar1a;
  660. // construct event reader
  661. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  662. // test set by constructor
  663. $this->assertEquals([], $er->recurringMonthsOfYearNamed());
  664. /** test rrule recurrance with weekly days*/
  665. $vCalendar = clone $this->vCalendar1a;
  666. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYMONTH=7;BYMONTHDAY=1');
  667. // construct event reader
  668. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  669. // test set by constructor
  670. $this->assertEquals(['July'], $er->recurringMonthsOfYearNamed());
  671. }
  672. public function testRecurringIterationDaily(): void {
  673. /** test rrule recurrance with daily frequency*/
  674. $vCalendar = clone $this->vCalendar1a;
  675. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=DAILY;INTERVAL=3;UNTIL=20240714T040000Z');
  676. // construct event reader
  677. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  678. // test initial recurrance
  679. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  680. // test next recurrance
  681. $er->recurrenceAdvance();
  682. $this->assertEquals((new \DateTime('20240704T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  683. // test next recurrance
  684. $er->recurrenceAdvance();
  685. $this->assertEquals((new \DateTime('20240707T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  686. // test next recurrance
  687. $er->recurrenceAdvance();
  688. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  689. // test next recurrance
  690. $er->recurrenceAdvance();
  691. $this->assertEquals((new \DateTime('20240713T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  692. // test next recurrance (This is past the last recurrance and should return null)
  693. $er->recurrenceAdvance();
  694. $this->assertNull($er->recurrenceDate());
  695. // test rewind to initial recurrance
  696. $er->recurrenceRewind();
  697. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  698. // test next recurrance
  699. $er->recurrenceAdvanceTo((new \DateTime('20240709T080000')));
  700. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  701. }
  702. public function testRecurringIterationWeekly(): void {
  703. /** test rrule recurrance with weekly frequency*/
  704. $vCalendar = clone $this->vCalendar1a;
  705. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20240713T040000Z');
  706. // construct event reader
  707. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  708. // test initial recurrance
  709. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  710. // test next recurrance
  711. $er->recurrenceAdvance();
  712. $this->assertEquals((new \DateTime('20240703T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  713. // test next recurrance
  714. $er->recurrenceAdvance();
  715. $this->assertEquals((new \DateTime('20240705T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  716. // test next recurrance
  717. $er->recurrenceAdvance();
  718. $this->assertEquals((new \DateTime('20240708T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  719. // test next recurrance
  720. $er->recurrenceAdvance();
  721. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  722. // test next recurrance
  723. $er->recurrenceAdvance();
  724. $this->assertEquals((new \DateTime('20240712T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  725. // test next recurrance (This is past the last recurrance and should return null)
  726. $er->recurrenceAdvance();
  727. $this->assertNull($er->recurrenceDate());
  728. // test rewind to initial recurrance
  729. $er->recurrenceRewind();
  730. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  731. // test next recurrance
  732. $er->recurrenceAdvanceTo((new \DateTime('20240709T080000')));
  733. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  734. }
  735. public function testRecurringIterationMonthlyAbsolute(): void {
  736. /** test rrule recurrance with monthly absolute frequency on the 1st of each month*/
  737. $vCalendar = clone $this->vCalendar1a;
  738. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;COUNT=3;BYMONTHDAY=1');
  739. // construct event reader
  740. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  741. // test initial recurrance
  742. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  743. // test next recurrance
  744. $er->recurrenceAdvance();
  745. $this->assertEquals((new \DateTime('20240801T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  746. // test next recurrance
  747. $er->recurrenceAdvance();
  748. $this->assertEquals((new \DateTime('20240901T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  749. // test next recurrance (This is past the last recurrance and should return null)
  750. $er->recurrenceAdvance();
  751. $this->assertNull($er->recurrenceDate());
  752. // test rewind to initial recurrance
  753. $er->recurrenceRewind();
  754. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  755. // test next recurrance
  756. $er->recurrenceAdvanceTo((new \DateTime('20240809T080000')));
  757. $this->assertEquals((new \DateTime('20240901T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  758. }
  759. public function testRecurringIterationMonthlyRelative(): void {
  760. /** test rrule recurrance with monthly relative frequency on the first monday of each month*/
  761. $vCalendar = clone $this->vCalendar1a;
  762. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;COUNT=3;BYDAY=MO;BYSETPOS=1');
  763. // construct event reader
  764. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  765. // test initial recurrance
  766. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  767. // test next recurrance
  768. $er->recurrenceAdvance();
  769. $this->assertEquals((new \DateTime('20240805T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  770. // test next recurrance
  771. $er->recurrenceAdvance();
  772. $this->assertEquals((new \DateTime('20240902T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  773. // test next recurrance (This is past the last recurrance and should return null)
  774. $er->recurrenceAdvance();
  775. $this->assertNull($er->recurrenceDate());
  776. // test rewind to initial recurrance
  777. $er->recurrenceRewind();
  778. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  779. // test next recurrance
  780. $er->recurrenceAdvanceTo((new \DateTime('20240809T080000')));
  781. $this->assertEquals((new \DateTime('20240902T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  782. }
  783. public function testRecurringIterationYearlyAbsolute(): void {
  784. /** test rrule recurrance with yearly absolute frequency on the 1st of july*/
  785. $vCalendar = clone $this->vCalendar1a;
  786. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;COUNT=3;BYMONTH=7');
  787. // construct event reader
  788. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  789. // test initial recurrance
  790. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  791. // test next recurrance
  792. $er->recurrenceAdvance();
  793. $this->assertEquals((new \DateTime('20250701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  794. // test next recurrance
  795. $er->recurrenceAdvance();
  796. $this->assertEquals((new \DateTime('20260701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  797. // test next recurrance (This is past the last recurrance and should return null)
  798. $er->recurrenceAdvance();
  799. $this->assertNull($er->recurrenceDate());
  800. // test rewind to initial recurrance
  801. $er->recurrenceRewind();
  802. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  803. // test next recurrance
  804. $er->recurrenceAdvanceTo((new \DateTime('20250809T080000')));
  805. $this->assertEquals((new \DateTime('20260701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  806. }
  807. public function testRecurringIterationYearlyRelative(): void {
  808. /** test rrule recurrance with yearly relative frequency on the first monday of july*/
  809. $vCalendar = clone $this->vCalendar1a;
  810. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;COUNT=3;BYMONTH=7;BYDAY=MO;BYSETPOS=1');
  811. // construct event reader
  812. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  813. // test initial recurrance
  814. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  815. // test next recurrance
  816. $er->recurrenceAdvance();
  817. $this->assertEquals((new \DateTime('20250707T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  818. // test next recurrance
  819. $er->recurrenceAdvance();
  820. $this->assertEquals((new \DateTime('20260706T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  821. // test next recurrance (This is past the last recurrance and should return null)
  822. $er->recurrenceAdvance();
  823. $this->assertNull($er->recurrenceDate());
  824. // test rewind to initial recurrance
  825. $er->recurrenceRewind();
  826. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  827. // test next recurrance
  828. $er->recurrenceAdvanceTo((new \DateTime('20250809T080000')));
  829. $this->assertEquals((new \DateTime('20260706T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  830. }
  831. public function testRecurringIterationFixed(): void {
  832. /** test rrule recurrance with yearly relative frequency on the first monday of july*/
  833. $vCalendar = clone $this->vCalendar1a;
  834. $vCalendar->VEVENT[0]->add('RDATE', '20240703T080000,20240905T080000,20241231T080000');
  835. // construct event reader
  836. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  837. // test initial recurrance
  838. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  839. // test next recurrance
  840. $er->recurrenceAdvance();
  841. $this->assertEquals((new \DateTime('20240703T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  842. // test next recurrance
  843. $er->recurrenceAdvance();
  844. $this->assertEquals((new \DateTime('20240905T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  845. // test next recurrance
  846. $er->recurrenceAdvance();
  847. $this->assertEquals((new \DateTime('20241231T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  848. // test next recurrance (This is past the last recurrance and should return null)
  849. $er->recurrenceAdvance();
  850. $this->assertNull($er->recurrenceDate());
  851. // test rewind to initial recurrance
  852. $er->recurrenceRewind();
  853. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  854. // test next recurrance
  855. $er->recurrenceAdvanceTo((new \DateTime('20240809T080000')));
  856. $this->assertEquals((new \DateTime('20240905T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  857. }
  858. }