diff options
Diffstat (limited to 'apps/dav/tests/unit/CalDAV/CalDavBackendTest.php')
-rw-r--r-- | apps/dav/tests/unit/CalDAV/CalDavBackendTest.php | 406 |
1 files changed, 345 insertions, 61 deletions
diff --git a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php index ef4cfb2aaab..f9205d5d322 100644 --- a/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php +++ b/apps/dav/tests/unit/CalDAV/CalDavBackendTest.php @@ -1,33 +1,10 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @copyright Copyright (c) 2017 Georg Ehrke - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author dartcafe <github@dartcafe.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author leith abdulla <online-nextcloud@eleith.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Citharel <nextcloud@tcit.fr> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @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/> - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCA\DAV\Tests\unit\CalDAV; @@ -42,6 +19,7 @@ use OCA\DAV\DAV\Sharing\Plugin as SharingPlugin; use OCA\DAV\Events\CalendarDeletedEvent; use OCP\IConfig; use OCP\IL10N; +use Psr\Log\NullLogger; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\PropPatch; use Sabre\DAV\Xml\Property\Href; @@ -52,8 +30,6 @@ use function time; * Class CalDavBackendTest * * @group DB - * - * @package OCA\DAV\Tests\unit\CalDAV */ class CalDavBackendTest extends AbstractCalDavBackend { public function testCalendarOperations(): void { @@ -83,7 +59,7 @@ class CalDavBackendTest extends AbstractCalDavBackend { self::assertEmpty($calendars); } - public function providesSharingData() { + public static function providesSharingData(): array { return [ [true, true, true, false, [ [ @@ -136,13 +112,11 @@ class CalDavBackendTest extends AbstractCalDavBackend { ]; } - /** - * @dataProvider providesSharingData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('providesSharingData')] public function testCalendarSharing($userCanRead, $userCanWrite, $groupCanRead, $groupCanWrite, $add, $principals): void { $logger = $this->createMock(\Psr\Log\LoggerInterface::class); $config = $this->createMock(IConfig::class); - /** @var IL10N|MockObject $l10n */ + $l10n = $this->createMock(IL10N::class); $l10n->expects($this->any()) ->method('t') @@ -427,9 +401,7 @@ EOD; $this->assertCount(0, $calendarObjects); } - /** - * @dataProvider providesCalendarQueryParameters - */ + #[\PHPUnit\Framework\Attributes\DataProvider('providesCalendarQueryParameters')] public function testCalendarQuery($expectedEventsInResult, $propFilters, $compFilter): void { $calendarId = $this->createTestCalendar(); $events = []; @@ -482,7 +454,7 @@ EOD; $this->assertNotNull($co); } - public function providesCalendarQueryParameters() { + public static function providesCalendarQueryParameters(): array { return [ 'all' => [[0, 1, 2, 3], [], []], 'only-todos' => [[], ['name' => 'VTODO'], []], @@ -493,19 +465,91 @@ EOD; ]; } - public function testSyncSupport(): void { - $calendarId = $this->createTestCalendar(); + public function testCalendarSynchronization(): void { - // fist call without synctoken - $changes = $this->backend->getChangesForCalendar($calendarId, '', 1); - $syncToken = $changes['syncToken']; + // construct calendar for testing + $calendarId = $this->createTestCalendar(); - // add a change - $event = $this->createEvent($calendarId, '20130912T130000Z', '20130912T140000Z'); + /** test fresh sync state with NO events in calendar */ + // construct test state + $stateTest = ['syncToken' => 1, 'added' => [], 'modified' => [], 'deleted' => []]; + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '', 1); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test fresh sync state with NO events in calendar'); + + /** test delta sync state with NO events in calendar */ + // construct test state + $stateTest = ['syncToken' => 1, 'added' => [], 'modified' => [], 'deleted' => []]; + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '2', 1); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test delta sync state with NO events in calendar'); + + /** add events to calendar */ + $event1 = $this->createEvent($calendarId, '20240701T130000Z', '20240701T140000Z'); + $event2 = $this->createEvent($calendarId, '20240701T140000Z', '20240701T150000Z'); + $event3 = $this->createEvent($calendarId, '20240701T150000Z', '20240701T160000Z'); + + /** test fresh sync state with events in calendar */ + // construct expected state + $stateTest = ['syncToken' => 4, 'added' => [$event1, $event2, $event3], 'modified' => [], 'deleted' => []]; + sort($stateTest['added']); + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '', 1); + // sort live state results + sort($stateLive['added']); + sort($stateLive['modified']); + sort($stateLive['deleted']); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test fresh sync state with events in calendar'); + + /** test delta sync state with events in calendar */ + // construct expected state + $stateTest = ['syncToken' => 4, 'added' => [$event2, $event3], 'modified' => [], 'deleted' => []]; + sort($stateTest['added']); + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '2', 1); + // sort live state results + sort($stateLive['added']); + sort($stateLive['modified']); + sort($stateLive['deleted']); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test delta sync state with events in calendar'); + + /** modify/delete events in calendar */ + $this->deleteEvent($calendarId, $event1); + $this->modifyEvent($calendarId, $event2, '20250701T140000Z', '20250701T150000Z'); + + /** test fresh sync state with modified/deleted events in calendar */ + // construct expected state + $stateTest = ['syncToken' => 6, 'added' => [$event2, $event3], 'modified' => [], 'deleted' => []]; + sort($stateTest['added']); + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '', 1); + // sort live state results + sort($stateLive['added']); + sort($stateLive['modified']); + sort($stateLive['deleted']); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test fresh sync state with modified/deleted events in calendar'); + + /** test delta sync state with modified/deleted events in calendar */ + // construct expected state + $stateTest = ['syncToken' => 6, 'added' => [$event3], 'modified' => [$event2], 'deleted' => [$event1]]; + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '3', 1); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test delta sync state with modified/deleted events in calendar'); + + /** test delta sync state with modified/deleted events in calendar and invalid token */ + // construct expected state + $stateTest = ['syncToken' => 6, 'added' => [], 'modified' => [], 'deleted' => []]; + // retrieve live state + $stateLive = $this->backend->getChangesForCalendar($calendarId, '6', 1); + // test live state + $this->assertEquals($stateTest, $stateLive, 'Failed test delta sync state with modified/deleted events in calendar and invalid token'); - // look for changes - $changes = $this->backend->getChangesForCalendar($calendarId, $syncToken, 1); - $this->assertEquals($event, $changes['added'][0]); } public function testPublications(): void { @@ -571,7 +615,7 @@ EOD; $this->assertCount(0, $subscriptions); } - public function providesSchedulingData() { + public static function providesSchedulingData(): array { $data = <<<EOS BEGIN:VCALENDAR VERSION:2.0 @@ -644,9 +688,9 @@ EOS; } /** - * @dataProvider providesSchedulingData * @param $objectData */ + #[\PHPUnit\Framework\Attributes\DataProvider('providesSchedulingData')] public function testScheduling($objectData): void { $this->backend->createSchedulingObject(self::UNIT_TEST_USER, 'Sample Schedule', $objectData); @@ -662,9 +706,7 @@ EOS; $this->assertCount(0, $sos); } - /** - * @dataProvider providesCalDataForGetDenormalizedData - */ + #[\PHPUnit\Framework\Attributes\DataProvider('providesCalDataForGetDenormalizedData')] public function testGetDenormalizedData($expected, $key, $calData): void { try { $actual = $this->backend->getDenormalizedData($calData); @@ -677,7 +719,7 @@ EOS; } } - public function providesCalDataForGetDenormalizedData(): array { + public static function providesCalDataForGetDenormalizedData(): array { return [ 'first occurrence before unix epoch starts' => [0, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nDTSTART;VALUE=DATE:16040222\r\nDTEND;VALUE=DATE:16040223\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], 'no first occurrence because yearly' => [null, 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.1.1//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nUID:413F269B-B51B-46B1-AFB6-40055C53A4DC\r\nDTSTAMP:20160309T095056Z\r\nRRULE:FREQ=YEARLY\r\nSUMMARY:SUMMARY\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], @@ -686,7 +728,7 @@ EOS; 'last occurrence before unix epoch starts' => [0, 'lastOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.3.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:19110324\r\nDTEND;VALUE=DATE:19110325\r\nDTSTAMP:20200927T180638Z\r\nUID:asdfasdfasdf@google.com\r\nCREATED:20200626T181848Z\r\nDESCRIPTION:Very old event\r\nLAST-MODIFIED:20200922T192707Z\r\nSUMMARY:Some old event\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], - 'first occurrence is found when not first VEVENT in group' => [(new DateTime('2020-09-01T110000', new DateTimeZone("America/Los_Angeles")))->getTimestamp(), 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.3.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nDTSTART;TZID=America/Los_Angeles:20201013T110000\r\nDTEND;TZID=America/Los_Angeles:20201013T120000\r\nDTSTAMP:20200927T180638Z\r\nUID:asdf0000@google.com\r\nRECURRENCE-ID;TZID=America/Los_Angeles:20201013T110000\r\nCREATED:20160330T034726Z\r\nLAST-MODIFIED:20200925T042014Z\r\nSTATUS:CONFIRMED\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nDTSTART;TZID=America/Los_Angeles:20200901T110000\r\nDTEND;TZID=America/Los_Angeles:20200901T120000\r\nRRULE:FREQ=WEEKLY;BYDAY=TU\r\nEXDATE;TZID=America/Los_Angeles:20200922T110000\r\nEXDATE;TZID=America/Los_Angeles:20200915T110000\r\nEXDATE;TZID=America/Los_Angeles:20200908T110000\r\nDTSTAMP:20200927T180638Z\r\nUID:asdf0000@google.com\r\nCREATED:20160330T034726Z\r\nLAST-MODIFIED:20200915T162810Z\r\nSTATUS:CONFIRMED\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], + 'first occurrence is found when not first VEVENT in group' => [(new DateTime('2020-09-01T110000', new DateTimeZone('America/Los_Angeles')))->getTimestamp(), 'firstOccurence', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Sabre//Sabre VObject 4.3.0//EN\r\nCALSCALE:GREGORIAN\r\nBEGIN:VEVENT\r\nDTSTART;TZID=America/Los_Angeles:20201013T110000\r\nDTEND;TZID=America/Los_Angeles:20201013T120000\r\nDTSTAMP:20200927T180638Z\r\nUID:asdf0000@google.com\r\nRECURRENCE-ID;TZID=America/Los_Angeles:20201013T110000\r\nCREATED:20160330T034726Z\r\nLAST-MODIFIED:20200925T042014Z\r\nSTATUS:CONFIRMED\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nDTSTART;TZID=America/Los_Angeles:20200901T110000\r\nDTEND;TZID=America/Los_Angeles:20200901T120000\r\nRRULE:FREQ=WEEKLY;BYDAY=TU\r\nEXDATE;TZID=America/Los_Angeles:20200922T110000\r\nEXDATE;TZID=America/Los_Angeles:20200915T110000\r\nEXDATE;TZID=America/Los_Angeles:20200908T110000\r\nDTSTAMP:20200927T180638Z\r\nUID:asdf0000@google.com\r\nCREATED:20160330T034726Z\r\nLAST-MODIFIED:20200915T162810Z\r\nSTATUS:CONFIRMED\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"], 'CLASS:PRIVATE' => [CalDavBackend::CLASSIFICATION_PRIVATE, 'classification', "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//dmfs.org//mimedir.icalendar//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nX-LIC-LOCATION:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:CEST\r\nDTSTART:19700329T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:CET\r\nDTSTART:19701025T030000\r\nRRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:20160419T130000\r\nSUMMARY:Test\r\nCLASS:PRIVATE\r\nTRANSP:OPAQUE\r\nSTATUS:CONFIRMED\r\nDTEND;TZID=Europe/Berlin:20160419T140000\r\nLAST-MODIFIED:20160419T074202Z\r\nDTSTAMP:20160419T074202Z\r\nCREATED:20160419T074202Z\r\nUID:2e468c48-7860-492e-bc52-92fa0daeeccf.1461051722310\r\nEND:VEVENT\r\nEND:VCALENDAR"], @@ -830,9 +872,7 @@ EOD; $this->assertEquals(count($search5), 0); } - /** - * @dataProvider searchDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')] public function testSearch(bool $isShared, array $searchOptions, int $count): void { $calendarId = $this->createTestCalendar(); @@ -932,7 +972,7 @@ EOD; $this->assertCount($count, $result); } - public function searchDataProvider() { + public static function searchDataProvider(): array { return [ [false, [], 4], [true, ['timerange' => ['start' => new DateTime('2013-09-12 13:00:00'), 'end' => new DateTime('2013-09-12 14:00:00')]], 2], @@ -1443,7 +1483,7 @@ EOD; self::assertSame(0, $deleted); } - public function testSearchAndExpandRecurrences() { + public function testSearchAndExpandRecurrences(): void { $calendarId = $this->createTestCalendar(); $calendarInfo = [ 'id' => $calendarId, @@ -1598,4 +1638,248 @@ EOD; self::assertEqualsCanonicalizing([$uri1, $uri3], $changesAfter['modified']); self::assertEquals([$uri2], $changesAfter['deleted']); } + + public function testSearchWithLimitAndTimeRange(): void { + $calendarId = $this->createTestCalendar(); + $calendarInfo = [ + 'id' => $calendarId, + 'principaluri' => 'user1', + '{http://owncloud.org/ns}owner-principal' => 'user1', + ]; + + $testFiles = [ + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-1.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-2.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-3.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-4.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-5.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-6.ics', + ]; + + foreach ($testFiles as $testFile) { + $objectUri = static::getUniqueID('search-limit-timerange-'); + $calendarData = \file_get_contents($testFile); + $this->backend->createCalendarObject($calendarId, $objectUri, $calendarData); + } + + $start = new DateTimeImmutable('2024-05-06T00:00:00Z'); + $end = $start->add(new DateInterval('P14D')); + + $results = $this->backend->search( + $calendarInfo, + '', + [], + [ + 'timerange' => [ + 'start' => $start, + 'end' => $end, + ] + ], + 4, + null, + ); + + $this->assertCount(2, $results); + + $this->assertEquals('Cake Tasting', $results[0]['objects'][0]['SUMMARY'][0]); + $this->assertGreaterThanOrEqual( + $start->getTimestamp(), + $results[0]['objects'][0]['DTSTART'][0]->getTimestamp(), + 'Recurrence starting before requested start', + ); + + $this->assertEquals('Pasta Day', $results[1]['objects'][0]['SUMMARY'][0]); + $this->assertGreaterThanOrEqual( + $start->getTimestamp(), + $results[1]['objects'][0]['DTSTART'][0]->getTimestamp(), + 'Recurrence starting before requested start', + ); + } + + public function testSearchWithLimitAndTimeRangeShouldNotReturnMoreObjectsThenLimit(): void { + $calendarId = $this->createTestCalendar(); + $calendarInfo = [ + 'id' => $calendarId, + 'principaluri' => 'user1', + '{http://owncloud.org/ns}owner-principal' => 'user1', + ]; + + $testFiles = [ + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-1.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-2.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-3.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-4.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-5.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-6.ics', + ]; + + foreach ($testFiles as $testFile) { + $objectUri = static::getUniqueID('search-limit-timerange-'); + $calendarData = \file_get_contents($testFile); + $this->backend->createCalendarObject($calendarId, $objectUri, $calendarData); + } + + $start = new DateTimeImmutable('2024-05-06T00:00:00Z'); + $end = $start->add(new DateInterval('P14D')); + + $results = $this->backend->search( + $calendarInfo, + '', + [], + [ + 'timerange' => [ + 'start' => $start, + 'end' => $end, + ] + ], + 1, + null, + ); + + $this->assertCount(1, $results); + + $this->assertEquals('Cake Tasting', $results[0]['objects'][0]['SUMMARY'][0]); + $this->assertGreaterThanOrEqual( + $start->getTimestamp(), + $results[0]['objects'][0]['DTSTART'][0]->getTimestamp(), + 'Recurrence starting before requested start', + ); + } + + public function testSearchWithLimitAndTimeRangeShouldReturnObjectsInTheSameOrder(): void { + $calendarId = $this->createTestCalendar(); + $calendarInfo = [ + 'id' => $calendarId, + 'principaluri' => 'user1', + '{http://owncloud.org/ns}owner-principal' => 'user1', + ]; + + $testFiles = [ + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-1.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-2.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-3.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-4.ics', + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-6.ics', // <-- intentional! + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-5.ics', + ]; + + foreach ($testFiles as $testFile) { + $objectUri = static::getUniqueID('search-limit-timerange-'); + $calendarData = \file_get_contents($testFile); + $this->backend->createCalendarObject($calendarId, $objectUri, $calendarData); + } + + $start = new DateTimeImmutable('2024-05-06T00:00:00Z'); + $end = $start->add(new DateInterval('P14D')); + + $results = $this->backend->search( + $calendarInfo, + '', + [], + [ + 'timerange' => [ + 'start' => $start, + 'end' => $end, + ] + ], + 2, + null, + ); + + $this->assertCount(2, $results); + + $this->assertEquals('Cake Tasting', $results[0]['objects'][0]['SUMMARY'][0]); + $this->assertGreaterThanOrEqual( + $start->getTimestamp(), + $results[0]['objects'][0]['DTSTART'][0]->getTimestamp(), + 'Recurrence starting before requested start', + ); + + $this->assertEquals('Pasta Day', $results[1]['objects'][0]['SUMMARY'][0]); + $this->assertGreaterThanOrEqual( + $start->getTimestamp(), + $results[1]['objects'][0]['DTSTART'][0]->getTimestamp(), + 'Recurrence starting before requested start', + ); + } + + public function testSearchShouldReturnObjectsInTheSameOrderMissingDate(): void { + $calendarId = $this->createTestCalendar(); + $calendarInfo = [ + 'id' => $calendarId, + 'principaluri' => 'user1', + '{http://owncloud.org/ns}owner-principal' => 'user1', + ]; + + $testFiles = [ + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-6.ics', // <-- intentional! + __DIR__ . '/../test_fixtures/caldav-search-limit-timerange-5.ics', + __DIR__ . '/../test_fixtures/caldav-search-missing-start-1.ics', + __DIR__ . '/../test_fixtures/caldav-search-missing-start-2.ics', + ]; + + foreach ($testFiles as $testFile) { + $objectUri = static::getUniqueID('search-return-objects-in-same-order-'); + $calendarData = \file_get_contents($testFile); + $this->backend->createCalendarObject($calendarId, $objectUri, $calendarData); + } + + $results = $this->backend->search( + $calendarInfo, + '', + [], + [], + 4, + null, + ); + + $this->assertCount(4, $results); + + $this->assertEquals('Cake Tasting', $results[0]['objects'][0]['SUMMARY'][0]); + $this->assertEquals('Pasta Day', $results[1]['objects'][0]['SUMMARY'][0]); + $this->assertEquals('Missing DTSTART 1', $results[2]['objects'][0]['SUMMARY'][0]); + $this->assertEquals('Missing DTSTART 2', $results[3]['objects'][0]['SUMMARY'][0]); + } + + public function testUnshare(): void { + $principalGroup = 'principal:' . self::UNIT_TEST_GROUP; + $principalUser = 'principal:' . self::UNIT_TEST_USER; + + $l10n = $this->createMock(IL10N::class); + $l10n->method('t') + ->willReturnCallback(fn ($text, $parameters = []) => vsprintf($text, $parameters)); + $config = $this->createMock(IConfig::class); + $logger = new NullLogger(); + + $this->principal->expects($this->exactly(2)) + ->method('findByUri') + ->willReturnMap([ + [$principalGroup, '', self::UNIT_TEST_GROUP], + [$principalUser, '', self::UNIT_TEST_USER], + ]); + $this->groupManager->expects($this->once()) + ->method('groupExists') + ->willReturn(true); + $this->dispatcher->expects($this->exactly(2)) + ->method('dispatchTyped'); + + $calendarId = $this->createTestCalendar(); + $calendarInfo = $this->backend->getCalendarById($calendarId); + + $calendar = new Calendar($this->backend, $calendarInfo, $l10n, $config, $logger); + + $this->backend->updateShares( + shareable: $calendar, + add: [ + ['href' => $principalGroup, 'readOnly' => false] + ], + remove: [] + ); + + $this->backend->unshare( + shareable: $calendar, + principal: $principalUser + ); + + } } |