EventsSearchProviderTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2020, Georg Ehrke
  5. *
  6. * @author Georg Ehrke <oc.list@georgehrke.com>
  7. * @author John Molakvoæ <skjnldsv@protonmail.com>
  8. *
  9. * @license GNU AGPL version 3 or any later version
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. *
  24. */
  25. namespace OCA\DAV\Tests\unit\Search;
  26. use OCA\DAV\CalDAV\CalDavBackend;
  27. use OCA\DAV\Search\EventsSearchProvider;
  28. use OCP\App\IAppManager;
  29. use OCP\IL10N;
  30. use OCP\IURLGenerator;
  31. use OCP\IUser;
  32. use OCP\Search\IFilter;
  33. use OCP\Search\ISearchQuery;
  34. use OCP\Search\SearchResult;
  35. use OCP\Search\SearchResultEntry;
  36. use Sabre\VObject\Reader;
  37. use Test\TestCase;
  38. class EventsSearchProviderTest extends TestCase {
  39. /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */
  40. private $appManager;
  41. /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
  42. private $l10n;
  43. /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
  44. private $urlGenerator;
  45. /** @var CalDavBackend|\PHPUnit\Framework\MockObject\MockObject */
  46. private $backend;
  47. /** @var EventsSearchProvider */
  48. private $provider;
  49. // NO SUMMARY
  50. private $vEvent0 = 'BEGIN:VCALENDAR'.PHP_EOL.
  51. 'VERSION:2.0'.PHP_EOL.
  52. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL.
  53. 'CALSCALE:GREGORIAN'.PHP_EOL.
  54. 'BEGIN:VEVENT'.PHP_EOL.
  55. 'CREATED:20161004T144433Z'.PHP_EOL.
  56. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL.
  57. 'DTEND;VALUE=DATE:20161008'.PHP_EOL.
  58. 'TRANSP:TRANSPARENT'.PHP_EOL.
  59. 'DTSTART;VALUE=DATE:20161005'.PHP_EOL.
  60. 'DTSTAMP:20161004T144437Z'.PHP_EOL.
  61. 'SEQUENCE:0'.PHP_EOL.
  62. 'END:VEVENT'.PHP_EOL.
  63. 'END:VCALENDAR';
  64. // TIMED SAME DAY
  65. private $vEvent1 = 'BEGIN:VCALENDAR'.PHP_EOL.
  66. 'VERSION:2.0'.PHP_EOL.
  67. 'PRODID:-//Tests//'.PHP_EOL.
  68. 'CALSCALE:GREGORIAN'.PHP_EOL.
  69. 'BEGIN:VTIMEZONE'.PHP_EOL.
  70. 'TZID:Europe/Berlin'.PHP_EOL.
  71. 'BEGIN:DAYLIGHT'.PHP_EOL.
  72. 'TZOFFSETFROM:+0100'.PHP_EOL.
  73. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL.
  74. 'DTSTART:19810329T020000'.PHP_EOL.
  75. 'TZNAME:GMT+2'.PHP_EOL.
  76. 'TZOFFSETTO:+0200'.PHP_EOL.
  77. 'END:DAYLIGHT'.PHP_EOL.
  78. 'BEGIN:STANDARD'.PHP_EOL.
  79. 'TZOFFSETFROM:+0200'.PHP_EOL.
  80. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL.
  81. 'DTSTART:19961027T030000'.PHP_EOL.
  82. 'TZNAME:GMT+1'.PHP_EOL.
  83. 'TZOFFSETTO:+0100'.PHP_EOL.
  84. 'END:STANDARD'.PHP_EOL.
  85. 'END:VTIMEZONE'.PHP_EOL.
  86. 'BEGIN:VEVENT'.PHP_EOL.
  87. 'CREATED:20160809T163629Z'.PHP_EOL.
  88. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL.
  89. 'DTEND;TZID=Europe/Berlin:20160816T100000'.PHP_EOL.
  90. 'TRANSP:OPAQUE'.PHP_EOL.
  91. 'SUMMARY:Test Europe Berlin'.PHP_EOL.
  92. 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL.
  93. 'DTSTAMP:20160809T163632Z'.PHP_EOL.
  94. 'SEQUENCE:0'.PHP_EOL.
  95. 'END:VEVENT'.PHP_EOL.
  96. 'END:VCALENDAR';
  97. // TIMED DIFFERENT DAY
  98. private $vEvent2 = 'BEGIN:VCALENDAR'.PHP_EOL.
  99. 'VERSION:2.0'.PHP_EOL.
  100. 'PRODID:-//Tests//'.PHP_EOL.
  101. 'CALSCALE:GREGORIAN'.PHP_EOL.
  102. 'BEGIN:VTIMEZONE'.PHP_EOL.
  103. 'TZID:Europe/Berlin'.PHP_EOL.
  104. 'BEGIN:DAYLIGHT'.PHP_EOL.
  105. 'TZOFFSETFROM:+0100'.PHP_EOL.
  106. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL.
  107. 'DTSTART:19810329T020000'.PHP_EOL.
  108. 'TZNAME:GMT+2'.PHP_EOL.
  109. 'TZOFFSETTO:+0200'.PHP_EOL.
  110. 'END:DAYLIGHT'.PHP_EOL.
  111. 'BEGIN:STANDARD'.PHP_EOL.
  112. 'TZOFFSETFROM:+0200'.PHP_EOL.
  113. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL.
  114. 'DTSTART:19961027T030000'.PHP_EOL.
  115. 'TZNAME:GMT+1'.PHP_EOL.
  116. 'TZOFFSETTO:+0100'.PHP_EOL.
  117. 'END:STANDARD'.PHP_EOL.
  118. 'END:VTIMEZONE'.PHP_EOL.
  119. 'BEGIN:VEVENT'.PHP_EOL.
  120. 'CREATED:20160809T163629Z'.PHP_EOL.
  121. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL.
  122. 'DTEND;TZID=Europe/Berlin:20160817T100000'.PHP_EOL.
  123. 'TRANSP:OPAQUE'.PHP_EOL.
  124. 'SUMMARY:Test Europe Berlin'.PHP_EOL.
  125. 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL.
  126. 'DTSTAMP:20160809T163632Z'.PHP_EOL.
  127. 'SEQUENCE:0'.PHP_EOL.
  128. 'END:VEVENT'.PHP_EOL.
  129. 'END:VCALENDAR';
  130. // ALL-DAY ONE-DAY
  131. private $vEvent3 = 'BEGIN:VCALENDAR'.PHP_EOL.
  132. 'VERSION:2.0'.PHP_EOL.
  133. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL.
  134. 'CALSCALE:GREGORIAN'.PHP_EOL.
  135. 'BEGIN:VEVENT'.PHP_EOL.
  136. 'CREATED:20161004T144433Z'.PHP_EOL.
  137. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL.
  138. 'DTEND;VALUE=DATE:20161006'.PHP_EOL.
  139. 'TRANSP:TRANSPARENT'.PHP_EOL.
  140. 'DTSTART;VALUE=DATE:20161005'.PHP_EOL.
  141. 'DTSTAMP:20161004T144437Z'.PHP_EOL.
  142. 'SEQUENCE:0'.PHP_EOL.
  143. 'END:VEVENT'.PHP_EOL.
  144. 'END:VCALENDAR';
  145. // ALL-DAY MULTIPLE DAYS
  146. private $vEvent4 = 'BEGIN:VCALENDAR'.PHP_EOL.
  147. 'VERSION:2.0'.PHP_EOL.
  148. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL.
  149. 'CALSCALE:GREGORIAN'.PHP_EOL.
  150. 'BEGIN:VEVENT'.PHP_EOL.
  151. 'CREATED:20161004T144433Z'.PHP_EOL.
  152. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL.
  153. 'DTEND;VALUE=DATE:20161008'.PHP_EOL.
  154. 'TRANSP:TRANSPARENT'.PHP_EOL.
  155. 'DTSTART;VALUE=DATE:20161005'.PHP_EOL.
  156. 'DTSTAMP:20161004T144437Z'.PHP_EOL.
  157. 'SEQUENCE:0'.PHP_EOL.
  158. 'END:VEVENT'.PHP_EOL.
  159. 'END:VCALENDAR';
  160. // DURATION
  161. private $vEvent5 = 'BEGIN:VCALENDAR'.PHP_EOL.
  162. 'VERSION:2.0'.PHP_EOL.
  163. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL.
  164. 'CALSCALE:GREGORIAN'.PHP_EOL.
  165. 'BEGIN:VEVENT'.PHP_EOL.
  166. 'CREATED:20161004T144433Z'.PHP_EOL.
  167. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL.
  168. 'DURATION:P5D'.PHP_EOL.
  169. 'TRANSP:TRANSPARENT'.PHP_EOL.
  170. 'DTSTART;VALUE=DATE:20161005'.PHP_EOL.
  171. 'DTSTAMP:20161004T144437Z'.PHP_EOL.
  172. 'SEQUENCE:0'.PHP_EOL.
  173. 'END:VEVENT'.PHP_EOL.
  174. 'END:VCALENDAR';
  175. // NO DTEND - DATE
  176. private $vEvent6 = 'BEGIN:VCALENDAR'.PHP_EOL.
  177. 'VERSION:2.0'.PHP_EOL.
  178. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL.
  179. 'CALSCALE:GREGORIAN'.PHP_EOL.
  180. 'BEGIN:VEVENT'.PHP_EOL.
  181. 'CREATED:20161004T144433Z'.PHP_EOL.
  182. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL.
  183. 'TRANSP:TRANSPARENT'.PHP_EOL.
  184. 'DTSTART;VALUE=DATE:20161005'.PHP_EOL.
  185. 'DTSTAMP:20161004T144437Z'.PHP_EOL.
  186. 'SEQUENCE:0'.PHP_EOL.
  187. 'END:VEVENT'.PHP_EOL.
  188. 'END:VCALENDAR';
  189. // NO DTEND - DATE-TIME
  190. private $vEvent7 = 'BEGIN:VCALENDAR'.PHP_EOL.
  191. 'VERSION:2.0'.PHP_EOL.
  192. 'PRODID:-//Tests//'.PHP_EOL.
  193. 'CALSCALE:GREGORIAN'.PHP_EOL.
  194. 'BEGIN:VTIMEZONE'.PHP_EOL.
  195. 'TZID:Europe/Berlin'.PHP_EOL.
  196. 'BEGIN:DAYLIGHT'.PHP_EOL.
  197. 'TZOFFSETFROM:+0100'.PHP_EOL.
  198. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL.
  199. 'DTSTART:19810329T020000'.PHP_EOL.
  200. 'TZNAME:GMT+2'.PHP_EOL.
  201. 'TZOFFSETTO:+0200'.PHP_EOL.
  202. 'END:DAYLIGHT'.PHP_EOL.
  203. 'BEGIN:STANDARD'.PHP_EOL.
  204. 'TZOFFSETFROM:+0200'.PHP_EOL.
  205. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL.
  206. 'DTSTART:19961027T030000'.PHP_EOL.
  207. 'TZNAME:GMT+1'.PHP_EOL.
  208. 'TZOFFSETTO:+0100'.PHP_EOL.
  209. 'END:STANDARD'.PHP_EOL.
  210. 'END:VTIMEZONE'.PHP_EOL.
  211. 'BEGIN:VEVENT'.PHP_EOL.
  212. 'CREATED:20160809T163629Z'.PHP_EOL.
  213. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL.
  214. 'TRANSP:OPAQUE'.PHP_EOL.
  215. 'SUMMARY:Test Europe Berlin'.PHP_EOL.
  216. 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL.
  217. 'DTSTAMP:20160809T163632Z'.PHP_EOL.
  218. 'SEQUENCE:0'.PHP_EOL.
  219. 'END:VEVENT'.PHP_EOL.
  220. 'END:VCALENDAR';
  221. protected function setUp(): void {
  222. parent::setUp();
  223. $this->appManager = $this->createMock(IAppManager::class);
  224. $this->l10n = $this->createMock(IL10N::class);
  225. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  226. $this->backend = $this->createMock(CalDavBackend::class);
  227. $this->provider = new EventsSearchProvider(
  228. $this->appManager,
  229. $this->l10n,
  230. $this->urlGenerator,
  231. $this->backend
  232. );
  233. }
  234. public function testGetId(): void {
  235. $this->assertEquals('calendar', $this->provider->getId());
  236. }
  237. public function testGetName(): void {
  238. $this->l10n->expects($this->exactly(1))
  239. ->method('t')
  240. ->with('Events')
  241. ->willReturnArgument(0);
  242. $this->assertEquals('Events', $this->provider->getName());
  243. }
  244. public function testSearchAppDisabled(): void {
  245. $user = $this->createMock(IUser::class);
  246. $query = $this->createMock(ISearchQuery::class);
  247. $this->appManager->expects($this->once())
  248. ->method('isEnabledForUser')
  249. ->with('calendar', $user)
  250. ->willReturn(false);
  251. $this->l10n->expects($this->exactly(1))
  252. ->method('t')
  253. ->willReturnArgument(0);
  254. $this->backend->expects($this->never())
  255. ->method('getCalendarsForUser');
  256. $this->backend->expects($this->never())
  257. ->method('getSubscriptionsForUser');
  258. $this->backend->expects($this->never())
  259. ->method('searchPrincipalUri');
  260. $actual = $this->provider->search($user, $query);
  261. $data = $actual->jsonSerialize();
  262. $this->assertInstanceOf(SearchResult::class, $actual);
  263. $this->assertEquals('Events', $data['name']);
  264. $this->assertEmpty($data['entries']);
  265. $this->assertFalse($data['isPaginated']);
  266. $this->assertNull($data['cursor']);
  267. }
  268. public function testSearch(): void {
  269. $user = $this->createMock(IUser::class);
  270. $user->method('getUID')->willReturn('john.doe');
  271. $query = $this->createMock(ISearchQuery::class);
  272. $seachTermFilter = $this->createMock(IFilter::class);
  273. $query->method('getFilter')->willReturnCallback(function ($name) use ($seachTermFilter) {
  274. return match ($name) {
  275. 'term' => $seachTermFilter,
  276. default => null,
  277. };
  278. });
  279. $seachTermFilter->method('get')->willReturn('search term');
  280. $query->method('getLimit')->willReturn(5);
  281. $query->method('getCursor')->willReturn(20);
  282. $this->appManager->expects($this->once())
  283. ->method('isEnabledForUser')
  284. ->with('calendar', $user)
  285. ->willReturn(true);
  286. $this->l10n->method('t')->willReturnArgument(0);
  287. $this->backend->expects($this->once())
  288. ->method('getCalendarsForUser')
  289. ->with('principals/users/john.doe')
  290. ->willReturn([
  291. [
  292. 'id' => 99,
  293. 'principaluri' => 'principals/users/john.doe',
  294. 'uri' => 'calendar-uri-99',
  295. ], [
  296. 'id' => 123,
  297. 'principaluri' => 'principals/users/john.doe',
  298. 'uri' => 'calendar-uri-123',
  299. ]
  300. ]);
  301. $this->backend->expects($this->once())
  302. ->method('getSubscriptionsForUser')
  303. ->with('principals/users/john.doe')
  304. ->willReturn([
  305. [
  306. 'id' => 1337,
  307. 'principaluri' => 'principals/users/john.doe',
  308. 'uri' => 'subscription-uri-1337',
  309. ]
  310. ]);
  311. $this->backend->expects($this->once())
  312. ->method('searchPrincipalUri')
  313. ->with('principals/users/john.doe', 'search term', ['VEVENT'],
  314. ['SUMMARY', 'LOCATION', 'DESCRIPTION', 'ATTENDEE', 'ORGANIZER', 'CATEGORIES'],
  315. ['ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN']],
  316. ['limit' => 5, 'offset' => 20, 'timerange' => ['start' => null, 'end' => null]])
  317. ->willReturn([
  318. [
  319. 'calendarid' => 99,
  320. 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
  321. 'uri' => 'event0.ics',
  322. 'calendardata' => $this->vEvent0,
  323. ],
  324. [
  325. 'calendarid' => 123,
  326. 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
  327. 'uri' => 'event1.ics',
  328. 'calendardata' => $this->vEvent1,
  329. ],
  330. [
  331. 'calendarid' => 1337,
  332. 'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION,
  333. 'uri' => 'event2.ics',
  334. 'calendardata' => $this->vEvent2,
  335. ]
  336. ]);
  337. $provider = $this->getMockBuilder(EventsSearchProvider::class)
  338. ->setConstructorArgs([
  339. $this->appManager,
  340. $this->l10n,
  341. $this->urlGenerator,
  342. $this->backend,
  343. ])
  344. ->setMethods([
  345. 'getDeepLinkToCalendarApp',
  346. 'generateSubline',
  347. ])
  348. ->getMock();
  349. $provider->expects($this->exactly(3))
  350. ->method('generateSubline')
  351. ->willReturn('subline');
  352. $provider->expects($this->exactly(3))
  353. ->method('getDeepLinkToCalendarApp')
  354. ->withConsecutive(
  355. ['principals/users/john.doe', 'calendar-uri-99', 'event0.ics'],
  356. ['principals/users/john.doe', 'calendar-uri-123', 'event1.ics'],
  357. ['principals/users/john.doe', 'subscription-uri-1337', 'event2.ics']
  358. )
  359. ->willReturn('deep-link-to-calendar');
  360. $actual = $provider->search($user, $query);
  361. $data = $actual->jsonSerialize();
  362. $this->assertInstanceOf(SearchResult::class, $actual);
  363. $this->assertEquals('Events', $data['name']);
  364. $this->assertCount(3, $data['entries']);
  365. $this->assertTrue($data['isPaginated']);
  366. $this->assertEquals(23, $data['cursor']);
  367. $result0 = $data['entries'][0];
  368. $result0Data = $result0->jsonSerialize();
  369. $result1 = $data['entries'][1];
  370. $result1Data = $result1->jsonSerialize();
  371. $result2 = $data['entries'][2];
  372. $result2Data = $result2->jsonSerialize();
  373. $this->assertInstanceOf(SearchResultEntry::class, $result0);
  374. $this->assertEmpty($result0Data['thumbnailUrl']);
  375. $this->assertEquals('Untitled event', $result0Data['title']);
  376. $this->assertEquals('subline', $result0Data['subline']);
  377. $this->assertEquals('deep-link-to-calendar', $result0Data['resourceUrl']);
  378. $this->assertEquals('icon-calendar-dark', $result0Data['icon']);
  379. $this->assertFalse($result0Data['rounded']);
  380. $this->assertInstanceOf(SearchResultEntry::class, $result1);
  381. $this->assertEmpty($result1Data['thumbnailUrl']);
  382. $this->assertEquals('Test Europe Berlin', $result1Data['title']);
  383. $this->assertEquals('subline', $result1Data['subline']);
  384. $this->assertEquals('deep-link-to-calendar', $result1Data['resourceUrl']);
  385. $this->assertEquals('icon-calendar-dark', $result1Data['icon']);
  386. $this->assertFalse($result1Data['rounded']);
  387. $this->assertInstanceOf(SearchResultEntry::class, $result2);
  388. $this->assertEmpty($result2Data['thumbnailUrl']);
  389. $this->assertEquals('Test Europe Berlin', $result2Data['title']);
  390. $this->assertEquals('subline', $result2Data['subline']);
  391. $this->assertEquals('deep-link-to-calendar', $result2Data['resourceUrl']);
  392. $this->assertEquals('icon-calendar-dark', $result2Data['icon']);
  393. $this->assertFalse($result2Data['rounded']);
  394. }
  395. public function testGetDeepLinkToCalendarApp(): void {
  396. $this->urlGenerator->expects($this->once())
  397. ->method('linkTo')
  398. ->with('', 'remote.php')
  399. ->willReturn('link-to-remote.php');
  400. $this->urlGenerator->expects($this->once())
  401. ->method('linkToRoute')
  402. ->with('calendar.view.index')
  403. ->willReturn('link-to-route-calendar/');
  404. $this->urlGenerator->expects($this->once())
  405. ->method('getAbsoluteURL')
  406. ->with('link-to-route-calendar/edit/bGluay10by1yZW1vdGUucGhwL2Rhdi9jYWxlbmRhcnMvam9obi5kb2UvZm9vL2Jhci5pY3M=')
  407. ->willReturn('absolute-url-to-route');
  408. $actual = self::invokePrivate($this->provider, 'getDeepLinkToCalendarApp', ['principals/users/john.doe', 'foo', 'bar.ics']);
  409. $this->assertEquals('absolute-url-to-route', $actual);
  410. }
  411. /**
  412. * @param string $ics
  413. * @param string $expectedSubline
  414. *
  415. * @dataProvider generateSublineDataProvider
  416. */
  417. public function testGenerateSubline(string $ics, string $expectedSubline): void {
  418. $vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING);
  419. $eventComponent = $vCalendar->VEVENT;
  420. $this->l10n->method('l')
  421. ->willReturnCallback(static function (string $type, \DateTime $date, $_):string {
  422. if ($type === 'time') {
  423. return $date->format('H:i');
  424. }
  425. return $date->format('m-d');
  426. });
  427. $actual = self::invokePrivate($this->provider, 'generateSubline', [$eventComponent]);
  428. $this->assertEquals($expectedSubline, $actual);
  429. }
  430. public function generateSublineDataProvider(): array {
  431. return [
  432. [$this->vEvent1, '08-16 09:00 - 10:00'],
  433. [$this->vEvent2, '08-16 09:00 - 08-17 10:00'],
  434. [$this->vEvent3, '10-05'],
  435. [$this->vEvent4, '10-05 - 10-07'],
  436. [$this->vEvent5, '10-05 - 10-09'],
  437. [$this->vEvent6, '10-05'],
  438. [$this->vEvent7, '08-16 09:00 - 09:00'],
  439. ];
  440. }
  441. }