EventReaderTest.php 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  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 rdate (multiple property instances) recurrance */
  445. $vCalendar = clone $this->vCalendar1a;
  446. $vCalendar->VEVENT[0]->add('RDATE', '20240703');
  447. $vCalendar->VEVENT[0]->add('RDATE', '20240705');
  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 rdate as last date */
  453. $vCalendar = clone $this->vCalendar1a;
  454. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  455. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  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. /** test rrule and rdate recurrance with rrule as last date */
  461. $vCalendar = clone $this->vCalendar1a;
  462. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=7;BYDAY=MO,WE,FR');
  463. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240713');
  464. // construct event reader
  465. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  466. // test set by constructor
  467. $this->assertTrue($er->recurringConcludes());
  468. }
  469. public function testRecurringConcludesAfter(): void {
  470. /** test no recurrance */
  471. $vCalendar = clone $this->vCalendar1a;
  472. // construct event reader
  473. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  474. // test set by constructor
  475. $this->assertNull($er->recurringConcludesAfter());
  476. /** test rrule recurrance with count */
  477. $vCalendar = clone $this->vCalendar1a;
  478. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  479. // construct event reader
  480. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  481. // test set by constructor
  482. $this->assertEquals(6, $er->recurringConcludesAfter());
  483. /** test rdate recurrance */
  484. $vCalendar = clone $this->vCalendar1a;
  485. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  486. // construct event reader
  487. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  488. // test set by constructor
  489. $this->assertEquals(2, $er->recurringConcludesAfter());
  490. /** test rdate (multiple property instances) recurrance */
  491. $vCalendar = clone $this->vCalendar1a;
  492. $vCalendar->VEVENT[0]->add('RDATE', '20240703');
  493. $vCalendar->VEVENT[0]->add('RDATE', '20240705');
  494. // construct event reader
  495. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  496. // test set by constructor
  497. $this->assertEquals(2, $er->recurringConcludesAfter());
  498. /** test rrule and rdate recurrance */
  499. $vCalendar = clone $this->vCalendar1a;
  500. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  501. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  502. // construct event reader
  503. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  504. // test set by constructor
  505. $this->assertEquals(8, $er->recurringConcludesAfter());
  506. }
  507. public function testRecurringConcludesOn(): void {
  508. /** test no recurrance */
  509. $vCalendar = clone $this->vCalendar1a;
  510. // construct event reader
  511. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  512. // test set by constructor
  513. $this->assertNull($er->recurringConcludesOn());
  514. /** test rrule recurrance with no end */
  515. $vCalendar = clone $this->vCalendar1a;
  516. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR');
  517. // construct event reader
  518. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  519. // test set by constructor
  520. $this->assertNull($er->recurringConcludesOn());
  521. /** test rrule recurrance with until date end */
  522. $vCalendar = clone $this->vCalendar1a;
  523. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  524. // construct event reader
  525. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  526. // test set by constructor
  527. // TODO: Fix until time zone
  528. //$this->assertEquals((new \DateTime('20240712T080000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  529. /** test rdate recurrance */
  530. $vCalendar = clone $this->vCalendar1a;
  531. $vCalendar->VEVENT[0]->add('RDATE', '20240703,20240705');
  532. // construct event reader
  533. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  534. // test set by constructor
  535. $this->assertEquals((new \DateTime('20240705T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  536. /** test rdate (multiple property instances) recurrance */
  537. $vCalendar = clone $this->vCalendar1a;
  538. $vCalendar->VEVENT[0]->add('RDATE', '20240703');
  539. $vCalendar->VEVENT[0]->add('RDATE', '20240705');
  540. // construct event reader
  541. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  542. // test set by constructor
  543. $this->assertEquals((new \DateTime('20240705T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  544. /** test rrule and rdate recurrance with rdate as last date */
  545. $vCalendar = clone $this->vCalendar1a;
  546. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
  547. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240715');
  548. // construct event reader
  549. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  550. // test set by constructor
  551. $this->assertEquals((new \DateTime('20240715T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  552. /** test rrule and rdate recurrance with rrule as last date */
  553. $vCalendar = clone $this->vCalendar1a;
  554. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=7;BYDAY=MO,WE,FR');
  555. $vCalendar->VEVENT[0]->add('RDATE', '20240706,20240713');
  556. // construct event reader
  557. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  558. // test set by constructor
  559. $this->assertEquals((new \DateTime('20240715T080000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
  560. }
  561. public function testRecurringDaysOfWeek(): void {
  562. /** test no recurrance */
  563. $vCalendar = clone $this->vCalendar1a;
  564. // construct event reader
  565. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  566. // test set by constructor
  567. $this->assertEquals([], $er->recurringDaysOfWeek());
  568. /** test rrule recurrance with weekly days*/
  569. $vCalendar = clone $this->vCalendar1a;
  570. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  571. // construct event reader
  572. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  573. // test set by constructor
  574. $this->assertEquals(['MO','WE','FR'], $er->recurringDaysOfWeek());
  575. }
  576. public function testRecurringDaysOfWeekNamed(): void {
  577. /** test no recurrance */
  578. $vCalendar = clone $this->vCalendar1a;
  579. // construct event reader
  580. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  581. // test set by constructor
  582. $this->assertEquals([], $er->recurringDaysOfWeekNamed());
  583. /** test rrule recurrance with weekly days*/
  584. $vCalendar = clone $this->vCalendar1a;
  585. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;UNTIL=20240712T080000Z;BYDAY=MO,WE,FR');
  586. // construct event reader
  587. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  588. // test set by constructor
  589. $this->assertEquals(['Monday','Wednesday','Friday'], $er->recurringDaysOfWeekNamed());
  590. }
  591. public function testRecurringDaysOfMonth(): void {
  592. /** test no recurrance */
  593. $vCalendar = clone $this->vCalendar1a;
  594. // construct event reader
  595. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  596. // test set by constructor
  597. $this->assertEquals([], $er->recurringDaysOfMonth());
  598. /** test rrule recurrance with monthly absolute dates*/
  599. $vCalendar = clone $this->vCalendar1a;
  600. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYMONTHDAY=6,13,20,27');
  601. // construct event reader
  602. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  603. // test set by constructor
  604. $this->assertEquals([6,13,20,27], $er->recurringDaysOfMonth());
  605. }
  606. public function testRecurringDaysOfYear(): void {
  607. /** test no recurrance */
  608. $vCalendar = clone $this->vCalendar1a;
  609. // construct event reader
  610. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  611. // test set by constructor
  612. $this->assertEquals([], $er->recurringDaysOfYear());
  613. /** test rrule recurrance with monthly absolute dates*/
  614. $vCalendar = clone $this->vCalendar1a;
  615. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;BYYEARDAY=1,30,180,365');
  616. // construct event reader
  617. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  618. // test set by constructor
  619. $this->assertEquals([1,30,180,365], $er->recurringDaysOfYear());
  620. }
  621. public function testRecurringWeeksOfMonth(): void {
  622. /** test no recurrance */
  623. $vCalendar = clone $this->vCalendar1a;
  624. // construct event reader
  625. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  626. // test set by constructor
  627. $this->assertEquals([], $er->recurringWeeksOfMonth());
  628. /** test rrule recurrance with monthly days*/
  629. $vCalendar = clone $this->vCalendar1a;
  630. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYDAY=MO;BYSETPOS=1');
  631. // construct event reader
  632. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  633. // test set by constructor
  634. $this->assertEquals([1], $er->recurringWeeksOfMonth());
  635. }
  636. public function testRecurringWeeksOfMonthNamed(): void {
  637. /** test no recurrance */
  638. $vCalendar = clone $this->vCalendar1a;
  639. // construct event reader
  640. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  641. // test set by constructor
  642. $this->assertEquals([], $er->recurringWeeksOfMonthNamed());
  643. /** test rrule recurrance with weekly days*/
  644. $vCalendar = clone $this->vCalendar1a;
  645. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;BYDAY=MO;BYSETPOS=1');
  646. // construct event reader
  647. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  648. // test set by constructor
  649. $this->assertEquals(['First'], $er->recurringWeeksOfMonthNamed());
  650. }
  651. public function testRecurringWeeksOfYear(): void {
  652. /** test no recurrance */
  653. $vCalendar = clone $this->vCalendar1a;
  654. // construct event reader
  655. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  656. // test set by constructor
  657. $this->assertEquals([], $er->recurringWeeksOfYear());
  658. /** test rrule recurrance with monthly days*/
  659. $vCalendar = clone $this->vCalendar1a;
  660. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYWEEKNO=35,42;BYDAY=TU');
  661. // construct event reader
  662. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  663. // test set by constructor
  664. $this->assertEquals([35,42], $er->recurringWeeksOfYear());
  665. }
  666. public function testRecurringMonthsOfYear(): void {
  667. /** test no recurrance */
  668. $vCalendar = clone $this->vCalendar1a;
  669. // construct event reader
  670. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  671. // test set by constructor
  672. $this->assertEquals([], $er->recurringMonthsOfYear());
  673. /** test rrule recurrance with monthly days*/
  674. $vCalendar = clone $this->vCalendar1a;
  675. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYMONTH=7;BYMONTHDAY=1');
  676. // construct event reader
  677. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  678. // test set by constructor
  679. $this->assertEquals([7], $er->recurringMonthsOfYear());
  680. }
  681. public function testRecurringMonthsOfYearNamed(): void {
  682. /** test no recurrance */
  683. $vCalendar = clone $this->vCalendar1a;
  684. // construct event reader
  685. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  686. // test set by constructor
  687. $this->assertEquals([], $er->recurringMonthsOfYearNamed());
  688. /** test rrule recurrance with weekly days*/
  689. $vCalendar = clone $this->vCalendar1a;
  690. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;INTERVAL=1;BYMONTH=7;BYMONTHDAY=1');
  691. // construct event reader
  692. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  693. // test set by constructor
  694. $this->assertEquals(['July'], $er->recurringMonthsOfYearNamed());
  695. }
  696. public function testRecurringIterationDaily(): void {
  697. /** test rrule recurrance with daily frequency*/
  698. $vCalendar = clone $this->vCalendar1a;
  699. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=DAILY;INTERVAL=3;UNTIL=20240714T040000Z');
  700. // construct event reader
  701. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  702. // test initial recurrance
  703. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  704. // test next recurrance
  705. $er->recurrenceAdvance();
  706. $this->assertEquals((new \DateTime('20240704T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  707. // test next recurrance
  708. $er->recurrenceAdvance();
  709. $this->assertEquals((new \DateTime('20240707T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  710. // test next recurrance
  711. $er->recurrenceAdvance();
  712. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  713. // test next recurrance
  714. $er->recurrenceAdvance();
  715. $this->assertEquals((new \DateTime('20240713T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  716. // test next recurrance (This is past the last recurrance and should return null)
  717. $er->recurrenceAdvance();
  718. $this->assertNull($er->recurrenceDate());
  719. // test rewind to initial recurrance
  720. $er->recurrenceRewind();
  721. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  722. // test next recurrance
  723. $er->recurrenceAdvanceTo((new \DateTime('20240709T080000')));
  724. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  725. }
  726. public function testRecurringIterationWeekly(): void {
  727. /** test rrule recurrance with weekly frequency*/
  728. $vCalendar = clone $this->vCalendar1a;
  729. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20240713T040000Z');
  730. // construct event reader
  731. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  732. // test initial recurrance
  733. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  734. // test next recurrance
  735. $er->recurrenceAdvance();
  736. $this->assertEquals((new \DateTime('20240703T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  737. // test next recurrance
  738. $er->recurrenceAdvance();
  739. $this->assertEquals((new \DateTime('20240705T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  740. // test next recurrance
  741. $er->recurrenceAdvance();
  742. $this->assertEquals((new \DateTime('20240708T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  743. // test next recurrance
  744. $er->recurrenceAdvance();
  745. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  746. // test next recurrance
  747. $er->recurrenceAdvance();
  748. $this->assertEquals((new \DateTime('20240712T080000', (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('20240709T080000')));
  757. $this->assertEquals((new \DateTime('20240710T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  758. }
  759. public function testRecurringIterationMonthlyAbsolute(): void {
  760. /** test rrule recurrance with monthly absolute frequency on the 1st of each month*/
  761. $vCalendar = clone $this->vCalendar1a;
  762. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;COUNT=3;BYMONTHDAY=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('20240801T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  770. // test next recurrance
  771. $er->recurrenceAdvance();
  772. $this->assertEquals((new \DateTime('20240901T080000', (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('20240901T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  782. }
  783. public function testRecurringIterationMonthlyRelative(): void {
  784. /** test rrule recurrance with monthly relative frequency on the first monday of each month*/
  785. $vCalendar = clone $this->vCalendar1a;
  786. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=MONTHLY;COUNT=3;BYDAY=MO;BYSETPOS=1');
  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('20240805T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  794. // test next recurrance
  795. $er->recurrenceAdvance();
  796. $this->assertEquals((new \DateTime('20240902T080000', (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('20240809T080000')));
  805. $this->assertEquals((new \DateTime('20240902T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  806. }
  807. public function testRecurringIterationYearlyAbsolute(): void {
  808. /** test rrule recurrance with yearly absolute frequency on the 1st of july*/
  809. $vCalendar = clone $this->vCalendar1a;
  810. $vCalendar->VEVENT[0]->add('RRULE', 'FREQ=YEARLY;COUNT=3;BYMONTH=7');
  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('20250701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  818. // test next recurrance
  819. $er->recurrenceAdvance();
  820. $this->assertEquals((new \DateTime('20260701T080000', (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('20260701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  830. }
  831. public function testRecurringIterationYearlyRelative(): 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('RRULE', 'FREQ=YEARLY;COUNT=3;BYMONTH=7;BYDAY=MO;BYSETPOS=1');
  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('20250707T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  842. // test next recurrance
  843. $er->recurrenceAdvance();
  844. $this->assertEquals((new \DateTime('20260706T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  845. // test next recurrance (This is past the last recurrance and should return null)
  846. $er->recurrenceAdvance();
  847. $this->assertNull($er->recurrenceDate());
  848. // test rewind to initial recurrance
  849. $er->recurrenceRewind();
  850. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  851. // test next recurrance
  852. $er->recurrenceAdvanceTo((new \DateTime('20250809T080000')));
  853. $this->assertEquals((new \DateTime('20260706T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  854. }
  855. public function testRecurringIterationFixed(): void {
  856. /** test rrule recurrance with yearly relative frequency on the first monday of july*/
  857. $vCalendar = clone $this->vCalendar1a;
  858. $vCalendar->VEVENT[0]->add('RDATE', '20240703T080000,20240905T080000,20241231T080000');
  859. // construct event reader
  860. $er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
  861. // test initial recurrance
  862. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  863. // test next recurrance
  864. $er->recurrenceAdvance();
  865. $this->assertEquals((new \DateTime('20240703T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  866. // test next recurrance
  867. $er->recurrenceAdvance();
  868. $this->assertEquals((new \DateTime('20240905T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  869. // test next recurrance
  870. $er->recurrenceAdvance();
  871. $this->assertEquals((new \DateTime('20241231T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  872. // test next recurrance (This is past the last recurrance and should return null)
  873. $er->recurrenceAdvance();
  874. $this->assertNull($er->recurrenceDate());
  875. // test rewind to initial recurrance
  876. $er->recurrenceRewind();
  877. $this->assertEquals((new \DateTime('20240701T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  878. // test next recurrance
  879. $er->recurrenceAdvanceTo((new \DateTime('20240809T080000')));
  880. $this->assertEquals((new \DateTime('20240905T080000', (new DateTimeZone('America/Toronto')))), $er->recurrenceDate());
  881. }
  882. }