diff options
author | Georg Ehrke <developer@georgehrke.com> | 2020-07-27 16:14:15 +0200 |
---|---|---|
committer | Georg Ehrke <developer@georgehrke.com> | 2020-08-04 16:01:59 +0200 |
commit | 900617e7d7260804ec89a03ca0201340d7585c8b (patch) | |
tree | 9311f493a11016e247f2378368b46e42a14e35b8 /apps/dav/tests | |
parent | c124b485f123fb24cb1d305e5ea62cbb6ae077c9 (diff) | |
download | nextcloud-server-900617e7d7260804ec89a03ca0201340d7585c8b.tar.gz nextcloud-server-900617e7d7260804ec89a03ca0201340d7585c8b.zip |
Add Event and Task Backends for Unified Search
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
Diffstat (limited to 'apps/dav/tests')
5 files changed, 1113 insertions, 13 deletions
diff --git a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php index 4c6c8549055..79da92148af 100644 --- a/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php +++ b/apps/dav/tests/unit/CalDAV/AbstractCalDavBackend.php @@ -121,7 +121,12 @@ abstract class AbstractCalDavBackend extends TestCase { $this->principal->expects($this->any())->method('getGroupMembership') ->withAnyParameters() ->willReturn([self::UNIT_TEST_GROUP, self::UNIT_TEST_GROUP2]); - $calendars = $this->backend->getCalendarsForUser(self::UNIT_TEST_USER); + $this->cleanupForPrincipal(self::UNIT_TEST_USER); + $this->cleanupForPrincipal(self::UNIT_TEST_USER1); + } + + private function cleanupForPrincipal($principal): void { + $calendars = $this->backend->getCalendarsForUser($principal); foreach ($calendars as $calendar) { $this->dispatcher->expects($this->at(0)) ->method('dispatch') @@ -129,7 +134,7 @@ abstract class AbstractCalDavBackend extends TestCase { $this->backend->deleteCalendar($calendar['id']); } - $subscriptions = $this->backend->getSubscriptionsForUser(self::UNIT_TEST_USER); + $subscriptions = $this->backend->getSubscriptionsForUser($principal); foreach ($subscriptions as $subscription) { $this->backend->deleteSubscription($subscription['id']); } diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index bd6a8856d51..4e343340f25 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -605,21 +605,21 @@ DTSTART;TZID=Europe/Warsaw:20170325T150000 DTEND;TZID=Europe/Warsaw:20170325T160000 TRANSP:OPAQUE DESCRIPTION:Magiczna treść uzyskana za pomocą magicznego proszku.\n\nę - żźćńłóÓŻŹĆŁĘ€śśśŚŚ\n \,\,))))))))\;\,\n + żźćńłóÓŻŹĆŁĘ€śśśŚŚ\n \,\,))))))))\;\,\n __))))))))))))))\,\n \\|/ -\\(((((''''((((((((.\n -*-==/// - ///(('' . `))))))\,\n /|\\ ))| o \;-. '((((( - \,(\,\n ( `| / ) \;))))' + ///(('' . `))))))\,\n /|\\ ))| o \;-. '((((( + \,(\,\n ( `| / ) \;))))' \,_))^\;(~\n | | | \,))((((_ _____- -----~~~-. %\,\;(\;(>'\;'~\n o_)\; \; )))(((` ~--- ~ `:: \\ %%~~)(v\;(`('~\n \; ''''```` - `: `:::|\\\,__\,%% )\;`'\; ~\n | _ - ) / `:|`----' `-'\n ______/\\/~ | + `: `:::|\\\,__\,%% )\;`'\; ~\n | _ + ) / `:|`----' `-'\n ______/\\/~ | / /\n /~\;\;.____/\;\;' / ___--\ - ,-( `\;\;\;/\n / // _\;______\;'------~~~~~ /\;\;/\\ /\n - // | | / \; \\\;\;\,\\\n (<_ | \; - /'\,/-----' _>\n \\_| ||_ - //~\;~~~~~~~~~\n `\\_| (\,~~ -Tua Xiong\n - \\~\\\n + ,-( `\;\;\;/\n / // _\;______\;'------~~~~~ /\;\;/\\ /\n + // | | / \; \\\;\;\,\\\n (<_ | \; + /'\,/-----' _>\n \\_| ||_ + //~\;~~~~~~~~~\n `\\_| (\,~~ -Tua Xiong\n + \\~\\\n ~~\n\n SEQUENCE:1 X-MOZ-GENERATION:1 @@ -999,4 +999,282 @@ EOD; $this->assertEquals($calendarInfoUser['id'], $calendarInfoUser1['id']); $this->assertEquals($calendarInfoUser['uri'], $calendarInfoUser1['uri']); } + + public function testSearchPrincipal(): void { + $myPublic = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:My Test (public) +CLASS:PUBLIC +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-1 +END:VEVENT +END:VCALENDAR +EOD; + $myPrivate = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:My Test (private) +CLASS:PRIVATE +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-2 +END:VEVENT +END:VCALENDAR +EOD; + $myConfidential = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:My Test (confidential) +CLASS:CONFIDENTIAL +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-3 +END:VEVENT +END:VCALENDAR +EOD; + + $sharerPublic = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:Sharer Test (public) +CLASS:PUBLIC +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-4 +END:VEVENT +END:VCALENDAR +EOD; + $sharerPrivate = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:Sharer Test (private) +CLASS:PRIVATE +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-5 +END:VEVENT +END:VCALENDAR +EOD; + $sharerConfidential = <<<EOD +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//dmfs.org//mimedir.icalendar//EN +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20160419T130000 +SUMMARY:Sharer Test (confidential) +CLASS:CONFIDENTIAL +TRANSP:OPAQUE +STATUS:CONFIRMED +DTEND;TZID=Europe/Berlin:20160419T140000 +LAST-MODIFIED:20160419T074202Z +DTSTAMP:20160419T074202Z +CREATED:20160419T074202Z +UID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310-6 +END:VEVENT +END:VCALENDAR +EOD; + + $l10n = $this->createMock(IL10N::class); + $l10n + ->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); + $config = $this->createMock(IConfig::class); + $this->userManager->expects($this->any()) + ->method('userExists') + ->willReturn(true); + $this->groupManager->expects($this->any()) + ->method('groupExists') + ->willReturn(true); + + $me = self::UNIT_TEST_USER; + $sharer = self::UNIT_TEST_USER1; + $this->backend->createCalendar($me, 'calendar-uri-me', []); + $this->backend->createCalendar($sharer, 'calendar-uri-sharer', []); + + $myCalendars = $this->backend->getCalendarsForUser($me); + $this->assertCount(1, $myCalendars); + + $sharerCalendars = $this->backend->getCalendarsForUser($sharer); + $this->assertCount(1, $sharerCalendars); + $sharerCalendar = new Calendar($this->backend, $sharerCalendars[0], $l10n, $config); + $this->backend->updateShares($sharerCalendar, [ + [ + 'href' => 'principal:' . $me, + 'readOnly' => false, + ], + ], []); + + $this->assertCount(2, $this->backend->getCalendarsForUser($me)); + + $this->backend->createCalendarObject($myCalendars[0]['id'], 'event0.ics', $myPublic); + $this->backend->createCalendarObject($myCalendars[0]['id'], 'event1.ics', $myPrivate); + $this->backend->createCalendarObject($myCalendars[0]['id'], 'event2.ics', $myConfidential); + + $this->backend->createCalendarObject($sharerCalendars[0]['id'], 'event3.ics', $sharerPublic); + $this->backend->createCalendarObject($sharerCalendars[0]['id'], 'event4.ics', $sharerPrivate); + $this->backend->createCalendarObject($sharerCalendars[0]['id'], 'event5.ics', $sharerConfidential); + + $mySearchResults = $this->backend->searchPrincipalUri($me, 'Test', ['VEVENT'], ['SUMMARY'], []); + $sharerSearchResults = $this->backend->searchPrincipalUri($sharer, 'Test', ['VEVENT'], ['SUMMARY'], []); + + $this->assertCount(4, $mySearchResults); + $this->assertCount(3, $sharerSearchResults); + + $this->assertEquals($myPublic, $mySearchResults[0]['calendardata']); + $this->assertEquals($myPrivate, $mySearchResults[1]['calendardata']); + $this->assertEquals($myConfidential, $mySearchResults[2]['calendardata']); + $this->assertEquals($sharerPublic, $mySearchResults[3]['calendardata']); + + $this->assertEquals($sharerPublic, $sharerSearchResults[0]['calendardata']); + $this->assertEquals($sharerPrivate, $sharerSearchResults[1]['calendardata']); + $this->assertEquals($sharerConfidential, $sharerSearchResults[2]['calendardata']); + } } diff --git a/apps/dav/tests/unit/Search/ContactsSearchProviderTest.php b/apps/dav/tests/unit/Search/ContactsSearchProviderTest.php index d89d8dd1690..e0cfe3245ba 100644 --- a/apps/dav/tests/unit/Search/ContactsSearchProviderTest.php +++ b/apps/dav/tests/unit/Search/ContactsSearchProviderTest.php @@ -224,7 +224,7 @@ class ContactsSearchProviderTest extends TestCase { $this->assertEquals('icon-contacts-dark', $result0Data['iconClass']); $this->assertTrue($result0Data['rounded']); - $this->assertInstanceOf(ContactsSearchResultEntry::class, $result0); + $this->assertInstanceOf(ContactsSearchResultEntry::class, $result1); $this->assertEquals('absolute-thumbnail-url?photo', $result1Data['thumbnailUrl']); $this->assertEquals('FN of Test2', $result1Data['title']); $this->assertEquals('subline', $result1Data['subline']); diff --git a/apps/dav/tests/unit/Search/EventsSearchProviderTest.php b/apps/dav/tests/unit/Search/EventsSearchProviderTest.php new file mode 100644 index 00000000000..f0d6329db5c --- /dev/null +++ b/apps/dav/tests/unit/Search/EventsSearchProviderTest.php @@ -0,0 +1,473 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2020, Georg Ehrke + * + * @author Georg Ehrke <oc.list@georgehrke.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OCA\DAV\Tests\unit\Search; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Search\EventsSearchProvider; +use OCA\DAV\Search\EventsSearchResultEntry; +use OCP\App\IAppManager; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Search\ISearchQuery; +use OCP\Search\SearchResult; +use Sabre\VObject\Reader; +use Test\TestCase; + +class EventsSearchProviderTest extends TestCase { + + /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ + private $appManager; + + /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ + private $l10n; + + /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ + private $urlGenerator; + + /** @var CalDavBackend|\PHPUnit\Framework\MockObject\MockObject */ + private $backend; + + /** @var EventsSearchProvider */ + private $provider; + + // NO SUMMARY + private $vEvent0 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20161004T144433Z'.PHP_EOL. + 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL. + 'DTEND;VALUE=DATE:20161008'.PHP_EOL. + 'TRANSP:TRANSPARENT'.PHP_EOL. + 'DTSTART;VALUE=DATE:20161005'.PHP_EOL. + 'DTSTAMP:20161004T144437Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // TIMED SAME DAY + private $vEvent1 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Tests//'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VTIMEZONE'.PHP_EOL. + 'TZID:Europe/Berlin'.PHP_EOL. + 'BEGIN:DAYLIGHT'.PHP_EOL. + 'TZOFFSETFROM:+0100'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19810329T020000'.PHP_EOL. + 'TZNAME:GMT+2'.PHP_EOL. + 'TZOFFSETTO:+0200'.PHP_EOL. + 'END:DAYLIGHT'.PHP_EOL. + 'BEGIN:STANDARD'.PHP_EOL. + 'TZOFFSETFROM:+0200'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19961027T030000'.PHP_EOL. + 'TZNAME:GMT+1'.PHP_EOL. + 'TZOFFSETTO:+0100'.PHP_EOL. + 'END:STANDARD'.PHP_EOL. + 'END:VTIMEZONE'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20160809T163629Z'.PHP_EOL. + 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL. + 'DTEND;TZID=Europe/Berlin:20160816T100000'.PHP_EOL. + 'TRANSP:OPAQUE'.PHP_EOL. + 'SUMMARY:Test Europe Berlin'.PHP_EOL. + 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL. + 'DTSTAMP:20160809T163632Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // TIMED DIFFERENT DAY + private $vEvent2 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Tests//'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VTIMEZONE'.PHP_EOL. + 'TZID:Europe/Berlin'.PHP_EOL. + 'BEGIN:DAYLIGHT'.PHP_EOL. + 'TZOFFSETFROM:+0100'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19810329T020000'.PHP_EOL. + 'TZNAME:GMT+2'.PHP_EOL. + 'TZOFFSETTO:+0200'.PHP_EOL. + 'END:DAYLIGHT'.PHP_EOL. + 'BEGIN:STANDARD'.PHP_EOL. + 'TZOFFSETFROM:+0200'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19961027T030000'.PHP_EOL. + 'TZNAME:GMT+1'.PHP_EOL. + 'TZOFFSETTO:+0100'.PHP_EOL. + 'END:STANDARD'.PHP_EOL. + 'END:VTIMEZONE'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20160809T163629Z'.PHP_EOL. + 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL. + 'DTEND;TZID=Europe/Berlin:20160817T100000'.PHP_EOL. + 'TRANSP:OPAQUE'.PHP_EOL. + 'SUMMARY:Test Europe Berlin'.PHP_EOL. + 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL. + 'DTSTAMP:20160809T163632Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // ALL-DAY ONE-DAY + private $vEvent3 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20161004T144433Z'.PHP_EOL. + 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL. + 'DTEND;VALUE=DATE:20161006'.PHP_EOL. + 'TRANSP:TRANSPARENT'.PHP_EOL. + 'DTSTART;VALUE=DATE:20161005'.PHP_EOL. + 'DTSTAMP:20161004T144437Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // ALL-DAY MULTIPLE DAYS + private $vEvent4 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20161004T144433Z'.PHP_EOL. + 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL. + 'DTEND;VALUE=DATE:20161008'.PHP_EOL. + 'TRANSP:TRANSPARENT'.PHP_EOL. + 'DTSTART;VALUE=DATE:20161005'.PHP_EOL. + 'DTSTAMP:20161004T144437Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // DURATION + private $vEvent5 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20161004T144433Z'.PHP_EOL. + 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL. + 'DURATION:P5D'.PHP_EOL. + 'TRANSP:TRANSPARENT'.PHP_EOL. + 'DTSTART;VALUE=DATE:20161005'.PHP_EOL. + 'DTSTAMP:20161004T144437Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // NO DTEND - DATE + private $vEvent6 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20161004T144433Z'.PHP_EOL. + 'UID:85560E76-1B0D-47E1-A735-21625767FCA4'.PHP_EOL. + 'TRANSP:TRANSPARENT'.PHP_EOL. + 'DTSTART;VALUE=DATE:20161005'.PHP_EOL. + 'DTSTAMP:20161004T144437Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + // NO DTEND - DATE-TIME + private $vEvent7 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'PRODID:-//Tests//'.PHP_EOL. + 'CALSCALE:GREGORIAN'.PHP_EOL. + 'BEGIN:VTIMEZONE'.PHP_EOL. + 'TZID:Europe/Berlin'.PHP_EOL. + 'BEGIN:DAYLIGHT'.PHP_EOL. + 'TZOFFSETFROM:+0100'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19810329T020000'.PHP_EOL. + 'TZNAME:GMT+2'.PHP_EOL. + 'TZOFFSETTO:+0200'.PHP_EOL. + 'END:DAYLIGHT'.PHP_EOL. + 'BEGIN:STANDARD'.PHP_EOL. + 'TZOFFSETFROM:+0200'.PHP_EOL. + 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU'.PHP_EOL. + 'DTSTART:19961027T030000'.PHP_EOL. + 'TZNAME:GMT+1'.PHP_EOL. + 'TZOFFSETTO:+0100'.PHP_EOL. + 'END:STANDARD'.PHP_EOL. + 'END:VTIMEZONE'.PHP_EOL. + 'BEGIN:VEVENT'.PHP_EOL. + 'CREATED:20160809T163629Z'.PHP_EOL. + 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02'.PHP_EOL. + 'TRANSP:OPAQUE'.PHP_EOL. + 'SUMMARY:Test Europe Berlin'.PHP_EOL. + 'DTSTART;TZID=Europe/Berlin:20160816T090000'.PHP_EOL. + 'DTSTAMP:20160809T163632Z'.PHP_EOL. + 'SEQUENCE:0'.PHP_EOL. + 'END:VEVENT'.PHP_EOL. + 'END:VCALENDAR'; + + protected function setUp(): void { + parent::setUp(); + + $this->appManager = $this->createMock(IAppManager::class); + $this->l10n = $this->createMock(IL10N::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->backend = $this->createMock(CalDavBackend::class); + + $this->provider = new EventsSearchProvider( + $this->appManager, + $this->l10n, + $this->urlGenerator, + $this->backend + ); + } + + public function testGetId(): void { + $this->assertEquals('calendar-dav', $this->provider->getId()); + } + + public function testGetName(): void { + $this->l10n->expects($this->exactly(1)) + ->method('t') + ->with('Events') + ->willReturnArgument(0); + + $this->assertEquals('Events', $this->provider->getName()); + } + + public function testSearchAppDisabled(): void { + $user = $this->createMock(IUser::class); + $query = $this->createMock(ISearchQuery::class); + $this->appManager->expects($this->once()) + ->method('isEnabledForUser') + ->with('calendar', $user) + ->willReturn(false); + $this->l10n->expects($this->exactly(1)) + ->method('t') + ->willReturnArgument(0); + $this->backend->expects($this->never()) + ->method('getCalendarsForUser'); + $this->backend->expects($this->never()) + ->method('getSubscriptionsForUser'); + $this->backend->expects($this->never()) + ->method('searchPrincipalUri'); + + $actual = $this->provider->search($user, $query); + $data = $actual->jsonSerialize(); + $this->assertInstanceOf(SearchResult::class, $actual); + $this->assertEquals('Events', $data['name']); + $this->assertEmpty($data['entries']); + $this->assertFalse($data['isPaginated']); + $this->assertNull($data['cursor']); + } + + public function testSearch(): void { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('john.doe'); + $query = $this->createMock(ISearchQuery::class); + $query->method('getTerm')->willReturn('search term'); + $query->method('getLimit')->willReturn(5); + $query->method('getCursor')->willReturn(20); + $this->appManager->expects($this->once()) + ->method('isEnabledForUser') + ->with('calendar', $user) + ->willReturn(true); + $this->l10n->method('t')->willReturnArgument(0); + + $this->backend->expects($this->once()) + ->method('getCalendarsForUser') + ->with('principals/users/john.doe') + ->willReturn([ + [ + 'id' => 99, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'calendar-uri-99', + ], [ + 'id' => 123, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'calendar-uri-123', + ] + ]); + $this->backend->expects($this->once()) + ->method('getSubscriptionsForUser') + ->with('principals/users/john.doe') + ->willReturn([ + [ + 'id' => 1337, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'subscription-uri-1337', + ] + ]); + $this->backend->expects($this->once()) + ->method('searchPrincipalUri') + ->with('principals/users/john.doe', 'search term', ['VEVENT'], + ['SUMMARY', 'LOCATION', 'DESCRIPTION', 'ATTENDEE', 'ORGANIZER', 'CATEGORIES'], + ['ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN']], + ['limit' => 5, 'offset' => 20]) + ->willReturn([ + [ + 'calendarid' => 99, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR, + 'uri' => 'event0.ics', + 'calendardata' => $this->vEvent0, + ], + [ + 'calendarid' => 123, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR, + 'uri' => 'event1.ics', + 'calendardata' => $this->vEvent1, + ], + [ + 'calendarid' => 1337, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION, + 'uri' => 'event2.ics', + 'calendardata' => $this->vEvent2, + ] + ]); + + $provider = $this->getMockBuilder(EventsSearchProvider::class) + ->setConstructorArgs([ + $this->appManager, + $this->l10n, + $this->urlGenerator, + $this->backend, + ]) + ->setMethods([ + 'getDeepLinkToCalendarApp', + 'generateSubline', + ]) + ->getMock(); + + $provider->expects($this->exactly(3)) + ->method('generateSubline') + ->willReturn('subline'); + $provider->expects($this->exactly(3)) + ->method('getDeepLinkToCalendarApp') + ->withConsecutive( + ['principals/users/john.doe', 'calendar-uri-99', 'event0.ics'], + ['principals/users/john.doe', 'calendar-uri-123', 'event1.ics'], + ['principals/users/john.doe', 'subscription-uri-1337', 'event2.ics'] + ) + ->willReturn('deep-link-to-calendar'); + + $actual = $provider->search($user, $query); + $data = $actual->jsonSerialize(); + $this->assertInstanceOf(SearchResult::class, $actual); + $this->assertEquals('Events', $data['name']); + $this->assertCount(3, $data['entries']); + $this->assertTrue($data['isPaginated']); + $this->assertEquals(23, $data['cursor']); + + $result0 = $data['entries'][0]; + $result0Data = $result0->jsonSerialize(); + $result1 = $data['entries'][1]; + $result1Data = $result1->jsonSerialize(); + $result2 = $data['entries'][2]; + $result2Data = $result2->jsonSerialize(); + + $this->assertInstanceOf(EventsSearchResultEntry::class, $result0); + $this->assertEmpty($result0Data['thumbnailUrl']); + $this->assertEquals('Untitled event', $result0Data['title']); + $this->assertEquals('subline', $result0Data['subline']); + $this->assertEquals('deep-link-to-calendar', $result0Data['resourceUrl']); + $this->assertEquals('icon-calendar-dark', $result0Data['iconClass']); + $this->assertFalse($result0Data['rounded']); + + $this->assertInstanceOf(EventsSearchResultEntry::class, $result1); + $this->assertEmpty($result1Data['thumbnailUrl']); + $this->assertEquals('Test Europe Berlin', $result1Data['title']); + $this->assertEquals('subline', $result1Data['subline']); + $this->assertEquals('deep-link-to-calendar', $result1Data['resourceUrl']); + $this->assertEquals('icon-calendar-dark', $result1Data['iconClass']); + $this->assertFalse($result1Data['rounded']); + + $this->assertInstanceOf(EventsSearchResultEntry::class, $result2); + $this->assertEmpty($result2Data['thumbnailUrl']); + $this->assertEquals('Test Europe Berlin', $result2Data['title']); + $this->assertEquals('subline', $result2Data['subline']); + $this->assertEquals('deep-link-to-calendar', $result2Data['resourceUrl']); + $this->assertEquals('icon-calendar-dark', $result2Data['iconClass']); + $this->assertFalse($result2Data['rounded']); + } + + public function testGetDeepLinkToCalendarApp(): void { + $this->urlGenerator->expects($this->at(0)) + ->method('linkTo') + ->with('', 'remote.php') + ->willReturn('link-to-remote.php'); + $this->urlGenerator->expects($this->at(1)) + ->method('linkToRoute') + ->with('calendar.view.index') + ->willReturn('link-to-route-calendar/'); + $this->urlGenerator->expects($this->at(2)) + ->method('getAbsoluteURL') + ->with('link-to-route-calendar/edit/bGluay10by1yZW1vdGUucGhwL2Rhdi9jYWxlbmRhcnMvam9obi5kb2UvZm9vL2Jhci5pY3M=') + ->willReturn('absolute-url-to-route'); + + $actual = self::invokePrivate($this->provider, 'getDeepLinkToCalendarApp', ['principals/users/john.doe', 'foo', 'bar.ics']); + + $this->assertEquals('absolute-url-to-route', $actual); + } + + /** + * @param string $ics + * @param string $expectedSubline + * + * @dataProvider generateSublineDataProvider + */ + public function testGenerateSubline(string $ics, string $expectedSubline): void { + $vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING); + $eventComponent = $vCalendar->VEVENT; + + $this->l10n->method('l') + ->willReturnCallback(static function (string $type, \DateTime $date, $_):string { + if ($type === 'time') { + return $date->format('H:i'); + } + + return $date->format('m-d'); + }); + + $actual = self::invokePrivate($this->provider, 'generateSubline', [$eventComponent]); + $this->assertEquals($expectedSubline, $actual); + } + + public function generateSublineDataProvider(): array { + return [ + [$this->vEvent1, '08-16 09:00 - 10:00'], + [$this->vEvent2, '08-16 09:00 - 08-17 10:00'], + [$this->vEvent3, '10-05'], + [$this->vEvent4, '10-05 - 10-07'], + [$this->vEvent5, '10-05 - 10-09'], + [$this->vEvent6, '10-05'], + [$this->vEvent7, '08-16 09:00 - 09:00'], + ]; + } +} diff --git a/apps/dav/tests/unit/Search/TasksSearchProviderTest.php b/apps/dav/tests/unit/Search/TasksSearchProviderTest.php new file mode 100644 index 00000000000..30f57270e95 --- /dev/null +++ b/apps/dav/tests/unit/Search/TasksSearchProviderTest.php @@ -0,0 +1,344 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2020, Georg Ehrke + * + * @author Georg Ehrke <oc.list@georgehrke.com> + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OCA\DAV\Tests\unit\Search; + +use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Search\TasksSearchProvider; +use OCA\DAV\Search\TasksSearchResultEntry; +use OCP\App\IAppManager; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Search\ISearchQuery; +use OCP\Search\SearchResult; +use Sabre\VObject\Reader; +use Test\TestCase; + +class TasksSearchProviderTest extends TestCase { + + /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ + private $appManager; + + /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ + private $l10n; + + /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ + private $urlGenerator; + + /** @var CalDavBackend|\PHPUnit\Framework\MockObject\MockObject */ + private $backend; + + /** @var TasksSearchProvider */ + private $provider; + + // NO DUE NOR COMPLETED NOR SUMMARY + private $vTodo0 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'PRODID:TEST'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'BEGIN:VTODO'.PHP_EOL. + 'UID:20070313T123432Z-456553@example.com'.PHP_EOL. + 'DTSTAMP:20070313T123432Z'.PHP_EOL. + 'STATUS:NEEDS-ACTION'.PHP_EOL. + 'END:VTODO'.PHP_EOL. + 'END:VCALENDAR'; + + // DUE AND COMPLETED + private $vTodo1 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'PRODID:TEST'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'BEGIN:VTODO'.PHP_EOL. + 'UID:20070313T123432Z-456553@example.com'.PHP_EOL. + 'DTSTAMP:20070313T123432Z'.PHP_EOL. + 'COMPLETED:20070707T100000Z'.PHP_EOL. + 'DUE;VALUE=DATE:20070501'.PHP_EOL. + 'SUMMARY:Task title'.PHP_EOL. + 'STATUS:NEEDS-ACTION'.PHP_EOL. + 'END:VTODO'.PHP_EOL. + 'END:VCALENDAR'; + + // COMPLETED ONLY + private $vTodo2 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'PRODID:TEST'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'BEGIN:VTODO'.PHP_EOL. + 'UID:20070313T123432Z-456553@example.com'.PHP_EOL. + 'DTSTAMP:20070313T123432Z'.PHP_EOL. + 'COMPLETED:20070707T100000Z'.PHP_EOL. + 'SUMMARY:Task title'.PHP_EOL. + 'STATUS:NEEDS-ACTION'.PHP_EOL. + 'END:VTODO'.PHP_EOL. + 'END:VCALENDAR'; + + // DUE DATE + private $vTodo3 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'PRODID:TEST'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'BEGIN:VTODO'.PHP_EOL. + 'UID:20070313T123432Z-456553@example.com'.PHP_EOL. + 'DTSTAMP:20070313T123432Z'.PHP_EOL. + 'DUE;VALUE=DATE:20070501'.PHP_EOL. + 'SUMMARY:Task title'.PHP_EOL. + 'STATUS:NEEDS-ACTION'.PHP_EOL. + 'END:VTODO'.PHP_EOL. + 'END:VCALENDAR'; + + // DUE DATETIME + private $vTodo4 = 'BEGIN:VCALENDAR'.PHP_EOL. + 'PRODID:TEST'.PHP_EOL. + 'VERSION:2.0'.PHP_EOL. + 'BEGIN:VTODO'.PHP_EOL. + 'UID:20070313T123432Z-456553@example.com'.PHP_EOL. + 'DTSTAMP:20070313T123432Z'.PHP_EOL. + 'DUE:20070709T130000Z'.PHP_EOL. + 'SUMMARY:Task title'.PHP_EOL. + 'STATUS:NEEDS-ACTION'.PHP_EOL. + 'END:VTODO'.PHP_EOL. + 'END:VCALENDAR'; + + protected function setUp(): void { + parent::setUp(); + + $this->appManager = $this->createMock(IAppManager::class); + $this->l10n = $this->createMock(IL10N::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->backend = $this->createMock(CalDavBackend::class); + + $this->provider = new TasksSearchProvider( + $this->appManager, + $this->l10n, + $this->urlGenerator, + $this->backend + ); + } + + public function testGetId(): void { + $this->assertEquals('tasks-dav', $this->provider->getId()); + } + + public function testGetName(): void { + $this->l10n->expects($this->exactly(1)) + ->method('t') + ->with('Tasks') + ->willReturnArgument(0); + + $this->assertEquals('Tasks', $this->provider->getName()); + } + + public function testSearchAppDisabled(): void { + $user = $this->createMock(IUser::class); + $query = $this->createMock(ISearchQuery::class); + $this->appManager->expects($this->once()) + ->method('isEnabledForUser') + ->with('tasks', $user) + ->willReturn(false); + $this->l10n->expects($this->exactly(1)) + ->method('t') + ->willReturnArgument(0); + $this->backend->expects($this->never()) + ->method('getCalendarsForUser'); + $this->backend->expects($this->never()) + ->method('getSubscriptionsForUser'); + $this->backend->expects($this->never()) + ->method('searchPrincipalUri'); + + $actual = $this->provider->search($user, $query); + $data = $actual->jsonSerialize(); + $this->assertInstanceOf(SearchResult::class, $actual); + $this->assertEquals('Tasks', $data['name']); + $this->assertEmpty($data['entries']); + $this->assertFalse($data['isPaginated']); + $this->assertNull($data['cursor']); + } + + public function testSearch(): void { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('john.doe'); + $query = $this->createMock(ISearchQuery::class); + $query->method('getTerm')->willReturn('search term'); + $query->method('getLimit')->willReturn(5); + $query->method('getCursor')->willReturn(20); + $this->appManager->expects($this->once()) + ->method('isEnabledForUser') + ->with('tasks', $user) + ->willReturn(true); + $this->l10n->method('t')->willReturnArgument(0); + + $this->backend->expects($this->once()) + ->method('getCalendarsForUser') + ->with('principals/users/john.doe') + ->willReturn([ + [ + 'id' => 99, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'calendar-uri-99', + ], [ + 'id' => 123, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'calendar-uri-123', + ] + ]); + $this->backend->expects($this->once()) + ->method('getSubscriptionsForUser') + ->with('principals/users/john.doe') + ->willReturn([ + [ + 'id' => 1337, + 'principaluri' => 'principals/users/john.doe', + 'uri' => 'subscription-uri-1337', + ] + ]); + $this->backend->expects($this->once()) + ->method('searchPrincipalUri') + ->with('principals/users/john.doe', 'search term', ['VTODO'], + ['SUMMARY', 'DESCRIPTION', 'CATEGORIES'], + [], + ['limit' => 5, 'offset' => 20]) + ->willReturn([ + [ + 'calendarid' => 99, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR, + 'uri' => 'todo0.ics', + 'calendardata' => $this->vTodo0, + ], + [ + 'calendarid' => 123, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR, + 'uri' => 'todo1.ics', + 'calendardata' => $this->vTodo1, + ], + [ + 'calendarid' => 1337, + 'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION, + 'uri' => 'todo2.ics', + 'calendardata' => $this->vTodo2, + ] + ]); + + $provider = $this->getMockBuilder(TasksSearchProvider::class) + ->setConstructorArgs([ + $this->appManager, + $this->l10n, + $this->urlGenerator, + $this->backend, + ]) + ->setMethods([ + 'getDeepLinkToTasksApp', + 'generateSubline', + ]) + ->getMock(); + + $provider->expects($this->exactly(3)) + ->method('generateSubline') + ->willReturn('subline'); + $provider->expects($this->exactly(3)) + ->method('getDeepLinkToTasksApp') + ->withConsecutive( + ['calendar-uri-99', 'todo0.ics'], + ['calendar-uri-123', 'todo1.ics'], + ['subscription-uri-1337', 'todo2.ics'] + ) + ->willReturn('deep-link-to-tasks'); + + $actual = $provider->search($user, $query); + $data = $actual->jsonSerialize(); + $this->assertInstanceOf(SearchResult::class, $actual); + $this->assertEquals('Tasks', $data['name']); + $this->assertCount(3, $data['entries']); + $this->assertTrue($data['isPaginated']); + $this->assertEquals(23, $data['cursor']); + + $result0 = $data['entries'][0]; + $result0Data = $result0->jsonSerialize(); + $result1 = $data['entries'][1]; + $result1Data = $result1->jsonSerialize(); + $result2 = $data['entries'][2]; + $result2Data = $result2->jsonSerialize(); + + $this->assertInstanceOf(TasksSearchResultEntry::class, $result0); + $this->assertEmpty($result0Data['thumbnailUrl']); + $this->assertEquals('Untitled task', $result0Data['title']); + $this->assertEquals('subline', $result0Data['subline']); + $this->assertEquals('deep-link-to-tasks', $result0Data['resourceUrl']); + $this->assertEquals('icon-checkmark', $result0Data['iconClass']); + $this->assertFalse($result0Data['rounded']); + + $this->assertInstanceOf(TasksSearchResultEntry::class, $result1); + $this->assertEmpty($result1Data['thumbnailUrl']); + $this->assertEquals('Task title', $result1Data['title']); + $this->assertEquals('subline', $result1Data['subline']); + $this->assertEquals('deep-link-to-tasks', $result1Data['resourceUrl']); + $this->assertEquals('icon-checkmark', $result1Data['iconClass']); + $this->assertFalse($result1Data['rounded']); + + $this->assertInstanceOf(TasksSearchResultEntry::class, $result2); + $this->assertEmpty($result2Data['thumbnailUrl']); + $this->assertEquals('Task title', $result2Data['title']); + $this->assertEquals('subline', $result2Data['subline']); + $this->assertEquals('deep-link-to-tasks', $result2Data['resourceUrl']); + $this->assertEquals('icon-checkmark', $result2Data['iconClass']); + $this->assertFalse($result2Data['rounded']); + } + + public function testGetDeepLinkToTasksApp(): void { + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('tasks.page.index') + ->willReturn('link-to-route-tasks.index'); + $this->urlGenerator->expects($this->once()) + ->method('getAbsoluteURL') + ->with('link-to-route-tasks.index#/calendars/uri-john.doe/tasks/task-uri.ics') + ->willReturn('absolute-url-link-to-route-tasks.index#/calendars/uri-john.doe/tasks/task-uri.ics'); + + $actual = self::invokePrivate($this->provider, 'getDeepLinkToTasksApp', ['uri-john.doe', 'task-uri.ics']); + $this->assertEquals('absolute-url-link-to-route-tasks.index#/calendars/uri-john.doe/tasks/task-uri.ics', $actual); + } + + /** + * @param string $ics + * @param string $expectedSubline + * + * @dataProvider generateSublineDataProvider + */ + public function testGenerateSubline(string $ics, string $expectedSubline): void { + $vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING); + $taskComponent = $vCalendar->VTODO; + + $this->l10n->method('t')->willReturnArgument(0); + $this->l10n->method('l')->willReturnArgument(''); + + $actual = self::invokePrivate($this->provider, 'generateSubline', [$taskComponent]); + $this->assertEquals($expectedSubline, $actual); + } + + public function generateSublineDataProvider(): array { + return [ + [$this->vTodo0, ''], + [$this->vTodo1, 'Completed on %s'], + [$this->vTodo2, 'Completed on %s'], + [$this->vTodo3, 'Due on %s'], + [$this->vTodo4, 'Due on %s by %s'], + ]; + } +} |