Completed
Push — master ( 5262ba...247b25 )
by
unknown
30:03 queued 13s
created
apps/dav/tests/unit/CalDAV/CalendarHomeTest.php 1 patch
Indentation   +397 added lines, -397 removed lines patch added patch discarded remove patch
@@ -27,407 +27,407 @@
 block discarded – undo
27 27
 use Test\TestCase;
28 28
 
29 29
 class CalendarHomeTest extends TestCase {
30
-	private CalDavBackend&MockObject $backend;
31
-	private array $principalInfo = [];
32
-	private PluginManager&MockObject $pluginManager;
33
-	private LoggerInterface&MockObject $logger;
34
-	private FederatedCalendarFactory&MockObject $federatedCalendarFactory;
35
-	private CalendarHome $calendarHome;
36
-
37
-	protected function setUp(): void {
38
-		parent::setUp();
39
-
40
-		$this->backend = $this->createMock(CalDavBackend::class);
41
-		$this->principalInfo = [
42
-			'uri' => 'user-principal-123',
43
-		];
44
-		$this->pluginManager = $this->createMock(PluginManager::class);
45
-		$this->logger = $this->createMock(LoggerInterface::class);
46
-		$this->federatedCalendarFactory = $this->createMock(FederatedCalendarFactory::class);
47
-
48
-		$this->calendarHome = new CalendarHome(
49
-			$this->backend,
50
-			$this->principalInfo,
51
-			$this->logger,
52
-			$this->federatedCalendarFactory,
53
-			false
54
-		);
55
-
56
-		// Replace PluginManager with our mock
57
-		$reflection = new \ReflectionClass($this->calendarHome);
58
-		$reflectionProperty = $reflection->getProperty('pluginManager');
59
-		$reflectionProperty->setValue($this->calendarHome, $this->pluginManager);
60
-	}
61
-
62
-	public function testCreateCalendarValidName(): void {
63
-		/** @var MkCol&MockObject $mkCol */
64
-		$mkCol = $this->createMock(MkCol::class);
65
-
66
-		$mkCol->method('getResourceType')
67
-			->willReturn(['{DAV:}collection',
68
-				'{urn:ietf:params:xml:ns:caldav}calendar']);
69
-		$mkCol->method('getRemainingValues')
70
-			->willReturn(['... properties ...']);
71
-
72
-		$this->backend->expects(self::once())
73
-			->method('createCalendar')
74
-			->with('user-principal-123', 'name123', ['... properties ...']);
75
-
76
-		$this->calendarHome->createExtendedCollection('name123', $mkCol);
77
-	}
78
-
79
-	public function testCreateCalendarReservedName(): void {
80
-		$this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
81
-		$this->expectExceptionMessage('The resource you tried to create has a reserved name');
82
-
83
-		/** @var MkCol&MockObject $mkCol */
84
-		$mkCol = $this->createMock(MkCol::class);
85
-
86
-		$this->calendarHome->createExtendedCollection('contact_birthdays', $mkCol);
87
-	}
88
-
89
-	public function testCreateCalendarReservedNameAppGenerated(): void {
90
-		$this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
91
-		$this->expectExceptionMessage('The resource you tried to create has a reserved name');
92
-
93
-		/** @var MkCol&MockObject $mkCol */
94
-		$mkCol = $this->createMock(MkCol::class);
95
-
96
-		$this->calendarHome->createExtendedCollection('app-generated--example--foo-1', $mkCol);
97
-	}
98
-
99
-	public function testGetChildren():void {
100
-		$this->backend
101
-			->expects(self::once())
102
-			->method('getCalendarsForUser')
103
-			->with('user-principal-123')
104
-			->willReturn([]);
105
-
106
-		$this->backend
107
-			->expects(self::once())
108
-			->method('getFederatedCalendarsForUser')
109
-			->with('user-principal-123')
110
-			->willReturn([]);
111
-
112
-		$this->backend
113
-			->expects(self::once())
114
-			->method('getSubscriptionsForUser')
115
-			->with('user-principal-123')
116
-			->willReturn([]);
117
-
118
-		$calendarPlugin1 = $this->createMock(ICalendarProvider::class);
119
-		$calendarPlugin1
120
-			->expects(self::once())
121
-			->method('fetchAllForCalendarHome')
122
-			->with('user-principal-123')
123
-			->willReturn(['plugin1calendar1', 'plugin1calendar2']);
124
-
125
-		$calendarPlugin2 = $this->createMock(ICalendarProvider::class);
126
-		$calendarPlugin2
127
-			->expects(self::once())
128
-			->method('fetchAllForCalendarHome')
129
-			->with('user-principal-123')
130
-			->willReturn(['plugin2calendar1', 'plugin2calendar2']);
131
-
132
-		$this->pluginManager
133
-			->expects(self::once())
134
-			->method('getCalendarPlugins')
135
-			->with()
136
-			->willReturn([$calendarPlugin1, $calendarPlugin2]);
137
-
138
-		$actual = $this->calendarHome->getChildren();
139
-
140
-		$this->assertCount(7, $actual);
141
-		$this->assertInstanceOf(Inbox::class, $actual[0]);
142
-		$this->assertInstanceOf(Outbox::class, $actual[1]);
143
-		$this->assertInstanceOf(TrashbinHome::class, $actual[2]);
144
-		$this->assertEquals('plugin1calendar1', $actual[3]);
145
-		$this->assertEquals('plugin1calendar2', $actual[4]);
146
-		$this->assertEquals('plugin2calendar1', $actual[5]);
147
-		$this->assertEquals('plugin2calendar2', $actual[6]);
148
-	}
149
-
150
-	public function testGetChildNonAppGenerated():void {
151
-		$this->backend
152
-			->expects(self::once())
153
-			->method('getCalendarByUri')
154
-			->with('user-principal-123')
155
-			->willReturn([]);
156
-
157
-		$this->backend
158
-			->expects(self::once())
159
-			->method('getCalendarsForUser')
160
-			->with('user-principal-123')
161
-			->willReturn([]);
162
-
163
-		$this->backend
164
-			->expects(self::never())
165
-			->method('getFederatedCalendarsForUser');
166
-
167
-		$this->backend
168
-			->expects(self::once())
169
-			->method('getSubscriptionsForUser')
170
-			->with('user-principal-123')
171
-			->willReturn([]);
172
-
173
-		$this->pluginManager
174
-			->expects(self::never())
175
-			->method('getCalendarPlugins');
176
-
177
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
178
-		$this->expectExceptionMessage('Node with name \'personal\' could not be found');
179
-
180
-		$this->calendarHome->getChild('personal');
181
-	}
182
-
183
-	public function testGetChildAppGenerated():void {
184
-		$this->backend
185
-			->expects(self::once())
186
-			->method('getCalendarByUri')
187
-			->with('user-principal-123')
188
-			->willReturn([]);
189
-
190
-		$this->backend
191
-			->expects(self::once())
192
-			->method('getCalendarsForUser')
193
-			->with('user-principal-123')
194
-			->willReturn([]);
195
-
196
-		$this->backend
197
-			->expects(self::never())
198
-			->method('getFederatedCalendarsForUser');
199
-
200
-		$this->backend
201
-			->expects(self::once())
202
-			->method('getSubscriptionsForUser')
203
-			->with('user-principal-123')
204
-			->willReturn([]);
205
-
206
-		$calendarPlugin1 = $this->createMock(ICalendarProvider::class);
207
-		$calendarPlugin1
208
-			->expects(self::once())
209
-			->method('getAppId')
210
-			->with()
211
-			->willReturn('calendar_plugin_1');
212
-		$calendarPlugin1
213
-			->expects(self::never())
214
-			->method('hasCalendarInCalendarHome');
215
-		$calendarPlugin1
216
-			->expects(self::never())
217
-			->method('getCalendarInCalendarHome');
218
-
219
-		$externalCalendarMock = $this->createMock(ExternalCalendar::class);
220
-
221
-		$calendarPlugin2 = $this->createMock(ICalendarProvider::class);
222
-		$calendarPlugin2
223
-			->expects(self::once())
224
-			->method('getAppId')
225
-			->with()
226
-			->willReturn('calendar_plugin_2');
227
-		$calendarPlugin2
228
-			->expects(self::once())
229
-			->method('hasCalendarInCalendarHome')
230
-			->with('user-principal-123', 'calendar-uri-from-backend')
231
-			->willReturn(true);
232
-		$calendarPlugin2
233
-			->expects(self::once())
234
-			->method('getCalendarInCalendarHome')
235
-			->with('user-principal-123', 'calendar-uri-from-backend')
236
-			->willReturn($externalCalendarMock);
237
-
238
-		$this->pluginManager
239
-			->expects(self::once())
240
-			->method('getCalendarPlugins')
241
-			->with()
242
-			->willReturn([$calendarPlugin1, $calendarPlugin2]);
243
-
244
-		$actual = $this->calendarHome->getChild('app-generated--calendar_plugin_2--calendar-uri-from-backend');
245
-		$this->assertEquals($externalCalendarMock, $actual);
246
-	}
247
-
248
-	public function testGetChildrenSubscriptions(): void {
249
-		$this->backend
250
-			->expects(self::once())
251
-			->method('getCalendarsForUser')
252
-			->with('user-principal-123')
253
-			->willReturn([]);
254
-
255
-		$this->backend
256
-			->expects(self::once())
257
-			->method('getFederatedCalendarsForUser')
258
-			->with('user-principal-123')
259
-			->willReturn([]);
260
-
261
-		$this->backend
262
-			->expects(self::once())
263
-			->method('getSubscriptionsForUser')
264
-			->with('user-principal-123')
265
-			->willReturn([
266
-				[
267
-					'id' => 'subscription-1',
268
-					'uri' => 'subscription-1',
269
-					'principaluri' => 'user-principal-123',
270
-					'source' => 'https://localhost/subscription-1',
271
-					// A subscription array has actually more properties.
272
-				],
273
-				[
274
-					'id' => 'subscription-2',
275
-					'uri' => 'subscription-2',
276
-					'principaluri' => 'user-principal-123',
277
-					'source' => 'https://localhost/subscription-2',
278
-					// A subscription array has actually more properties.
279
-				]
280
-			]);
281
-
282
-		/*
30
+    private CalDavBackend&MockObject $backend;
31
+    private array $principalInfo = [];
32
+    private PluginManager&MockObject $pluginManager;
33
+    private LoggerInterface&MockObject $logger;
34
+    private FederatedCalendarFactory&MockObject $federatedCalendarFactory;
35
+    private CalendarHome $calendarHome;
36
+
37
+    protected function setUp(): void {
38
+        parent::setUp();
39
+
40
+        $this->backend = $this->createMock(CalDavBackend::class);
41
+        $this->principalInfo = [
42
+            'uri' => 'user-principal-123',
43
+        ];
44
+        $this->pluginManager = $this->createMock(PluginManager::class);
45
+        $this->logger = $this->createMock(LoggerInterface::class);
46
+        $this->federatedCalendarFactory = $this->createMock(FederatedCalendarFactory::class);
47
+
48
+        $this->calendarHome = new CalendarHome(
49
+            $this->backend,
50
+            $this->principalInfo,
51
+            $this->logger,
52
+            $this->federatedCalendarFactory,
53
+            false
54
+        );
55
+
56
+        // Replace PluginManager with our mock
57
+        $reflection = new \ReflectionClass($this->calendarHome);
58
+        $reflectionProperty = $reflection->getProperty('pluginManager');
59
+        $reflectionProperty->setValue($this->calendarHome, $this->pluginManager);
60
+    }
61
+
62
+    public function testCreateCalendarValidName(): void {
63
+        /** @var MkCol&MockObject $mkCol */
64
+        $mkCol = $this->createMock(MkCol::class);
65
+
66
+        $mkCol->method('getResourceType')
67
+            ->willReturn(['{DAV:}collection',
68
+                '{urn:ietf:params:xml:ns:caldav}calendar']);
69
+        $mkCol->method('getRemainingValues')
70
+            ->willReturn(['... properties ...']);
71
+
72
+        $this->backend->expects(self::once())
73
+            ->method('createCalendar')
74
+            ->with('user-principal-123', 'name123', ['... properties ...']);
75
+
76
+        $this->calendarHome->createExtendedCollection('name123', $mkCol);
77
+    }
78
+
79
+    public function testCreateCalendarReservedName(): void {
80
+        $this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
81
+        $this->expectExceptionMessage('The resource you tried to create has a reserved name');
82
+
83
+        /** @var MkCol&MockObject $mkCol */
84
+        $mkCol = $this->createMock(MkCol::class);
85
+
86
+        $this->calendarHome->createExtendedCollection('contact_birthdays', $mkCol);
87
+    }
88
+
89
+    public function testCreateCalendarReservedNameAppGenerated(): void {
90
+        $this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
91
+        $this->expectExceptionMessage('The resource you tried to create has a reserved name');
92
+
93
+        /** @var MkCol&MockObject $mkCol */
94
+        $mkCol = $this->createMock(MkCol::class);
95
+
96
+        $this->calendarHome->createExtendedCollection('app-generated--example--foo-1', $mkCol);
97
+    }
98
+
99
+    public function testGetChildren():void {
100
+        $this->backend
101
+            ->expects(self::once())
102
+            ->method('getCalendarsForUser')
103
+            ->with('user-principal-123')
104
+            ->willReturn([]);
105
+
106
+        $this->backend
107
+            ->expects(self::once())
108
+            ->method('getFederatedCalendarsForUser')
109
+            ->with('user-principal-123')
110
+            ->willReturn([]);
111
+
112
+        $this->backend
113
+            ->expects(self::once())
114
+            ->method('getSubscriptionsForUser')
115
+            ->with('user-principal-123')
116
+            ->willReturn([]);
117
+
118
+        $calendarPlugin1 = $this->createMock(ICalendarProvider::class);
119
+        $calendarPlugin1
120
+            ->expects(self::once())
121
+            ->method('fetchAllForCalendarHome')
122
+            ->with('user-principal-123')
123
+            ->willReturn(['plugin1calendar1', 'plugin1calendar2']);
124
+
125
+        $calendarPlugin2 = $this->createMock(ICalendarProvider::class);
126
+        $calendarPlugin2
127
+            ->expects(self::once())
128
+            ->method('fetchAllForCalendarHome')
129
+            ->with('user-principal-123')
130
+            ->willReturn(['plugin2calendar1', 'plugin2calendar2']);
131
+
132
+        $this->pluginManager
133
+            ->expects(self::once())
134
+            ->method('getCalendarPlugins')
135
+            ->with()
136
+            ->willReturn([$calendarPlugin1, $calendarPlugin2]);
137
+
138
+        $actual = $this->calendarHome->getChildren();
139
+
140
+        $this->assertCount(7, $actual);
141
+        $this->assertInstanceOf(Inbox::class, $actual[0]);
142
+        $this->assertInstanceOf(Outbox::class, $actual[1]);
143
+        $this->assertInstanceOf(TrashbinHome::class, $actual[2]);
144
+        $this->assertEquals('plugin1calendar1', $actual[3]);
145
+        $this->assertEquals('plugin1calendar2', $actual[4]);
146
+        $this->assertEquals('plugin2calendar1', $actual[5]);
147
+        $this->assertEquals('plugin2calendar2', $actual[6]);
148
+    }
149
+
150
+    public function testGetChildNonAppGenerated():void {
151
+        $this->backend
152
+            ->expects(self::once())
153
+            ->method('getCalendarByUri')
154
+            ->with('user-principal-123')
155
+            ->willReturn([]);
156
+
157
+        $this->backend
158
+            ->expects(self::once())
159
+            ->method('getCalendarsForUser')
160
+            ->with('user-principal-123')
161
+            ->willReturn([]);
162
+
163
+        $this->backend
164
+            ->expects(self::never())
165
+            ->method('getFederatedCalendarsForUser');
166
+
167
+        $this->backend
168
+            ->expects(self::once())
169
+            ->method('getSubscriptionsForUser')
170
+            ->with('user-principal-123')
171
+            ->willReturn([]);
172
+
173
+        $this->pluginManager
174
+            ->expects(self::never())
175
+            ->method('getCalendarPlugins');
176
+
177
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
178
+        $this->expectExceptionMessage('Node with name \'personal\' could not be found');
179
+
180
+        $this->calendarHome->getChild('personal');
181
+    }
182
+
183
+    public function testGetChildAppGenerated():void {
184
+        $this->backend
185
+            ->expects(self::once())
186
+            ->method('getCalendarByUri')
187
+            ->with('user-principal-123')
188
+            ->willReturn([]);
189
+
190
+        $this->backend
191
+            ->expects(self::once())
192
+            ->method('getCalendarsForUser')
193
+            ->with('user-principal-123')
194
+            ->willReturn([]);
195
+
196
+        $this->backend
197
+            ->expects(self::never())
198
+            ->method('getFederatedCalendarsForUser');
199
+
200
+        $this->backend
201
+            ->expects(self::once())
202
+            ->method('getSubscriptionsForUser')
203
+            ->with('user-principal-123')
204
+            ->willReturn([]);
205
+
206
+        $calendarPlugin1 = $this->createMock(ICalendarProvider::class);
207
+        $calendarPlugin1
208
+            ->expects(self::once())
209
+            ->method('getAppId')
210
+            ->with()
211
+            ->willReturn('calendar_plugin_1');
212
+        $calendarPlugin1
213
+            ->expects(self::never())
214
+            ->method('hasCalendarInCalendarHome');
215
+        $calendarPlugin1
216
+            ->expects(self::never())
217
+            ->method('getCalendarInCalendarHome');
218
+
219
+        $externalCalendarMock = $this->createMock(ExternalCalendar::class);
220
+
221
+        $calendarPlugin2 = $this->createMock(ICalendarProvider::class);
222
+        $calendarPlugin2
223
+            ->expects(self::once())
224
+            ->method('getAppId')
225
+            ->with()
226
+            ->willReturn('calendar_plugin_2');
227
+        $calendarPlugin2
228
+            ->expects(self::once())
229
+            ->method('hasCalendarInCalendarHome')
230
+            ->with('user-principal-123', 'calendar-uri-from-backend')
231
+            ->willReturn(true);
232
+        $calendarPlugin2
233
+            ->expects(self::once())
234
+            ->method('getCalendarInCalendarHome')
235
+            ->with('user-principal-123', 'calendar-uri-from-backend')
236
+            ->willReturn($externalCalendarMock);
237
+
238
+        $this->pluginManager
239
+            ->expects(self::once())
240
+            ->method('getCalendarPlugins')
241
+            ->with()
242
+            ->willReturn([$calendarPlugin1, $calendarPlugin2]);
243
+
244
+        $actual = $this->calendarHome->getChild('app-generated--calendar_plugin_2--calendar-uri-from-backend');
245
+        $this->assertEquals($externalCalendarMock, $actual);
246
+    }
247
+
248
+    public function testGetChildrenSubscriptions(): void {
249
+        $this->backend
250
+            ->expects(self::once())
251
+            ->method('getCalendarsForUser')
252
+            ->with('user-principal-123')
253
+            ->willReturn([]);
254
+
255
+        $this->backend
256
+            ->expects(self::once())
257
+            ->method('getFederatedCalendarsForUser')
258
+            ->with('user-principal-123')
259
+            ->willReturn([]);
260
+
261
+        $this->backend
262
+            ->expects(self::once())
263
+            ->method('getSubscriptionsForUser')
264
+            ->with('user-principal-123')
265
+            ->willReturn([
266
+                [
267
+                    'id' => 'subscription-1',
268
+                    'uri' => 'subscription-1',
269
+                    'principaluri' => 'user-principal-123',
270
+                    'source' => 'https://localhost/subscription-1',
271
+                    // A subscription array has actually more properties.
272
+                ],
273
+                [
274
+                    'id' => 'subscription-2',
275
+                    'uri' => 'subscription-2',
276
+                    'principaluri' => 'user-principal-123',
277
+                    'source' => 'https://localhost/subscription-2',
278
+                    // A subscription array has actually more properties.
279
+                ]
280
+            ]);
281
+
282
+        /*
283 283
 		 * @FIXME: PluginManager should be injected via constructor.
284 284
 		 */
285 285
 
286
-		$pluginManager = $this->createMock(PluginManager::class);
287
-		$pluginManager
288
-			->expects(self::once())
289
-			->method('getCalendarPlugins')
290
-			->with()
291
-			->willReturn([]);
292
-
293
-		$calendarHome = new CalendarHome(
294
-			$this->backend,
295
-			$this->principalInfo,
296
-			$this->logger,
297
-			$this->federatedCalendarFactory,
298
-			false
299
-		);
300
-
301
-		$reflection = new \ReflectionClass($calendarHome);
302
-		$reflectionProperty = $reflection->getProperty('pluginManager');
303
-		$reflectionProperty->setValue($calendarHome, $pluginManager);
304
-
305
-		$actual = $calendarHome->getChildren();
306
-
307
-		$this->assertCount(5, $actual);
308
-		$this->assertInstanceOf(Inbox::class, $actual[0]);
309
-		$this->assertInstanceOf(Outbox::class, $actual[1]);
310
-		$this->assertInstanceOf(TrashbinHome::class, $actual[2]);
311
-		$this->assertInstanceOf(Subscription::class, $actual[3]);
312
-		$this->assertInstanceOf(Subscription::class, $actual[4]);
313
-	}
314
-
315
-	public function testGetChildrenCachedSubscriptions(): void {
316
-		$this->backend
317
-			->expects(self::once())
318
-			->method('getCalendarsForUser')
319
-			->with('user-principal-123')
320
-			->willReturn([]);
321
-
322
-		$this->backend
323
-			->expects(self::once())
324
-			->method('getFederatedCalendarsForUser')
325
-			->with('user-principal-123')
326
-			->willReturn([]);
327
-
328
-		$this->backend
329
-			->expects(self::once())
330
-			->method('getSubscriptionsForUser')
331
-			->with('user-principal-123')
332
-			->willReturn([
333
-				[
334
-					'id' => 'subscription-1',
335
-					'uri' => 'subscription-1',
336
-					'principaluris' => 'user-principal-123',
337
-					'source' => 'https://localhost/subscription-1',
338
-					// A subscription array has actually more properties.
339
-				],
340
-				[
341
-					'id' => 'subscription-2',
342
-					'uri' => 'subscription-2',
343
-					'principaluri' => 'user-principal-123',
344
-					'source' => 'https://localhost/subscription-2',
345
-					// A subscription array has actually more properties.
346
-				]
347
-			]);
348
-
349
-		/*
286
+        $pluginManager = $this->createMock(PluginManager::class);
287
+        $pluginManager
288
+            ->expects(self::once())
289
+            ->method('getCalendarPlugins')
290
+            ->with()
291
+            ->willReturn([]);
292
+
293
+        $calendarHome = new CalendarHome(
294
+            $this->backend,
295
+            $this->principalInfo,
296
+            $this->logger,
297
+            $this->federatedCalendarFactory,
298
+            false
299
+        );
300
+
301
+        $reflection = new \ReflectionClass($calendarHome);
302
+        $reflectionProperty = $reflection->getProperty('pluginManager');
303
+        $reflectionProperty->setValue($calendarHome, $pluginManager);
304
+
305
+        $actual = $calendarHome->getChildren();
306
+
307
+        $this->assertCount(5, $actual);
308
+        $this->assertInstanceOf(Inbox::class, $actual[0]);
309
+        $this->assertInstanceOf(Outbox::class, $actual[1]);
310
+        $this->assertInstanceOf(TrashbinHome::class, $actual[2]);
311
+        $this->assertInstanceOf(Subscription::class, $actual[3]);
312
+        $this->assertInstanceOf(Subscription::class, $actual[4]);
313
+    }
314
+
315
+    public function testGetChildrenCachedSubscriptions(): void {
316
+        $this->backend
317
+            ->expects(self::once())
318
+            ->method('getCalendarsForUser')
319
+            ->with('user-principal-123')
320
+            ->willReturn([]);
321
+
322
+        $this->backend
323
+            ->expects(self::once())
324
+            ->method('getFederatedCalendarsForUser')
325
+            ->with('user-principal-123')
326
+            ->willReturn([]);
327
+
328
+        $this->backend
329
+            ->expects(self::once())
330
+            ->method('getSubscriptionsForUser')
331
+            ->with('user-principal-123')
332
+            ->willReturn([
333
+                [
334
+                    'id' => 'subscription-1',
335
+                    'uri' => 'subscription-1',
336
+                    'principaluris' => 'user-principal-123',
337
+                    'source' => 'https://localhost/subscription-1',
338
+                    // A subscription array has actually more properties.
339
+                ],
340
+                [
341
+                    'id' => 'subscription-2',
342
+                    'uri' => 'subscription-2',
343
+                    'principaluri' => 'user-principal-123',
344
+                    'source' => 'https://localhost/subscription-2',
345
+                    // A subscription array has actually more properties.
346
+                ]
347
+            ]);
348
+
349
+        /*
350 350
 		 * @FIXME: PluginManager should be injected via constructor.
351 351
 		 */
352 352
 
353
-		$pluginManager = $this->createMock(PluginManager::class);
354
-		$pluginManager
355
-			->expects(self::once())
356
-			->method('getCalendarPlugins')
357
-			->with()
358
-			->willReturn([]);
359
-
360
-		$calendarHome = new CalendarHome(
361
-			$this->backend,
362
-			$this->principalInfo,
363
-			$this->logger,
364
-			$this->federatedCalendarFactory,
365
-			true
366
-		);
367
-
368
-		$reflection = new \ReflectionClass($calendarHome);
369
-		$reflectionProperty = $reflection->getProperty('pluginManager');
370
-		$reflectionProperty->setValue($calendarHome, $pluginManager);
371
-
372
-		$actual = $calendarHome->getChildren();
373
-
374
-		$this->assertCount(5, $actual);
375
-		$this->assertInstanceOf(Inbox::class, $actual[0]);
376
-		$this->assertInstanceOf(Outbox::class, $actual[1]);
377
-		$this->assertInstanceOf(TrashbinHome::class, $actual[2]);
378
-		$this->assertInstanceOf(CachedSubscription::class, $actual[3]);
379
-		$this->assertInstanceOf(CachedSubscription::class, $actual[4]);
380
-	}
381
-
382
-	public function testGetChildrenFederatedCalendars(): void {
383
-		$this->backend
384
-			->expects(self::once())
385
-			->method('getCalendarsForUser')
386
-			->with('user-principal-123')
387
-			->willReturn([]);
388
-
389
-		$this->backend
390
-			->expects(self::once())
391
-			->method('getFederatedCalendarsForUser')
392
-			->with('user-principal-123')
393
-			->willReturn([
394
-				[
395
-					'id' => 10,
396
-					'uri' => 'fed-cal-1',
397
-					'principaluri' => 'user-principal-123',
398
-					'{DAV:}displayname' => 'Federated calendar 1',
399
-					'{http://sabredav.org/ns}sync-token' => 3,
400
-					'{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/3',
401
-					'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
402
-					'{http://owncloud.org/ns}owner-principal' => 'principals/remote-users/c2hhcmVyQGhvc3QudGxkCg==',
403
-					'{http://owncloud.org/ns}read-only' => 1
404
-				],
405
-				[
406
-					'id' => 11,
407
-					'uri' => 'fed-cal-2',
408
-					'principaluri' => 'user-principal-123',
409
-					'{DAV:}displayname' => 'Federated calendar 2',
410
-					'{http://sabredav.org/ns}sync-token' => 5,
411
-					'{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/5',
412
-					'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
413
-					'{http://owncloud.org/ns}owner-principal' => 'principals/remote-users/c2hhcmVyQGhvc3QudGxkCg==',
414
-					'{http://owncloud.org/ns}read-only' => 1
415
-				],
416
-			]);
417
-
418
-		$this->backend
419
-			->expects(self::once())
420
-			->method('getSubscriptionsForUser')
421
-			->with('user-principal-123')
422
-			->willReturn([]);
423
-
424
-		$actual = $this->calendarHome->getChildren();
425
-
426
-		$this->assertCount(5, $actual);
427
-		$this->assertInstanceOf(Inbox::class, $actual[0]);
428
-		$this->assertInstanceOf(Outbox::class, $actual[1]);
429
-		$this->assertInstanceOf(TrashbinHome::class, $actual[2]);
430
-		$this->assertInstanceOf(FederatedCalendar::class, $actual[3]);
431
-		$this->assertInstanceOf(FederatedCalendar::class, $actual[4]);
432
-	}
353
+        $pluginManager = $this->createMock(PluginManager::class);
354
+        $pluginManager
355
+            ->expects(self::once())
356
+            ->method('getCalendarPlugins')
357
+            ->with()
358
+            ->willReturn([]);
359
+
360
+        $calendarHome = new CalendarHome(
361
+            $this->backend,
362
+            $this->principalInfo,
363
+            $this->logger,
364
+            $this->federatedCalendarFactory,
365
+            true
366
+        );
367
+
368
+        $reflection = new \ReflectionClass($calendarHome);
369
+        $reflectionProperty = $reflection->getProperty('pluginManager');
370
+        $reflectionProperty->setValue($calendarHome, $pluginManager);
371
+
372
+        $actual = $calendarHome->getChildren();
373
+
374
+        $this->assertCount(5, $actual);
375
+        $this->assertInstanceOf(Inbox::class, $actual[0]);
376
+        $this->assertInstanceOf(Outbox::class, $actual[1]);
377
+        $this->assertInstanceOf(TrashbinHome::class, $actual[2]);
378
+        $this->assertInstanceOf(CachedSubscription::class, $actual[3]);
379
+        $this->assertInstanceOf(CachedSubscription::class, $actual[4]);
380
+    }
381
+
382
+    public function testGetChildrenFederatedCalendars(): void {
383
+        $this->backend
384
+            ->expects(self::once())
385
+            ->method('getCalendarsForUser')
386
+            ->with('user-principal-123')
387
+            ->willReturn([]);
388
+
389
+        $this->backend
390
+            ->expects(self::once())
391
+            ->method('getFederatedCalendarsForUser')
392
+            ->with('user-principal-123')
393
+            ->willReturn([
394
+                [
395
+                    'id' => 10,
396
+                    'uri' => 'fed-cal-1',
397
+                    'principaluri' => 'user-principal-123',
398
+                    '{DAV:}displayname' => 'Federated calendar 1',
399
+                    '{http://sabredav.org/ns}sync-token' => 3,
400
+                    '{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/3',
401
+                    '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
402
+                    '{http://owncloud.org/ns}owner-principal' => 'principals/remote-users/c2hhcmVyQGhvc3QudGxkCg==',
403
+                    '{http://owncloud.org/ns}read-only' => 1
404
+                ],
405
+                [
406
+                    'id' => 11,
407
+                    'uri' => 'fed-cal-2',
408
+                    'principaluri' => 'user-principal-123',
409
+                    '{DAV:}displayname' => 'Federated calendar 2',
410
+                    '{http://sabredav.org/ns}sync-token' => 5,
411
+                    '{http://calendarserver.org/ns/}getctag' => 'http://sabre.io/ns/sync/5',
412
+                    '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
413
+                    '{http://owncloud.org/ns}owner-principal' => 'principals/remote-users/c2hhcmVyQGhvc3QudGxkCg==',
414
+                    '{http://owncloud.org/ns}read-only' => 1
415
+                ],
416
+            ]);
417
+
418
+        $this->backend
419
+            ->expects(self::once())
420
+            ->method('getSubscriptionsForUser')
421
+            ->with('user-principal-123')
422
+            ->willReturn([]);
423
+
424
+        $actual = $this->calendarHome->getChildren();
425
+
426
+        $this->assertCount(5, $actual);
427
+        $this->assertInstanceOf(Inbox::class, $actual[0]);
428
+        $this->assertInstanceOf(Outbox::class, $actual[1]);
429
+        $this->assertInstanceOf(TrashbinHome::class, $actual[2]);
430
+        $this->assertInstanceOf(FederatedCalendar::class, $actual[3]);
431
+        $this->assertInstanceOf(FederatedCalendar::class, $actual[4]);
432
+    }
433 433
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/Sharing/BackendTest.php 1 patch
Indentation   +380 added lines, -380 removed lines patch added patch discarded remove patch
@@ -26,384 +26,384 @@
 block discarded – undo
26 26
 
27 27
 class BackendTest extends TestCase {
28 28
 
29
-	private IDBConnection&MockObject $db;
30
-	private IUserManager&MockObject $userManager;
31
-	private IGroupManager&MockObject $groupManager;
32
-	private Principal&MockObject $principalBackend;
33
-	private ICache&MockObject $shareCache;
34
-	private LoggerInterface&MockObject $logger;
35
-	private ICacheFactory&MockObject $cacheFactory;
36
-	private Service&MockObject $calendarService;
37
-	private RemoteUserPrincipalBackend&MockObject $remoteUserPrincipalBackend;
38
-	private FederationSharingService&MockObject $federationSharingService;
39
-	private CalendarSharingBackend $backend;
40
-
41
-	protected function setUp(): void {
42
-		parent::setUp();
43
-		$this->db = $this->createMock(IDBConnection::class);
44
-		$this->userManager = $this->createMock(IUserManager::class);
45
-		$this->groupManager = $this->createMock(IGroupManager::class);
46
-		$this->principalBackend = $this->createMock(Principal::class);
47
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
48
-		$this->shareCache = $this->createMock(ICache::class);
49
-		$this->logger = $this->createMock(LoggerInterface::class);
50
-		$this->calendarService = $this->createMock(Service::class);
51
-		$this->cacheFactory->expects(self::any())
52
-			->method('createInMemory')
53
-			->willReturn($this->shareCache);
54
-		$this->remoteUserPrincipalBackend = $this->createMock(RemoteUserPrincipalBackend::class);
55
-		$this->federationSharingService = $this->createMock(FederationSharingService::class);
56
-
57
-		$this->backend = new CalendarSharingBackend(
58
-			$this->userManager,
59
-			$this->groupManager,
60
-			$this->principalBackend,
61
-			$this->remoteUserPrincipalBackend,
62
-			$this->cacheFactory,
63
-			$this->calendarService,
64
-			$this->federationSharingService,
65
-			$this->logger,
66
-		);
67
-	}
68
-
69
-	public function testUpdateShareCalendarBob(): void {
70
-		$shareable = $this->createConfiguredMock(IShareable::class, [
71
-			'getOwner' => 'principals/users/alice',
72
-			'getResourceId' => 42,
73
-		]);
74
-		$add = [
75
-			[
76
-				'href' => 'principal:principals/users/bob',
77
-				'readOnly' => true,
78
-			]
79
-		];
80
-		$principal = 'principals/users/bob';
81
-
82
-		$this->shareCache->expects(self::once())
83
-			->method('clear');
84
-		$this->principalBackend->expects(self::once())
85
-			->method('findByUri')
86
-			->willReturn($principal);
87
-		$this->userManager->expects(self::once())
88
-			->method('userExists')
89
-			->willReturn(true);
90
-		$this->groupManager->expects(self::never())
91
-			->method('groupExists');
92
-		$this->calendarService->expects(self::once())
93
-			->method('shareWith')
94
-			->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
95
-
96
-		$this->backend->updateShares($shareable, $add, []);
97
-	}
98
-
99
-	public function testUpdateShareCalendarGroup(): void {
100
-		$shareable = $this->createConfiguredMock(IShareable::class, [
101
-			'getOwner' => 'principals/users/alice',
102
-			'getResourceId' => 42,
103
-		]);
104
-		$add = [
105
-			[
106
-				'href' => 'principal:principals/groups/bob',
107
-				'readOnly' => true,
108
-			]
109
-		];
110
-		$principal = 'principals/groups/bob';
111
-
112
-		$this->shareCache->expects(self::once())
113
-			->method('clear');
114
-		$this->principalBackend->expects(self::once())
115
-			->method('findByUri')
116
-			->willReturn($principal);
117
-		$this->userManager->expects(self::never())
118
-			->method('userExists');
119
-		$this->groupManager->expects(self::once())
120
-			->method('groupExists')
121
-			->willReturn(true);
122
-		$this->calendarService->expects(self::once())
123
-			->method('shareWith')
124
-			->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
125
-
126
-		$this->backend->updateShares($shareable, $add, []);
127
-	}
128
-
129
-	public function testUpdateShareContactsBob(): void {
130
-		$shareable = $this->createConfiguredMock(IShareable::class, [
131
-			'getOwner' => 'principals/users/alice',
132
-			'getResourceId' => 42,
133
-		]);
134
-		$add = [
135
-			[
136
-				'href' => 'principal:principals/users/bob',
137
-				'readOnly' => true,
138
-			]
139
-		];
140
-		$principal = 'principals/users/bob';
141
-
142
-		$this->shareCache->expects(self::once())
143
-			->method('clear');
144
-		$this->principalBackend->expects(self::once())
145
-			->method('findByUri')
146
-			->willReturn($principal);
147
-		$this->userManager->expects(self::once())
148
-			->method('userExists')
149
-			->willReturn(true);
150
-		$this->groupManager->expects(self::never())
151
-			->method('groupExists');
152
-		$this->calendarService->expects(self::once())
153
-			->method('shareWith')
154
-			->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
155
-
156
-		$this->backend->updateShares($shareable, $add, []);
157
-	}
158
-
159
-	public function testUpdateShareContactsGroup(): void {
160
-		$shareable = $this->createConfiguredMock(IShareable::class, [
161
-			'getOwner' => 'principals/users/alice',
162
-			'getResourceId' => 42,
163
-		]);
164
-		$add = [
165
-			[
166
-				'href' => 'principal:principals/groups/bob',
167
-				'readOnly' => true,
168
-			]
169
-		];
170
-		$principal = 'principals/groups/bob';
171
-
172
-		$this->shareCache->expects(self::once())
173
-			->method('clear');
174
-		$this->principalBackend->expects(self::once())
175
-			->method('findByUri')
176
-			->willReturn($principal);
177
-		$this->userManager->expects(self::never())
178
-			->method('userExists');
179
-		$this->groupManager->expects(self::once())
180
-			->method('groupExists')
181
-			->willReturn(true);
182
-		$this->calendarService->expects(self::once())
183
-			->method('shareWith')
184
-			->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
185
-
186
-		$this->backend->updateShares($shareable, $add, []);
187
-	}
188
-
189
-	public function testUpdateShareCircle(): void {
190
-		$shareable = $this->createConfiguredMock(IShareable::class, [
191
-			'getOwner' => 'principals/users/alice',
192
-			'getResourceId' => 42,
193
-		]);
194
-		$add = [
195
-			[
196
-				'href' => 'principal:principals/circles/bob',
197
-				'readOnly' => true,
198
-			]
199
-		];
200
-		$principal = 'principals/groups/bob';
201
-
202
-		$this->shareCache->expects(self::once())
203
-			->method('clear');
204
-		$this->principalBackend->expects(self::once())
205
-			->method('findByUri')
206
-			->willReturn($principal);
207
-		$this->userManager->expects(self::never())
208
-			->method('userExists');
209
-		$this->groupManager->expects(self::once())
210
-			->method('groupExists')
211
-			->willReturn(true);
212
-		$this->calendarService->expects(self::once())
213
-			->method('shareWith')
214
-			->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
215
-
216
-		$this->backend->updateShares($shareable, $add, []);
217
-	}
218
-
219
-	public function testUnshareBob(): void {
220
-		$shareable = $this->createConfiguredMock(IShareable::class, [
221
-			'getOwner' => 'principals/users/alice',
222
-			'getResourceId' => 42,
223
-		]);
224
-		$remove = [
225
-			'principal:principals/users/bob',
226
-		];
227
-		$principal = 'principals/users/bob';
228
-
229
-		$this->shareCache->expects(self::once())
230
-			->method('clear');
231
-		$this->principalBackend->expects(self::once())
232
-			->method('findByUri')
233
-			->willReturn($principal);
234
-		$this->calendarService->expects(self::once())
235
-			->method('deleteShare')
236
-			->with($shareable->getResourceId(), $principal);
237
-		$this->calendarService->expects(self::never())
238
-			->method('unshare');
239
-
240
-		$this->backend->updateShares($shareable, [], $remove);
241
-	}
242
-
243
-	public function testUnshareWithBobGroup(): void {
244
-		$shareable = $this->createConfiguredMock(IShareable::class, [
245
-			'getOwner' => 'principals/users/alice',
246
-			'getResourceId' => 42,
247
-		]);
248
-		$remove = [
249
-			'principal:principals/users/bob',
250
-		];
251
-		$oldShares = [
252
-			[
253
-				'href' => 'principal:principals/groups/bob',
254
-				'commonName' => 'bob',
255
-				'status' => 1,
256
-				'readOnly' => true,
257
-				'{http://owncloud.org/ns}principal' => 'principals/groups/bob',
258
-				'{http://owncloud.org/ns}group-share' => true,
259
-			]
260
-		];
261
-
262
-
263
-		$this->shareCache->expects(self::once())
264
-			->method('clear');
265
-		$this->principalBackend->expects(self::once())
266
-			->method('findByUri')
267
-			->willReturn('principals/users/bob');
268
-		$this->calendarService->expects(self::once())
269
-			->method('deleteShare')
270
-			->with($shareable->getResourceId(), 'principals/users/bob');
271
-		$this->calendarService->expects(self::never())
272
-			->method('unshare');
273
-
274
-		$this->backend->updateShares($shareable, [], $remove, $oldShares);
275
-	}
276
-
277
-	public function testGetShares(): void {
278
-		$resourceId = 42;
279
-		$principal = 'principals/groups/bob';
280
-		$rows = [
281
-			[
282
-				'principaluri' => $principal,
283
-				'access' => Backend::ACCESS_READ,
284
-			]
285
-		];
286
-		$expected = [
287
-			[
288
-				'href' => 'principal:principals/groups/bob',
289
-				'commonName' => 'bob',
290
-				'status' => 1,
291
-				'readOnly' => true,
292
-				'{http://owncloud.org/ns}principal' => $principal,
293
-				'{http://owncloud.org/ns}group-share' => true,
294
-			]
295
-		];
296
-
297
-
298
-		$this->shareCache->expects(self::once())
299
-			->method('get')
300
-			->with((string)$resourceId)
301
-			->willReturn(null);
302
-		$this->calendarService->expects(self::once())
303
-			->method('getShares')
304
-			->with($resourceId)
305
-			->willReturn($rows);
306
-		$this->principalBackend->expects(self::once())
307
-			->method('getPrincipalByPath')
308
-			->with($principal)
309
-			->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
310
-		$this->shareCache->expects(self::once())
311
-			->method('set')
312
-			->with((string)$resourceId, $expected);
313
-
314
-		$result = $this->backend->getShares($resourceId);
315
-		$this->assertEquals($expected, $result);
316
-	}
317
-
318
-	public function testGetSharesAddressbooks(): void {
319
-		$service = $this->createMock(\OCA\DAV\CardDAV\Sharing\Service::class);
320
-		$backend = new ContactsSharingBackend(
321
-			$this->userManager,
322
-			$this->groupManager,
323
-			$this->principalBackend,
324
-			$this->remoteUserPrincipalBackend,
325
-			$this->cacheFactory,
326
-			$service,
327
-			$this->federationSharingService,
328
-			$this->logger);
329
-		$resourceId = 42;
330
-		$principal = 'principals/groups/bob';
331
-		$rows = [
332
-			[
333
-				'principaluri' => $principal,
334
-				'access' => Backend::ACCESS_READ,
335
-			]
336
-		];
337
-		$expected = [
338
-			[
339
-				'href' => 'principal:principals/groups/bob',
340
-				'commonName' => 'bob',
341
-				'status' => 1,
342
-				'readOnly' => true,
343
-				'{http://owncloud.org/ns}principal' => $principal,
344
-				'{http://owncloud.org/ns}group-share' => true,
345
-			]
346
-		];
347
-
348
-		$this->shareCache->expects(self::once())
349
-			->method('get')
350
-			->with((string)$resourceId)
351
-			->willReturn(null);
352
-		$service->expects(self::once())
353
-			->method('getShares')
354
-			->with($resourceId)
355
-			->willReturn($rows);
356
-		$this->principalBackend->expects(self::once())
357
-			->method('getPrincipalByPath')
358
-			->with($principal)
359
-			->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
360
-		$this->shareCache->expects(self::once())
361
-			->method('set')
362
-			->with((string)$resourceId, $expected);
363
-
364
-		$result = $backend->getShares($resourceId);
365
-		$this->assertEquals($expected, $result);
366
-	}
367
-
368
-	public function testPreloadShares(): void {
369
-		$resourceIds = [42, 99];
370
-		$rows = [
371
-			[
372
-				'resourceid' => 42,
373
-				'principaluri' => 'principals/groups/bob',
374
-				'access' => Backend::ACCESS_READ,
375
-			],
376
-			[
377
-				'resourceid' => 99,
378
-				'principaluri' => 'principals/users/carlos',
379
-				'access' => Backend::ACCESS_READ_WRITE,
380
-			]
381
-		];
382
-		$principalResults = [
383
-			['uri' => 'principals/groups/bob', '{DAV:}displayname' => 'bob'],
384
-			['uri' => 'principals/users/carlos', '{DAV:}displayname' => 'carlos'],
385
-		];
386
-
387
-		$this->shareCache->expects(self::exactly(2))
388
-			->method('get')
389
-			->willReturn(null);
390
-		$this->calendarService->expects(self::once())
391
-			->method('getSharesForIds')
392
-			->with($resourceIds)
393
-			->willReturn($rows);
394
-		$this->principalBackend->expects(self::exactly(2))
395
-			->method('getPrincipalByPath')
396
-			->willReturnCallback(function (string $principal) use ($principalResults) {
397
-				switch ($principal) {
398
-					case 'principals/groups/bob':
399
-						return $principalResults[0];
400
-					default:
401
-						return $principalResults[1];
402
-				}
403
-			});
404
-		$this->shareCache->expects(self::exactly(2))
405
-			->method('set');
406
-
407
-		$this->backend->preloadShares($resourceIds);
408
-	}
29
+    private IDBConnection&MockObject $db;
30
+    private IUserManager&MockObject $userManager;
31
+    private IGroupManager&MockObject $groupManager;
32
+    private Principal&MockObject $principalBackend;
33
+    private ICache&MockObject $shareCache;
34
+    private LoggerInterface&MockObject $logger;
35
+    private ICacheFactory&MockObject $cacheFactory;
36
+    private Service&MockObject $calendarService;
37
+    private RemoteUserPrincipalBackend&MockObject $remoteUserPrincipalBackend;
38
+    private FederationSharingService&MockObject $federationSharingService;
39
+    private CalendarSharingBackend $backend;
40
+
41
+    protected function setUp(): void {
42
+        parent::setUp();
43
+        $this->db = $this->createMock(IDBConnection::class);
44
+        $this->userManager = $this->createMock(IUserManager::class);
45
+        $this->groupManager = $this->createMock(IGroupManager::class);
46
+        $this->principalBackend = $this->createMock(Principal::class);
47
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
48
+        $this->shareCache = $this->createMock(ICache::class);
49
+        $this->logger = $this->createMock(LoggerInterface::class);
50
+        $this->calendarService = $this->createMock(Service::class);
51
+        $this->cacheFactory->expects(self::any())
52
+            ->method('createInMemory')
53
+            ->willReturn($this->shareCache);
54
+        $this->remoteUserPrincipalBackend = $this->createMock(RemoteUserPrincipalBackend::class);
55
+        $this->federationSharingService = $this->createMock(FederationSharingService::class);
56
+
57
+        $this->backend = new CalendarSharingBackend(
58
+            $this->userManager,
59
+            $this->groupManager,
60
+            $this->principalBackend,
61
+            $this->remoteUserPrincipalBackend,
62
+            $this->cacheFactory,
63
+            $this->calendarService,
64
+            $this->federationSharingService,
65
+            $this->logger,
66
+        );
67
+    }
68
+
69
+    public function testUpdateShareCalendarBob(): void {
70
+        $shareable = $this->createConfiguredMock(IShareable::class, [
71
+            'getOwner' => 'principals/users/alice',
72
+            'getResourceId' => 42,
73
+        ]);
74
+        $add = [
75
+            [
76
+                'href' => 'principal:principals/users/bob',
77
+                'readOnly' => true,
78
+            ]
79
+        ];
80
+        $principal = 'principals/users/bob';
81
+
82
+        $this->shareCache->expects(self::once())
83
+            ->method('clear');
84
+        $this->principalBackend->expects(self::once())
85
+            ->method('findByUri')
86
+            ->willReturn($principal);
87
+        $this->userManager->expects(self::once())
88
+            ->method('userExists')
89
+            ->willReturn(true);
90
+        $this->groupManager->expects(self::never())
91
+            ->method('groupExists');
92
+        $this->calendarService->expects(self::once())
93
+            ->method('shareWith')
94
+            ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
95
+
96
+        $this->backend->updateShares($shareable, $add, []);
97
+    }
98
+
99
+    public function testUpdateShareCalendarGroup(): void {
100
+        $shareable = $this->createConfiguredMock(IShareable::class, [
101
+            'getOwner' => 'principals/users/alice',
102
+            'getResourceId' => 42,
103
+        ]);
104
+        $add = [
105
+            [
106
+                'href' => 'principal:principals/groups/bob',
107
+                'readOnly' => true,
108
+            ]
109
+        ];
110
+        $principal = 'principals/groups/bob';
111
+
112
+        $this->shareCache->expects(self::once())
113
+            ->method('clear');
114
+        $this->principalBackend->expects(self::once())
115
+            ->method('findByUri')
116
+            ->willReturn($principal);
117
+        $this->userManager->expects(self::never())
118
+            ->method('userExists');
119
+        $this->groupManager->expects(self::once())
120
+            ->method('groupExists')
121
+            ->willReturn(true);
122
+        $this->calendarService->expects(self::once())
123
+            ->method('shareWith')
124
+            ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
125
+
126
+        $this->backend->updateShares($shareable, $add, []);
127
+    }
128
+
129
+    public function testUpdateShareContactsBob(): void {
130
+        $shareable = $this->createConfiguredMock(IShareable::class, [
131
+            'getOwner' => 'principals/users/alice',
132
+            'getResourceId' => 42,
133
+        ]);
134
+        $add = [
135
+            [
136
+                'href' => 'principal:principals/users/bob',
137
+                'readOnly' => true,
138
+            ]
139
+        ];
140
+        $principal = 'principals/users/bob';
141
+
142
+        $this->shareCache->expects(self::once())
143
+            ->method('clear');
144
+        $this->principalBackend->expects(self::once())
145
+            ->method('findByUri')
146
+            ->willReturn($principal);
147
+        $this->userManager->expects(self::once())
148
+            ->method('userExists')
149
+            ->willReturn(true);
150
+        $this->groupManager->expects(self::never())
151
+            ->method('groupExists');
152
+        $this->calendarService->expects(self::once())
153
+            ->method('shareWith')
154
+            ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
155
+
156
+        $this->backend->updateShares($shareable, $add, []);
157
+    }
158
+
159
+    public function testUpdateShareContactsGroup(): void {
160
+        $shareable = $this->createConfiguredMock(IShareable::class, [
161
+            'getOwner' => 'principals/users/alice',
162
+            'getResourceId' => 42,
163
+        ]);
164
+        $add = [
165
+            [
166
+                'href' => 'principal:principals/groups/bob',
167
+                'readOnly' => true,
168
+            ]
169
+        ];
170
+        $principal = 'principals/groups/bob';
171
+
172
+        $this->shareCache->expects(self::once())
173
+            ->method('clear');
174
+        $this->principalBackend->expects(self::once())
175
+            ->method('findByUri')
176
+            ->willReturn($principal);
177
+        $this->userManager->expects(self::never())
178
+            ->method('userExists');
179
+        $this->groupManager->expects(self::once())
180
+            ->method('groupExists')
181
+            ->willReturn(true);
182
+        $this->calendarService->expects(self::once())
183
+            ->method('shareWith')
184
+            ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
185
+
186
+        $this->backend->updateShares($shareable, $add, []);
187
+    }
188
+
189
+    public function testUpdateShareCircle(): void {
190
+        $shareable = $this->createConfiguredMock(IShareable::class, [
191
+            'getOwner' => 'principals/users/alice',
192
+            'getResourceId' => 42,
193
+        ]);
194
+        $add = [
195
+            [
196
+                'href' => 'principal:principals/circles/bob',
197
+                'readOnly' => true,
198
+            ]
199
+        ];
200
+        $principal = 'principals/groups/bob';
201
+
202
+        $this->shareCache->expects(self::once())
203
+            ->method('clear');
204
+        $this->principalBackend->expects(self::once())
205
+            ->method('findByUri')
206
+            ->willReturn($principal);
207
+        $this->userManager->expects(self::never())
208
+            ->method('userExists');
209
+        $this->groupManager->expects(self::once())
210
+            ->method('groupExists')
211
+            ->willReturn(true);
212
+        $this->calendarService->expects(self::once())
213
+            ->method('shareWith')
214
+            ->with($shareable->getResourceId(), $principal, Backend::ACCESS_READ);
215
+
216
+        $this->backend->updateShares($shareable, $add, []);
217
+    }
218
+
219
+    public function testUnshareBob(): void {
220
+        $shareable = $this->createConfiguredMock(IShareable::class, [
221
+            'getOwner' => 'principals/users/alice',
222
+            'getResourceId' => 42,
223
+        ]);
224
+        $remove = [
225
+            'principal:principals/users/bob',
226
+        ];
227
+        $principal = 'principals/users/bob';
228
+
229
+        $this->shareCache->expects(self::once())
230
+            ->method('clear');
231
+        $this->principalBackend->expects(self::once())
232
+            ->method('findByUri')
233
+            ->willReturn($principal);
234
+        $this->calendarService->expects(self::once())
235
+            ->method('deleteShare')
236
+            ->with($shareable->getResourceId(), $principal);
237
+        $this->calendarService->expects(self::never())
238
+            ->method('unshare');
239
+
240
+        $this->backend->updateShares($shareable, [], $remove);
241
+    }
242
+
243
+    public function testUnshareWithBobGroup(): void {
244
+        $shareable = $this->createConfiguredMock(IShareable::class, [
245
+            'getOwner' => 'principals/users/alice',
246
+            'getResourceId' => 42,
247
+        ]);
248
+        $remove = [
249
+            'principal:principals/users/bob',
250
+        ];
251
+        $oldShares = [
252
+            [
253
+                'href' => 'principal:principals/groups/bob',
254
+                'commonName' => 'bob',
255
+                'status' => 1,
256
+                'readOnly' => true,
257
+                '{http://owncloud.org/ns}principal' => 'principals/groups/bob',
258
+                '{http://owncloud.org/ns}group-share' => true,
259
+            ]
260
+        ];
261
+
262
+
263
+        $this->shareCache->expects(self::once())
264
+            ->method('clear');
265
+        $this->principalBackend->expects(self::once())
266
+            ->method('findByUri')
267
+            ->willReturn('principals/users/bob');
268
+        $this->calendarService->expects(self::once())
269
+            ->method('deleteShare')
270
+            ->with($shareable->getResourceId(), 'principals/users/bob');
271
+        $this->calendarService->expects(self::never())
272
+            ->method('unshare');
273
+
274
+        $this->backend->updateShares($shareable, [], $remove, $oldShares);
275
+    }
276
+
277
+    public function testGetShares(): void {
278
+        $resourceId = 42;
279
+        $principal = 'principals/groups/bob';
280
+        $rows = [
281
+            [
282
+                'principaluri' => $principal,
283
+                'access' => Backend::ACCESS_READ,
284
+            ]
285
+        ];
286
+        $expected = [
287
+            [
288
+                'href' => 'principal:principals/groups/bob',
289
+                'commonName' => 'bob',
290
+                'status' => 1,
291
+                'readOnly' => true,
292
+                '{http://owncloud.org/ns}principal' => $principal,
293
+                '{http://owncloud.org/ns}group-share' => true,
294
+            ]
295
+        ];
296
+
297
+
298
+        $this->shareCache->expects(self::once())
299
+            ->method('get')
300
+            ->with((string)$resourceId)
301
+            ->willReturn(null);
302
+        $this->calendarService->expects(self::once())
303
+            ->method('getShares')
304
+            ->with($resourceId)
305
+            ->willReturn($rows);
306
+        $this->principalBackend->expects(self::once())
307
+            ->method('getPrincipalByPath')
308
+            ->with($principal)
309
+            ->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
310
+        $this->shareCache->expects(self::once())
311
+            ->method('set')
312
+            ->with((string)$resourceId, $expected);
313
+
314
+        $result = $this->backend->getShares($resourceId);
315
+        $this->assertEquals($expected, $result);
316
+    }
317
+
318
+    public function testGetSharesAddressbooks(): void {
319
+        $service = $this->createMock(\OCA\DAV\CardDAV\Sharing\Service::class);
320
+        $backend = new ContactsSharingBackend(
321
+            $this->userManager,
322
+            $this->groupManager,
323
+            $this->principalBackend,
324
+            $this->remoteUserPrincipalBackend,
325
+            $this->cacheFactory,
326
+            $service,
327
+            $this->federationSharingService,
328
+            $this->logger);
329
+        $resourceId = 42;
330
+        $principal = 'principals/groups/bob';
331
+        $rows = [
332
+            [
333
+                'principaluri' => $principal,
334
+                'access' => Backend::ACCESS_READ,
335
+            ]
336
+        ];
337
+        $expected = [
338
+            [
339
+                'href' => 'principal:principals/groups/bob',
340
+                'commonName' => 'bob',
341
+                'status' => 1,
342
+                'readOnly' => true,
343
+                '{http://owncloud.org/ns}principal' => $principal,
344
+                '{http://owncloud.org/ns}group-share' => true,
345
+            ]
346
+        ];
347
+
348
+        $this->shareCache->expects(self::once())
349
+            ->method('get')
350
+            ->with((string)$resourceId)
351
+            ->willReturn(null);
352
+        $service->expects(self::once())
353
+            ->method('getShares')
354
+            ->with($resourceId)
355
+            ->willReturn($rows);
356
+        $this->principalBackend->expects(self::once())
357
+            ->method('getPrincipalByPath')
358
+            ->with($principal)
359
+            ->willReturn(['uri' => $principal, '{DAV:}displayname' => 'bob']);
360
+        $this->shareCache->expects(self::once())
361
+            ->method('set')
362
+            ->with((string)$resourceId, $expected);
363
+
364
+        $result = $backend->getShares($resourceId);
365
+        $this->assertEquals($expected, $result);
366
+    }
367
+
368
+    public function testPreloadShares(): void {
369
+        $resourceIds = [42, 99];
370
+        $rows = [
371
+            [
372
+                'resourceid' => 42,
373
+                'principaluri' => 'principals/groups/bob',
374
+                'access' => Backend::ACCESS_READ,
375
+            ],
376
+            [
377
+                'resourceid' => 99,
378
+                'principaluri' => 'principals/users/carlos',
379
+                'access' => Backend::ACCESS_READ_WRITE,
380
+            ]
381
+        ];
382
+        $principalResults = [
383
+            ['uri' => 'principals/groups/bob', '{DAV:}displayname' => 'bob'],
384
+            ['uri' => 'principals/users/carlos', '{DAV:}displayname' => 'carlos'],
385
+        ];
386
+
387
+        $this->shareCache->expects(self::exactly(2))
388
+            ->method('get')
389
+            ->willReturn(null);
390
+        $this->calendarService->expects(self::once())
391
+            ->method('getSharesForIds')
392
+            ->with($resourceIds)
393
+            ->willReturn($rows);
394
+        $this->principalBackend->expects(self::exactly(2))
395
+            ->method('getPrincipalByPath')
396
+            ->willReturnCallback(function (string $principal) use ($principalResults) {
397
+                switch ($principal) {
398
+                    case 'principals/groups/bob':
399
+                        return $principalResults[0];
400
+                    default:
401
+                        return $principalResults[1];
402
+                }
403
+            });
404
+        $this->shareCache->expects(self::exactly(2))
405
+            ->method('set');
406
+
407
+        $this->backend->preloadShares($resourceIds);
408
+    }
409 409
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/CardDAV/SyncServiceTest.php 1 patch
Indentation   +371 added lines, -371 removed lines patch added patch discarded remove patch
@@ -29,103 +29,103 @@  discard block
 block discarded – undo
29 29
 
30 30
 class SyncServiceTest extends TestCase {
31 31
 
32
-	protected CardDavBackend&MockObject $backend;
33
-	protected IUserManager&MockObject $userManager;
34
-	protected IDBConnection&MockObject $dbConnection;
35
-	protected LoggerInterface $logger;
36
-	protected Converter&MockObject $converter;
37
-	protected IClient&MockObject $client;
38
-	protected IConfig&MockObject $config;
39
-	protected SyncService $service;
40
-
41
-	public function setUp(): void {
42
-		parent::setUp();
43
-
44
-		$addressBook = [
45
-			'id' => 1,
46
-			'uri' => 'system',
47
-			'principaluri' => 'principals/system/system',
48
-			'{DAV:}displayname' => 'system',
49
-			// watch out, incomplete address book mock.
50
-		];
51
-
52
-		$this->backend = $this->createMock(CardDavBackend::class);
53
-		$this->backend->method('getAddressBooksByUri')
54
-			->with('principals/system/system', 1)
55
-			->willReturn($addressBook);
56
-
57
-		$this->userManager = $this->createMock(IUserManager::class);
58
-		$this->dbConnection = $this->createMock(IDBConnection::class);
59
-		$this->logger = new NullLogger();
60
-		$this->converter = $this->createMock(Converter::class);
61
-		$this->client = $this->createMock(IClient::class);
62
-		$this->config = $this->createMock(IConfig::class);
63
-
64
-		$clientService = $this->createMock(IClientService::class);
65
-		$clientService->method('newClient')
66
-			->willReturn($this->client);
67
-
68
-		$this->service = new SyncService(
69
-			$clientService,
70
-			$this->config,
71
-			$this->backend,
72
-			$this->userManager,
73
-			$this->dbConnection,
74
-			$this->logger,
75
-			$this->converter,
76
-		);
77
-	}
78
-
79
-	public function testEmptySync(): void {
80
-		$this->backend->expects($this->exactly(0))
81
-			->method('createCard');
82
-		$this->backend->expects($this->exactly(0))
83
-			->method('updateCard');
84
-		$this->backend->expects($this->exactly(0))
85
-			->method('deleteCard');
86
-
87
-		$body = '<?xml version="1.0"?>
32
+    protected CardDavBackend&MockObject $backend;
33
+    protected IUserManager&MockObject $userManager;
34
+    protected IDBConnection&MockObject $dbConnection;
35
+    protected LoggerInterface $logger;
36
+    protected Converter&MockObject $converter;
37
+    protected IClient&MockObject $client;
38
+    protected IConfig&MockObject $config;
39
+    protected SyncService $service;
40
+
41
+    public function setUp(): void {
42
+        parent::setUp();
43
+
44
+        $addressBook = [
45
+            'id' => 1,
46
+            'uri' => 'system',
47
+            'principaluri' => 'principals/system/system',
48
+            '{DAV:}displayname' => 'system',
49
+            // watch out, incomplete address book mock.
50
+        ];
51
+
52
+        $this->backend = $this->createMock(CardDavBackend::class);
53
+        $this->backend->method('getAddressBooksByUri')
54
+            ->with('principals/system/system', 1)
55
+            ->willReturn($addressBook);
56
+
57
+        $this->userManager = $this->createMock(IUserManager::class);
58
+        $this->dbConnection = $this->createMock(IDBConnection::class);
59
+        $this->logger = new NullLogger();
60
+        $this->converter = $this->createMock(Converter::class);
61
+        $this->client = $this->createMock(IClient::class);
62
+        $this->config = $this->createMock(IConfig::class);
63
+
64
+        $clientService = $this->createMock(IClientService::class);
65
+        $clientService->method('newClient')
66
+            ->willReturn($this->client);
67
+
68
+        $this->service = new SyncService(
69
+            $clientService,
70
+            $this->config,
71
+            $this->backend,
72
+            $this->userManager,
73
+            $this->dbConnection,
74
+            $this->logger,
75
+            $this->converter,
76
+        );
77
+    }
78
+
79
+    public function testEmptySync(): void {
80
+        $this->backend->expects($this->exactly(0))
81
+            ->method('createCard');
82
+        $this->backend->expects($this->exactly(0))
83
+            ->method('updateCard');
84
+        $this->backend->expects($this->exactly(0))
85
+            ->method('deleteCard');
86
+
87
+        $body = '<?xml version="1.0"?>
88 88
 <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns">
89 89
     <d:sync-token>http://sabre.io/ns/sync/1</d:sync-token>
90 90
 </d:multistatus>';
91 91
 
92
-		$requestResponse = new Response(new PsrResponse(
93
-			207,
94
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
95
-			$body
96
-		));
97
-
98
-		$this->client
99
-			->method('request')
100
-			->willReturn($requestResponse);
101
-
102
-		$token = $this->service->syncRemoteAddressBook(
103
-			'',
104
-			'system',
105
-			'system',
106
-			'1234567890',
107
-			null,
108
-			'1',
109
-			'principals/system/system',
110
-			[]
111
-		)[0];
112
-
113
-		$this->assertEquals('http://sabre.io/ns/sync/1', $token);
114
-	}
115
-
116
-	public function testSyncWithNewElement(): void {
117
-		$this->backend->expects($this->exactly(1))
118
-			->method('createCard');
119
-		$this->backend->expects($this->exactly(0))
120
-			->method('updateCard');
121
-		$this->backend->expects($this->exactly(0))
122
-			->method('deleteCard');
123
-
124
-		$this->backend->method('getCard')
125
-			->willReturn(false);
126
-
127
-
128
-		$body = '<?xml version="1.0"?>
92
+        $requestResponse = new Response(new PsrResponse(
93
+            207,
94
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
95
+            $body
96
+        ));
97
+
98
+        $this->client
99
+            ->method('request')
100
+            ->willReturn($requestResponse);
101
+
102
+        $token = $this->service->syncRemoteAddressBook(
103
+            '',
104
+            'system',
105
+            'system',
106
+            '1234567890',
107
+            null,
108
+            '1',
109
+            'principals/system/system',
110
+            []
111
+        )[0];
112
+
113
+        $this->assertEquals('http://sabre.io/ns/sync/1', $token);
114
+    }
115
+
116
+    public function testSyncWithNewElement(): void {
117
+        $this->backend->expects($this->exactly(1))
118
+            ->method('createCard');
119
+        $this->backend->expects($this->exactly(0))
120
+            ->method('updateCard');
121
+        $this->backend->expects($this->exactly(0))
122
+            ->method('deleteCard');
123
+
124
+        $this->backend->method('getCard')
125
+            ->willReturn(false);
126
+
127
+
128
+        $body = '<?xml version="1.0"?>
129 129
 <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns">
130 130
     <d:response>
131 131
         <d:href>/remote.php/dav/addressbooks/system/system/system/Database:alice.vcf</d:href>
@@ -140,17 +140,17 @@  discard block
 block discarded – undo
140 140
     <d:sync-token>http://sabre.io/ns/sync/2</d:sync-token>
141 141
 </d:multistatus>';
142 142
 
143
-		$reportResponse = new Response(new PsrResponse(
144
-			207,
145
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
146
-			$body
147
-		));
143
+        $reportResponse = new Response(new PsrResponse(
144
+            207,
145
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
146
+            $body
147
+        ));
148 148
 
149
-		$this->client
150
-			->method('request')
151
-			->willReturn($reportResponse);
149
+        $this->client
150
+            ->method('request')
151
+            ->willReturn($reportResponse);
152 152
 
153
-		$vCard = 'BEGIN:VCARD
153
+        $vCard = 'BEGIN:VCARD
154 154
 VERSION:3.0
155 155
 PRODID:-//Sabre//Sabre VObject 4.5.4//EN
156 156
 UID:alice
@@ -160,43 +160,43 @@  discard block
 block discarded – undo
160 160
 CLOUD:[email protected]
161 161
 END:VCARD';
162 162
 
163
-		$getResponse = new Response(new PsrResponse(
164
-			200,
165
-			['Content-Type' => 'text/vcard; charset=utf-8', 'Content-Length' => strlen($vCard)],
166
-			$vCard,
167
-		));
168
-
169
-		$this->client
170
-			->method('get')
171
-			->willReturn($getResponse);
172
-
173
-		$token = $this->service->syncRemoteAddressBook(
174
-			'',
175
-			'system',
176
-			'system',
177
-			'1234567890',
178
-			null,
179
-			'1',
180
-			'principals/system/system',
181
-			[]
182
-		)[0];
183
-
184
-		$this->assertEquals('http://sabre.io/ns/sync/2', $token);
185
-	}
186
-
187
-	public function testSyncWithUpdatedElement(): void {
188
-		$this->backend->expects($this->exactly(0))
189
-			->method('createCard');
190
-		$this->backend->expects($this->exactly(1))
191
-			->method('updateCard');
192
-		$this->backend->expects($this->exactly(0))
193
-			->method('deleteCard');
194
-
195
-		$this->backend->method('getCard')
196
-			->willReturn(true);
197
-
198
-
199
-		$body = '<?xml version="1.0"?>
163
+        $getResponse = new Response(new PsrResponse(
164
+            200,
165
+            ['Content-Type' => 'text/vcard; charset=utf-8', 'Content-Length' => strlen($vCard)],
166
+            $vCard,
167
+        ));
168
+
169
+        $this->client
170
+            ->method('get')
171
+            ->willReturn($getResponse);
172
+
173
+        $token = $this->service->syncRemoteAddressBook(
174
+            '',
175
+            'system',
176
+            'system',
177
+            '1234567890',
178
+            null,
179
+            '1',
180
+            'principals/system/system',
181
+            []
182
+        )[0];
183
+
184
+        $this->assertEquals('http://sabre.io/ns/sync/2', $token);
185
+    }
186
+
187
+    public function testSyncWithUpdatedElement(): void {
188
+        $this->backend->expects($this->exactly(0))
189
+            ->method('createCard');
190
+        $this->backend->expects($this->exactly(1))
191
+            ->method('updateCard');
192
+        $this->backend->expects($this->exactly(0))
193
+            ->method('deleteCard');
194
+
195
+        $this->backend->method('getCard')
196
+            ->willReturn(true);
197
+
198
+
199
+        $body = '<?xml version="1.0"?>
200 200
 <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns">
201 201
     <d:response>
202 202
         <d:href>/remote.php/dav/addressbooks/system/system/system/Database:alice.vcf</d:href>
@@ -211,17 +211,17 @@  discard block
 block discarded – undo
211 211
     <d:sync-token>http://sabre.io/ns/sync/3</d:sync-token>
212 212
 </d:multistatus>';
213 213
 
214
-		$reportResponse = new Response(new PsrResponse(
215
-			207,
216
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
217
-			$body
218
-		));
214
+        $reportResponse = new Response(new PsrResponse(
215
+            207,
216
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
217
+            $body
218
+        ));
219 219
 
220
-		$this->client
221
-			->method('request')
222
-			->willReturn($reportResponse);
220
+        $this->client
221
+            ->method('request')
222
+            ->willReturn($reportResponse);
223 223
 
224
-		$vCard = 'BEGIN:VCARD
224
+        $vCard = 'BEGIN:VCARD
225 225
 VERSION:3.0
226 226
 PRODID:-//Sabre//Sabre VObject 4.5.4//EN
227 227
 UID:alice
@@ -231,39 +231,39 @@  discard block
 block discarded – undo
231 231
 CLOUD:[email protected]
232 232
 END:VCARD';
233 233
 
234
-		$getResponse = new Response(new PsrResponse(
235
-			200,
236
-			['Content-Type' => 'text/vcard; charset=utf-8', 'Content-Length' => strlen($vCard)],
237
-			$vCard,
238
-		));
239
-
240
-		$this->client
241
-			->method('get')
242
-			->willReturn($getResponse);
243
-
244
-		$token = $this->service->syncRemoteAddressBook(
245
-			'',
246
-			'system',
247
-			'system',
248
-			'1234567890',
249
-			null,
250
-			'1',
251
-			'principals/system/system',
252
-			[]
253
-		)[0];
254
-
255
-		$this->assertEquals('http://sabre.io/ns/sync/3', $token);
256
-	}
257
-
258
-	public function testSyncWithDeletedElement(): void {
259
-		$this->backend->expects($this->exactly(0))
260
-			->method('createCard');
261
-		$this->backend->expects($this->exactly(0))
262
-			->method('updateCard');
263
-		$this->backend->expects($this->exactly(1))
264
-			->method('deleteCard');
265
-
266
-		$body = '<?xml version="1.0"?>
234
+        $getResponse = new Response(new PsrResponse(
235
+            200,
236
+            ['Content-Type' => 'text/vcard; charset=utf-8', 'Content-Length' => strlen($vCard)],
237
+            $vCard,
238
+        ));
239
+
240
+        $this->client
241
+            ->method('get')
242
+            ->willReturn($getResponse);
243
+
244
+        $token = $this->service->syncRemoteAddressBook(
245
+            '',
246
+            'system',
247
+            'system',
248
+            '1234567890',
249
+            null,
250
+            '1',
251
+            'principals/system/system',
252
+            []
253
+        )[0];
254
+
255
+        $this->assertEquals('http://sabre.io/ns/sync/3', $token);
256
+    }
257
+
258
+    public function testSyncWithDeletedElement(): void {
259
+        $this->backend->expects($this->exactly(0))
260
+            ->method('createCard');
261
+        $this->backend->expects($this->exactly(0))
262
+            ->method('updateCard');
263
+        $this->backend->expects($this->exactly(1))
264
+            ->method('deleteCard');
265
+
266
+        $body = '<?xml version="1.0"?>
267 267
 <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns">
268 268
 <d:response>
269 269
     <d:href>/remote.php/dav/addressbooks/system/system/system/Database:alice.vcf</d:href>
@@ -272,209 +272,209 @@  discard block
 block discarded – undo
272 272
 <d:sync-token>http://sabre.io/ns/sync/4</d:sync-token>
273 273
 </d:multistatus>';
274 274
 
275
-		$reportResponse = new Response(new PsrResponse(
276
-			207,
277
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
278
-			$body
279
-		));
280
-
281
-		$this->client
282
-			->method('request')
283
-			->willReturn($reportResponse);
284
-
285
-		$token = $this->service->syncRemoteAddressBook(
286
-			'',
287
-			'system',
288
-			'system',
289
-			'1234567890',
290
-			null,
291
-			'1',
292
-			'principals/system/system',
293
-			[]
294
-		)[0];
295
-
296
-		$this->assertEquals('http://sabre.io/ns/sync/4', $token);
297
-	}
298
-
299
-	public function testEnsureSystemAddressBookExists(): void {
300
-		/** @var CardDavBackend&MockObject $backend */
301
-		$backend = $this->createMock(CardDavBackend::class);
302
-		$backend->expects($this->exactly(1))->method('createAddressBook');
303
-		$backend->expects($this->exactly(2))
304
-			->method('getAddressBooksByUri')
305
-			->willReturnOnConsecutiveCalls(
306
-				null,
307
-				[],
308
-			);
309
-
310
-		$userManager = $this->createMock(IUserManager::class);
311
-		$dbConnection = $this->createMock(IDBConnection::class);
312
-		$logger = $this->createMock(LoggerInterface::class);
313
-		$converter = $this->createMock(Converter::class);
314
-		$clientService = $this->createMock(IClientService::class);
315
-		$config = $this->createMock(IConfig::class);
316
-
317
-		$ss = new SyncService($clientService, $config, $backend, $userManager, $dbConnection, $logger, $converter);
318
-		$ss->ensureSystemAddressBookExists('principals/users/adam', 'contacts', []);
319
-	}
320
-
321
-	public static function dataActivatedUsers(): array {
322
-		return [
323
-			[true, 1, 1, 1],
324
-			[false, 0, 0, 3],
325
-		];
326
-	}
327
-
328
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataActivatedUsers')]
329
-	public function testUpdateAndDeleteUser(bool $activated, int $createCalls, int $updateCalls, int $deleteCalls): void {
330
-		/** @var CardDavBackend | MockObject $backend */
331
-		$backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
332
-		$logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
333
-
334
-		$backend->expects($this->exactly($createCalls))->method('createCard');
335
-		$backend->expects($this->exactly($updateCalls))->method('updateCard');
336
-		$backend->expects($this->exactly($deleteCalls))->method('deleteCard');
337
-
338
-		$backend->method('getCard')->willReturnOnConsecutiveCalls(false, [
339
-			'carddata' => "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.8//EN\r\nUID:test-user\r\nFN:test-user\r\nN:test-user;;;;\r\nEND:VCARD\r\n\r\n"
340
-		]);
341
-
342
-		$backend->method('getAddressBooksByUri')
343
-			->with('principals/system/system', 'system')
344
-			->willReturn(['id' => -1]);
345
-
346
-		$userManager = $this->createMock(IUserManager::class);
347
-		$dbConnection = $this->createMock(IDBConnection::class);
348
-		$user = $this->createMock(IUser::class);
349
-		$user->method('getBackendClassName')->willReturn('unittest');
350
-		$user->method('getUID')->willReturn('test-user');
351
-		$user->method('getCloudId')->willReturn('cloudId');
352
-		$user->method('getDisplayName')->willReturn('test-user');
353
-		$user->method('isEnabled')->willReturn($activated);
354
-		$converter = $this->createMock(Converter::class);
355
-		$converter->expects($this->any())
356
-			->method('createCardFromUser')
357
-			->willReturn($this->createMock(VCard::class));
358
-
359
-		$clientService = $this->createMock(IClientService::class);
360
-		$config = $this->createMock(IConfig::class);
361
-
362
-		$ss = new SyncService($clientService, $config, $backend, $userManager, $dbConnection, $logger, $converter);
363
-		$ss->updateUser($user);
364
-
365
-		$ss->updateUser($user);
366
-
367
-		$ss->deleteUser($user);
368
-	}
369
-
370
-	public function testDeleteAddressbookWhenAccessRevoked(): void {
371
-		$this->expectException(ClientExceptionInterface::class);
372
-
373
-		$this->backend->expects($this->exactly(0))
374
-			->method('createCard');
375
-		$this->backend->expects($this->exactly(0))
376
-			->method('updateCard');
377
-		$this->backend->expects($this->exactly(0))
378
-			->method('deleteCard');
379
-		$this->backend->expects($this->exactly(1))
380
-			->method('deleteAddressBook');
381
-
382
-		$request = new PsrRequest(
383
-			'REPORT',
384
-			'https://server2.internal/remote.php/dav/addressbooks/system/system/system',
385
-			['Content-Type' => 'application/xml'],
386
-		);
387
-
388
-		$body = '<?xml version="1.0" encoding="utf-8"?>
275
+        $reportResponse = new Response(new PsrResponse(
276
+            207,
277
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
278
+            $body
279
+        ));
280
+
281
+        $this->client
282
+            ->method('request')
283
+            ->willReturn($reportResponse);
284
+
285
+        $token = $this->service->syncRemoteAddressBook(
286
+            '',
287
+            'system',
288
+            'system',
289
+            '1234567890',
290
+            null,
291
+            '1',
292
+            'principals/system/system',
293
+            []
294
+        )[0];
295
+
296
+        $this->assertEquals('http://sabre.io/ns/sync/4', $token);
297
+    }
298
+
299
+    public function testEnsureSystemAddressBookExists(): void {
300
+        /** @var CardDavBackend&MockObject $backend */
301
+        $backend = $this->createMock(CardDavBackend::class);
302
+        $backend->expects($this->exactly(1))->method('createAddressBook');
303
+        $backend->expects($this->exactly(2))
304
+            ->method('getAddressBooksByUri')
305
+            ->willReturnOnConsecutiveCalls(
306
+                null,
307
+                [],
308
+            );
309
+
310
+        $userManager = $this->createMock(IUserManager::class);
311
+        $dbConnection = $this->createMock(IDBConnection::class);
312
+        $logger = $this->createMock(LoggerInterface::class);
313
+        $converter = $this->createMock(Converter::class);
314
+        $clientService = $this->createMock(IClientService::class);
315
+        $config = $this->createMock(IConfig::class);
316
+
317
+        $ss = new SyncService($clientService, $config, $backend, $userManager, $dbConnection, $logger, $converter);
318
+        $ss->ensureSystemAddressBookExists('principals/users/adam', 'contacts', []);
319
+    }
320
+
321
+    public static function dataActivatedUsers(): array {
322
+        return [
323
+            [true, 1, 1, 1],
324
+            [false, 0, 0, 3],
325
+        ];
326
+    }
327
+
328
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataActivatedUsers')]
329
+    public function testUpdateAndDeleteUser(bool $activated, int $createCalls, int $updateCalls, int $deleteCalls): void {
330
+        /** @var CardDavBackend | MockObject $backend */
331
+        $backend = $this->getMockBuilder(CardDavBackend::class)->disableOriginalConstructor()->getMock();
332
+        $logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock();
333
+
334
+        $backend->expects($this->exactly($createCalls))->method('createCard');
335
+        $backend->expects($this->exactly($updateCalls))->method('updateCard');
336
+        $backend->expects($this->exactly($deleteCalls))->method('deleteCard');
337
+
338
+        $backend->method('getCard')->willReturnOnConsecutiveCalls(false, [
339
+            'carddata' => "BEGIN:VCARD\r\nVERSION:3.0\r\nPRODID:-//Sabre//Sabre VObject 3.4.8//EN\r\nUID:test-user\r\nFN:test-user\r\nN:test-user;;;;\r\nEND:VCARD\r\n\r\n"
340
+        ]);
341
+
342
+        $backend->method('getAddressBooksByUri')
343
+            ->with('principals/system/system', 'system')
344
+            ->willReturn(['id' => -1]);
345
+
346
+        $userManager = $this->createMock(IUserManager::class);
347
+        $dbConnection = $this->createMock(IDBConnection::class);
348
+        $user = $this->createMock(IUser::class);
349
+        $user->method('getBackendClassName')->willReturn('unittest');
350
+        $user->method('getUID')->willReturn('test-user');
351
+        $user->method('getCloudId')->willReturn('cloudId');
352
+        $user->method('getDisplayName')->willReturn('test-user');
353
+        $user->method('isEnabled')->willReturn($activated);
354
+        $converter = $this->createMock(Converter::class);
355
+        $converter->expects($this->any())
356
+            ->method('createCardFromUser')
357
+            ->willReturn($this->createMock(VCard::class));
358
+
359
+        $clientService = $this->createMock(IClientService::class);
360
+        $config = $this->createMock(IConfig::class);
361
+
362
+        $ss = new SyncService($clientService, $config, $backend, $userManager, $dbConnection, $logger, $converter);
363
+        $ss->updateUser($user);
364
+
365
+        $ss->updateUser($user);
366
+
367
+        $ss->deleteUser($user);
368
+    }
369
+
370
+    public function testDeleteAddressbookWhenAccessRevoked(): void {
371
+        $this->expectException(ClientExceptionInterface::class);
372
+
373
+        $this->backend->expects($this->exactly(0))
374
+            ->method('createCard');
375
+        $this->backend->expects($this->exactly(0))
376
+            ->method('updateCard');
377
+        $this->backend->expects($this->exactly(0))
378
+            ->method('deleteCard');
379
+        $this->backend->expects($this->exactly(1))
380
+            ->method('deleteAddressBook');
381
+
382
+        $request = new PsrRequest(
383
+            'REPORT',
384
+            'https://server2.internal/remote.php/dav/addressbooks/system/system/system',
385
+            ['Content-Type' => 'application/xml'],
386
+        );
387
+
388
+        $body = '<?xml version="1.0" encoding="utf-8"?>
389 389
 <d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
390 390
   <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
391 391
   <s:message>No public access to this resource., Username or password was incorrect, No \'Authorization: Bearer\' header found. Either the client didn\'t send one, or the server is mis-configured, Username or password was incorrect</s:message>
392 392
 </d:error>';
393 393
 
394
-		$response = new PsrResponse(
395
-			401,
396
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
397
-			$body
398
-		);
394
+        $response = new PsrResponse(
395
+            401,
396
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
397
+            $body
398
+        );
399 399
 
400
-		$message = 'Client error: `REPORT https://server2.internal/cloud/remote.php/dav/addressbooks/system/system/system` resulted in a `401 Unauthorized` response:
400
+        $message = 'Client error: `REPORT https://server2.internal/cloud/remote.php/dav/addressbooks/system/system/system` resulted in a `401 Unauthorized` response:
401 401
 <?xml version="1.0" encoding="utf-8"?>
402 402
 <d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
403 403
   <s:exception>Sabre\DA (truncated...)
404 404
 ';
405 405
 
406
-		$reportException = new ClientException(
407
-			$message,
408
-			$request,
409
-			$response
410
-		);
411
-
412
-		$this->client
413
-			->method('request')
414
-			->willThrowException($reportException);
415
-
416
-		$this->service->syncRemoteAddressBook(
417
-			'',
418
-			'system',
419
-			'system',
420
-			'1234567890',
421
-			null,
422
-			'1',
423
-			'principals/system/system',
424
-			[]
425
-		);
426
-	}
427
-
428
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerUseAbsoluteUriReport')]
429
-	public function testUseAbsoluteUriReport(string $host, string $expected): void {
430
-		$body = '<?xml version="1.0"?>
406
+        $reportException = new ClientException(
407
+            $message,
408
+            $request,
409
+            $response
410
+        );
411
+
412
+        $this->client
413
+            ->method('request')
414
+            ->willThrowException($reportException);
415
+
416
+        $this->service->syncRemoteAddressBook(
417
+            '',
418
+            'system',
419
+            'system',
420
+            '1234567890',
421
+            null,
422
+            '1',
423
+            'principals/system/system',
424
+            []
425
+        );
426
+    }
427
+
428
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerUseAbsoluteUriReport')]
429
+    public function testUseAbsoluteUriReport(string $host, string $expected): void {
430
+        $body = '<?xml version="1.0"?>
431 431
 <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:card="urn:ietf:params:xml:ns:carddav" xmlns:oc="http://owncloud.org/ns">
432 432
     <d:sync-token>http://sabre.io/ns/sync/1</d:sync-token>
433 433
 </d:multistatus>';
434 434
 
435
-		$requestResponse = new Response(new PsrResponse(
436
-			207,
437
-			['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
438
-			$body
439
-		));
440
-
441
-		$this->client
442
-			->method('request')
443
-			->with(
444
-				'REPORT',
445
-				$this->callback(function ($uri) use ($expected) {
446
-					$this->assertEquals($expected, $uri);
447
-					return true;
448
-				}),
449
-				$this->callback(function ($options) {
450
-					$this->assertIsArray($options);
451
-					return true;
452
-				}),
453
-			)
454
-			->willReturn($requestResponse);
455
-
456
-		$this->service->syncRemoteAddressBook(
457
-			$host,
458
-			'system',
459
-			'remote.php/dav/addressbooks/system/system/system',
460
-			'1234567890',
461
-			null,
462
-			'1',
463
-			'principals/system/system',
464
-			[]
465
-		);
466
-	}
467
-
468
-	public static function providerUseAbsoluteUriReport(): array {
469
-		return [
470
-			['https://server.internal', 'https://server.internal/remote.php/dav/addressbooks/system/system/system'],
471
-			['https://server.internal/', 'https://server.internal/remote.php/dav/addressbooks/system/system/system'],
472
-			['https://server.internal/nextcloud', 'https://server.internal/nextcloud/remote.php/dav/addressbooks/system/system/system'],
473
-			['https://server.internal/nextcloud/', 'https://server.internal/nextcloud/remote.php/dav/addressbooks/system/system/system'],
474
-			['https://server.internal:8080', 'https://server.internal:8080/remote.php/dav/addressbooks/system/system/system'],
475
-			['https://server.internal:8080/', 'https://server.internal:8080/remote.php/dav/addressbooks/system/system/system'],
476
-			['https://server.internal:8080/nextcloud', 'https://server.internal:8080/nextcloud/remote.php/dav/addressbooks/system/system/system'],
477
-			['https://server.internal:8080/nextcloud/', 'https://server.internal:8080/nextcloud/remote.php/dav/addressbooks/system/system/system'],
478
-		];
479
-	}
435
+        $requestResponse = new Response(new PsrResponse(
436
+            207,
437
+            ['Content-Type' => 'application/xml; charset=utf-8', 'Content-Length' => strlen($body)],
438
+            $body
439
+        ));
440
+
441
+        $this->client
442
+            ->method('request')
443
+            ->with(
444
+                'REPORT',
445
+                $this->callback(function ($uri) use ($expected) {
446
+                    $this->assertEquals($expected, $uri);
447
+                    return true;
448
+                }),
449
+                $this->callback(function ($options) {
450
+                    $this->assertIsArray($options);
451
+                    return true;
452
+                }),
453
+            )
454
+            ->willReturn($requestResponse);
455
+
456
+        $this->service->syncRemoteAddressBook(
457
+            $host,
458
+            'system',
459
+            'remote.php/dav/addressbooks/system/system/system',
460
+            '1234567890',
461
+            null,
462
+            '1',
463
+            'principals/system/system',
464
+            []
465
+        );
466
+    }
467
+
468
+    public static function providerUseAbsoluteUriReport(): array {
469
+        return [
470
+            ['https://server.internal', 'https://server.internal/remote.php/dav/addressbooks/system/system/system'],
471
+            ['https://server.internal/', 'https://server.internal/remote.php/dav/addressbooks/system/system/system'],
472
+            ['https://server.internal/nextcloud', 'https://server.internal/nextcloud/remote.php/dav/addressbooks/system/system/system'],
473
+            ['https://server.internal/nextcloud/', 'https://server.internal/nextcloud/remote.php/dav/addressbooks/system/system/system'],
474
+            ['https://server.internal:8080', 'https://server.internal:8080/remote.php/dav/addressbooks/system/system/system'],
475
+            ['https://server.internal:8080/', 'https://server.internal:8080/remote.php/dav/addressbooks/system/system/system'],
476
+            ['https://server.internal:8080/nextcloud', 'https://server.internal:8080/nextcloud/remote.php/dav/addressbooks/system/system/system'],
477
+            ['https://server.internal:8080/nextcloud/', 'https://server.internal:8080/nextcloud/remote.php/dav/addressbooks/system/system/system'],
478
+        ];
479
+    }
480 480
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/CardDAV/CardDavBackendTest.php 1 patch
Indentation   +875 added lines, -875 removed lines patch added patch discarded remove patch
@@ -48,879 +48,879 @@
 block discarded – undo
48 48
  * @package OCA\DAV\Tests\unit\CardDAV
49 49
  */
50 50
 class CardDavBackendTest extends TestCase {
51
-	private Principal&MockObject $principal;
52
-	private IUserManager&MockObject $userManager;
53
-	private IGroupManager&MockObject $groupManager;
54
-	private IEventDispatcher&MockObject $dispatcher;
55
-	private IConfig&MockObject $config;
56
-	private RemoteUserPrincipalBackend&MockObject $remoteUserPrincipalBackend;
57
-	private FederationSharingService&MockObject $federationSharingService;
58
-	private Backend $sharingBackend;
59
-	private IDBConnection $db;
60
-	private CardDavBackend $backend;
61
-	private string $dbCardsTable = 'cards';
62
-	private string $dbCardsPropertiesTable = 'cards_properties';
63
-
64
-	public const UNIT_TEST_USER = 'principals/users/carddav-unit-test';
65
-	public const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
66
-	public const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
67
-
68
-	private $vcardTest0 = 'BEGIN:VCARD' . PHP_EOL
69
-		. 'VERSION:3.0' . PHP_EOL
70
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
71
-		. 'UID:Test' . PHP_EOL
72
-		. 'FN:Test' . PHP_EOL
73
-		. 'N:Test;;;;' . PHP_EOL
74
-		. 'END:VCARD';
75
-
76
-	private $vcardTest1 = 'BEGIN:VCARD' . PHP_EOL
77
-		. 'VERSION:3.0' . PHP_EOL
78
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
79
-		. 'UID:Test2' . PHP_EOL
80
-		. 'FN:Test2' . PHP_EOL
81
-		. 'N:Test2;;;;' . PHP_EOL
82
-		. 'END:VCARD';
83
-
84
-	private $vcardTest2 = 'BEGIN:VCARD' . PHP_EOL
85
-		. 'VERSION:3.0' . PHP_EOL
86
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
87
-		. 'UID:Test3' . PHP_EOL
88
-		. 'FN:Test3' . PHP_EOL
89
-		. 'N:Test3;;;;' . PHP_EOL
90
-		. 'END:VCARD';
91
-
92
-	private $vcardTestNoUID = 'BEGIN:VCARD' . PHP_EOL
93
-		. 'VERSION:3.0' . PHP_EOL
94
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
95
-		. 'FN:TestNoUID' . PHP_EOL
96
-		. 'N:TestNoUID;;;;' . PHP_EOL
97
-		. 'END:VCARD';
98
-
99
-	protected function setUp(): void {
100
-		parent::setUp();
101
-
102
-		$this->userManager = $this->createMock(IUserManager::class);
103
-		$this->groupManager = $this->createMock(IGroupManager::class);
104
-		$this->config = $this->createMock(IConfig::class);
105
-		$this->principal = $this->getMockBuilder(Principal::class)
106
-			->setConstructorArgs([
107
-				$this->userManager,
108
-				$this->groupManager,
109
-				$this->createMock(IAccountManager::class),
110
-				$this->createMock(ShareManager::class),
111
-				$this->createMock(IUserSession::class),
112
-				$this->createMock(IAppManager::class),
113
-				$this->createMock(ProxyMapper::class),
114
-				$this->createMock(KnownUserService::class),
115
-				$this->config,
116
-				$this->createMock(IFactory::class)
117
-			])
118
-			->onlyMethods(['getPrincipalByPath', 'getGroupMembership', 'findByUri'])
119
-			->getMock();
120
-		$this->principal->method('getPrincipalByPath')
121
-			->willReturn([
122
-				'uri' => 'principals/best-friend',
123
-				'{DAV:}displayname' => 'User\'s displayname',
124
-			]);
125
-		$this->principal->method('getGroupMembership')
126
-			->withAnyParameters()
127
-			->willReturn([self::UNIT_TEST_GROUP]);
128
-		$this->dispatcher = $this->createMock(IEventDispatcher::class);
129
-		$this->remoteUserPrincipalBackend = $this->createMock(RemoteUserPrincipalBackend::class);
130
-		$this->federationSharingService = $this->createMock(FederationSharingService::class);
131
-
132
-		$this->db = Server::get(IDBConnection::class);
133
-		$this->sharingBackend = new Backend($this->userManager,
134
-			$this->groupManager,
135
-			$this->principal,
136
-			$this->remoteUserPrincipalBackend,
137
-			$this->createMock(ICacheFactory::class),
138
-			new Service(new SharingMapper($this->db)),
139
-			$this->federationSharingService,
140
-			$this->createMock(LoggerInterface::class)
141
-		);
142
-
143
-		$this->backend = new CardDavBackend($this->db,
144
-			$this->principal,
145
-			$this->userManager,
146
-			$this->dispatcher,
147
-			$this->sharingBackend,
148
-			$this->config,
149
-		);
150
-		// start every test with a empty cards_properties and cards table
151
-		$query = $this->db->getQueryBuilder();
152
-		$query->delete('cards_properties')->executeStatement();
153
-		$query = $this->db->getQueryBuilder();
154
-		$query->delete('cards')->executeStatement();
155
-
156
-		$this->principal->method('getGroupMembership')
157
-			->withAnyParameters()
158
-			->willReturn([self::UNIT_TEST_GROUP]);
159
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
160
-		foreach ($books as $book) {
161
-			$this->backend->deleteAddressBook($book['id']);
162
-		}
163
-	}
164
-
165
-	protected function tearDown(): void {
166
-		if (is_null($this->backend)) {
167
-			return;
168
-		}
169
-
170
-		$this->principal->method('getGroupMembership')
171
-			->withAnyParameters()
172
-			->willReturn([self::UNIT_TEST_GROUP]);
173
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
174
-		foreach ($books as $book) {
175
-			$this->backend->deleteAddressBook($book['id']);
176
-		}
177
-
178
-		parent::tearDown();
179
-	}
180
-
181
-	public function testAddressBookOperations(): void {
182
-		// create a new address book
183
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
184
-
185
-		$this->assertEquals(1, $this->backend->getAddressBooksForUserCount(self::UNIT_TEST_USER));
186
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
187
-		$this->assertEquals(1, count($books));
188
-		$this->assertEquals('Example', $books[0]['{DAV:}displayname']);
189
-		$this->assertEquals('User\'s displayname', $books[0]['{http://nextcloud.com/ns}owner-displayname']);
190
-
191
-		// update its display name
192
-		$patch = new PropPatch([
193
-			'{DAV:}displayname' => 'Unit test',
194
-			'{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Addressbook used for unit testing'
195
-		]);
196
-		$this->backend->updateAddressBook($books[0]['id'], $patch);
197
-		$patch->commit();
198
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
199
-		$this->assertEquals(1, count($books));
200
-		$this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
201
-		$this->assertEquals('Addressbook used for unit testing', $books[0]['{urn:ietf:params:xml:ns:carddav}addressbook-description']);
202
-
203
-		// delete the address book
204
-		$this->backend->deleteAddressBook($books[0]['id']);
205
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
206
-		$this->assertEquals(0, count($books));
207
-	}
208
-
209
-	public function testAddressBookSharing(): void {
210
-		$this->userManager->expects($this->any())
211
-			->method('userExists')
212
-			->willReturn(true);
213
-		$this->groupManager->expects($this->any())
214
-			->method('groupExists')
215
-			->willReturn(true);
216
-		$this->principal->expects(self::atLeastOnce())
217
-			->method('findByUri')
218
-			->willReturnOnConsecutiveCalls(self::UNIT_TEST_USER1, self::UNIT_TEST_GROUP);
219
-
220
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
221
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
222
-		$this->assertEquals(1, count($books));
223
-		$l = $this->createMock(IL10N::class);
224
-		$addressBook = new AddressBook($this->backend, $books[0], $l);
225
-		$this->backend->updateShares($addressBook, [
226
-			[
227
-				'href' => 'principal:' . self::UNIT_TEST_USER1,
228
-			],
229
-			[
230
-				'href' => 'principal:' . self::UNIT_TEST_GROUP,
231
-			]
232
-		], []);
233
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
234
-		$this->assertEquals(1, count($books));
235
-
236
-		// delete the address book
237
-		$this->backend->deleteAddressBook($books[0]['id']);
238
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
239
-		$this->assertEquals(0, count($books));
240
-	}
241
-
242
-	public function testCardOperations(): void {
243
-		/** @var CardDavBackend&MockObject $backend */
244
-		$backend = $this->getMockBuilder(CardDavBackend::class)
245
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
246
-			->onlyMethods(['updateProperties', 'purgeProperties'])
247
-			->getMock();
248
-
249
-		// create a new address book
250
-		$backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
251
-		$books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
252
-		$this->assertEquals(1, count($books));
253
-		$bookId = $books[0]['id'];
254
-
255
-		$uri = $this->getUniqueID('card');
256
-		// updateProperties is expected twice, once for createCard and once for updateCard
257
-		$calls = [
258
-			[$bookId, $uri, $this->vcardTest0],
259
-			[$bookId, $uri, $this->vcardTest1],
260
-		];
261
-		$backend->expects($this->exactly(count($calls)))
262
-			->method('updateProperties')
263
-			->willReturnCallback(function () use (&$calls): void {
264
-				$expected = array_shift($calls);
265
-				$this->assertEquals($expected, func_get_args());
266
-			});
267
-
268
-		// Expect event
269
-		$this->dispatcher
270
-			->expects($this->exactly(3))
271
-			->method('dispatchTyped');
272
-
273
-		// create a card
274
-		$backend->createCard($bookId, $uri, $this->vcardTest0);
275
-
276
-		// get all the cards
277
-		$cards = $backend->getCards($bookId);
278
-		$this->assertEquals(1, count($cards));
279
-		$this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
280
-
281
-		// get the cards
282
-		$card = $backend->getCard($bookId, $uri);
283
-		$this->assertNotNull($card);
284
-		$this->assertArrayHasKey('id', $card);
285
-		$this->assertArrayHasKey('uri', $card);
286
-		$this->assertArrayHasKey('lastmodified', $card);
287
-		$this->assertArrayHasKey('etag', $card);
288
-		$this->assertArrayHasKey('size', $card);
289
-		$this->assertEquals($this->vcardTest0, $card['carddata']);
290
-
291
-		// update the card
292
-		$backend->updateCard($bookId, $uri, $this->vcardTest1);
293
-		$card = $backend->getCard($bookId, $uri);
294
-		$this->assertEquals($this->vcardTest1, $card['carddata']);
295
-
296
-		// delete the card
297
-		$backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
298
-		$backend->deleteCard($bookId, $uri);
299
-		$cards = $backend->getCards($bookId);
300
-		$this->assertEquals(0, count($cards));
301
-	}
302
-
303
-	public function testMultiCard(): void {
304
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
305
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
306
-			->onlyMethods(['updateProperties'])
307
-			->getMock();
308
-
309
-		// create a new address book
310
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
311
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
312
-		$this->assertEquals(1, count($books));
313
-		$bookId = $books[0]['id'];
314
-
315
-		// create a card
316
-		$uri0 = self::getUniqueID('card');
317
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
318
-		$uri1 = self::getUniqueID('card');
319
-		$this->backend->createCard($bookId, $uri1, $this->vcardTest1);
320
-		$uri2 = self::getUniqueID('card');
321
-		$this->backend->createCard($bookId, $uri2, $this->vcardTest2);
322
-
323
-		// get all the cards
324
-		$cards = $this->backend->getCards($bookId);
325
-		$this->assertEquals(3, count($cards));
326
-		usort($cards, function ($a, $b) {
327
-			return $a['id'] < $b['id'] ? -1 : 1;
328
-		});
329
-
330
-		$this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
331
-		$this->assertEquals($this->vcardTest1, $cards[1]['carddata']);
332
-		$this->assertEquals($this->vcardTest2, $cards[2]['carddata']);
333
-
334
-		// get the cards 1 & 2 (not 0)
335
-		$cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
336
-		$this->assertEquals(2, count($cards));
337
-		usort($cards, function ($a, $b) {
338
-			return $a['id'] < $b['id'] ? -1 : 1;
339
-		});
340
-		foreach ($cards as $index => $card) {
341
-			$this->assertArrayHasKey('id', $card);
342
-			$this->assertArrayHasKey('uri', $card);
343
-			$this->assertArrayHasKey('lastmodified', $card);
344
-			$this->assertArrayHasKey('etag', $card);
345
-			$this->assertArrayHasKey('size', $card);
346
-			$this->assertEquals($this->{ 'vcardTest' . ($index + 1) }, $card['carddata']);
347
-		}
348
-
349
-		// delete the card
350
-		$this->backend->deleteCard($bookId, $uri0);
351
-		$this->backend->deleteCard($bookId, $uri1);
352
-		$this->backend->deleteCard($bookId, $uri2);
353
-		$cards = $this->backend->getCards($bookId);
354
-		$this->assertEquals(0, count($cards));
355
-	}
356
-
357
-	public function testMultipleUIDOnDifferentAddressbooks(): void {
358
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
359
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
360
-			->onlyMethods(['updateProperties'])
361
-			->getMock();
362
-
363
-		// create 2 new address books
364
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
365
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example2', []);
366
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
367
-		$this->assertEquals(2, count($books));
368
-		$bookId0 = $books[0]['id'];
369
-		$bookId1 = $books[1]['id'];
370
-
371
-		// create a card
372
-		$uri0 = $this->getUniqueID('card');
373
-		$this->backend->createCard($bookId0, $uri0, $this->vcardTest0);
374
-
375
-		// create another card with same uid but in second address book
376
-		$uri1 = $this->getUniqueID('card');
377
-		$this->backend->createCard($bookId1, $uri1, $this->vcardTest0);
378
-	}
379
-
380
-	public function testMultipleUIDDenied(): void {
381
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
382
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
383
-			->onlyMethods(['updateProperties'])
384
-			->getMock();
385
-
386
-		// create a new address book
387
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
388
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
389
-		$this->assertEquals(1, count($books));
390
-		$bookId = $books[0]['id'];
391
-
392
-		// create a card
393
-		$uri0 = $this->getUniqueID('card');
394
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
395
-
396
-		// create another card with same uid
397
-		$uri1 = $this->getUniqueID('card');
398
-		$this->expectException(BadRequest::class);
399
-		$test = $this->backend->createCard($bookId, $uri1, $this->vcardTest0);
400
-	}
401
-
402
-	public function testNoValidUID(): void {
403
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
404
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
405
-			->onlyMethods(['updateProperties'])
406
-			->getMock();
407
-
408
-		// create a new address book
409
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
410
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
411
-		$this->assertEquals(1, count($books));
412
-		$bookId = $books[0]['id'];
413
-
414
-		// create a card without uid
415
-		$uri1 = $this->getUniqueID('card');
416
-		$this->expectException(BadRequest::class);
417
-		$test = $this->backend->createCard($bookId, $uri1, $this->vcardTestNoUID);
418
-	}
419
-
420
-	public function testDeleteWithoutCard(): void {
421
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
422
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
423
-			->onlyMethods([
424
-				'getCardId',
425
-				'addChange',
426
-				'purgeProperties',
427
-				'updateProperties',
428
-			])
429
-			->getMock();
430
-
431
-		// create a new address book
432
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
433
-		$books = $this->backend->getUsersOwnAddressBooks(self::UNIT_TEST_USER);
434
-		$this->assertEquals(1, count($books));
435
-
436
-		$bookId = $books[0]['id'];
437
-		$uri = $this->getUniqueID('card');
438
-
439
-		// create a new address book
440
-		$this->backend->expects($this->once())
441
-			->method('getCardId')
442
-			->with($bookId, $uri)
443
-			->willThrowException(new \InvalidArgumentException());
444
-
445
-		$calls = [
446
-			[$bookId, $uri, 1],
447
-			[$bookId, $uri, 3],
448
-		];
449
-		$this->backend->expects($this->exactly(count($calls)))
450
-			->method('addChange')
451
-			->willReturnCallback(function () use (&$calls): void {
452
-				$expected = array_shift($calls);
453
-				$this->assertEquals($expected, func_get_args());
454
-			});
455
-		$this->backend->expects($this->never())
456
-			->method('purgeProperties');
457
-
458
-		// create a card
459
-		$this->backend->createCard($bookId, $uri, $this->vcardTest0);
460
-
461
-		// delete the card
462
-		$this->assertTrue($this->backend->deleteCard($bookId, $uri));
463
-	}
464
-
465
-	public function testSyncSupport(): void {
466
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
467
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
468
-			->onlyMethods(['updateProperties'])
469
-			->getMock();
470
-
471
-		// create a new address book
472
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
473
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
474
-		$this->assertEquals(1, count($books));
475
-		$bookId = $books[0]['id'];
476
-
477
-		// fist call without synctoken
478
-		$changes = $this->backend->getChangesForAddressBook($bookId, '', 1);
479
-		$syncToken = $changes['syncToken'];
480
-
481
-		// add a change
482
-		$uri0 = $this->getUniqueID('card');
483
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
484
-
485
-		// look for changes
486
-		$changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
487
-		$this->assertEquals($uri0, $changes['added'][0]);
488
-	}
489
-
490
-	public function testSharing(): void {
491
-		$this->userManager->expects($this->any())
492
-			->method('userExists')
493
-			->willReturn(true);
494
-		$this->groupManager->expects($this->any())
495
-			->method('groupExists')
496
-			->willReturn(true);
497
-		$this->principal->expects(self::any())
498
-			->method('findByUri')
499
-			->willReturn(self::UNIT_TEST_USER1);
500
-
501
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
502
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
503
-		$this->assertEquals(1, count($books));
504
-
505
-		$l = $this->createMock(IL10N::class);
506
-		$exampleBook = new AddressBook($this->backend, $books[0], $l);
507
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
508
-
509
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
510
-		$this->assertEquals(1, count($shares));
511
-
512
-		// adding the same sharee again has no effect
513
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
514
-
515
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
516
-		$this->assertEquals(1, count($shares));
517
-
518
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
519
-		$this->assertEquals(1, count($books));
520
-
521
-		$this->backend->updateShares($exampleBook, [], ['principal:' . self::UNIT_TEST_USER1]);
522
-
523
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
524
-		$this->assertEquals(0, count($shares));
525
-
526
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
527
-		$this->assertEquals(0, count($books));
528
-	}
529
-
530
-	public function testUpdateProperties(): void {
531
-		$bookId = 42;
532
-		$cardUri = 'card-uri';
533
-		$cardId = 2;
534
-
535
-		$backend = $this->getMockBuilder(CardDavBackend::class)
536
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
537
-			->onlyMethods(['getCardId'])->getMock();
538
-
539
-		$backend->expects($this->any())->method('getCardId')->willReturn($cardId);
540
-
541
-		// add properties for new vCard
542
-		$vCard = new VCard();
543
-		$vCard->UID = $cardUri;
544
-		$vCard->FN = 'John Doe';
545
-		$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
546
-
547
-		$query = $this->db->getQueryBuilder();
548
-		$query->select('*')
549
-			->from('cards_properties')
550
-			->orderBy('name');
551
-
552
-		$qResult = $query->execute();
553
-		$result = $qResult->fetchAll();
554
-		$qResult->closeCursor();
555
-
556
-		$this->assertSame(2, count($result));
557
-
558
-		$this->assertSame('FN', $result[0]['name']);
559
-		$this->assertSame('John Doe', $result[0]['value']);
560
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
561
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
562
-
563
-		$this->assertSame('UID', $result[1]['name']);
564
-		$this->assertSame($cardUri, $result[1]['value']);
565
-		$this->assertSame($bookId, (int)$result[1]['addressbookid']);
566
-		$this->assertSame($cardId, (int)$result[1]['cardid']);
567
-
568
-		// update properties for existing vCard
569
-		$vCard = new VCard();
570
-		$vCard->UID = $cardUri;
571
-		$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
572
-
573
-		$query = $this->db->getQueryBuilder();
574
-		$query->select('*')
575
-			->from('cards_properties');
576
-
577
-		$qResult = $query->execute();
578
-		$result = $qResult->fetchAll();
579
-		$qResult->closeCursor();
580
-
581
-		$this->assertSame(1, count($result));
582
-
583
-		$this->assertSame('UID', $result[0]['name']);
584
-		$this->assertSame($cardUri, $result[0]['value']);
585
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
586
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
587
-	}
588
-
589
-	public function testPurgeProperties(): void {
590
-		$query = $this->db->getQueryBuilder();
591
-		$query->insert('cards_properties')
592
-			->values(
593
-				[
594
-					'addressbookid' => $query->createNamedParameter(1),
595
-					'cardid' => $query->createNamedParameter(1),
596
-					'name' => $query->createNamedParameter('name1'),
597
-					'value' => $query->createNamedParameter('value1'),
598
-					'preferred' => $query->createNamedParameter(0)
599
-				]
600
-			);
601
-		$query->execute();
602
-
603
-		$query = $this->db->getQueryBuilder();
604
-		$query->insert('cards_properties')
605
-			->values(
606
-				[
607
-					'addressbookid' => $query->createNamedParameter(1),
608
-					'cardid' => $query->createNamedParameter(2),
609
-					'name' => $query->createNamedParameter('name2'),
610
-					'value' => $query->createNamedParameter('value2'),
611
-					'preferred' => $query->createNamedParameter(0)
612
-				]
613
-			);
614
-		$query->execute();
615
-
616
-		$this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
617
-
618
-		$query = $this->db->getQueryBuilder();
619
-		$query->select('*')
620
-			->from('cards_properties');
621
-
622
-		$qResult = $query->execute();
623
-		$result = $qResult->fetchAll();
624
-		$qResult->closeCursor();
625
-
626
-		$this->assertSame(1, count($result));
627
-		$this->assertSame(1, (int)$result[0]['addressbookid']);
628
-		$this->assertSame(2, (int)$result[0]['cardid']);
629
-	}
630
-
631
-	public function testGetCardId(): void {
632
-		$query = $this->db->getQueryBuilder();
633
-
634
-		$query->insert('cards')
635
-			->values(
636
-				[
637
-					'addressbookid' => $query->createNamedParameter(1),
638
-					'carddata' => $query->createNamedParameter(''),
639
-					'uri' => $query->createNamedParameter('uri'),
640
-					'lastmodified' => $query->createNamedParameter(4738743),
641
-					'etag' => $query->createNamedParameter('etag'),
642
-					'size' => $query->createNamedParameter(120)
643
-				]
644
-			);
645
-		$query->execute();
646
-		$id = $query->getLastInsertId();
647
-
648
-		$this->assertSame($id,
649
-			$this->invokePrivate($this->backend, 'getCardId', [1, 'uri']));
650
-	}
651
-
652
-
653
-	public function testGetCardIdFailed(): void {
654
-		$this->expectException(\InvalidArgumentException::class);
655
-
656
-		$this->invokePrivate($this->backend, 'getCardId', [1, 'uri']);
657
-	}
658
-
659
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSearch')]
660
-	public function testSearch(string $pattern, array $properties, array $options, array $expected): void {
661
-		/** @var VCard $vCards */
662
-		$vCards = [];
663
-		$vCards[0] = new VCard();
664
-		$vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
665
-		$vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
666
-		$vCards[0]->add(new Text($vCards[0], 'CLOUD', '[email protected]'));
667
-		$vCards[1] = new VCard();
668
-		$vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
669
-		$vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
670
-		$vCards[2] = new VCard();
671
-		$vCards[2]->add(new Text($vCards[2], 'UID', 'uid'));
672
-		$vCards[2]->add(new Text($vCards[2], 'FN', 'find without options'));
673
-		$vCards[2]->add(new Text($vCards[2], 'CLOUD', '[email protected]'));
674
-
675
-		$vCardIds = [];
676
-		$query = $this->db->getQueryBuilder();
677
-		for ($i = 0; $i < 3; $i++) {
678
-			$query->insert($this->dbCardsTable)
679
-				->values(
680
-					[
681
-						'addressbookid' => $query->createNamedParameter(0),
682
-						'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
683
-						'uri' => $query->createNamedParameter('uri' . $i),
684
-						'lastmodified' => $query->createNamedParameter(time()),
685
-						'etag' => $query->createNamedParameter('etag' . $i),
686
-						'size' => $query->createNamedParameter(120),
687
-					]
688
-				);
689
-			$query->execute();
690
-			$vCardIds[] = $query->getLastInsertId();
691
-		}
692
-
693
-		$query = $this->db->getQueryBuilder();
694
-		$query->insert($this->dbCardsPropertiesTable)
695
-			->values(
696
-				[
697
-					'addressbookid' => $query->createNamedParameter(0),
698
-					'cardid' => $query->createNamedParameter($vCardIds[0]),
699
-					'name' => $query->createNamedParameter('FN'),
700
-					'value' => $query->createNamedParameter('John Doe'),
701
-					'preferred' => $query->createNamedParameter(0)
702
-				]
703
-			);
704
-		$query->execute();
705
-		$query = $this->db->getQueryBuilder();
706
-		$query->insert($this->dbCardsPropertiesTable)
707
-			->values(
708
-				[
709
-					'addressbookid' => $query->createNamedParameter(0),
710
-					'cardid' => $query->createNamedParameter($vCardIds[0]),
711
-					'name' => $query->createNamedParameter('CLOUD'),
712
-					'value' => $query->createNamedParameter('[email protected]'),
713
-					'preferred' => $query->createNamedParameter(0)
714
-				]
715
-			);
716
-		$query->execute();
717
-		$query = $this->db->getQueryBuilder();
718
-		$query->insert($this->dbCardsPropertiesTable)
719
-			->values(
720
-				[
721
-					'addressbookid' => $query->createNamedParameter(0),
722
-					'cardid' => $query->createNamedParameter($vCardIds[1]),
723
-					'name' => $query->createNamedParameter('FN'),
724
-					'value' => $query->createNamedParameter('John M. Doe'),
725
-					'preferred' => $query->createNamedParameter(0)
726
-				]
727
-			);
728
-		$query->execute();
729
-		$query = $this->db->getQueryBuilder();
730
-		$query->insert($this->dbCardsPropertiesTable)
731
-			->values(
732
-				[
733
-					'addressbookid' => $query->createNamedParameter(0),
734
-					'cardid' => $query->createNamedParameter($vCardIds[2]),
735
-					'name' => $query->createNamedParameter('FN'),
736
-					'value' => $query->createNamedParameter('find without options'),
737
-					'preferred' => $query->createNamedParameter(0)
738
-				]
739
-			);
740
-		$query->execute();
741
-		$query = $this->db->getQueryBuilder();
742
-		$query->insert($this->dbCardsPropertiesTable)
743
-			->values(
744
-				[
745
-					'addressbookid' => $query->createNamedParameter(0),
746
-					'cardid' => $query->createNamedParameter($vCardIds[2]),
747
-					'name' => $query->createNamedParameter('CLOUD'),
748
-					'value' => $query->createNamedParameter('[email protected]'),
749
-					'preferred' => $query->createNamedParameter(0)
750
-				]
751
-			);
752
-		$query->execute();
753
-
754
-		$result = $this->backend->search(0, $pattern, $properties, $options);
755
-
756
-		// check result
757
-		$this->assertSame(count($expected), count($result));
758
-		$found = [];
759
-		foreach ($result as $r) {
760
-			foreach ($expected as $exp) {
761
-				if ($r['uri'] === $exp[0] && strpos($r['carddata'], $exp[1]) > 0) {
762
-					$found[$exp[1]] = true;
763
-					break;
764
-				}
765
-			}
766
-		}
767
-
768
-		$this->assertSame(count($expected), count($found));
769
-	}
770
-
771
-	public static function dataTestSearch(): array {
772
-		return [
773
-			['John', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
774
-			['M. Doe', ['FN'], [], [['uri1', 'John M. Doe']]],
775
-			['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
776
-			'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
777
-			'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
778
-			'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]],
779
-			'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]],
780
-			'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
781
-			'find not empty CLOUD' => ['%_%', ['CLOUD'], ['escape_like_param' => false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
782
-		];
783
-	}
784
-
785
-	public function testGetCardUri(): void {
786
-		$query = $this->db->getQueryBuilder();
787
-		$query->insert($this->dbCardsTable)
788
-			->values(
789
-				[
790
-					'addressbookid' => $query->createNamedParameter(1),
791
-					'carddata' => $query->createNamedParameter('carddata', IQueryBuilder::PARAM_LOB),
792
-					'uri' => $query->createNamedParameter('uri'),
793
-					'lastmodified' => $query->createNamedParameter(5489543),
794
-					'etag' => $query->createNamedParameter('etag'),
795
-					'size' => $query->createNamedParameter(120),
796
-				]
797
-			);
798
-		$query->execute();
799
-
800
-		$id = $query->getLastInsertId();
801
-
802
-		$this->assertSame('uri', $this->backend->getCardUri($id));
803
-	}
804
-
805
-
806
-	public function testGetCardUriFailed(): void {
807
-		$this->expectException(\InvalidArgumentException::class);
808
-
809
-		$this->backend->getCardUri(1);
810
-	}
811
-
812
-	public function testGetContact(): void {
813
-		$query = $this->db->getQueryBuilder();
814
-		for ($i = 0; $i < 2; $i++) {
815
-			$query->insert($this->dbCardsTable)
816
-				->values(
817
-					[
818
-						'addressbookid' => $query->createNamedParameter($i),
819
-						'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
820
-						'uri' => $query->createNamedParameter('uri' . $i),
821
-						'lastmodified' => $query->createNamedParameter(5489543),
822
-						'etag' => $query->createNamedParameter('etag' . $i),
823
-						'size' => $query->createNamedParameter(120),
824
-					]
825
-				);
826
-			$query->execute();
827
-		}
828
-
829
-		$result = $this->backend->getContact(0, 'uri0');
830
-		$this->assertSame(8, count($result));
831
-		$this->assertSame(0, (int)$result['addressbookid']);
832
-		$this->assertSame('uri0', $result['uri']);
833
-		$this->assertSame(5489543, (int)$result['lastmodified']);
834
-		$this->assertSame('"etag0"', $result['etag']);
835
-		$this->assertSame(120, (int)$result['size']);
836
-
837
-		// this shouldn't return any result because 'uri1' is in address book 1
838
-		// see https://github.com/nextcloud/server/issues/229
839
-		$result = $this->backend->getContact(0, 'uri1');
840
-		$this->assertEmpty($result);
841
-	}
842
-
843
-	public function testGetContactFail(): void {
844
-		$this->assertEmpty($this->backend->getContact(0, 'uri'));
845
-	}
846
-
847
-	public function testCollectCardProperties(): void {
848
-		$query = $this->db->getQueryBuilder();
849
-		$query->insert($this->dbCardsPropertiesTable)
850
-			->values(
851
-				[
852
-					'addressbookid' => $query->createNamedParameter(666),
853
-					'cardid' => $query->createNamedParameter(777),
854
-					'name' => $query->createNamedParameter('FN'),
855
-					'value' => $query->createNamedParameter('John Doe'),
856
-					'preferred' => $query->createNamedParameter(0)
857
-				]
858
-			)
859
-			->execute();
860
-
861
-		$result = $this->backend->collectCardProperties(666, 'FN');
862
-		$this->assertEquals(['John Doe'], $result);
863
-	}
864
-
865
-	/**
866
-	 * @throws \OCP\DB\Exception
867
-	 * @throws \Sabre\DAV\Exception\BadRequest
868
-	 */
869
-	public function testPruneOutdatedSyncTokens(): void {
870
-		$addressBookId = $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
871
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, '', 1);
872
-		$syncToken = $changes['syncToken'];
873
-
874
-		$uri = $this->getUniqueID('card');
875
-		$this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
876
-		$this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
877
-
878
-		// Do not delete anything if week data as old as ts=0
879
-		$deleted = $this->backend->pruneOutdatedSyncTokens(0, 0);
880
-		self::assertSame(0, $deleted);
881
-
882
-		$deleted = $this->backend->pruneOutdatedSyncTokens(0, time());
883
-		// At least one from the object creation and one from the object update
884
-		$this->assertGreaterThanOrEqual(2, $deleted);
885
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 1);
886
-		$this->assertEmpty($changes['added']);
887
-		$this->assertEmpty($changes['modified']);
888
-		$this->assertEmpty($changes['deleted']);
889
-
890
-		// Test that objects remain
891
-
892
-		// Currently changes are empty
893
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
894
-		$this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted']));
895
-
896
-		// Create card
897
-		$uri = $this->getUniqueID('card');
898
-		$this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
899
-		// We now have one add
900
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
901
-		$this->assertEquals(1, count($changes['added']));
902
-		$this->assertEmpty($changes['modified']);
903
-		$this->assertEmpty($changes['deleted']);
904
-
905
-		// Update card
906
-		$this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
907
-		// One add, one modify, but shortened to modify
908
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
909
-		$this->assertEmpty($changes['added']);
910
-		$this->assertEquals(1, count($changes['modified']));
911
-		$this->assertEmpty($changes['deleted']);
912
-
913
-		// Delete all but last change
914
-		$deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
915
-		$this->assertEquals(1, $deleted); // We had two changes before, now one
916
-
917
-		// Only update should remain
918
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
919
-		$this->assertEmpty($changes['added']);
920
-		$this->assertEquals(1, count($changes['modified']));
921
-		$this->assertEmpty($changes['deleted']);
922
-
923
-		// Check that no crash occurs when prune is called without current changes
924
-		$deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
925
-	}
51
+    private Principal&MockObject $principal;
52
+    private IUserManager&MockObject $userManager;
53
+    private IGroupManager&MockObject $groupManager;
54
+    private IEventDispatcher&MockObject $dispatcher;
55
+    private IConfig&MockObject $config;
56
+    private RemoteUserPrincipalBackend&MockObject $remoteUserPrincipalBackend;
57
+    private FederationSharingService&MockObject $federationSharingService;
58
+    private Backend $sharingBackend;
59
+    private IDBConnection $db;
60
+    private CardDavBackend $backend;
61
+    private string $dbCardsTable = 'cards';
62
+    private string $dbCardsPropertiesTable = 'cards_properties';
63
+
64
+    public const UNIT_TEST_USER = 'principals/users/carddav-unit-test';
65
+    public const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
66
+    public const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
67
+
68
+    private $vcardTest0 = 'BEGIN:VCARD' . PHP_EOL
69
+        . 'VERSION:3.0' . PHP_EOL
70
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
71
+        . 'UID:Test' . PHP_EOL
72
+        . 'FN:Test' . PHP_EOL
73
+        . 'N:Test;;;;' . PHP_EOL
74
+        . 'END:VCARD';
75
+
76
+    private $vcardTest1 = 'BEGIN:VCARD' . PHP_EOL
77
+        . 'VERSION:3.0' . PHP_EOL
78
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
79
+        . 'UID:Test2' . PHP_EOL
80
+        . 'FN:Test2' . PHP_EOL
81
+        . 'N:Test2;;;;' . PHP_EOL
82
+        . 'END:VCARD';
83
+
84
+    private $vcardTest2 = 'BEGIN:VCARD' . PHP_EOL
85
+        . 'VERSION:3.0' . PHP_EOL
86
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
87
+        . 'UID:Test3' . PHP_EOL
88
+        . 'FN:Test3' . PHP_EOL
89
+        . 'N:Test3;;;;' . PHP_EOL
90
+        . 'END:VCARD';
91
+
92
+    private $vcardTestNoUID = 'BEGIN:VCARD' . PHP_EOL
93
+        . 'VERSION:3.0' . PHP_EOL
94
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
95
+        . 'FN:TestNoUID' . PHP_EOL
96
+        . 'N:TestNoUID;;;;' . PHP_EOL
97
+        . 'END:VCARD';
98
+
99
+    protected function setUp(): void {
100
+        parent::setUp();
101
+
102
+        $this->userManager = $this->createMock(IUserManager::class);
103
+        $this->groupManager = $this->createMock(IGroupManager::class);
104
+        $this->config = $this->createMock(IConfig::class);
105
+        $this->principal = $this->getMockBuilder(Principal::class)
106
+            ->setConstructorArgs([
107
+                $this->userManager,
108
+                $this->groupManager,
109
+                $this->createMock(IAccountManager::class),
110
+                $this->createMock(ShareManager::class),
111
+                $this->createMock(IUserSession::class),
112
+                $this->createMock(IAppManager::class),
113
+                $this->createMock(ProxyMapper::class),
114
+                $this->createMock(KnownUserService::class),
115
+                $this->config,
116
+                $this->createMock(IFactory::class)
117
+            ])
118
+            ->onlyMethods(['getPrincipalByPath', 'getGroupMembership', 'findByUri'])
119
+            ->getMock();
120
+        $this->principal->method('getPrincipalByPath')
121
+            ->willReturn([
122
+                'uri' => 'principals/best-friend',
123
+                '{DAV:}displayname' => 'User\'s displayname',
124
+            ]);
125
+        $this->principal->method('getGroupMembership')
126
+            ->withAnyParameters()
127
+            ->willReturn([self::UNIT_TEST_GROUP]);
128
+        $this->dispatcher = $this->createMock(IEventDispatcher::class);
129
+        $this->remoteUserPrincipalBackend = $this->createMock(RemoteUserPrincipalBackend::class);
130
+        $this->federationSharingService = $this->createMock(FederationSharingService::class);
131
+
132
+        $this->db = Server::get(IDBConnection::class);
133
+        $this->sharingBackend = new Backend($this->userManager,
134
+            $this->groupManager,
135
+            $this->principal,
136
+            $this->remoteUserPrincipalBackend,
137
+            $this->createMock(ICacheFactory::class),
138
+            new Service(new SharingMapper($this->db)),
139
+            $this->federationSharingService,
140
+            $this->createMock(LoggerInterface::class)
141
+        );
142
+
143
+        $this->backend = new CardDavBackend($this->db,
144
+            $this->principal,
145
+            $this->userManager,
146
+            $this->dispatcher,
147
+            $this->sharingBackend,
148
+            $this->config,
149
+        );
150
+        // start every test with a empty cards_properties and cards table
151
+        $query = $this->db->getQueryBuilder();
152
+        $query->delete('cards_properties')->executeStatement();
153
+        $query = $this->db->getQueryBuilder();
154
+        $query->delete('cards')->executeStatement();
155
+
156
+        $this->principal->method('getGroupMembership')
157
+            ->withAnyParameters()
158
+            ->willReturn([self::UNIT_TEST_GROUP]);
159
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
160
+        foreach ($books as $book) {
161
+            $this->backend->deleteAddressBook($book['id']);
162
+        }
163
+    }
164
+
165
+    protected function tearDown(): void {
166
+        if (is_null($this->backend)) {
167
+            return;
168
+        }
169
+
170
+        $this->principal->method('getGroupMembership')
171
+            ->withAnyParameters()
172
+            ->willReturn([self::UNIT_TEST_GROUP]);
173
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
174
+        foreach ($books as $book) {
175
+            $this->backend->deleteAddressBook($book['id']);
176
+        }
177
+
178
+        parent::tearDown();
179
+    }
180
+
181
+    public function testAddressBookOperations(): void {
182
+        // create a new address book
183
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
184
+
185
+        $this->assertEquals(1, $this->backend->getAddressBooksForUserCount(self::UNIT_TEST_USER));
186
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
187
+        $this->assertEquals(1, count($books));
188
+        $this->assertEquals('Example', $books[0]['{DAV:}displayname']);
189
+        $this->assertEquals('User\'s displayname', $books[0]['{http://nextcloud.com/ns}owner-displayname']);
190
+
191
+        // update its display name
192
+        $patch = new PropPatch([
193
+            '{DAV:}displayname' => 'Unit test',
194
+            '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Addressbook used for unit testing'
195
+        ]);
196
+        $this->backend->updateAddressBook($books[0]['id'], $patch);
197
+        $patch->commit();
198
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
199
+        $this->assertEquals(1, count($books));
200
+        $this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
201
+        $this->assertEquals('Addressbook used for unit testing', $books[0]['{urn:ietf:params:xml:ns:carddav}addressbook-description']);
202
+
203
+        // delete the address book
204
+        $this->backend->deleteAddressBook($books[0]['id']);
205
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
206
+        $this->assertEquals(0, count($books));
207
+    }
208
+
209
+    public function testAddressBookSharing(): void {
210
+        $this->userManager->expects($this->any())
211
+            ->method('userExists')
212
+            ->willReturn(true);
213
+        $this->groupManager->expects($this->any())
214
+            ->method('groupExists')
215
+            ->willReturn(true);
216
+        $this->principal->expects(self::atLeastOnce())
217
+            ->method('findByUri')
218
+            ->willReturnOnConsecutiveCalls(self::UNIT_TEST_USER1, self::UNIT_TEST_GROUP);
219
+
220
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
221
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
222
+        $this->assertEquals(1, count($books));
223
+        $l = $this->createMock(IL10N::class);
224
+        $addressBook = new AddressBook($this->backend, $books[0], $l);
225
+        $this->backend->updateShares($addressBook, [
226
+            [
227
+                'href' => 'principal:' . self::UNIT_TEST_USER1,
228
+            ],
229
+            [
230
+                'href' => 'principal:' . self::UNIT_TEST_GROUP,
231
+            ]
232
+        ], []);
233
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
234
+        $this->assertEquals(1, count($books));
235
+
236
+        // delete the address book
237
+        $this->backend->deleteAddressBook($books[0]['id']);
238
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
239
+        $this->assertEquals(0, count($books));
240
+    }
241
+
242
+    public function testCardOperations(): void {
243
+        /** @var CardDavBackend&MockObject $backend */
244
+        $backend = $this->getMockBuilder(CardDavBackend::class)
245
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
246
+            ->onlyMethods(['updateProperties', 'purgeProperties'])
247
+            ->getMock();
248
+
249
+        // create a new address book
250
+        $backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
251
+        $books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
252
+        $this->assertEquals(1, count($books));
253
+        $bookId = $books[0]['id'];
254
+
255
+        $uri = $this->getUniqueID('card');
256
+        // updateProperties is expected twice, once for createCard and once for updateCard
257
+        $calls = [
258
+            [$bookId, $uri, $this->vcardTest0],
259
+            [$bookId, $uri, $this->vcardTest1],
260
+        ];
261
+        $backend->expects($this->exactly(count($calls)))
262
+            ->method('updateProperties')
263
+            ->willReturnCallback(function () use (&$calls): void {
264
+                $expected = array_shift($calls);
265
+                $this->assertEquals($expected, func_get_args());
266
+            });
267
+
268
+        // Expect event
269
+        $this->dispatcher
270
+            ->expects($this->exactly(3))
271
+            ->method('dispatchTyped');
272
+
273
+        // create a card
274
+        $backend->createCard($bookId, $uri, $this->vcardTest0);
275
+
276
+        // get all the cards
277
+        $cards = $backend->getCards($bookId);
278
+        $this->assertEquals(1, count($cards));
279
+        $this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
280
+
281
+        // get the cards
282
+        $card = $backend->getCard($bookId, $uri);
283
+        $this->assertNotNull($card);
284
+        $this->assertArrayHasKey('id', $card);
285
+        $this->assertArrayHasKey('uri', $card);
286
+        $this->assertArrayHasKey('lastmodified', $card);
287
+        $this->assertArrayHasKey('etag', $card);
288
+        $this->assertArrayHasKey('size', $card);
289
+        $this->assertEquals($this->vcardTest0, $card['carddata']);
290
+
291
+        // update the card
292
+        $backend->updateCard($bookId, $uri, $this->vcardTest1);
293
+        $card = $backend->getCard($bookId, $uri);
294
+        $this->assertEquals($this->vcardTest1, $card['carddata']);
295
+
296
+        // delete the card
297
+        $backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
298
+        $backend->deleteCard($bookId, $uri);
299
+        $cards = $backend->getCards($bookId);
300
+        $this->assertEquals(0, count($cards));
301
+    }
302
+
303
+    public function testMultiCard(): void {
304
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
305
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
306
+            ->onlyMethods(['updateProperties'])
307
+            ->getMock();
308
+
309
+        // create a new address book
310
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
311
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
312
+        $this->assertEquals(1, count($books));
313
+        $bookId = $books[0]['id'];
314
+
315
+        // create a card
316
+        $uri0 = self::getUniqueID('card');
317
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
318
+        $uri1 = self::getUniqueID('card');
319
+        $this->backend->createCard($bookId, $uri1, $this->vcardTest1);
320
+        $uri2 = self::getUniqueID('card');
321
+        $this->backend->createCard($bookId, $uri2, $this->vcardTest2);
322
+
323
+        // get all the cards
324
+        $cards = $this->backend->getCards($bookId);
325
+        $this->assertEquals(3, count($cards));
326
+        usort($cards, function ($a, $b) {
327
+            return $a['id'] < $b['id'] ? -1 : 1;
328
+        });
329
+
330
+        $this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
331
+        $this->assertEquals($this->vcardTest1, $cards[1]['carddata']);
332
+        $this->assertEquals($this->vcardTest2, $cards[2]['carddata']);
333
+
334
+        // get the cards 1 & 2 (not 0)
335
+        $cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
336
+        $this->assertEquals(2, count($cards));
337
+        usort($cards, function ($a, $b) {
338
+            return $a['id'] < $b['id'] ? -1 : 1;
339
+        });
340
+        foreach ($cards as $index => $card) {
341
+            $this->assertArrayHasKey('id', $card);
342
+            $this->assertArrayHasKey('uri', $card);
343
+            $this->assertArrayHasKey('lastmodified', $card);
344
+            $this->assertArrayHasKey('etag', $card);
345
+            $this->assertArrayHasKey('size', $card);
346
+            $this->assertEquals($this->{ 'vcardTest' . ($index + 1) }, $card['carddata']);
347
+        }
348
+
349
+        // delete the card
350
+        $this->backend->deleteCard($bookId, $uri0);
351
+        $this->backend->deleteCard($bookId, $uri1);
352
+        $this->backend->deleteCard($bookId, $uri2);
353
+        $cards = $this->backend->getCards($bookId);
354
+        $this->assertEquals(0, count($cards));
355
+    }
356
+
357
+    public function testMultipleUIDOnDifferentAddressbooks(): void {
358
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
359
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend,$this->config])
360
+            ->onlyMethods(['updateProperties'])
361
+            ->getMock();
362
+
363
+        // create 2 new address books
364
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
365
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example2', []);
366
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
367
+        $this->assertEquals(2, count($books));
368
+        $bookId0 = $books[0]['id'];
369
+        $bookId1 = $books[1]['id'];
370
+
371
+        // create a card
372
+        $uri0 = $this->getUniqueID('card');
373
+        $this->backend->createCard($bookId0, $uri0, $this->vcardTest0);
374
+
375
+        // create another card with same uid but in second address book
376
+        $uri1 = $this->getUniqueID('card');
377
+        $this->backend->createCard($bookId1, $uri1, $this->vcardTest0);
378
+    }
379
+
380
+    public function testMultipleUIDDenied(): void {
381
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
382
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
383
+            ->onlyMethods(['updateProperties'])
384
+            ->getMock();
385
+
386
+        // create a new address book
387
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
388
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
389
+        $this->assertEquals(1, count($books));
390
+        $bookId = $books[0]['id'];
391
+
392
+        // create a card
393
+        $uri0 = $this->getUniqueID('card');
394
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
395
+
396
+        // create another card with same uid
397
+        $uri1 = $this->getUniqueID('card');
398
+        $this->expectException(BadRequest::class);
399
+        $test = $this->backend->createCard($bookId, $uri1, $this->vcardTest0);
400
+    }
401
+
402
+    public function testNoValidUID(): void {
403
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
404
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
405
+            ->onlyMethods(['updateProperties'])
406
+            ->getMock();
407
+
408
+        // create a new address book
409
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
410
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
411
+        $this->assertEquals(1, count($books));
412
+        $bookId = $books[0]['id'];
413
+
414
+        // create a card without uid
415
+        $uri1 = $this->getUniqueID('card');
416
+        $this->expectException(BadRequest::class);
417
+        $test = $this->backend->createCard($bookId, $uri1, $this->vcardTestNoUID);
418
+    }
419
+
420
+    public function testDeleteWithoutCard(): void {
421
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
422
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
423
+            ->onlyMethods([
424
+                'getCardId',
425
+                'addChange',
426
+                'purgeProperties',
427
+                'updateProperties',
428
+            ])
429
+            ->getMock();
430
+
431
+        // create a new address book
432
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
433
+        $books = $this->backend->getUsersOwnAddressBooks(self::UNIT_TEST_USER);
434
+        $this->assertEquals(1, count($books));
435
+
436
+        $bookId = $books[0]['id'];
437
+        $uri = $this->getUniqueID('card');
438
+
439
+        // create a new address book
440
+        $this->backend->expects($this->once())
441
+            ->method('getCardId')
442
+            ->with($bookId, $uri)
443
+            ->willThrowException(new \InvalidArgumentException());
444
+
445
+        $calls = [
446
+            [$bookId, $uri, 1],
447
+            [$bookId, $uri, 3],
448
+        ];
449
+        $this->backend->expects($this->exactly(count($calls)))
450
+            ->method('addChange')
451
+            ->willReturnCallback(function () use (&$calls): void {
452
+                $expected = array_shift($calls);
453
+                $this->assertEquals($expected, func_get_args());
454
+            });
455
+        $this->backend->expects($this->never())
456
+            ->method('purgeProperties');
457
+
458
+        // create a card
459
+        $this->backend->createCard($bookId, $uri, $this->vcardTest0);
460
+
461
+        // delete the card
462
+        $this->assertTrue($this->backend->deleteCard($bookId, $uri));
463
+    }
464
+
465
+    public function testSyncSupport(): void {
466
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
467
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
468
+            ->onlyMethods(['updateProperties'])
469
+            ->getMock();
470
+
471
+        // create a new address book
472
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
473
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
474
+        $this->assertEquals(1, count($books));
475
+        $bookId = $books[0]['id'];
476
+
477
+        // fist call without synctoken
478
+        $changes = $this->backend->getChangesForAddressBook($bookId, '', 1);
479
+        $syncToken = $changes['syncToken'];
480
+
481
+        // add a change
482
+        $uri0 = $this->getUniqueID('card');
483
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
484
+
485
+        // look for changes
486
+        $changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
487
+        $this->assertEquals($uri0, $changes['added'][0]);
488
+    }
489
+
490
+    public function testSharing(): void {
491
+        $this->userManager->expects($this->any())
492
+            ->method('userExists')
493
+            ->willReturn(true);
494
+        $this->groupManager->expects($this->any())
495
+            ->method('groupExists')
496
+            ->willReturn(true);
497
+        $this->principal->expects(self::any())
498
+            ->method('findByUri')
499
+            ->willReturn(self::UNIT_TEST_USER1);
500
+
501
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
502
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
503
+        $this->assertEquals(1, count($books));
504
+
505
+        $l = $this->createMock(IL10N::class);
506
+        $exampleBook = new AddressBook($this->backend, $books[0], $l);
507
+        $this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
508
+
509
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
510
+        $this->assertEquals(1, count($shares));
511
+
512
+        // adding the same sharee again has no effect
513
+        $this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
514
+
515
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
516
+        $this->assertEquals(1, count($shares));
517
+
518
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
519
+        $this->assertEquals(1, count($books));
520
+
521
+        $this->backend->updateShares($exampleBook, [], ['principal:' . self::UNIT_TEST_USER1]);
522
+
523
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
524
+        $this->assertEquals(0, count($shares));
525
+
526
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
527
+        $this->assertEquals(0, count($books));
528
+    }
529
+
530
+    public function testUpdateProperties(): void {
531
+        $bookId = 42;
532
+        $cardUri = 'card-uri';
533
+        $cardId = 2;
534
+
535
+        $backend = $this->getMockBuilder(CardDavBackend::class)
536
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend, $this->config])
537
+            ->onlyMethods(['getCardId'])->getMock();
538
+
539
+        $backend->expects($this->any())->method('getCardId')->willReturn($cardId);
540
+
541
+        // add properties for new vCard
542
+        $vCard = new VCard();
543
+        $vCard->UID = $cardUri;
544
+        $vCard->FN = 'John Doe';
545
+        $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
546
+
547
+        $query = $this->db->getQueryBuilder();
548
+        $query->select('*')
549
+            ->from('cards_properties')
550
+            ->orderBy('name');
551
+
552
+        $qResult = $query->execute();
553
+        $result = $qResult->fetchAll();
554
+        $qResult->closeCursor();
555
+
556
+        $this->assertSame(2, count($result));
557
+
558
+        $this->assertSame('FN', $result[0]['name']);
559
+        $this->assertSame('John Doe', $result[0]['value']);
560
+        $this->assertSame($bookId, (int)$result[0]['addressbookid']);
561
+        $this->assertSame($cardId, (int)$result[0]['cardid']);
562
+
563
+        $this->assertSame('UID', $result[1]['name']);
564
+        $this->assertSame($cardUri, $result[1]['value']);
565
+        $this->assertSame($bookId, (int)$result[1]['addressbookid']);
566
+        $this->assertSame($cardId, (int)$result[1]['cardid']);
567
+
568
+        // update properties for existing vCard
569
+        $vCard = new VCard();
570
+        $vCard->UID = $cardUri;
571
+        $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
572
+
573
+        $query = $this->db->getQueryBuilder();
574
+        $query->select('*')
575
+            ->from('cards_properties');
576
+
577
+        $qResult = $query->execute();
578
+        $result = $qResult->fetchAll();
579
+        $qResult->closeCursor();
580
+
581
+        $this->assertSame(1, count($result));
582
+
583
+        $this->assertSame('UID', $result[0]['name']);
584
+        $this->assertSame($cardUri, $result[0]['value']);
585
+        $this->assertSame($bookId, (int)$result[0]['addressbookid']);
586
+        $this->assertSame($cardId, (int)$result[0]['cardid']);
587
+    }
588
+
589
+    public function testPurgeProperties(): void {
590
+        $query = $this->db->getQueryBuilder();
591
+        $query->insert('cards_properties')
592
+            ->values(
593
+                [
594
+                    'addressbookid' => $query->createNamedParameter(1),
595
+                    'cardid' => $query->createNamedParameter(1),
596
+                    'name' => $query->createNamedParameter('name1'),
597
+                    'value' => $query->createNamedParameter('value1'),
598
+                    'preferred' => $query->createNamedParameter(0)
599
+                ]
600
+            );
601
+        $query->execute();
602
+
603
+        $query = $this->db->getQueryBuilder();
604
+        $query->insert('cards_properties')
605
+            ->values(
606
+                [
607
+                    'addressbookid' => $query->createNamedParameter(1),
608
+                    'cardid' => $query->createNamedParameter(2),
609
+                    'name' => $query->createNamedParameter('name2'),
610
+                    'value' => $query->createNamedParameter('value2'),
611
+                    'preferred' => $query->createNamedParameter(0)
612
+                ]
613
+            );
614
+        $query->execute();
615
+
616
+        $this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
617
+
618
+        $query = $this->db->getQueryBuilder();
619
+        $query->select('*')
620
+            ->from('cards_properties');
621
+
622
+        $qResult = $query->execute();
623
+        $result = $qResult->fetchAll();
624
+        $qResult->closeCursor();
625
+
626
+        $this->assertSame(1, count($result));
627
+        $this->assertSame(1, (int)$result[0]['addressbookid']);
628
+        $this->assertSame(2, (int)$result[0]['cardid']);
629
+    }
630
+
631
+    public function testGetCardId(): void {
632
+        $query = $this->db->getQueryBuilder();
633
+
634
+        $query->insert('cards')
635
+            ->values(
636
+                [
637
+                    'addressbookid' => $query->createNamedParameter(1),
638
+                    'carddata' => $query->createNamedParameter(''),
639
+                    'uri' => $query->createNamedParameter('uri'),
640
+                    'lastmodified' => $query->createNamedParameter(4738743),
641
+                    'etag' => $query->createNamedParameter('etag'),
642
+                    'size' => $query->createNamedParameter(120)
643
+                ]
644
+            );
645
+        $query->execute();
646
+        $id = $query->getLastInsertId();
647
+
648
+        $this->assertSame($id,
649
+            $this->invokePrivate($this->backend, 'getCardId', [1, 'uri']));
650
+    }
651
+
652
+
653
+    public function testGetCardIdFailed(): void {
654
+        $this->expectException(\InvalidArgumentException::class);
655
+
656
+        $this->invokePrivate($this->backend, 'getCardId', [1, 'uri']);
657
+    }
658
+
659
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSearch')]
660
+    public function testSearch(string $pattern, array $properties, array $options, array $expected): void {
661
+        /** @var VCard $vCards */
662
+        $vCards = [];
663
+        $vCards[0] = new VCard();
664
+        $vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
665
+        $vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
666
+        $vCards[0]->add(new Text($vCards[0], 'CLOUD', '[email protected]'));
667
+        $vCards[1] = new VCard();
668
+        $vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
669
+        $vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
670
+        $vCards[2] = new VCard();
671
+        $vCards[2]->add(new Text($vCards[2], 'UID', 'uid'));
672
+        $vCards[2]->add(new Text($vCards[2], 'FN', 'find without options'));
673
+        $vCards[2]->add(new Text($vCards[2], 'CLOUD', '[email protected]'));
674
+
675
+        $vCardIds = [];
676
+        $query = $this->db->getQueryBuilder();
677
+        for ($i = 0; $i < 3; $i++) {
678
+            $query->insert($this->dbCardsTable)
679
+                ->values(
680
+                    [
681
+                        'addressbookid' => $query->createNamedParameter(0),
682
+                        'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
683
+                        'uri' => $query->createNamedParameter('uri' . $i),
684
+                        'lastmodified' => $query->createNamedParameter(time()),
685
+                        'etag' => $query->createNamedParameter('etag' . $i),
686
+                        'size' => $query->createNamedParameter(120),
687
+                    ]
688
+                );
689
+            $query->execute();
690
+            $vCardIds[] = $query->getLastInsertId();
691
+        }
692
+
693
+        $query = $this->db->getQueryBuilder();
694
+        $query->insert($this->dbCardsPropertiesTable)
695
+            ->values(
696
+                [
697
+                    'addressbookid' => $query->createNamedParameter(0),
698
+                    'cardid' => $query->createNamedParameter($vCardIds[0]),
699
+                    'name' => $query->createNamedParameter('FN'),
700
+                    'value' => $query->createNamedParameter('John Doe'),
701
+                    'preferred' => $query->createNamedParameter(0)
702
+                ]
703
+            );
704
+        $query->execute();
705
+        $query = $this->db->getQueryBuilder();
706
+        $query->insert($this->dbCardsPropertiesTable)
707
+            ->values(
708
+                [
709
+                    'addressbookid' => $query->createNamedParameter(0),
710
+                    'cardid' => $query->createNamedParameter($vCardIds[0]),
711
+                    'name' => $query->createNamedParameter('CLOUD'),
712
+                    'value' => $query->createNamedParameter('[email protected]'),
713
+                    'preferred' => $query->createNamedParameter(0)
714
+                ]
715
+            );
716
+        $query->execute();
717
+        $query = $this->db->getQueryBuilder();
718
+        $query->insert($this->dbCardsPropertiesTable)
719
+            ->values(
720
+                [
721
+                    'addressbookid' => $query->createNamedParameter(0),
722
+                    'cardid' => $query->createNamedParameter($vCardIds[1]),
723
+                    'name' => $query->createNamedParameter('FN'),
724
+                    'value' => $query->createNamedParameter('John M. Doe'),
725
+                    'preferred' => $query->createNamedParameter(0)
726
+                ]
727
+            );
728
+        $query->execute();
729
+        $query = $this->db->getQueryBuilder();
730
+        $query->insert($this->dbCardsPropertiesTable)
731
+            ->values(
732
+                [
733
+                    'addressbookid' => $query->createNamedParameter(0),
734
+                    'cardid' => $query->createNamedParameter($vCardIds[2]),
735
+                    'name' => $query->createNamedParameter('FN'),
736
+                    'value' => $query->createNamedParameter('find without options'),
737
+                    'preferred' => $query->createNamedParameter(0)
738
+                ]
739
+            );
740
+        $query->execute();
741
+        $query = $this->db->getQueryBuilder();
742
+        $query->insert($this->dbCardsPropertiesTable)
743
+            ->values(
744
+                [
745
+                    'addressbookid' => $query->createNamedParameter(0),
746
+                    'cardid' => $query->createNamedParameter($vCardIds[2]),
747
+                    'name' => $query->createNamedParameter('CLOUD'),
748
+                    'value' => $query->createNamedParameter('[email protected]'),
749
+                    'preferred' => $query->createNamedParameter(0)
750
+                ]
751
+            );
752
+        $query->execute();
753
+
754
+        $result = $this->backend->search(0, $pattern, $properties, $options);
755
+
756
+        // check result
757
+        $this->assertSame(count($expected), count($result));
758
+        $found = [];
759
+        foreach ($result as $r) {
760
+            foreach ($expected as $exp) {
761
+                if ($r['uri'] === $exp[0] && strpos($r['carddata'], $exp[1]) > 0) {
762
+                    $found[$exp[1]] = true;
763
+                    break;
764
+                }
765
+            }
766
+        }
767
+
768
+        $this->assertSame(count($expected), count($found));
769
+    }
770
+
771
+    public static function dataTestSearch(): array {
772
+        return [
773
+            ['John', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
774
+            ['M. Doe', ['FN'], [], [['uri1', 'John M. Doe']]],
775
+            ['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
776
+            'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
777
+            'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
778
+            'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]],
779
+            'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]],
780
+            'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
781
+            'find not empty CLOUD' => ['%_%', ['CLOUD'], ['escape_like_param' => false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
782
+        ];
783
+    }
784
+
785
+    public function testGetCardUri(): void {
786
+        $query = $this->db->getQueryBuilder();
787
+        $query->insert($this->dbCardsTable)
788
+            ->values(
789
+                [
790
+                    'addressbookid' => $query->createNamedParameter(1),
791
+                    'carddata' => $query->createNamedParameter('carddata', IQueryBuilder::PARAM_LOB),
792
+                    'uri' => $query->createNamedParameter('uri'),
793
+                    'lastmodified' => $query->createNamedParameter(5489543),
794
+                    'etag' => $query->createNamedParameter('etag'),
795
+                    'size' => $query->createNamedParameter(120),
796
+                ]
797
+            );
798
+        $query->execute();
799
+
800
+        $id = $query->getLastInsertId();
801
+
802
+        $this->assertSame('uri', $this->backend->getCardUri($id));
803
+    }
804
+
805
+
806
+    public function testGetCardUriFailed(): void {
807
+        $this->expectException(\InvalidArgumentException::class);
808
+
809
+        $this->backend->getCardUri(1);
810
+    }
811
+
812
+    public function testGetContact(): void {
813
+        $query = $this->db->getQueryBuilder();
814
+        for ($i = 0; $i < 2; $i++) {
815
+            $query->insert($this->dbCardsTable)
816
+                ->values(
817
+                    [
818
+                        'addressbookid' => $query->createNamedParameter($i),
819
+                        'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
820
+                        'uri' => $query->createNamedParameter('uri' . $i),
821
+                        'lastmodified' => $query->createNamedParameter(5489543),
822
+                        'etag' => $query->createNamedParameter('etag' . $i),
823
+                        'size' => $query->createNamedParameter(120),
824
+                    ]
825
+                );
826
+            $query->execute();
827
+        }
828
+
829
+        $result = $this->backend->getContact(0, 'uri0');
830
+        $this->assertSame(8, count($result));
831
+        $this->assertSame(0, (int)$result['addressbookid']);
832
+        $this->assertSame('uri0', $result['uri']);
833
+        $this->assertSame(5489543, (int)$result['lastmodified']);
834
+        $this->assertSame('"etag0"', $result['etag']);
835
+        $this->assertSame(120, (int)$result['size']);
836
+
837
+        // this shouldn't return any result because 'uri1' is in address book 1
838
+        // see https://github.com/nextcloud/server/issues/229
839
+        $result = $this->backend->getContact(0, 'uri1');
840
+        $this->assertEmpty($result);
841
+    }
842
+
843
+    public function testGetContactFail(): void {
844
+        $this->assertEmpty($this->backend->getContact(0, 'uri'));
845
+    }
846
+
847
+    public function testCollectCardProperties(): void {
848
+        $query = $this->db->getQueryBuilder();
849
+        $query->insert($this->dbCardsPropertiesTable)
850
+            ->values(
851
+                [
852
+                    'addressbookid' => $query->createNamedParameter(666),
853
+                    'cardid' => $query->createNamedParameter(777),
854
+                    'name' => $query->createNamedParameter('FN'),
855
+                    'value' => $query->createNamedParameter('John Doe'),
856
+                    'preferred' => $query->createNamedParameter(0)
857
+                ]
858
+            )
859
+            ->execute();
860
+
861
+        $result = $this->backend->collectCardProperties(666, 'FN');
862
+        $this->assertEquals(['John Doe'], $result);
863
+    }
864
+
865
+    /**
866
+     * @throws \OCP\DB\Exception
867
+     * @throws \Sabre\DAV\Exception\BadRequest
868
+     */
869
+    public function testPruneOutdatedSyncTokens(): void {
870
+        $addressBookId = $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
871
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, '', 1);
872
+        $syncToken = $changes['syncToken'];
873
+
874
+        $uri = $this->getUniqueID('card');
875
+        $this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
876
+        $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
877
+
878
+        // Do not delete anything if week data as old as ts=0
879
+        $deleted = $this->backend->pruneOutdatedSyncTokens(0, 0);
880
+        self::assertSame(0, $deleted);
881
+
882
+        $deleted = $this->backend->pruneOutdatedSyncTokens(0, time());
883
+        // At least one from the object creation and one from the object update
884
+        $this->assertGreaterThanOrEqual(2, $deleted);
885
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 1);
886
+        $this->assertEmpty($changes['added']);
887
+        $this->assertEmpty($changes['modified']);
888
+        $this->assertEmpty($changes['deleted']);
889
+
890
+        // Test that objects remain
891
+
892
+        // Currently changes are empty
893
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
894
+        $this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted']));
895
+
896
+        // Create card
897
+        $uri = $this->getUniqueID('card');
898
+        $this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
899
+        // We now have one add
900
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
901
+        $this->assertEquals(1, count($changes['added']));
902
+        $this->assertEmpty($changes['modified']);
903
+        $this->assertEmpty($changes['deleted']);
904
+
905
+        // Update card
906
+        $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
907
+        // One add, one modify, but shortened to modify
908
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
909
+        $this->assertEmpty($changes['added']);
910
+        $this->assertEquals(1, count($changes['modified']));
911
+        $this->assertEmpty($changes['deleted']);
912
+
913
+        // Delete all but last change
914
+        $deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
915
+        $this->assertEquals(1, $deleted); // We had two changes before, now one
916
+
917
+        // Only update should remain
918
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
919
+        $this->assertEmpty($changes['added']);
920
+        $this->assertEquals(1, count($changes['modified']));
921
+        $this->assertEmpty($changes['deleted']);
922
+
923
+        // Check that no crash occurs when prune is called without current changes
924
+        $deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
925
+    }
926 926
 }
Please login to merge, or discard this patch.
apps/dav/appinfo/v1/caldav.php 1 patch
Indentation   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -38,25 +38,25 @@  discard block
 block discarded – undo
38 38
 use Psr\Log\LoggerInterface;
39 39
 
40 40
 $authBackend = new Auth(
41
-	Server::get(ISession::class),
42
-	Server::get(IUserSession::class),
43
-	Server::get(IRequest::class),
44
-	Server::get(\OC\Authentication\TwoFactorAuth\Manager::class),
45
-	Server::get(IThrottler::class),
46
-	'principals/'
41
+    Server::get(ISession::class),
42
+    Server::get(IUserSession::class),
43
+    Server::get(IRequest::class),
44
+    Server::get(\OC\Authentication\TwoFactorAuth\Manager::class),
45
+    Server::get(IThrottler::class),
46
+    'principals/'
47 47
 );
48 48
 $principalBackend = new Principal(
49
-	Server::get(IUserManager::class),
50
-	Server::get(IGroupManager::class),
51
-	Server::get(IAccountManager::class),
52
-	Server::get(\OCP\Share\IManager::class),
53
-	Server::get(IUserSession::class),
54
-	Server::get(IAppManager::class),
55
-	Server::get(ProxyMapper::class),
56
-	Server::get(KnownUserService::class),
57
-	Server::get(IConfig::class),
58
-	\OC::$server->getL10NFactory(),
59
-	'principals/'
49
+    Server::get(IUserManager::class),
50
+    Server::get(IGroupManager::class),
51
+    Server::get(IAccountManager::class),
52
+    Server::get(\OCP\Share\IManager::class),
53
+    Server::get(IUserSession::class),
54
+    Server::get(IAppManager::class),
55
+    Server::get(ProxyMapper::class),
56
+    Server::get(KnownUserService::class),
57
+    Server::get(IConfig::class),
58
+    \OC::$server->getL10NFactory(),
59
+    'principals/'
60 60
 );
61 61
 $db = Server::get(IDBConnection::class);
62 62
 $userManager = Server::get(IUserManager::class);
@@ -69,16 +69,16 @@  discard block
 block discarded – undo
69 69
 $federatedCalendarFactory = Server::get(FederatedCalendarFactory::class);
70 70
 
71 71
 $calDavBackend = new CalDavBackend(
72
-	$db,
73
-	$principalBackend,
74
-	$userManager,
75
-	$random,
76
-	$logger,
77
-	$dispatcher,
78
-	$config,
79
-	Server::get(\OCA\DAV\CalDAV\Sharing\Backend::class),
80
-	Server::get(FederatedCalendarMapper::class),
81
-	true
72
+    $db,
73
+    $principalBackend,
74
+    $userManager,
75
+    $random,
76
+    $logger,
77
+    $dispatcher,
78
+    $config,
79
+    Server::get(\OCA\DAV\CalDAV\Sharing\Backend::class),
80
+    Server::get(FederatedCalendarMapper::class),
81
+    true
82 82
 );
83 83
 
84 84
 $debugging = Server::get(IConfig::class)->getSystemValue('debug', false);
@@ -92,8 +92,8 @@  discard block
 block discarded – undo
92 92
 $addressBookRoot->disableListing = !$debugging; // Disable listing
93 93
 
94 94
 $nodes = [
95
-	$principalCollection,
96
-	$addressBookRoot,
95
+    $principalCollection,
96
+    $addressBookRoot,
97 97
 ];
98 98
 
99 99
 // Fire up server
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
 
110 110
 $server->addPlugin(new LegacyDAVACL());
111 111
 if ($debugging) {
112
-	$server->addPlugin(new Sabre\DAV\Browser\Plugin());
112
+    $server->addPlugin(new Sabre\DAV\Browser\Plugin());
113 113
 }
114 114
 
115 115
 $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 $server->addPlugin(new \OCA\DAV\CalDAV\Schedule\Plugin(Server::get(IConfig::class), Server::get(LoggerInterface::class), Server::get(DefaultCalendarValidator::class)));
118 118
 
119 119
 if ($sendInvitations) {
120
-	$server->addPlugin(Server::get(IMipPlugin::class));
120
+    $server->addPlugin(Server::get(IMipPlugin::class));
121 121
 }
122 122
 $server->addPlugin(new ExceptionLoggerPlugin('caldav', $logger));
123 123
 $server->addPlugin(Server::get(RateLimitingPlugin::class));
Please login to merge, or discard this patch.
apps/federation/lib/Command/SyncFederationCalendars.php 1 patch
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -15,45 +15,45 @@
 block discarded – undo
15 15
 use Symfony\Component\Console\Output\OutputInterface;
16 16
 
17 17
 class SyncFederationCalendars extends Command {
18
-	public function __construct(
19
-		private readonly FederatedCalendarSyncService $syncService,
20
-		private readonly FederatedCalendarMapper $federatedCalendarMapper,
21
-	) {
22
-		parent::__construct();
23
-	}
24
-
25
-	protected function configure() {
26
-		$this
27
-			->setName('federation:sync-calendars')
28
-			->setDescription('Synchronize all incoming federated calendar shares');
29
-	}
30
-
31
-	protected function execute(InputInterface $input, OutputInterface $output): int {
32
-		$calendarCount = $this->federatedCalendarMapper->countAll();
33
-		if ($calendarCount === 0) {
34
-			$output->writeln('There are no federated calendars');
35
-			return 0;
36
-		}
37
-
38
-		$progress = new ProgressBar($output, $calendarCount);
39
-		$progress->start();
40
-
41
-		$calendars = $this->federatedCalendarMapper->findAll();
42
-		foreach ($calendars as $calendar) {
43
-			try {
44
-				$this->syncService->syncOne($calendar);
45
-			} catch (\Exception $e) {
46
-				$url = $calendar->getUri();
47
-				$msg = $e->getMessage();
48
-				$output->writeln("\n<error>Failed to sync calendar $url: $msg</error>");
49
-			}
50
-
51
-			$progress->advance();
52
-		}
53
-
54
-		$progress->finish();
55
-		$output->writeln('');
56
-
57
-		return 0;
58
-	}
18
+    public function __construct(
19
+        private readonly FederatedCalendarSyncService $syncService,
20
+        private readonly FederatedCalendarMapper $federatedCalendarMapper,
21
+    ) {
22
+        parent::__construct();
23
+    }
24
+
25
+    protected function configure() {
26
+        $this
27
+            ->setName('federation:sync-calendars')
28
+            ->setDescription('Synchronize all incoming federated calendar shares');
29
+    }
30
+
31
+    protected function execute(InputInterface $input, OutputInterface $output): int {
32
+        $calendarCount = $this->federatedCalendarMapper->countAll();
33
+        if ($calendarCount === 0) {
34
+            $output->writeln('There are no federated calendars');
35
+            return 0;
36
+        }
37
+
38
+        $progress = new ProgressBar($output, $calendarCount);
39
+        $progress->start();
40
+
41
+        $calendars = $this->federatedCalendarMapper->findAll();
42
+        foreach ($calendars as $calendar) {
43
+            try {
44
+                $this->syncService->syncOne($calendar);
45
+            } catch (\Exception $e) {
46
+                $url = $calendar->getUri();
47
+                $msg = $e->getMessage();
48
+                $output->writeln("\n<error>Failed to sync calendar $url: $msg</error>");
49
+            }
50
+
51
+            $progress->advance();
52
+        }
53
+
54
+        $progress->finish();
55
+        $output->writeln('');
56
+
57
+        return 0;
58
+    }
59 59
 }
Please login to merge, or discard this patch.