Completed
Push — master ( 953027...3b6ea8 )
by
unknown
21:16 queued 15s
created
apps/encryption/tests/Settings/AdminTest.php 1 patch
Indentation   +51 added lines, -51 removed lines patch added patch discarded remove patch
@@ -21,62 +21,62 @@
 block discarded – undo
21 21
 
22 22
 class AdminTest extends TestCase {
23 23
 
24
-	protected Admin $admin;
24
+    protected Admin $admin;
25 25
 
26
-	protected IL10N&MockObject $l;
27
-	protected LoggerInterface&MockObject $logger;
28
-	protected IUserSession&MockObject $userSession;
29
-	protected IConfig&MockObject $config;
30
-	protected IUserManager&MockObject $userManager;
31
-	protected ISession&MockObject $session;
26
+    protected IL10N&MockObject $l;
27
+    protected LoggerInterface&MockObject $logger;
28
+    protected IUserSession&MockObject $userSession;
29
+    protected IConfig&MockObject $config;
30
+    protected IUserManager&MockObject $userManager;
31
+    protected ISession&MockObject $session;
32 32
 
33
-	protected function setUp(): void {
34
-		parent::setUp();
33
+    protected function setUp(): void {
34
+        parent::setUp();
35 35
 
36
-		$this->l = $this->getMockBuilder(IL10N::class)->getMock();
37
-		$this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
38
-		$this->userSession = $this->getMockBuilder(IUserSession::class)->getMock();
39
-		$this->config = $this->getMockBuilder(IConfig::class)->getMock();
40
-		$this->userManager = $this->getMockBuilder(IUserManager::class)->getMock();
41
-		$this->session = $this->getMockBuilder(ISession::class)->getMock();
36
+        $this->l = $this->getMockBuilder(IL10N::class)->getMock();
37
+        $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
38
+        $this->userSession = $this->getMockBuilder(IUserSession::class)->getMock();
39
+        $this->config = $this->getMockBuilder(IConfig::class)->getMock();
40
+        $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock();
41
+        $this->session = $this->getMockBuilder(ISession::class)->getMock();
42 42
 
43
-		$this->admin = new Admin(
44
-			$this->l,
45
-			$this->logger,
46
-			$this->userSession,
47
-			$this->config,
48
-			$this->userManager,
49
-			$this->session
50
-		);
51
-	}
43
+        $this->admin = new Admin(
44
+            $this->l,
45
+            $this->logger,
46
+            $this->userSession,
47
+            $this->config,
48
+            $this->userManager,
49
+            $this->session
50
+        );
51
+    }
52 52
 
53
-	public function testGetForm(): void {
54
-		$this->config
55
-			->method('getAppValue')
56
-			->will($this->returnCallback(function ($app, $key, $default) {
57
-				if ($app === 'encryption' && $key === 'recoveryAdminEnabled' && $default === '0') {
58
-					return '1';
59
-				}
60
-				if ($app === 'encryption' && $key === 'encryptHomeStorage' && $default === '1') {
61
-					return '1';
62
-				}
63
-				return $default;
64
-			}));
65
-		$params = [
66
-			'recoveryEnabled' => '1',
67
-			'initStatus' => '0',
68
-			'encryptHomeStorage' => true,
69
-			'masterKeyEnabled' => true
70
-		];
71
-		$expected = new TemplateResponse('encryption', 'settings-admin', $params, '');
72
-		$this->assertEquals($expected, $this->admin->getForm());
73
-	}
53
+    public function testGetForm(): void {
54
+        $this->config
55
+            ->method('getAppValue')
56
+            ->will($this->returnCallback(function ($app, $key, $default) {
57
+                if ($app === 'encryption' && $key === 'recoveryAdminEnabled' && $default === '0') {
58
+                    return '1';
59
+                }
60
+                if ($app === 'encryption' && $key === 'encryptHomeStorage' && $default === '1') {
61
+                    return '1';
62
+                }
63
+                return $default;
64
+            }));
65
+        $params = [
66
+            'recoveryEnabled' => '1',
67
+            'initStatus' => '0',
68
+            'encryptHomeStorage' => true,
69
+            'masterKeyEnabled' => true
70
+        ];
71
+        $expected = new TemplateResponse('encryption', 'settings-admin', $params, '');
72
+        $this->assertEquals($expected, $this->admin->getForm());
73
+    }
74 74
 
75
-	public function testGetSection(): void {
76
-		$this->assertSame('security', $this->admin->getSection());
77
-	}
75
+    public function testGetSection(): void {
76
+        $this->assertSame('security', $this->admin->getSection());
77
+    }
78 78
 
79
-	public function testGetPriority(): void {
80
-		$this->assertSame(11, $this->admin->getPriority());
81
-	}
79
+    public function testGetPriority(): void {
80
+        $this->assertSame(11, $this->admin->getPriority());
81
+    }
82 82
 }
Please login to merge, or discard this patch.
apps/encryption/tests/Users/SetupTest.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -17,61 +17,61 @@
 block discarded – undo
17 17
 
18 18
 class SetupTest extends TestCase {
19 19
 
20
-	protected Setup $instance;
21
-
22
-	protected KeyManager&MockObject $keyManagerMock;
23
-	protected Crypt&MockObject $cryptMock;
24
-
25
-	protected function setUp(): void {
26
-		parent::setUp();
27
-		$this->cryptMock = $this->getMockBuilder(Crypt::class)
28
-			->disableOriginalConstructor()
29
-			->getMock();
30
-
31
-		$this->keyManagerMock = $this->getMockBuilder(KeyManager::class)
32
-			->disableOriginalConstructor()
33
-			->getMock();
34
-
35
-		$this->instance = new Setup(
36
-			$this->cryptMock,
37
-			$this->keyManagerMock);
38
-	}
39
-
40
-
41
-	public function testSetupSystem(): void {
42
-		$this->keyManagerMock->expects($this->once())->method('validateShareKey');
43
-		$this->keyManagerMock->expects($this->once())->method('validateMasterKey');
44
-
45
-		$this->instance->setupSystem();
46
-	}
47
-
48
-	/**
49
-	 * @dataProvider dataTestSetupUser
50
-	 *
51
-	 * @param bool $hasKeys
52
-	 * @param bool $expected
53
-	 */
54
-	public function testSetupUser($hasKeys, $expected): void {
55
-		$this->keyManagerMock->expects($this->once())->method('userHasKeys')
56
-			->with('uid')->willReturn($hasKeys);
57
-
58
-		if ($hasKeys) {
59
-			$this->keyManagerMock->expects($this->never())->method('storeKeyPair');
60
-		} else {
61
-			$this->cryptMock->expects($this->once())->method('createKeyPair')->willReturn(['publicKey' => 'publicKey', 'privateKey' => 'privateKey']);
62
-			$this->keyManagerMock->expects($this->once())->method('storeKeyPair')
63
-				->with('uid', 'password', ['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])->willReturn(true);
64
-		}
65
-
66
-		$this->assertSame($expected,
67
-			$this->instance->setupUser('uid', 'password')
68
-		);
69
-	}
70
-
71
-	public static function dataTestSetupUser(): array {
72
-		return [
73
-			[true, true],
74
-			[false, true]
75
-		];
76
-	}
20
+    protected Setup $instance;
21
+
22
+    protected KeyManager&MockObject $keyManagerMock;
23
+    protected Crypt&MockObject $cryptMock;
24
+
25
+    protected function setUp(): void {
26
+        parent::setUp();
27
+        $this->cryptMock = $this->getMockBuilder(Crypt::class)
28
+            ->disableOriginalConstructor()
29
+            ->getMock();
30
+
31
+        $this->keyManagerMock = $this->getMockBuilder(KeyManager::class)
32
+            ->disableOriginalConstructor()
33
+            ->getMock();
34
+
35
+        $this->instance = new Setup(
36
+            $this->cryptMock,
37
+            $this->keyManagerMock);
38
+    }
39
+
40
+
41
+    public function testSetupSystem(): void {
42
+        $this->keyManagerMock->expects($this->once())->method('validateShareKey');
43
+        $this->keyManagerMock->expects($this->once())->method('validateMasterKey');
44
+
45
+        $this->instance->setupSystem();
46
+    }
47
+
48
+    /**
49
+     * @dataProvider dataTestSetupUser
50
+     *
51
+     * @param bool $hasKeys
52
+     * @param bool $expected
53
+     */
54
+    public function testSetupUser($hasKeys, $expected): void {
55
+        $this->keyManagerMock->expects($this->once())->method('userHasKeys')
56
+            ->with('uid')->willReturn($hasKeys);
57
+
58
+        if ($hasKeys) {
59
+            $this->keyManagerMock->expects($this->never())->method('storeKeyPair');
60
+        } else {
61
+            $this->cryptMock->expects($this->once())->method('createKeyPair')->willReturn(['publicKey' => 'publicKey', 'privateKey' => 'privateKey']);
62
+            $this->keyManagerMock->expects($this->once())->method('storeKeyPair')
63
+                ->with('uid', 'password', ['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])->willReturn(true);
64
+        }
65
+
66
+        $this->assertSame($expected,
67
+            $this->instance->setupUser('uid', 'password')
68
+        );
69
+    }
70
+
71
+    public static function dataTestSetupUser(): array {
72
+        return [
73
+            [true, true],
74
+            [false, true]
75
+        ];
76
+    }
77 77
 }
Please login to merge, or discard this patch.
apps/encryption/tests/KeyManagerTest.php 1 patch
Indentation   +678 added lines, -678 removed lines patch added patch discarded remove patch
@@ -31,682 +31,682 @@
 block discarded – undo
31 31
 
32 32
 class KeyManagerTest extends TestCase {
33 33
 
34
-	protected KeyManager $instance;
35
-
36
-	protected string $userId;
37
-	protected string $systemKeyId;
38
-	protected IStorage&MockObject $keyStorageMock;
39
-	protected Crypt&MockObject $cryptMock;
40
-	protected IUserSession&MockObject $userMock;
41
-	protected Session&MockObject $sessionMock;
42
-	protected LoggerInterface&MockObject $logMock;
43
-	protected Util&MockObject $utilMock;
44
-	protected IConfig&MockObject $configMock;
45
-	protected ILockingProvider&MockObject $lockingProviderMock;
46
-
47
-	protected function setUp(): void {
48
-		parent::setUp();
49
-		$this->userId = 'user1';
50
-		$this->systemKeyId = 'systemKeyId';
51
-		$this->keyStorageMock = $this->createMock(IStorage::class);
52
-		$this->cryptMock = $this->getMockBuilder(Crypt::class)
53
-			->disableOriginalConstructor()
54
-			->getMock();
55
-		$this->configMock = $this->createMock(IConfig::class);
56
-		$this->configMock->expects($this->any())
57
-			->method('getAppValue')
58
-			->willReturn($this->systemKeyId);
59
-		$this->userMock = $this->createMock(IUserSession::class);
60
-		$this->sessionMock = $this->getMockBuilder(Session::class)
61
-			->disableOriginalConstructor()
62
-			->getMock();
63
-		$this->logMock = $this->createMock(LoggerInterface::class);
64
-		$this->utilMock = $this->getMockBuilder(Util::class)
65
-			->disableOriginalConstructor()
66
-			->getMock();
67
-		$this->lockingProviderMock = $this->createMock(ILockingProvider::class);
68
-
69
-		$this->instance = new KeyManager(
70
-			$this->keyStorageMock,
71
-			$this->cryptMock,
72
-			$this->configMock,
73
-			$this->userMock,
74
-			$this->sessionMock,
75
-			$this->logMock,
76
-			$this->utilMock,
77
-			$this->lockingProviderMock
78
-		);
79
-	}
80
-
81
-	public function testDeleteShareKey(): void {
82
-		$this->keyStorageMock->expects($this->any())
83
-			->method('deleteFileKey')
84
-			->with($this->equalTo('/path'), $this->equalTo('keyId.shareKey'))
85
-			->willReturn(true);
86
-
87
-		$this->assertTrue(
88
-			$this->instance->deleteShareKey('/path', 'keyId')
89
-		);
90
-	}
91
-
92
-	public function testGetPrivateKey(): void {
93
-		$this->keyStorageMock->expects($this->any())
94
-			->method('getUserKey')
95
-			->with($this->equalTo($this->userId), $this->equalTo('privateKey'))
96
-			->willReturn('privateKey');
97
-
98
-
99
-		$this->assertSame('privateKey',
100
-			$this->instance->getPrivateKey($this->userId)
101
-		);
102
-	}
103
-
104
-	public function testGetPublicKey(): void {
105
-		$this->keyStorageMock->expects($this->any())
106
-			->method('getUserKey')
107
-			->with($this->equalTo($this->userId), $this->equalTo('publicKey'))
108
-			->willReturn('publicKey');
109
-
110
-
111
-		$this->assertSame('publicKey',
112
-			$this->instance->getPublicKey($this->userId)
113
-		);
114
-	}
115
-
116
-	public function testRecoveryKeyExists(): void {
117
-		$this->keyStorageMock->expects($this->any())
118
-			->method('getSystemUserKey')
119
-			->with($this->equalTo($this->systemKeyId . '.publicKey'))
120
-			->willReturn('recoveryKey');
121
-
122
-
123
-		$this->assertTrue($this->instance->recoveryKeyExists());
124
-	}
125
-
126
-	public function testCheckRecoveryKeyPassword(): void {
127
-		$this->keyStorageMock->expects($this->any())
128
-			->method('getSystemUserKey')
129
-			->with($this->equalTo($this->systemKeyId . '.privateKey'))
130
-			->willReturn('recoveryKey');
131
-		$this->cryptMock->expects($this->any())
132
-			->method('decryptPrivateKey')
133
-			->with($this->equalTo('recoveryKey'), $this->equalTo('pass'))
134
-			->willReturn('decryptedRecoveryKey');
135
-
136
-		$this->assertTrue($this->instance->checkRecoveryPassword('pass'));
137
-	}
138
-
139
-	public function testSetPublicKey(): void {
140
-		$this->keyStorageMock->expects($this->any())
141
-			->method('setUserKey')
142
-			->with(
143
-				$this->equalTo($this->userId),
144
-				$this->equalTo('publicKey'),
145
-				$this->equalTo('key'))
146
-			->willReturn(true);
147
-
148
-
149
-		$this->assertTrue(
150
-			$this->instance->setPublicKey($this->userId, 'key')
151
-		);
152
-	}
153
-
154
-	public function testSetPrivateKey(): void {
155
-		$this->keyStorageMock->expects($this->any())
156
-			->method('setUserKey')
157
-			->with(
158
-				$this->equalTo($this->userId),
159
-				$this->equalTo('privateKey'),
160
-				$this->equalTo('key'))
161
-			->willReturn(true);
162
-
163
-
164
-		$this->assertTrue(
165
-			$this->instance->setPrivateKey($this->userId, 'key')
166
-		);
167
-	}
168
-
169
-	/**
170
-	 * @dataProvider dataTestUserHasKeys
171
-	 */
172
-	public function testUserHasKeys($key, $expected): void {
173
-		$this->keyStorageMock->expects($this->exactly(2))
174
-			->method('getUserKey')
175
-			->with($this->equalTo($this->userId), $this->anything())
176
-			->willReturn($key);
177
-
178
-
179
-		$this->assertSame($expected,
180
-			$this->instance->userHasKeys($this->userId)
181
-		);
182
-	}
183
-
184
-	public static function dataTestUserHasKeys(): array {
185
-		return [
186
-			['key', true],
187
-			['', false]
188
-		];
189
-	}
190
-
191
-
192
-	public function testUserHasKeysMissingPrivateKey(): void {
193
-		$this->expectException(PrivateKeyMissingException::class);
194
-
195
-		$this->keyStorageMock->expects($this->exactly(2))
196
-			->method('getUserKey')
197
-			->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
198
-				if ($keyID === 'privateKey') {
199
-					return '';
200
-				}
201
-				return 'key';
202
-			});
203
-
204
-		$this->instance->userHasKeys($this->userId);
205
-	}
206
-
207
-
208
-	public function testUserHasKeysMissingPublicKey(): void {
209
-		$this->expectException(PublicKeyMissingException::class);
210
-
211
-		$this->keyStorageMock->expects($this->exactly(2))
212
-			->method('getUserKey')
213
-			->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
214
-				if ($keyID === 'publicKey') {
215
-					return '';
216
-				}
217
-				return 'key';
218
-			});
219
-
220
-		$this->instance->userHasKeys($this->userId);
221
-	}
222
-
223
-	/**
224
-	 * @dataProvider dataTestInit
225
-	 *
226
-	 * @param bool $useMasterKey
227
-	 */
228
-	public function testInit($useMasterKey): void {
229
-		/** @var KeyManager&MockObject $instance */
230
-		$instance = $this->getMockBuilder(KeyManager::class)
231
-			->setConstructorArgs(
232
-				[
233
-					$this->keyStorageMock,
234
-					$this->cryptMock,
235
-					$this->configMock,
236
-					$this->userMock,
237
-					$this->sessionMock,
238
-					$this->logMock,
239
-					$this->utilMock,
240
-					$this->lockingProviderMock
241
-				]
242
-			)->onlyMethods(['getMasterKeyId', 'getMasterKeyPassword', 'getSystemPrivateKey', 'getPrivateKey'])
243
-			->getMock();
244
-
245
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
246
-			->willReturn($useMasterKey);
247
-
248
-		$sessionSetStatusCalls = [];
249
-		$this->sessionMock->expects($this->exactly(2))
250
-			->method('setStatus')
251
-			->willReturnCallback(function (string $status) use (&$sessionSetStatusCalls) {
252
-				$sessionSetStatusCalls[] = $status;
253
-			});
254
-
255
-		$instance->expects($this->any())->method('getMasterKeyId')->willReturn('masterKeyId');
256
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
257
-		$instance->expects($this->any())->method('getSystemPrivateKey')->with('masterKeyId')->willReturn('privateMasterKey');
258
-		$instance->expects($this->any())->method('getPrivateKey')->with($this->userId)->willReturn('privateUserKey');
259
-
260
-		if ($useMasterKey) {
261
-			$this->cryptMock->expects($this->once())->method('decryptPrivateKey')
262
-				->with('privateMasterKey', 'masterKeyPassword', 'masterKeyId')
263
-				->willReturn('key');
264
-		} else {
265
-			$this->cryptMock->expects($this->once())->method('decryptPrivateKey')
266
-				->with('privateUserKey', 'pass', $this->userId)
267
-				->willReturn('key');
268
-		}
269
-
270
-		$this->sessionMock->expects($this->once())->method('setPrivateKey')
271
-			->with('key');
272
-
273
-		$this->assertTrue($instance->init($this->userId, 'pass'));
274
-		self::assertEquals([
275
-			Session::INIT_EXECUTED,
276
-			Session::INIT_SUCCESSFUL,
277
-		], $sessionSetStatusCalls);
278
-	}
279
-
280
-	public static function dataTestInit(): array {
281
-		return [
282
-			[true],
283
-			[false]
284
-		];
285
-	}
286
-
287
-
288
-	public function testSetRecoveryKey(): void {
289
-		$this->keyStorageMock->expects($this->exactly(2))
290
-			->method('setSystemUserKey')
291
-			->willReturn(true);
292
-		$this->cryptMock->expects($this->any())
293
-			->method('encryptPrivateKey')
294
-			->with($this->equalTo('privateKey'), $this->equalTo('pass'))
295
-			->willReturn('decryptedPrivateKey');
296
-
297
-
298
-		$this->assertTrue(
299
-			$this->instance->setRecoveryKey('pass',
300
-				['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])
301
-		);
302
-	}
303
-
304
-	public function testSetSystemPrivateKey(): void {
305
-		$this->keyStorageMock->expects($this->exactly(1))
306
-			->method('setSystemUserKey')
307
-			->with($this->equalTo('keyId.privateKey'), $this->equalTo('key'))
308
-			->willReturn(true);
309
-
310
-
311
-		$this->assertTrue(
312
-			$this->instance->setSystemPrivateKey('keyId', 'key')
313
-		);
314
-	}
315
-
316
-	public function testGetSystemPrivateKey(): void {
317
-		$this->keyStorageMock->expects($this->exactly(1))
318
-			->method('getSystemUserKey')
319
-			->with($this->equalTo('keyId.privateKey'))
320
-			->willReturn('systemPrivateKey');
321
-
322
-
323
-		$this->assertSame('systemPrivateKey',
324
-			$this->instance->getSystemPrivateKey('keyId')
325
-		);
326
-	}
327
-
328
-	public function testGetEncryptedFileKey(): void {
329
-		$this->keyStorageMock->expects($this->once())
330
-			->method('getFileKey')
331
-			->with('/', 'fileKey')
332
-			->willReturn(true);
333
-
334
-		$this->assertTrue($this->instance->getEncryptedFileKey('/'));
335
-	}
336
-
337
-	public static function dataTestGetFileKey(): array {
338
-		return [
339
-			['user1', false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
340
-			['user1', false, 'privateKey', '', 'multiKeyDecryptResult'],
341
-			['user1', false, false, 'legacyKey', ''],
342
-			['user1', false, false, '', ''],
343
-			['user1', true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
344
-			['user1', true, 'privateKey', '', 'multiKeyDecryptResult'],
345
-			['user1', true, false, 'legacyKey', ''],
346
-			['user1', true, false, '', ''],
347
-			[null, false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
348
-			[null, false, 'privateKey', '', 'multiKeyDecryptResult'],
349
-			[null, false, false, 'legacyKey', ''],
350
-			[null, false, false, '', ''],
351
-			[null, true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
352
-			[null, true, 'privateKey', '', 'multiKeyDecryptResult'],
353
-			[null, true, false, 'legacyKey', ''],
354
-			[null, true, false, '', ''],
355
-		];
356
-	}
357
-
358
-	/**
359
-	 * @dataProvider dataTestGetFileKey
360
-	 *
361
-	 * @param $uid
362
-	 * @param $isMasterKeyEnabled
363
-	 * @param $privateKey
364
-	 * @param $expected
365
-	 */
366
-	public function testGetFileKey($uid, $isMasterKeyEnabled, $privateKey, $encryptedFileKey, $expected): void {
367
-		$path = '/foo.txt';
368
-
369
-		if ($isMasterKeyEnabled) {
370
-			$expectedUid = 'masterKeyId';
371
-			$this->configMock->expects($this->any())->method('getSystemValue')->with('secret')
372
-				->willReturn('password');
373
-		} elseif (!$uid) {
374
-			$expectedUid = 'systemKeyId';
375
-		} else {
376
-			$expectedUid = $uid;
377
-		}
378
-
379
-		$this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
380
-
381
-		$this->keyStorageMock->expects($this->exactly(2))
382
-			->method('getFileKey')
383
-			->willReturnMap([
384
-				[$path, 'fileKey', 'OC_DEFAULT_MODULE', $encryptedFileKey],
385
-				[$path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE', 'fileKey'],
386
-			]);
387
-
388
-		$this->utilMock->expects($this->any())->method('isMasterKeyEnabled')
389
-			->willReturn($isMasterKeyEnabled);
390
-
391
-		if (is_null($uid)) {
392
-			$this->keyStorageMock->expects($this->once())
393
-				->method('getSystemUserKey')
394
-				->willReturn(true);
395
-			$this->cryptMock->expects($this->once())
396
-				->method('decryptPrivateKey')
397
-				->willReturn($privateKey);
398
-		} else {
399
-			$this->keyStorageMock->expects($this->never())
400
-				->method('getSystemUserKey');
401
-			$this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
402
-		}
403
-
404
-		if (!empty($encryptedFileKey)) {
405
-			$this->cryptMock->expects($this->never())
406
-				->method('multiKeyDecrypt');
407
-			if ($privateKey) {
408
-				$this->cryptMock->expects($this->once())
409
-					->method('multiKeyDecryptLegacy')
410
-					->willReturn('multiKeyDecryptResult');
411
-			} else {
412
-				$this->cryptMock->expects($this->never())
413
-					->method('multiKeyDecryptLegacy');
414
-			}
415
-		} else {
416
-			$this->cryptMock->expects($this->never())
417
-				->method('multiKeyDecryptLegacy');
418
-			if ($privateKey) {
419
-				$this->cryptMock->expects($this->once())
420
-					->method('multiKeyDecrypt')
421
-					->willReturn('multiKeyDecryptResult');
422
-			} else {
423
-				$this->cryptMock->expects($this->never())
424
-					->method('multiKeyDecrypt');
425
-			}
426
-		}
427
-
428
-		$this->assertSame($expected,
429
-			$this->instance->getFileKey($path, $uid, null)
430
-		);
431
-	}
432
-
433
-	public function testDeletePrivateKey(): void {
434
-		$this->keyStorageMock->expects($this->once())
435
-			->method('deleteUserKey')
436
-			->with('user1', 'privateKey')
437
-			->willReturn(true);
438
-
439
-		$this->assertTrue(self::invokePrivate($this->instance,
440
-			'deletePrivateKey',
441
-			[$this->userId]));
442
-	}
443
-
444
-	public function testDeleteAllFileKeys(): void {
445
-		$this->keyStorageMock->expects($this->once())
446
-			->method('deleteAllFileKeys')
447
-			->willReturn(true);
448
-
449
-		$this->assertTrue($this->instance->deleteAllFileKeys('/'));
450
-	}
451
-
452
-	/**
453
-	 * test add public share key and or recovery key to the list of public keys
454
-	 *
455
-	 * @dataProvider dataTestAddSystemKeys
456
-	 *
457
-	 * @param array $accessList
458
-	 * @param array $publicKeys
459
-	 * @param string $uid
460
-	 * @param array $expectedKeys
461
-	 */
462
-	public function testAddSystemKeys($accessList, $publicKeys, $uid, $expectedKeys): void {
463
-		$publicShareKeyId = 'publicShareKey';
464
-		$recoveryKeyId = 'recoveryKey';
465
-
466
-		$this->keyStorageMock->expects($this->any())
467
-			->method('getSystemUserKey')
468
-			->willReturnCallback(function ($keyId, $encryptionModuleId) {
469
-				return $keyId;
470
-			});
471
-
472
-		$this->utilMock->expects($this->any())
473
-			->method('isRecoveryEnabledForUser')
474
-			->willReturnCallback(function ($uid) {
475
-				if ($uid === 'user1') {
476
-					return true;
477
-				}
478
-				return false;
479
-			});
480
-
481
-		// set key IDs
482
-		self::invokePrivate($this->instance, 'publicShareKeyId', [$publicShareKeyId]);
483
-		self::invokePrivate($this->instance, 'recoveryKeyId', [$recoveryKeyId]);
484
-
485
-		$result = $this->instance->addSystemKeys($accessList, $publicKeys, $uid);
486
-
487
-		foreach ($expectedKeys as $expected) {
488
-			$this->assertArrayHasKey($expected, $result);
489
-		}
490
-
491
-		$this->assertSameSize($expectedKeys, $result);
492
-	}
493
-
494
-	/**
495
-	 * data provider for testAddSystemKeys()
496
-	 *
497
-	 * @return array
498
-	 */
499
-	public static function dataTestAddSystemKeys(): array {
500
-		return [
501
-			[['public' => true],[], 'user1', ['publicShareKey', 'recoveryKey']],
502
-			[['public' => false], [], 'user1', ['recoveryKey']],
503
-			[['public' => true],[], 'user2', ['publicShareKey']],
504
-			[['public' => false], [], 'user2', []],
505
-		];
506
-	}
507
-
508
-	public function testGetMasterKeyId(): void {
509
-		$this->assertSame('systemKeyId', $this->instance->getMasterKeyId());
510
-	}
511
-
512
-	public function testGetPublicMasterKey(): void {
513
-		$this->keyStorageMock->expects($this->once())->method('getSystemUserKey')
514
-			->with('systemKeyId.publicKey', Encryption::ID)
515
-			->willReturn(true);
516
-
517
-		$this->assertTrue(
518
-			$this->instance->getPublicMasterKey()
519
-		);
520
-	}
521
-
522
-	public function testGetMasterKeyPassword(): void {
523
-		$this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
524
-			->willReturn('password');
525
-
526
-		$this->assertSame('password',
527
-			$this->invokePrivate($this->instance, 'getMasterKeyPassword', [])
528
-		);
529
-	}
530
-
531
-
532
-	public function testGetMasterKeyPasswordException(): void {
533
-		$this->expectException(\Exception::class);
534
-
535
-		$this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
536
-			->willReturn('');
537
-
538
-		$this->invokePrivate($this->instance, 'getMasterKeyPassword', []);
539
-	}
540
-
541
-	/**
542
-	 * @dataProvider dataTestValidateMasterKey
543
-	 *
544
-	 * @param $masterKey
545
-	 */
546
-	public function testValidateMasterKey($masterKey): void {
547
-		/** @var KeyManager&MockObject $instance */
548
-		$instance = $this->getMockBuilder(KeyManager::class)
549
-			->setConstructorArgs(
550
-				[
551
-					$this->keyStorageMock,
552
-					$this->cryptMock,
553
-					$this->configMock,
554
-					$this->userMock,
555
-					$this->sessionMock,
556
-					$this->logMock,
557
-					$this->utilMock,
558
-					$this->lockingProviderMock
559
-				]
560
-			)->onlyMethods(['getPublicMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
561
-			->getMock();
562
-
563
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
564
-			->willReturn(true);
565
-
566
-		$instance->expects($this->once())->method('getPublicMasterKey')
567
-			->willReturn($masterKey);
568
-
569
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
570
-		$this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
571
-
572
-		if (empty($masterKey)) {
573
-			$this->cryptMock->expects($this->once())->method('createKeyPair')
574
-				->willReturn(['publicKey' => 'public', 'privateKey' => 'private']);
575
-			$this->keyStorageMock->expects($this->once())->method('setSystemUserKey')
576
-				->with('systemKeyId.publicKey', 'public', Encryption::ID);
577
-			$this->cryptMock->expects($this->once())->method('encryptPrivateKey')
578
-				->with('private', 'masterKeyPassword', 'systemKeyId')
579
-				->willReturn('EncryptedKey');
580
-			$this->lockingProviderMock->expects($this->once())
581
-				->method('acquireLock');
582
-			$instance->expects($this->once())->method('setSystemPrivateKey')
583
-				->with('systemKeyId', 'headerEncryptedKey');
584
-		} else {
585
-			$this->cryptMock->expects($this->never())->method('createKeyPair');
586
-			$this->keyStorageMock->expects($this->never())->method('setSystemUserKey');
587
-			$this->cryptMock->expects($this->never())->method('encryptPrivateKey');
588
-			$instance->expects($this->never())->method('setSystemPrivateKey');
589
-		}
590
-
591
-		$instance->validateMasterKey();
592
-	}
593
-
594
-	public function testValidateMasterKeyLocked(): void {
595
-		/** @var KeyManager&MockObject $instance */
596
-		$instance = $this->getMockBuilder(KeyManager::class)
597
-			->setConstructorArgs([
598
-				$this->keyStorageMock,
599
-				$this->cryptMock,
600
-				$this->configMock,
601
-				$this->userMock,
602
-				$this->sessionMock,
603
-				$this->logMock,
604
-				$this->utilMock,
605
-				$this->lockingProviderMock
606
-			])
607
-			->onlyMethods(['getPublicMasterKey', 'getPrivateMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
608
-			->getMock();
609
-
610
-		$this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
611
-			->willReturn(true);
612
-
613
-		$instance->expects($this->once())->method('getPublicMasterKey')
614
-			->willReturn('');
615
-		$instance->expects($this->once())->method('getPrivateMasterKey')
616
-			->willReturn('');
617
-
618
-		$instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
619
-		$this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
620
-
621
-		$this->lockingProviderMock->expects($this->once())
622
-			->method('acquireLock')
623
-			->willThrowException(new LockedException('encryption-generateMasterKey'));
624
-
625
-		$this->expectException(LockedException::class);
626
-		$instance->validateMasterKey();
627
-	}
628
-
629
-	public static function dataTestValidateMasterKey(): array {
630
-		return [
631
-			['masterKey'],
632
-			['']
633
-		];
634
-	}
635
-
636
-	public function testGetVersionWithoutFileInfo(): void {
637
-		$view = $this->getMockBuilder(View::class)
638
-			->disableOriginalConstructor()->getMock();
639
-		$view->expects($this->once())
640
-			->method('getFileInfo')
641
-			->with('/admin/files/myfile.txt')
642
-			->willReturn(false);
643
-
644
-		/** @var View $view */
645
-		$this->assertSame(0, $this->instance->getVersion('/admin/files/myfile.txt', $view));
646
-	}
647
-
648
-	public function testGetVersionWithFileInfo(): void {
649
-		$view = $this->getMockBuilder(View::class)
650
-			->disableOriginalConstructor()->getMock();
651
-		$fileInfo = $this->getMockBuilder(FileInfo::class)
652
-			->disableOriginalConstructor()->getMock();
653
-		$fileInfo->expects($this->once())
654
-			->method('getEncryptedVersion')
655
-			->willReturn(1337);
656
-		$view->expects($this->once())
657
-			->method('getFileInfo')
658
-			->with('/admin/files/myfile.txt')
659
-			->willReturn($fileInfo);
660
-
661
-		/** @var View $view */
662
-		$this->assertSame(1337, $this->instance->getVersion('/admin/files/myfile.txt', $view));
663
-	}
664
-
665
-	public function testSetVersionWithFileInfo(): void {
666
-		$view = $this->getMockBuilder(View::class)
667
-			->disableOriginalConstructor()->getMock();
668
-		$cache = $this->getMockBuilder(ICache::class)
669
-			->disableOriginalConstructor()->getMock();
670
-		$cache->expects($this->once())
671
-			->method('update')
672
-			->with(123, ['encrypted' => 5, 'encryptedVersion' => 5]);
673
-		$storage = $this->getMockBuilder(FilesIStorage::class)
674
-			->disableOriginalConstructor()->getMock();
675
-		$storage->expects($this->once())
676
-			->method('getCache')
677
-			->willReturn($cache);
678
-		$fileInfo = $this->getMockBuilder(FileInfo::class)
679
-			->disableOriginalConstructor()->getMock();
680
-		$fileInfo->expects($this->once())
681
-			->method('getStorage')
682
-			->willReturn($storage);
683
-		$fileInfo->expects($this->once())
684
-			->method('getId')
685
-			->willReturn(123);
686
-		$view->expects($this->once())
687
-			->method('getFileInfo')
688
-			->with('/admin/files/myfile.txt')
689
-			->willReturn($fileInfo);
690
-
691
-		/** @var View $view */
692
-		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
693
-	}
694
-
695
-	public function testSetVersionWithoutFileInfo(): void {
696
-		$view = $this->getMockBuilder(View::class)
697
-			->disableOriginalConstructor()->getMock();
698
-		$view->expects($this->once())
699
-			->method('getFileInfo')
700
-			->with('/admin/files/myfile.txt')
701
-			->willReturn(false);
702
-
703
-		/** @var View $view */
704
-		$this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
705
-	}
706
-
707
-	public function testBackupUserKeys(): void {
708
-		$this->keyStorageMock->expects($this->once())->method('backupUserKeys')
709
-			->with('OC_DEFAULT_MODULE', 'test', 'user1');
710
-		$this->instance->backupUserKeys('test', 'user1');
711
-	}
34
+    protected KeyManager $instance;
35
+
36
+    protected string $userId;
37
+    protected string $systemKeyId;
38
+    protected IStorage&MockObject $keyStorageMock;
39
+    protected Crypt&MockObject $cryptMock;
40
+    protected IUserSession&MockObject $userMock;
41
+    protected Session&MockObject $sessionMock;
42
+    protected LoggerInterface&MockObject $logMock;
43
+    protected Util&MockObject $utilMock;
44
+    protected IConfig&MockObject $configMock;
45
+    protected ILockingProvider&MockObject $lockingProviderMock;
46
+
47
+    protected function setUp(): void {
48
+        parent::setUp();
49
+        $this->userId = 'user1';
50
+        $this->systemKeyId = 'systemKeyId';
51
+        $this->keyStorageMock = $this->createMock(IStorage::class);
52
+        $this->cryptMock = $this->getMockBuilder(Crypt::class)
53
+            ->disableOriginalConstructor()
54
+            ->getMock();
55
+        $this->configMock = $this->createMock(IConfig::class);
56
+        $this->configMock->expects($this->any())
57
+            ->method('getAppValue')
58
+            ->willReturn($this->systemKeyId);
59
+        $this->userMock = $this->createMock(IUserSession::class);
60
+        $this->sessionMock = $this->getMockBuilder(Session::class)
61
+            ->disableOriginalConstructor()
62
+            ->getMock();
63
+        $this->logMock = $this->createMock(LoggerInterface::class);
64
+        $this->utilMock = $this->getMockBuilder(Util::class)
65
+            ->disableOriginalConstructor()
66
+            ->getMock();
67
+        $this->lockingProviderMock = $this->createMock(ILockingProvider::class);
68
+
69
+        $this->instance = new KeyManager(
70
+            $this->keyStorageMock,
71
+            $this->cryptMock,
72
+            $this->configMock,
73
+            $this->userMock,
74
+            $this->sessionMock,
75
+            $this->logMock,
76
+            $this->utilMock,
77
+            $this->lockingProviderMock
78
+        );
79
+    }
80
+
81
+    public function testDeleteShareKey(): void {
82
+        $this->keyStorageMock->expects($this->any())
83
+            ->method('deleteFileKey')
84
+            ->with($this->equalTo('/path'), $this->equalTo('keyId.shareKey'))
85
+            ->willReturn(true);
86
+
87
+        $this->assertTrue(
88
+            $this->instance->deleteShareKey('/path', 'keyId')
89
+        );
90
+    }
91
+
92
+    public function testGetPrivateKey(): void {
93
+        $this->keyStorageMock->expects($this->any())
94
+            ->method('getUserKey')
95
+            ->with($this->equalTo($this->userId), $this->equalTo('privateKey'))
96
+            ->willReturn('privateKey');
97
+
98
+
99
+        $this->assertSame('privateKey',
100
+            $this->instance->getPrivateKey($this->userId)
101
+        );
102
+    }
103
+
104
+    public function testGetPublicKey(): void {
105
+        $this->keyStorageMock->expects($this->any())
106
+            ->method('getUserKey')
107
+            ->with($this->equalTo($this->userId), $this->equalTo('publicKey'))
108
+            ->willReturn('publicKey');
109
+
110
+
111
+        $this->assertSame('publicKey',
112
+            $this->instance->getPublicKey($this->userId)
113
+        );
114
+    }
115
+
116
+    public function testRecoveryKeyExists(): void {
117
+        $this->keyStorageMock->expects($this->any())
118
+            ->method('getSystemUserKey')
119
+            ->with($this->equalTo($this->systemKeyId . '.publicKey'))
120
+            ->willReturn('recoveryKey');
121
+
122
+
123
+        $this->assertTrue($this->instance->recoveryKeyExists());
124
+    }
125
+
126
+    public function testCheckRecoveryKeyPassword(): void {
127
+        $this->keyStorageMock->expects($this->any())
128
+            ->method('getSystemUserKey')
129
+            ->with($this->equalTo($this->systemKeyId . '.privateKey'))
130
+            ->willReturn('recoveryKey');
131
+        $this->cryptMock->expects($this->any())
132
+            ->method('decryptPrivateKey')
133
+            ->with($this->equalTo('recoveryKey'), $this->equalTo('pass'))
134
+            ->willReturn('decryptedRecoveryKey');
135
+
136
+        $this->assertTrue($this->instance->checkRecoveryPassword('pass'));
137
+    }
138
+
139
+    public function testSetPublicKey(): void {
140
+        $this->keyStorageMock->expects($this->any())
141
+            ->method('setUserKey')
142
+            ->with(
143
+                $this->equalTo($this->userId),
144
+                $this->equalTo('publicKey'),
145
+                $this->equalTo('key'))
146
+            ->willReturn(true);
147
+
148
+
149
+        $this->assertTrue(
150
+            $this->instance->setPublicKey($this->userId, 'key')
151
+        );
152
+    }
153
+
154
+    public function testSetPrivateKey(): void {
155
+        $this->keyStorageMock->expects($this->any())
156
+            ->method('setUserKey')
157
+            ->with(
158
+                $this->equalTo($this->userId),
159
+                $this->equalTo('privateKey'),
160
+                $this->equalTo('key'))
161
+            ->willReturn(true);
162
+
163
+
164
+        $this->assertTrue(
165
+            $this->instance->setPrivateKey($this->userId, 'key')
166
+        );
167
+    }
168
+
169
+    /**
170
+     * @dataProvider dataTestUserHasKeys
171
+     */
172
+    public function testUserHasKeys($key, $expected): void {
173
+        $this->keyStorageMock->expects($this->exactly(2))
174
+            ->method('getUserKey')
175
+            ->with($this->equalTo($this->userId), $this->anything())
176
+            ->willReturn($key);
177
+
178
+
179
+        $this->assertSame($expected,
180
+            $this->instance->userHasKeys($this->userId)
181
+        );
182
+    }
183
+
184
+    public static function dataTestUserHasKeys(): array {
185
+        return [
186
+            ['key', true],
187
+            ['', false]
188
+        ];
189
+    }
190
+
191
+
192
+    public function testUserHasKeysMissingPrivateKey(): void {
193
+        $this->expectException(PrivateKeyMissingException::class);
194
+
195
+        $this->keyStorageMock->expects($this->exactly(2))
196
+            ->method('getUserKey')
197
+            ->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
198
+                if ($keyID === 'privateKey') {
199
+                    return '';
200
+                }
201
+                return 'key';
202
+            });
203
+
204
+        $this->instance->userHasKeys($this->userId);
205
+    }
206
+
207
+
208
+    public function testUserHasKeysMissingPublicKey(): void {
209
+        $this->expectException(PublicKeyMissingException::class);
210
+
211
+        $this->keyStorageMock->expects($this->exactly(2))
212
+            ->method('getUserKey')
213
+            ->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
214
+                if ($keyID === 'publicKey') {
215
+                    return '';
216
+                }
217
+                return 'key';
218
+            });
219
+
220
+        $this->instance->userHasKeys($this->userId);
221
+    }
222
+
223
+    /**
224
+     * @dataProvider dataTestInit
225
+     *
226
+     * @param bool $useMasterKey
227
+     */
228
+    public function testInit($useMasterKey): void {
229
+        /** @var KeyManager&MockObject $instance */
230
+        $instance = $this->getMockBuilder(KeyManager::class)
231
+            ->setConstructorArgs(
232
+                [
233
+                    $this->keyStorageMock,
234
+                    $this->cryptMock,
235
+                    $this->configMock,
236
+                    $this->userMock,
237
+                    $this->sessionMock,
238
+                    $this->logMock,
239
+                    $this->utilMock,
240
+                    $this->lockingProviderMock
241
+                ]
242
+            )->onlyMethods(['getMasterKeyId', 'getMasterKeyPassword', 'getSystemPrivateKey', 'getPrivateKey'])
243
+            ->getMock();
244
+
245
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
246
+            ->willReturn($useMasterKey);
247
+
248
+        $sessionSetStatusCalls = [];
249
+        $this->sessionMock->expects($this->exactly(2))
250
+            ->method('setStatus')
251
+            ->willReturnCallback(function (string $status) use (&$sessionSetStatusCalls) {
252
+                $sessionSetStatusCalls[] = $status;
253
+            });
254
+
255
+        $instance->expects($this->any())->method('getMasterKeyId')->willReturn('masterKeyId');
256
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
257
+        $instance->expects($this->any())->method('getSystemPrivateKey')->with('masterKeyId')->willReturn('privateMasterKey');
258
+        $instance->expects($this->any())->method('getPrivateKey')->with($this->userId)->willReturn('privateUserKey');
259
+
260
+        if ($useMasterKey) {
261
+            $this->cryptMock->expects($this->once())->method('decryptPrivateKey')
262
+                ->with('privateMasterKey', 'masterKeyPassword', 'masterKeyId')
263
+                ->willReturn('key');
264
+        } else {
265
+            $this->cryptMock->expects($this->once())->method('decryptPrivateKey')
266
+                ->with('privateUserKey', 'pass', $this->userId)
267
+                ->willReturn('key');
268
+        }
269
+
270
+        $this->sessionMock->expects($this->once())->method('setPrivateKey')
271
+            ->with('key');
272
+
273
+        $this->assertTrue($instance->init($this->userId, 'pass'));
274
+        self::assertEquals([
275
+            Session::INIT_EXECUTED,
276
+            Session::INIT_SUCCESSFUL,
277
+        ], $sessionSetStatusCalls);
278
+    }
279
+
280
+    public static function dataTestInit(): array {
281
+        return [
282
+            [true],
283
+            [false]
284
+        ];
285
+    }
286
+
287
+
288
+    public function testSetRecoveryKey(): void {
289
+        $this->keyStorageMock->expects($this->exactly(2))
290
+            ->method('setSystemUserKey')
291
+            ->willReturn(true);
292
+        $this->cryptMock->expects($this->any())
293
+            ->method('encryptPrivateKey')
294
+            ->with($this->equalTo('privateKey'), $this->equalTo('pass'))
295
+            ->willReturn('decryptedPrivateKey');
296
+
297
+
298
+        $this->assertTrue(
299
+            $this->instance->setRecoveryKey('pass',
300
+                ['publicKey' => 'publicKey', 'privateKey' => 'privateKey'])
301
+        );
302
+    }
303
+
304
+    public function testSetSystemPrivateKey(): void {
305
+        $this->keyStorageMock->expects($this->exactly(1))
306
+            ->method('setSystemUserKey')
307
+            ->with($this->equalTo('keyId.privateKey'), $this->equalTo('key'))
308
+            ->willReturn(true);
309
+
310
+
311
+        $this->assertTrue(
312
+            $this->instance->setSystemPrivateKey('keyId', 'key')
313
+        );
314
+    }
315
+
316
+    public function testGetSystemPrivateKey(): void {
317
+        $this->keyStorageMock->expects($this->exactly(1))
318
+            ->method('getSystemUserKey')
319
+            ->with($this->equalTo('keyId.privateKey'))
320
+            ->willReturn('systemPrivateKey');
321
+
322
+
323
+        $this->assertSame('systemPrivateKey',
324
+            $this->instance->getSystemPrivateKey('keyId')
325
+        );
326
+    }
327
+
328
+    public function testGetEncryptedFileKey(): void {
329
+        $this->keyStorageMock->expects($this->once())
330
+            ->method('getFileKey')
331
+            ->with('/', 'fileKey')
332
+            ->willReturn(true);
333
+
334
+        $this->assertTrue($this->instance->getEncryptedFileKey('/'));
335
+    }
336
+
337
+    public static function dataTestGetFileKey(): array {
338
+        return [
339
+            ['user1', false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
340
+            ['user1', false, 'privateKey', '', 'multiKeyDecryptResult'],
341
+            ['user1', false, false, 'legacyKey', ''],
342
+            ['user1', false, false, '', ''],
343
+            ['user1', true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
344
+            ['user1', true, 'privateKey', '', 'multiKeyDecryptResult'],
345
+            ['user1', true, false, 'legacyKey', ''],
346
+            ['user1', true, false, '', ''],
347
+            [null, false, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
348
+            [null, false, 'privateKey', '', 'multiKeyDecryptResult'],
349
+            [null, false, false, 'legacyKey', ''],
350
+            [null, false, false, '', ''],
351
+            [null, true, 'privateKey', 'legacyKey', 'multiKeyDecryptResult'],
352
+            [null, true, 'privateKey', '', 'multiKeyDecryptResult'],
353
+            [null, true, false, 'legacyKey', ''],
354
+            [null, true, false, '', ''],
355
+        ];
356
+    }
357
+
358
+    /**
359
+     * @dataProvider dataTestGetFileKey
360
+     *
361
+     * @param $uid
362
+     * @param $isMasterKeyEnabled
363
+     * @param $privateKey
364
+     * @param $expected
365
+     */
366
+    public function testGetFileKey($uid, $isMasterKeyEnabled, $privateKey, $encryptedFileKey, $expected): void {
367
+        $path = '/foo.txt';
368
+
369
+        if ($isMasterKeyEnabled) {
370
+            $expectedUid = 'masterKeyId';
371
+            $this->configMock->expects($this->any())->method('getSystemValue')->with('secret')
372
+                ->willReturn('password');
373
+        } elseif (!$uid) {
374
+            $expectedUid = 'systemKeyId';
375
+        } else {
376
+            $expectedUid = $uid;
377
+        }
378
+
379
+        $this->invokePrivate($this->instance, 'masterKeyId', ['masterKeyId']);
380
+
381
+        $this->keyStorageMock->expects($this->exactly(2))
382
+            ->method('getFileKey')
383
+            ->willReturnMap([
384
+                [$path, 'fileKey', 'OC_DEFAULT_MODULE', $encryptedFileKey],
385
+                [$path, $expectedUid . '.shareKey', 'OC_DEFAULT_MODULE', 'fileKey'],
386
+            ]);
387
+
388
+        $this->utilMock->expects($this->any())->method('isMasterKeyEnabled')
389
+            ->willReturn($isMasterKeyEnabled);
390
+
391
+        if (is_null($uid)) {
392
+            $this->keyStorageMock->expects($this->once())
393
+                ->method('getSystemUserKey')
394
+                ->willReturn(true);
395
+            $this->cryptMock->expects($this->once())
396
+                ->method('decryptPrivateKey')
397
+                ->willReturn($privateKey);
398
+        } else {
399
+            $this->keyStorageMock->expects($this->never())
400
+                ->method('getSystemUserKey');
401
+            $this->sessionMock->expects($this->once())->method('getPrivateKey')->willReturn($privateKey);
402
+        }
403
+
404
+        if (!empty($encryptedFileKey)) {
405
+            $this->cryptMock->expects($this->never())
406
+                ->method('multiKeyDecrypt');
407
+            if ($privateKey) {
408
+                $this->cryptMock->expects($this->once())
409
+                    ->method('multiKeyDecryptLegacy')
410
+                    ->willReturn('multiKeyDecryptResult');
411
+            } else {
412
+                $this->cryptMock->expects($this->never())
413
+                    ->method('multiKeyDecryptLegacy');
414
+            }
415
+        } else {
416
+            $this->cryptMock->expects($this->never())
417
+                ->method('multiKeyDecryptLegacy');
418
+            if ($privateKey) {
419
+                $this->cryptMock->expects($this->once())
420
+                    ->method('multiKeyDecrypt')
421
+                    ->willReturn('multiKeyDecryptResult');
422
+            } else {
423
+                $this->cryptMock->expects($this->never())
424
+                    ->method('multiKeyDecrypt');
425
+            }
426
+        }
427
+
428
+        $this->assertSame($expected,
429
+            $this->instance->getFileKey($path, $uid, null)
430
+        );
431
+    }
432
+
433
+    public function testDeletePrivateKey(): void {
434
+        $this->keyStorageMock->expects($this->once())
435
+            ->method('deleteUserKey')
436
+            ->with('user1', 'privateKey')
437
+            ->willReturn(true);
438
+
439
+        $this->assertTrue(self::invokePrivate($this->instance,
440
+            'deletePrivateKey',
441
+            [$this->userId]));
442
+    }
443
+
444
+    public function testDeleteAllFileKeys(): void {
445
+        $this->keyStorageMock->expects($this->once())
446
+            ->method('deleteAllFileKeys')
447
+            ->willReturn(true);
448
+
449
+        $this->assertTrue($this->instance->deleteAllFileKeys('/'));
450
+    }
451
+
452
+    /**
453
+     * test add public share key and or recovery key to the list of public keys
454
+     *
455
+     * @dataProvider dataTestAddSystemKeys
456
+     *
457
+     * @param array $accessList
458
+     * @param array $publicKeys
459
+     * @param string $uid
460
+     * @param array $expectedKeys
461
+     */
462
+    public function testAddSystemKeys($accessList, $publicKeys, $uid, $expectedKeys): void {
463
+        $publicShareKeyId = 'publicShareKey';
464
+        $recoveryKeyId = 'recoveryKey';
465
+
466
+        $this->keyStorageMock->expects($this->any())
467
+            ->method('getSystemUserKey')
468
+            ->willReturnCallback(function ($keyId, $encryptionModuleId) {
469
+                return $keyId;
470
+            });
471
+
472
+        $this->utilMock->expects($this->any())
473
+            ->method('isRecoveryEnabledForUser')
474
+            ->willReturnCallback(function ($uid) {
475
+                if ($uid === 'user1') {
476
+                    return true;
477
+                }
478
+                return false;
479
+            });
480
+
481
+        // set key IDs
482
+        self::invokePrivate($this->instance, 'publicShareKeyId', [$publicShareKeyId]);
483
+        self::invokePrivate($this->instance, 'recoveryKeyId', [$recoveryKeyId]);
484
+
485
+        $result = $this->instance->addSystemKeys($accessList, $publicKeys, $uid);
486
+
487
+        foreach ($expectedKeys as $expected) {
488
+            $this->assertArrayHasKey($expected, $result);
489
+        }
490
+
491
+        $this->assertSameSize($expectedKeys, $result);
492
+    }
493
+
494
+    /**
495
+     * data provider for testAddSystemKeys()
496
+     *
497
+     * @return array
498
+     */
499
+    public static function dataTestAddSystemKeys(): array {
500
+        return [
501
+            [['public' => true],[], 'user1', ['publicShareKey', 'recoveryKey']],
502
+            [['public' => false], [], 'user1', ['recoveryKey']],
503
+            [['public' => true],[], 'user2', ['publicShareKey']],
504
+            [['public' => false], [], 'user2', []],
505
+        ];
506
+    }
507
+
508
+    public function testGetMasterKeyId(): void {
509
+        $this->assertSame('systemKeyId', $this->instance->getMasterKeyId());
510
+    }
511
+
512
+    public function testGetPublicMasterKey(): void {
513
+        $this->keyStorageMock->expects($this->once())->method('getSystemUserKey')
514
+            ->with('systemKeyId.publicKey', Encryption::ID)
515
+            ->willReturn(true);
516
+
517
+        $this->assertTrue(
518
+            $this->instance->getPublicMasterKey()
519
+        );
520
+    }
521
+
522
+    public function testGetMasterKeyPassword(): void {
523
+        $this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
524
+            ->willReturn('password');
525
+
526
+        $this->assertSame('password',
527
+            $this->invokePrivate($this->instance, 'getMasterKeyPassword', [])
528
+        );
529
+    }
530
+
531
+
532
+    public function testGetMasterKeyPasswordException(): void {
533
+        $this->expectException(\Exception::class);
534
+
535
+        $this->configMock->expects($this->once())->method('getSystemValue')->with('secret')
536
+            ->willReturn('');
537
+
538
+        $this->invokePrivate($this->instance, 'getMasterKeyPassword', []);
539
+    }
540
+
541
+    /**
542
+     * @dataProvider dataTestValidateMasterKey
543
+     *
544
+     * @param $masterKey
545
+     */
546
+    public function testValidateMasterKey($masterKey): void {
547
+        /** @var KeyManager&MockObject $instance */
548
+        $instance = $this->getMockBuilder(KeyManager::class)
549
+            ->setConstructorArgs(
550
+                [
551
+                    $this->keyStorageMock,
552
+                    $this->cryptMock,
553
+                    $this->configMock,
554
+                    $this->userMock,
555
+                    $this->sessionMock,
556
+                    $this->logMock,
557
+                    $this->utilMock,
558
+                    $this->lockingProviderMock
559
+                ]
560
+            )->onlyMethods(['getPublicMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
561
+            ->getMock();
562
+
563
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
564
+            ->willReturn(true);
565
+
566
+        $instance->expects($this->once())->method('getPublicMasterKey')
567
+            ->willReturn($masterKey);
568
+
569
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
570
+        $this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
571
+
572
+        if (empty($masterKey)) {
573
+            $this->cryptMock->expects($this->once())->method('createKeyPair')
574
+                ->willReturn(['publicKey' => 'public', 'privateKey' => 'private']);
575
+            $this->keyStorageMock->expects($this->once())->method('setSystemUserKey')
576
+                ->with('systemKeyId.publicKey', 'public', Encryption::ID);
577
+            $this->cryptMock->expects($this->once())->method('encryptPrivateKey')
578
+                ->with('private', 'masterKeyPassword', 'systemKeyId')
579
+                ->willReturn('EncryptedKey');
580
+            $this->lockingProviderMock->expects($this->once())
581
+                ->method('acquireLock');
582
+            $instance->expects($this->once())->method('setSystemPrivateKey')
583
+                ->with('systemKeyId', 'headerEncryptedKey');
584
+        } else {
585
+            $this->cryptMock->expects($this->never())->method('createKeyPair');
586
+            $this->keyStorageMock->expects($this->never())->method('setSystemUserKey');
587
+            $this->cryptMock->expects($this->never())->method('encryptPrivateKey');
588
+            $instance->expects($this->never())->method('setSystemPrivateKey');
589
+        }
590
+
591
+        $instance->validateMasterKey();
592
+    }
593
+
594
+    public function testValidateMasterKeyLocked(): void {
595
+        /** @var KeyManager&MockObject $instance */
596
+        $instance = $this->getMockBuilder(KeyManager::class)
597
+            ->setConstructorArgs([
598
+                $this->keyStorageMock,
599
+                $this->cryptMock,
600
+                $this->configMock,
601
+                $this->userMock,
602
+                $this->sessionMock,
603
+                $this->logMock,
604
+                $this->utilMock,
605
+                $this->lockingProviderMock
606
+            ])
607
+            ->onlyMethods(['getPublicMasterKey', 'getPrivateMasterKey', 'setSystemPrivateKey', 'getMasterKeyPassword'])
608
+            ->getMock();
609
+
610
+        $this->utilMock->expects($this->once())->method('isMasterKeyEnabled')
611
+            ->willReturn(true);
612
+
613
+        $instance->expects($this->once())->method('getPublicMasterKey')
614
+            ->willReturn('');
615
+        $instance->expects($this->once())->method('getPrivateMasterKey')
616
+            ->willReturn('');
617
+
618
+        $instance->expects($this->any())->method('getMasterKeyPassword')->willReturn('masterKeyPassword');
619
+        $this->cryptMock->expects($this->any())->method('generateHeader')->willReturn('header');
620
+
621
+        $this->lockingProviderMock->expects($this->once())
622
+            ->method('acquireLock')
623
+            ->willThrowException(new LockedException('encryption-generateMasterKey'));
624
+
625
+        $this->expectException(LockedException::class);
626
+        $instance->validateMasterKey();
627
+    }
628
+
629
+    public static function dataTestValidateMasterKey(): array {
630
+        return [
631
+            ['masterKey'],
632
+            ['']
633
+        ];
634
+    }
635
+
636
+    public function testGetVersionWithoutFileInfo(): void {
637
+        $view = $this->getMockBuilder(View::class)
638
+            ->disableOriginalConstructor()->getMock();
639
+        $view->expects($this->once())
640
+            ->method('getFileInfo')
641
+            ->with('/admin/files/myfile.txt')
642
+            ->willReturn(false);
643
+
644
+        /** @var View $view */
645
+        $this->assertSame(0, $this->instance->getVersion('/admin/files/myfile.txt', $view));
646
+    }
647
+
648
+    public function testGetVersionWithFileInfo(): void {
649
+        $view = $this->getMockBuilder(View::class)
650
+            ->disableOriginalConstructor()->getMock();
651
+        $fileInfo = $this->getMockBuilder(FileInfo::class)
652
+            ->disableOriginalConstructor()->getMock();
653
+        $fileInfo->expects($this->once())
654
+            ->method('getEncryptedVersion')
655
+            ->willReturn(1337);
656
+        $view->expects($this->once())
657
+            ->method('getFileInfo')
658
+            ->with('/admin/files/myfile.txt')
659
+            ->willReturn($fileInfo);
660
+
661
+        /** @var View $view */
662
+        $this->assertSame(1337, $this->instance->getVersion('/admin/files/myfile.txt', $view));
663
+    }
664
+
665
+    public function testSetVersionWithFileInfo(): void {
666
+        $view = $this->getMockBuilder(View::class)
667
+            ->disableOriginalConstructor()->getMock();
668
+        $cache = $this->getMockBuilder(ICache::class)
669
+            ->disableOriginalConstructor()->getMock();
670
+        $cache->expects($this->once())
671
+            ->method('update')
672
+            ->with(123, ['encrypted' => 5, 'encryptedVersion' => 5]);
673
+        $storage = $this->getMockBuilder(FilesIStorage::class)
674
+            ->disableOriginalConstructor()->getMock();
675
+        $storage->expects($this->once())
676
+            ->method('getCache')
677
+            ->willReturn($cache);
678
+        $fileInfo = $this->getMockBuilder(FileInfo::class)
679
+            ->disableOriginalConstructor()->getMock();
680
+        $fileInfo->expects($this->once())
681
+            ->method('getStorage')
682
+            ->willReturn($storage);
683
+        $fileInfo->expects($this->once())
684
+            ->method('getId')
685
+            ->willReturn(123);
686
+        $view->expects($this->once())
687
+            ->method('getFileInfo')
688
+            ->with('/admin/files/myfile.txt')
689
+            ->willReturn($fileInfo);
690
+
691
+        /** @var View $view */
692
+        $this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
693
+    }
694
+
695
+    public function testSetVersionWithoutFileInfo(): void {
696
+        $view = $this->getMockBuilder(View::class)
697
+            ->disableOriginalConstructor()->getMock();
698
+        $view->expects($this->once())
699
+            ->method('getFileInfo')
700
+            ->with('/admin/files/myfile.txt')
701
+            ->willReturn(false);
702
+
703
+        /** @var View $view */
704
+        $this->instance->setVersion('/admin/files/myfile.txt', 5, $view);
705
+    }
706
+
707
+    public function testBackupUserKeys(): void {
708
+        $this->keyStorageMock->expects($this->once())->method('backupUserKeys')
709
+            ->with('OC_DEFAULT_MODULE', 'test', 'user1');
710
+        $this->instance->backupUserKeys('test', 'user1');
711
+    }
712 712
 }
Please login to merge, or discard this patch.
tests/lib/Files/FilenameValidatorTest.php 1 patch
Indentation   +482 added lines, -482 removed lines patch added patch discarded remove patch
@@ -26,486 +26,486 @@
 block discarded – undo
26 26
 
27 27
 class FilenameValidatorTest extends TestCase {
28 28
 
29
-	protected IFactory&MockObject $l10n;
30
-	protected IConfig&MockObject $config;
31
-	protected IDBConnection&MockObject $database;
32
-	protected LoggerInterface&MockObject $logger;
33
-
34
-	protected function setUp(): void {
35
-		parent::setUp();
36
-		$l10n = $this->createMock(IL10N::class);
37
-		$l10n->method('t')
38
-			->willReturnCallback(fn ($string, $params) => sprintf($string, ...$params));
39
-		$this->l10n = $this->createMock(IFactory::class);
40
-		$this->l10n
41
-			->method('get')
42
-			->with('core')
43
-			->willReturn($l10n);
44
-
45
-		$this->config = $this->createMock(IConfig::class);
46
-		$this->logger = $this->createMock(LoggerInterface::class);
47
-		$this->database = $this->createMock(IDBConnection::class);
48
-		$this->database->method('supports4ByteText')->willReturn(true);
49
-	}
50
-
51
-	/**
52
-	 * @dataProvider dataValidateFilename
53
-	 */
54
-	public function testValidateFilename(
55
-		string $filename,
56
-		array $forbiddenNames,
57
-		array $forbiddenBasenames,
58
-		array $forbiddenExtensions,
59
-		array $forbiddenCharacters,
60
-		?string $exception,
61
-	): void {
62
-		/** @var FilenameValidator&MockObject */
63
-		$validator = $this->getMockBuilder(FilenameValidator::class)
64
-			->onlyMethods([
65
-				'getForbiddenBasenames',
66
-				'getForbiddenCharacters',
67
-				'getForbiddenExtensions',
68
-				'getForbiddenFilenames',
69
-			])
70
-			->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger])
71
-			->getMock();
72
-
73
-		$validator->method('getForbiddenBasenames')
74
-			->willReturn($forbiddenBasenames);
75
-		$validator->method('getForbiddenCharacters')
76
-			->willReturn($forbiddenCharacters);
77
-		$validator->method('getForbiddenExtensions')
78
-			->willReturn($forbiddenExtensions);
79
-		$validator->method('getForbiddenFilenames')
80
-			->willReturn($forbiddenNames);
81
-
82
-		if ($exception !== null) {
83
-			$this->expectException($exception);
84
-		} else {
85
-			$this->expectNotToPerformAssertions();
86
-		}
87
-		$validator->validateFilename($filename);
88
-	}
89
-
90
-	/**
91
-	 * @dataProvider dataValidateFilename
92
-	 */
93
-	public function testIsFilenameValid(
94
-		string $filename,
95
-		array $forbiddenNames,
96
-		array $forbiddenBasenames,
97
-		array $forbiddenExtensions,
98
-		array $forbiddenCharacters,
99
-		?string $exception,
100
-	): void {
101
-		/** @var FilenameValidator&MockObject */
102
-		$validator = $this->getMockBuilder(FilenameValidator::class)
103
-			->onlyMethods([
104
-				'getForbiddenBasenames',
105
-				'getForbiddenExtensions',
106
-				'getForbiddenFilenames',
107
-				'getForbiddenCharacters',
108
-			])
109
-			->setConstructorArgs([$this->l10n, $this->database, $this->config, $this->logger])
110
-			->getMock();
111
-
112
-		$validator->method('getForbiddenBasenames')
113
-			->willReturn($forbiddenBasenames);
114
-		$validator->method('getForbiddenCharacters')
115
-			->willReturn($forbiddenCharacters);
116
-		$validator->method('getForbiddenExtensions')
117
-			->willReturn($forbiddenExtensions);
118
-		$validator->method('getForbiddenFilenames')
119
-			->willReturn($forbiddenNames);
120
-
121
-
122
-		$this->assertEquals($exception === null, $validator->isFilenameValid($filename));
123
-	}
124
-
125
-	public static function dataValidateFilename(): array {
126
-		return [
127
-			'valid name' => [
128
-				'a: b.txt', ['.htaccess'], [], [], [], null
129
-			],
130
-			'forbidden name in the middle is ok' => [
131
-				'a.htaccess.txt', ['.htaccess'], [], [], [], null
132
-			],
133
-			'valid name with some more parameters' => [
134
-				'a: b.txt', ['.htaccess'], [], ['exe'], ['~'], null
135
-			],
136
-			'valid name checks only the full name' => [
137
-				'.htaccess.sample', ['.htaccess'], [], [], [], null
138
-			],
139
-			'forbidden name' => [
140
-				'.htaccess', ['.htaccess'], [], [], [], ReservedWordException::class
141
-			],
142
-			'forbidden name - name is case insensitive' => [
143
-				'COM1', ['.htaccess', 'com1'], [], [], [], ReservedWordException::class
144
-			],
145
-			'forbidden basename' => [
146
-				// needed for Windows namespaces
147
-				'com1.suffix', ['.htaccess'], ['com1'], [], [], ReservedWordException::class
148
-			],
149
-			'forbidden basename case insensitive' => [
150
-				// needed for Windows namespaces
151
-				'COM1.suffix', ['.htaccess'], ['com1'], [], [], ReservedWordException::class
152
-			],
153
-			'forbidden basename for hidden files' => [
154
-				// needed for Windows namespaces
155
-				'.thumbs.db', ['.htaccess'], ['.thumbs'], [], [], ReservedWordException::class
156
-			],
157
-			'invalid character' => [
158
-				'a: b.txt', ['.htaccess'], [], [], [':'], InvalidCharacterInPathException::class
159
-			],
160
-			'invalid path' => [
161
-				'../../foo.bar', ['.htaccess'], [], [], ['/', '\\'], InvalidCharacterInPathException::class,
162
-			],
163
-			'invalid extension' => [
164
-				'a: b.txt', ['.htaccess'], [], ['.txt'], [], InvalidPathException::class
165
-			],
166
-			'invalid extension case insensitive' => [
167
-				'a: b.TXT', ['.htaccess'], [], ['.txt'], [], InvalidPathException::class
168
-			],
169
-			'empty filename' => [
170
-				'', [], [], [], [], EmptyFileNameException::class
171
-			],
172
-			'reserved unix name "."' => [
173
-				'.', [], [], [], [], InvalidDirectoryException::class
174
-			],
175
-			'reserved unix name ".."' => [
176
-				'..', [], [], [], [], InvalidDirectoryException::class
177
-			],
178
-			'weird but valid tripple dot name' => [
179
-				'...', [], [], [], [], null // is valid
180
-			],
181
-			'too long filename "."' => [
182
-				str_repeat('a', 251), [], [], [], [], FileNameTooLongException::class
183
-			],
184
-			// make sure to not split the list entries as they migh contain Unicode sequences
185
-			// in this example the "face in clouds" emoji contains the clouds emoji so only having clouds is ok
186
-			['
Please login to merge, or discard this patch.
tests/lib/App/AppManagerTest.php 1 patch
Indentation   +851 added lines, -851 removed lines patch added patch discarded remove patch
@@ -36,856 +36,856 @@
 block discarded – undo
36 36
  * @package Test\App
37 37
  */
38 38
 class AppManagerTest extends TestCase {
39
-	/**
40
-	 * @return AppConfig|MockObject
41
-	 */
42
-	protected function getAppConfig() {
43
-		$appConfig = [];
44
-		$config = $this->createMock(AppConfig::class);
45
-
46
-		$config->expects($this->any())
47
-			->method('getValue')
48
-			->willReturnCallback(function ($app, $key, $default) use (&$appConfig) {
49
-				return (isset($appConfig[$app]) and isset($appConfig[$app][$key])) ? $appConfig[$app][$key] : $default;
50
-			});
51
-		$config->expects($this->any())
52
-			->method('setValue')
53
-			->willReturnCallback(function ($app, $key, $value) use (&$appConfig) {
54
-				if (!isset($appConfig[$app])) {
55
-					$appConfig[$app] = [];
56
-				}
57
-				$appConfig[$app][$key] = $value;
58
-			});
59
-		$config->expects($this->any())
60
-			->method('getValues')
61
-			->willReturnCallback(function ($app, $key) use (&$appConfig) {
62
-				if ($app) {
63
-					return $appConfig[$app];
64
-				} else {
65
-					$values = [];
66
-					foreach ($appConfig as $appid => $appData) {
67
-						if (isset($appData[$key])) {
68
-							$values[$appid] = $appData[$key];
69
-						}
70
-					}
71
-					return $values;
72
-				}
73
-			});
74
-
75
-		return $config;
76
-	}
77
-
78
-	/** @var IUserSession|MockObject */
79
-	protected $userSession;
80
-
81
-	/** @var IConfig|MockObject */
82
-	private $config;
83
-
84
-	/** @var IGroupManager|MockObject */
85
-	protected $groupManager;
86
-
87
-	/** @var AppConfig|MockObject */
88
-	protected $appConfig;
89
-
90
-	/** @var ICache|MockObject */
91
-	protected $cache;
92
-
93
-	/** @var ICacheFactory|MockObject */
94
-	protected $cacheFactory;
95
-
96
-	/** @var IEventDispatcher|MockObject */
97
-	protected $eventDispatcher;
98
-
99
-	/** @var LoggerInterface|MockObject */
100
-	protected $logger;
101
-
102
-	protected IURLGenerator&MockObject $urlGenerator;
103
-
104
-	protected ServerVersion&MockObject $serverVersion;
105
-
106
-	/** @var IAppManager */
107
-	protected $manager;
108
-
109
-	protected function setUp(): void {
110
-		parent::setUp();
111
-
112
-		$this->userSession = $this->createMock(IUserSession::class);
113
-		$this->groupManager = $this->createMock(IGroupManager::class);
114
-		$this->config = $this->createMock(IConfig::class);
115
-		$this->appConfig = $this->getAppConfig();
116
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
117
-		$this->cache = $this->createMock(ICache::class);
118
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
119
-		$this->logger = $this->createMock(LoggerInterface::class);
120
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
121
-		$this->serverVersion = $this->createMock(ServerVersion::class);
122
-
123
-		$this->overwriteService(AppConfig::class, $this->appConfig);
124
-		$this->overwriteService(IURLGenerator::class, $this->urlGenerator);
125
-
126
-		$this->cacheFactory->expects($this->any())
127
-			->method('createDistributed')
128
-			->with('settings')
129
-			->willReturn($this->cache);
130
-
131
-		$this->config
132
-			->method('getSystemValueBool')
133
-			->with('installed', false)
134
-			->willReturn(true);
135
-
136
-		$this->manager = new AppManager(
137
-			$this->userSession,
138
-			$this->config,
139
-			$this->groupManager,
140
-			$this->cacheFactory,
141
-			$this->eventDispatcher,
142
-			$this->logger,
143
-			$this->serverVersion,
144
-		);
145
-	}
146
-
147
-	/**
148
-	 * @dataProvider dataGetAppIcon
149
-	 */
150
-	public function testGetAppIcon($callback, ?bool $dark, ?string $expected): void {
151
-		$this->urlGenerator->expects($this->atLeastOnce())
152
-			->method('imagePath')
153
-			->willReturnCallback($callback);
154
-
155
-		if ($dark !== null) {
156
-			$this->assertEquals($expected, $this->manager->getAppIcon('test', $dark));
157
-		} else {
158
-			$this->assertEquals($expected, $this->manager->getAppIcon('test'));
159
-		}
160
-	}
161
-
162
-	public static function dataGetAppIcon(): array {
163
-		$nothing = function ($appId) {
164
-			self::assertEquals('test', $appId);
165
-			throw new \RuntimeException();
166
-		};
167
-
168
-		$createCallback = function ($workingIcons) {
169
-			return function ($appId, $icon) use ($workingIcons) {
170
-				self::assertEquals('test', $appId);
171
-				if (in_array($icon, $workingIcons)) {
172
-					return '/path/' . $icon;
173
-				}
174
-				throw new \RuntimeException();
175
-			};
176
-		};
177
-
178
-		return [
179
-			'does not find anything' => [
180
-				$nothing,
181
-				false,
182
-				null,
183
-			],
184
-			'nothing if request dark but only bright available' => [
185
-				$createCallback(['app.svg']),
186
-				true,
187
-				null,
188
-			],
189
-			'nothing if request bright but only dark available' => [
190
-				$createCallback(['app-dark.svg']),
191
-				false,
192
-				null,
193
-			],
194
-			'bright and only app.svg' => [
195
-				$createCallback(['app.svg']),
196
-				false,
197
-				'/path/app.svg',
198
-			],
199
-			'dark and only app-dark.svg' => [
200
-				$createCallback(['app-dark.svg']),
201
-				true,
202
-				'/path/app-dark.svg',
203
-			],
204
-			'dark only appname -dark.svg' => [
205
-				$createCallback(['test-dark.svg']),
206
-				true,
207
-				'/path/test-dark.svg',
208
-			],
209
-			'bright and only appname.svg' => [
210
-				$createCallback(['test.svg']),
211
-				false,
212
-				'/path/test.svg',
213
-			],
214
-			'priotize custom over default' => [
215
-				$createCallback(['app.svg', 'test.svg']),
216
-				false,
217
-				'/path/test.svg',
218
-			],
219
-			'defaults to bright' => [
220
-				$createCallback(['test-dark.svg', 'test.svg']),
221
-				null,
222
-				'/path/test.svg',
223
-			],
224
-			'no dark icon on default' => [
225
-				$createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
226
-				false,
227
-				'/path/test.svg',
228
-			],
229
-			'no bright icon on dark' => [
230
-				$createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
231
-				true,
232
-				'/path/test-dark.svg',
233
-			],
234
-		];
235
-	}
236
-
237
-	public function testEnableApp(): void {
238
-		// making sure "files_trashbin" is disabled
239
-		if ($this->manager->isEnabledForUser('files_trashbin')) {
240
-			$this->manager->disableApp('files_trashbin');
241
-		}
242
-		$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('files_trashbin'));
243
-		$this->manager->enableApp('files_trashbin');
244
-		$this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
245
-	}
246
-
247
-	public function testDisableApp(): void {
248
-		$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppDisableEvent('files_trashbin'));
249
-		$this->manager->disableApp('files_trashbin');
250
-		$this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
251
-	}
252
-
253
-	public function testNotEnableIfNotInstalled(): void {
254
-		try {
255
-			$this->manager->enableApp('some_random_name_which_i_hope_is_not_an_app');
256
-			$this->assertFalse(true, 'If this line is reached the expected exception is not thrown.');
257
-		} catch (AppPathNotFoundException $e) {
258
-			// Exception is expected
259
-			$this->assertEquals('Could not find path for some_random_name_which_i_hope_is_not_an_app', $e->getMessage());
260
-		}
261
-
262
-		$this->assertEquals('no', $this->appConfig->getValue(
263
-			'some_random_name_which_i_hope_is_not_an_app', 'enabled', 'no'
264
-		));
265
-	}
266
-
267
-	public function testEnableAppForGroups(): void {
268
-		$group1 = $this->createMock(IGroup::class);
269
-		$group1->method('getGID')
270
-			->willReturn('group1');
271
-		$group2 = $this->createMock(IGroup::class);
272
-		$group2->method('getGID')
273
-			->willReturn('group2');
274
-
275
-		$groups = [$group1, $group2];
276
-
277
-		/** @var AppManager|MockObject $manager */
278
-		$manager = $this->getMockBuilder(AppManager::class)
279
-			->setConstructorArgs([
280
-				$this->userSession,
281
-				$this->config,
282
-				$this->groupManager,
283
-				$this->cacheFactory,
284
-				$this->eventDispatcher,
285
-				$this->logger,
286
-				$this->serverVersion,
287
-			])
288
-			->onlyMethods([
289
-				'getAppPath',
290
-			])
291
-			->getMock();
292
-
293
-		$manager->expects($this->exactly(2))
294
-			->method('getAppPath')
295
-			->with('test')
296
-			->willReturn('apps/test');
297
-
298
-		$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
299
-
300
-		$manager->enableAppForGroups('test', $groups);
301
-		$this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
302
-	}
303
-
304
-	public static function dataEnableAppForGroupsAllowedTypes(): array {
305
-		return [
306
-			[[]],
307
-			[[
308
-				'types' => [],
309
-			]],
310
-			[[
311
-				'types' => ['nickvergessen'],
312
-			]],
313
-		];
314
-	}
315
-
316
-	/**
317
-	 * @dataProvider dataEnableAppForGroupsAllowedTypes
318
-	 *
319
-	 * @param array $appInfo
320
-	 */
321
-	public function testEnableAppForGroupsAllowedTypes(array $appInfo): void {
322
-		$group1 = $this->createMock(IGroup::class);
323
-		$group1->method('getGID')
324
-			->willReturn('group1');
325
-		$group2 = $this->createMock(IGroup::class);
326
-		$group2->method('getGID')
327
-			->willReturn('group2');
328
-
329
-		$groups = [$group1, $group2];
330
-
331
-		/** @var AppManager|MockObject $manager */
332
-		$manager = $this->getMockBuilder(AppManager::class)
333
-			->setConstructorArgs([
334
-				$this->userSession,
335
-				$this->config,
336
-				$this->groupManager,
337
-				$this->cacheFactory,
338
-				$this->eventDispatcher,
339
-				$this->logger,
340
-				$this->serverVersion,
341
-			])
342
-			->onlyMethods([
343
-				'getAppPath',
344
-				'getAppInfo',
345
-			])
346
-			->getMock();
347
-
348
-		$manager->expects($this->once())
349
-			->method('getAppPath')
350
-			->with('test')
351
-			->willReturn('');
352
-
353
-		$manager->expects($this->once())
354
-			->method('getAppInfo')
355
-			->with('test')
356
-			->willReturn($appInfo);
357
-
358
-		$this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
359
-
360
-		$manager->enableAppForGroups('test', $groups);
361
-		$this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
362
-	}
363
-
364
-	public static function dataEnableAppForGroupsForbiddenTypes(): array {
365
-		return [
366
-			['filesystem'],
367
-			['prelogin'],
368
-			['authentication'],
369
-			['logging'],
370
-			['prevent_group_restriction'],
371
-		];
372
-	}
373
-
374
-	/**
375
-	 * @dataProvider dataEnableAppForGroupsForbiddenTypes
376
-	 *
377
-	 * @param string $type
378
-	 *
379
-	 */
380
-	public function testEnableAppForGroupsForbiddenTypes($type): void {
381
-		$this->expectException(\Exception::class);
382
-		$this->expectExceptionMessage('test can\'t be enabled for groups.');
383
-
384
-		$group1 = $this->createMock(IGroup::class);
385
-		$group1->method('getGID')
386
-			->willReturn('group1');
387
-		$group2 = $this->createMock(IGroup::class);
388
-		$group2->method('getGID')
389
-			->willReturn('group2');
390
-
391
-		$groups = [$group1, $group2];
392
-
393
-		/** @var AppManager|MockObject $manager */
394
-		$manager = $this->getMockBuilder(AppManager::class)
395
-			->setConstructorArgs([
396
-				$this->userSession,
397
-				$this->config,
398
-				$this->groupManager,
399
-				$this->cacheFactory,
400
-				$this->eventDispatcher,
401
-				$this->logger,
402
-				$this->serverVersion,
403
-			])
404
-			->onlyMethods([
405
-				'getAppPath',
406
-				'getAppInfo',
407
-			])
408
-			->getMock();
409
-
410
-		$manager->expects($this->once())
411
-			->method('getAppPath')
412
-			->with('test')
413
-			->willReturn('');
414
-
415
-		$manager->expects($this->once())
416
-			->method('getAppInfo')
417
-			->with('test')
418
-			->willReturn([
419
-				'types' => [$type],
420
-			]);
421
-
422
-		$this->eventDispatcher->expects($this->never())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
423
-
424
-		$manager->enableAppForGroups('test', $groups);
425
-	}
426
-
427
-	public function testIsInstalledEnabled(): void {
428
-		$this->appConfig->setValue('test', 'enabled', 'yes');
429
-		$this->assertTrue($this->manager->isEnabledForAnyone('test'));
430
-	}
431
-
432
-	public function testIsInstalledDisabled(): void {
433
-		$this->appConfig->setValue('test', 'enabled', 'no');
434
-		$this->assertFalse($this->manager->isEnabledForAnyone('test'));
435
-	}
436
-
437
-	public function testIsInstalledEnabledForGroups(): void {
438
-		$this->appConfig->setValue('test', 'enabled', '["foo"]');
439
-		$this->assertTrue($this->manager->isEnabledForAnyone('test'));
440
-	}
441
-
442
-	private function newUser($uid) {
443
-		$user = $this->createMock(IUser::class);
444
-		$user->method('getUID')
445
-			->willReturn($uid);
446
-
447
-		return $user;
448
-	}
449
-
450
-	public function testIsEnabledForUserEnabled(): void {
451
-		$this->appConfig->setValue('test', 'enabled', 'yes');
452
-		$user = $this->newUser('user1');
453
-		$this->assertTrue($this->manager->isEnabledForUser('test', $user));
454
-	}
455
-
456
-	public function testIsEnabledForUserDisabled(): void {
457
-		$this->appConfig->setValue('test', 'enabled', 'no');
458
-		$user = $this->newUser('user1');
459
-		$this->assertFalse($this->manager->isEnabledForUser('test', $user));
460
-	}
461
-
462
-	public function testGetAppPath(): void {
463
-		$this->assertEquals(\OC::$SERVERROOT . '/apps/files', $this->manager->getAppPath('files'));
464
-	}
465
-
466
-	public function testGetAppPathSymlink(): void {
467
-		$fakeAppDirname = sha1(uniqid('test', true));
468
-		$fakeAppPath = sys_get_temp_dir() . '/' . $fakeAppDirname;
469
-		$fakeAppLink = \OC::$SERVERROOT . '/' . $fakeAppDirname;
470
-
471
-		mkdir($fakeAppPath);
472
-		if (symlink($fakeAppPath, $fakeAppLink) === false) {
473
-			$this->markTestSkipped('Failed to create symlink');
474
-		}
475
-
476
-		// Use the symlink as the app path
477
-		\OC::$APPSROOTS[] = [
478
-			'path' => $fakeAppLink,
479
-			'url' => \OC::$WEBROOT . '/' . $fakeAppDirname,
480
-			'writable' => false,
481
-		];
482
-
483
-		$fakeTestAppPath = $fakeAppPath . '/' . 'test-test-app';
484
-		mkdir($fakeTestAppPath);
485
-
486
-		$generatedAppPath = $this->manager->getAppPath('test-test-app');
487
-
488
-		rmdir($fakeTestAppPath);
489
-		unlink($fakeAppLink);
490
-		rmdir($fakeAppPath);
491
-
492
-		$this->assertEquals($fakeAppLink . '/test-test-app', $generatedAppPath);
493
-	}
494
-
495
-	public function testGetAppPathFail(): void {
496
-		$this->expectException(AppPathNotFoundException::class);
497
-		$this->manager->getAppPath('testnotexisting');
498
-	}
499
-
500
-	public function testIsEnabledForUserEnabledForGroup(): void {
501
-		$user = $this->newUser('user1');
502
-		$this->groupManager->expects($this->once())
503
-			->method('getUserGroupIds')
504
-			->with($user)
505
-			->willReturn(['foo', 'bar']);
506
-
507
-		$this->appConfig->setValue('test', 'enabled', '["foo"]');
508
-		$this->assertTrue($this->manager->isEnabledForUser('test', $user));
509
-	}
510
-
511
-	public function testIsEnabledForUserDisabledForGroup(): void {
512
-		$user = $this->newUser('user1');
513
-		$this->groupManager->expects($this->once())
514
-			->method('getUserGroupIds')
515
-			->with($user)
516
-			->willReturn(['bar']);
517
-
518
-		$this->appConfig->setValue('test', 'enabled', '["foo"]');
519
-		$this->assertFalse($this->manager->isEnabledForUser('test', $user));
520
-	}
521
-
522
-	public function testIsEnabledForUserLoggedOut(): void {
523
-		$this->appConfig->setValue('test', 'enabled', '["foo"]');
524
-		$this->assertFalse($this->manager->isEnabledForUser('test'));
525
-	}
526
-
527
-	public function testIsEnabledForUserLoggedIn(): void {
528
-		$user = $this->newUser('user1');
529
-
530
-		$this->userSession->expects($this->once())
531
-			->method('getUser')
532
-			->willReturn($user);
533
-		$this->groupManager->expects($this->once())
534
-			->method('getUserGroupIds')
535
-			->with($user)
536
-			->willReturn(['foo', 'bar']);
537
-
538
-		$this->appConfig->setValue('test', 'enabled', '["foo"]');
539
-		$this->assertTrue($this->manager->isEnabledForUser('test'));
540
-	}
541
-
542
-	public function testGetEnabledApps(): void {
543
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
544
-		$this->appConfig->setValue('test2', 'enabled', 'no');
545
-		$this->appConfig->setValue('test3', 'enabled', '["foo"]');
546
-		$apps = [
547
-			'cloud_federation_api',
548
-			'dav',
549
-			'federatedfilesharing',
550
-			'files',
551
-			'lookup_server_connector',
552
-			'oauth2',
553
-			'profile',
554
-			'provisioning_api',
555
-			'settings',
556
-			'test1',
557
-			'test3',
558
-			'theming',
559
-			'twofactor_backupcodes',
560
-			'viewer',
561
-			'workflowengine',
562
-		];
563
-		$this->assertEquals($apps, $this->manager->getEnabledApps());
564
-	}
565
-
566
-	public function testGetAppsForUser(): void {
567
-		$user = $this->newUser('user1');
568
-		$this->groupManager->expects($this->any())
569
-			->method('getUserGroupIds')
570
-			->with($user)
571
-			->willReturn(['foo', 'bar']);
572
-
573
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
574
-		$this->appConfig->setValue('test2', 'enabled', 'no');
575
-		$this->appConfig->setValue('test3', 'enabled', '["foo"]');
576
-		$this->appConfig->setValue('test4', 'enabled', '["asd"]');
577
-		$enabled = [
578
-			'cloud_federation_api',
579
-			'dav',
580
-			'federatedfilesharing',
581
-			'files',
582
-			'lookup_server_connector',
583
-			'oauth2',
584
-			'profile',
585
-			'provisioning_api',
586
-			'settings',
587
-			'test1',
588
-			'test3',
589
-			'theming',
590
-			'twofactor_backupcodes',
591
-			'viewer',
592
-			'workflowengine',
593
-		];
594
-		$this->assertEquals($enabled, $this->manager->getEnabledAppsForUser($user));
595
-	}
596
-
597
-	public function testGetAppsNeedingUpgrade(): void {
598
-		/** @var AppManager|MockObject $manager */
599
-		$manager = $this->getMockBuilder(AppManager::class)
600
-			->setConstructorArgs([
601
-				$this->userSession,
602
-				$this->config,
603
-				$this->groupManager,
604
-				$this->cacheFactory,
605
-				$this->eventDispatcher,
606
-				$this->logger,
607
-				$this->serverVersion,
608
-			])
609
-			->onlyMethods(['getAppInfo'])
610
-			->getMock();
611
-
612
-		$appInfos = [
613
-			'cloud_federation_api' => ['id' => 'cloud_federation_api'],
614
-			'dav' => ['id' => 'dav'],
615
-			'files' => ['id' => 'files'],
616
-			'federatedfilesharing' => ['id' => 'federatedfilesharing'],
617
-			'profile' => ['id' => 'profile'],
618
-			'provisioning_api' => ['id' => 'provisioning_api'],
619
-			'lookup_server_connector' => ['id' => 'lookup_server_connector'],
620
-			'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'],
621
-			'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
622
-			'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
623
-			'test4' => ['id' => 'test4', 'version' => '3.0.0', 'requiremin' => '8.1.0'],
624
-			'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
625
-			'settings' => ['id' => 'settings'],
626
-			'theming' => ['id' => 'theming'],
627
-			'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
628
-			'viewer' => ['id' => 'viewer'],
629
-			'workflowengine' => ['id' => 'workflowengine'],
630
-			'oauth2' => ['id' => 'oauth2'],
631
-		];
632
-
633
-		$manager->expects($this->any())
634
-			->method('getAppInfo')
635
-			->willReturnCallback(
636
-				function ($appId) use ($appInfos) {
637
-					return $appInfos[$appId];
638
-				}
639
-			);
640
-
641
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
642
-		$this->appConfig->setValue('test1', 'installed_version', '1.0.0');
643
-		$this->appConfig->setValue('test2', 'enabled', 'yes');
644
-		$this->appConfig->setValue('test2', 'installed_version', '1.0.0');
645
-		$this->appConfig->setValue('test3', 'enabled', 'yes');
646
-		$this->appConfig->setValue('test3', 'installed_version', '1.0.0');
647
-		$this->appConfig->setValue('test4', 'enabled', 'yes');
648
-		$this->appConfig->setValue('test4', 'installed_version', '2.4.0');
649
-
650
-		$apps = $manager->getAppsNeedingUpgrade('8.2.0');
651
-
652
-		$this->assertCount(2, $apps);
653
-		$this->assertEquals('test1', $apps[0]['id']);
654
-		$this->assertEquals('test4', $apps[1]['id']);
655
-	}
656
-
657
-	public function testGetIncompatibleApps(): void {
658
-		/** @var AppManager|MockObject $manager */
659
-		$manager = $this->getMockBuilder(AppManager::class)
660
-			->setConstructorArgs([
661
-				$this->userSession,
662
-				$this->config,
663
-				$this->groupManager,
664
-				$this->cacheFactory,
665
-				$this->eventDispatcher,
666
-				$this->logger,
667
-				$this->serverVersion,
668
-			])
669
-			->onlyMethods(['getAppInfo'])
670
-			->getMock();
671
-
672
-		$appInfos = [
673
-			'cloud_federation_api' => ['id' => 'cloud_federation_api'],
674
-			'dav' => ['id' => 'dav'],
675
-			'files' => ['id' => 'files'],
676
-			'federatedfilesharing' => ['id' => 'federatedfilesharing'],
677
-			'profile' => ['id' => 'profile'],
678
-			'provisioning_api' => ['id' => 'provisioning_api'],
679
-			'lookup_server_connector' => ['id' => 'lookup_server_connector'],
680
-			'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'],
681
-			'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
682
-			'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
683
-			'settings' => ['id' => 'settings'],
684
-			'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
685
-			'theming' => ['id' => 'theming'],
686
-			'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
687
-			'workflowengine' => ['id' => 'workflowengine'],
688
-			'oauth2' => ['id' => 'oauth2'],
689
-			'viewer' => ['id' => 'viewer'],
690
-		];
691
-
692
-		$manager->expects($this->any())
693
-			->method('getAppInfo')
694
-			->willReturnCallback(
695
-				function ($appId) use ($appInfos) {
696
-					return $appInfos[$appId];
697
-				}
698
-			);
699
-
700
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
701
-		$this->appConfig->setValue('test2', 'enabled', 'yes');
702
-		$this->appConfig->setValue('test3', 'enabled', 'yes');
703
-
704
-		$apps = $manager->getIncompatibleApps('8.2.0');
705
-
706
-		$this->assertCount(2, $apps);
707
-		$this->assertEquals('test1', $apps[0]['id']);
708
-		$this->assertEquals('test3', $apps[1]['id']);
709
-	}
710
-
711
-	public function testGetEnabledAppsForGroup(): void {
712
-		$group = $this->createMock(IGroup::class);
713
-		$group->expects($this->any())
714
-			->method('getGID')
715
-			->willReturn('foo');
716
-
717
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
718
-		$this->appConfig->setValue('test2', 'enabled', 'no');
719
-		$this->appConfig->setValue('test3', 'enabled', '["foo"]');
720
-		$this->appConfig->setValue('test4', 'enabled', '["asd"]');
721
-		$enabled = [
722
-			'cloud_federation_api',
723
-			'dav',
724
-			'federatedfilesharing',
725
-			'files',
726
-			'lookup_server_connector',
727
-			'oauth2',
728
-			'profile',
729
-			'provisioning_api',
730
-			'settings',
731
-			'test1',
732
-			'test3',
733
-			'theming',
734
-			'twofactor_backupcodes',
735
-			'viewer',
736
-			'workflowengine',
737
-		];
738
-		$this->assertEquals($enabled, $this->manager->getEnabledAppsForGroup($group));
739
-	}
740
-
741
-	public function testGetAppRestriction(): void {
742
-		$this->appConfig->setValue('test1', 'enabled', 'yes');
743
-		$this->appConfig->setValue('test2', 'enabled', 'no');
744
-		$this->appConfig->setValue('test3', 'enabled', '["foo"]');
745
-
746
-		$this->assertEquals([], $this->manager->getAppRestriction('test1'));
747
-		$this->assertEquals([], $this->manager->getAppRestriction('test2'));
748
-		$this->assertEquals(['foo'], $this->manager->getAppRestriction('test3'));
749
-	}
750
-
751
-	public static function isBackendRequiredDataProvider(): array {
752
-		return [
753
-			// backend available
754
-			[
755
-				'caldav',
756
-				['app1' => ['caldav']],
757
-				true,
758
-			],
759
-			[
760
-				'caldav',
761
-				['app1' => [], 'app2' => ['foo'], 'app3' => ['caldav']],
762
-				true,
763
-			],
764
-			// backend not available
765
-			[
766
-				'caldav',
767
-				['app3' => [], 'app1' => ['foo'], 'app2' => ['bar', 'baz']],
768
-				false,
769
-			],
770
-			// no app available
771
-			[
772
-				'caldav',
773
-				[],
774
-				false,
775
-			],
776
-		];
777
-	}
778
-
779
-	/**
780
-	 * @dataProvider isBackendRequiredDataProvider
781
-	 */
782
-	public function testIsBackendRequired(
783
-		string $backend,
784
-		array $appBackends,
785
-		bool $expected,
786
-	): void {
787
-		$appInfoData = array_map(
788
-			static fn (array $backends) => ['dependencies' => ['backend' => $backends]],
789
-			$appBackends,
790
-		);
791
-
792
-		$reflection = new \ReflectionClass($this->manager);
793
-		$property = $reflection->getProperty('appInfos');
794
-		$property->setValue($this->manager, $appInfoData);
795
-
796
-		$this->assertEquals($expected, $this->manager->isBackendRequired($backend));
797
-	}
798
-
799
-	public function testGetAppVersion() {
800
-		$manager = $this->getMockBuilder(AppManager::class)
801
-			->setConstructorArgs([
802
-				$this->userSession,
803
-				$this->config,
804
-				$this->groupManager,
805
-				$this->cacheFactory,
806
-				$this->eventDispatcher,
807
-				$this->logger,
808
-				$this->serverVersion,
809
-			])
810
-			->onlyMethods([
811
-				'getAppInfo',
812
-			])
813
-			->getMock();
814
-
815
-		$manager->expects(self::once())
816
-			->method('getAppInfo')
817
-			->with('myapp')
818
-			->willReturn(['version' => '99.99.99-rc.99']);
819
-
820
-		$this->serverVersion
821
-			->expects(self::never())
822
-			->method('getVersionString');
823
-
824
-		$this->assertEquals(
825
-			'99.99.99-rc.99',
826
-			$manager->getAppVersion('myapp'),
827
-		);
828
-	}
829
-
830
-	public function testGetAppVersionCore() {
831
-		$manager = $this->getMockBuilder(AppManager::class)
832
-			->setConstructorArgs([
833
-				$this->userSession,
834
-				$this->config,
835
-				$this->groupManager,
836
-				$this->cacheFactory,
837
-				$this->eventDispatcher,
838
-				$this->logger,
839
-				$this->serverVersion,
840
-			])
841
-			->onlyMethods([
842
-				'getAppInfo',
843
-			])
844
-			->getMock();
845
-
846
-		$manager->expects(self::never())
847
-			->method('getAppInfo');
848
-
849
-		$this->serverVersion
850
-			->expects(self::once())
851
-			->method('getVersionString')
852
-			->willReturn('1.2.3-beta.4');
853
-
854
-		$this->assertEquals(
855
-			'1.2.3-beta.4',
856
-			$manager->getAppVersion('core'),
857
-		);
858
-	}
859
-
860
-	public function testGetAppVersionUnknown() {
861
-		$manager = $this->getMockBuilder(AppManager::class)
862
-			->setConstructorArgs([
863
-				$this->userSession,
864
-				$this->config,
865
-				$this->groupManager,
866
-				$this->cacheFactory,
867
-				$this->eventDispatcher,
868
-				$this->logger,
869
-				$this->serverVersion,
870
-			])
871
-			->onlyMethods([
872
-				'getAppInfo',
873
-			])
874
-			->getMock();
875
-
876
-		$manager->expects(self::once())
877
-			->method('getAppInfo')
878
-			->with('unknown')
879
-			->willReturn(null);
880
-
881
-		$this->serverVersion
882
-			->expects(self::never())
883
-			->method('getVersionString');
884
-
885
-		$this->assertEquals(
886
-			'0',
887
-			$manager->getAppVersion('unknown'),
888
-		);
889
-	}
39
+    /**
40
+     * @return AppConfig|MockObject
41
+     */
42
+    protected function getAppConfig() {
43
+        $appConfig = [];
44
+        $config = $this->createMock(AppConfig::class);
45
+
46
+        $config->expects($this->any())
47
+            ->method('getValue')
48
+            ->willReturnCallback(function ($app, $key, $default) use (&$appConfig) {
49
+                return (isset($appConfig[$app]) and isset($appConfig[$app][$key])) ? $appConfig[$app][$key] : $default;
50
+            });
51
+        $config->expects($this->any())
52
+            ->method('setValue')
53
+            ->willReturnCallback(function ($app, $key, $value) use (&$appConfig) {
54
+                if (!isset($appConfig[$app])) {
55
+                    $appConfig[$app] = [];
56
+                }
57
+                $appConfig[$app][$key] = $value;
58
+            });
59
+        $config->expects($this->any())
60
+            ->method('getValues')
61
+            ->willReturnCallback(function ($app, $key) use (&$appConfig) {
62
+                if ($app) {
63
+                    return $appConfig[$app];
64
+                } else {
65
+                    $values = [];
66
+                    foreach ($appConfig as $appid => $appData) {
67
+                        if (isset($appData[$key])) {
68
+                            $values[$appid] = $appData[$key];
69
+                        }
70
+                    }
71
+                    return $values;
72
+                }
73
+            });
74
+
75
+        return $config;
76
+    }
77
+
78
+    /** @var IUserSession|MockObject */
79
+    protected $userSession;
80
+
81
+    /** @var IConfig|MockObject */
82
+    private $config;
83
+
84
+    /** @var IGroupManager|MockObject */
85
+    protected $groupManager;
86
+
87
+    /** @var AppConfig|MockObject */
88
+    protected $appConfig;
89
+
90
+    /** @var ICache|MockObject */
91
+    protected $cache;
92
+
93
+    /** @var ICacheFactory|MockObject */
94
+    protected $cacheFactory;
95
+
96
+    /** @var IEventDispatcher|MockObject */
97
+    protected $eventDispatcher;
98
+
99
+    /** @var LoggerInterface|MockObject */
100
+    protected $logger;
101
+
102
+    protected IURLGenerator&MockObject $urlGenerator;
103
+
104
+    protected ServerVersion&MockObject $serverVersion;
105
+
106
+    /** @var IAppManager */
107
+    protected $manager;
108
+
109
+    protected function setUp(): void {
110
+        parent::setUp();
111
+
112
+        $this->userSession = $this->createMock(IUserSession::class);
113
+        $this->groupManager = $this->createMock(IGroupManager::class);
114
+        $this->config = $this->createMock(IConfig::class);
115
+        $this->appConfig = $this->getAppConfig();
116
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
117
+        $this->cache = $this->createMock(ICache::class);
118
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
119
+        $this->logger = $this->createMock(LoggerInterface::class);
120
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
121
+        $this->serverVersion = $this->createMock(ServerVersion::class);
122
+
123
+        $this->overwriteService(AppConfig::class, $this->appConfig);
124
+        $this->overwriteService(IURLGenerator::class, $this->urlGenerator);
125
+
126
+        $this->cacheFactory->expects($this->any())
127
+            ->method('createDistributed')
128
+            ->with('settings')
129
+            ->willReturn($this->cache);
130
+
131
+        $this->config
132
+            ->method('getSystemValueBool')
133
+            ->with('installed', false)
134
+            ->willReturn(true);
135
+
136
+        $this->manager = new AppManager(
137
+            $this->userSession,
138
+            $this->config,
139
+            $this->groupManager,
140
+            $this->cacheFactory,
141
+            $this->eventDispatcher,
142
+            $this->logger,
143
+            $this->serverVersion,
144
+        );
145
+    }
146
+
147
+    /**
148
+     * @dataProvider dataGetAppIcon
149
+     */
150
+    public function testGetAppIcon($callback, ?bool $dark, ?string $expected): void {
151
+        $this->urlGenerator->expects($this->atLeastOnce())
152
+            ->method('imagePath')
153
+            ->willReturnCallback($callback);
154
+
155
+        if ($dark !== null) {
156
+            $this->assertEquals($expected, $this->manager->getAppIcon('test', $dark));
157
+        } else {
158
+            $this->assertEquals($expected, $this->manager->getAppIcon('test'));
159
+        }
160
+    }
161
+
162
+    public static function dataGetAppIcon(): array {
163
+        $nothing = function ($appId) {
164
+            self::assertEquals('test', $appId);
165
+            throw new \RuntimeException();
166
+        };
167
+
168
+        $createCallback = function ($workingIcons) {
169
+            return function ($appId, $icon) use ($workingIcons) {
170
+                self::assertEquals('test', $appId);
171
+                if (in_array($icon, $workingIcons)) {
172
+                    return '/path/' . $icon;
173
+                }
174
+                throw new \RuntimeException();
175
+            };
176
+        };
177
+
178
+        return [
179
+            'does not find anything' => [
180
+                $nothing,
181
+                false,
182
+                null,
183
+            ],
184
+            'nothing if request dark but only bright available' => [
185
+                $createCallback(['app.svg']),
186
+                true,
187
+                null,
188
+            ],
189
+            'nothing if request bright but only dark available' => [
190
+                $createCallback(['app-dark.svg']),
191
+                false,
192
+                null,
193
+            ],
194
+            'bright and only app.svg' => [
195
+                $createCallback(['app.svg']),
196
+                false,
197
+                '/path/app.svg',
198
+            ],
199
+            'dark and only app-dark.svg' => [
200
+                $createCallback(['app-dark.svg']),
201
+                true,
202
+                '/path/app-dark.svg',
203
+            ],
204
+            'dark only appname -dark.svg' => [
205
+                $createCallback(['test-dark.svg']),
206
+                true,
207
+                '/path/test-dark.svg',
208
+            ],
209
+            'bright and only appname.svg' => [
210
+                $createCallback(['test.svg']),
211
+                false,
212
+                '/path/test.svg',
213
+            ],
214
+            'priotize custom over default' => [
215
+                $createCallback(['app.svg', 'test.svg']),
216
+                false,
217
+                '/path/test.svg',
218
+            ],
219
+            'defaults to bright' => [
220
+                $createCallback(['test-dark.svg', 'test.svg']),
221
+                null,
222
+                '/path/test.svg',
223
+            ],
224
+            'no dark icon on default' => [
225
+                $createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
226
+                false,
227
+                '/path/test.svg',
228
+            ],
229
+            'no bright icon on dark' => [
230
+                $createCallback(['test-dark.svg', 'test.svg', 'app-dark.svg', 'app.svg']),
231
+                true,
232
+                '/path/test-dark.svg',
233
+            ],
234
+        ];
235
+    }
236
+
237
+    public function testEnableApp(): void {
238
+        // making sure "files_trashbin" is disabled
239
+        if ($this->manager->isEnabledForUser('files_trashbin')) {
240
+            $this->manager->disableApp('files_trashbin');
241
+        }
242
+        $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('files_trashbin'));
243
+        $this->manager->enableApp('files_trashbin');
244
+        $this->assertEquals('yes', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
245
+    }
246
+
247
+    public function testDisableApp(): void {
248
+        $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppDisableEvent('files_trashbin'));
249
+        $this->manager->disableApp('files_trashbin');
250
+        $this->assertEquals('no', $this->appConfig->getValue('files_trashbin', 'enabled', 'no'));
251
+    }
252
+
253
+    public function testNotEnableIfNotInstalled(): void {
254
+        try {
255
+            $this->manager->enableApp('some_random_name_which_i_hope_is_not_an_app');
256
+            $this->assertFalse(true, 'If this line is reached the expected exception is not thrown.');
257
+        } catch (AppPathNotFoundException $e) {
258
+            // Exception is expected
259
+            $this->assertEquals('Could not find path for some_random_name_which_i_hope_is_not_an_app', $e->getMessage());
260
+        }
261
+
262
+        $this->assertEquals('no', $this->appConfig->getValue(
263
+            'some_random_name_which_i_hope_is_not_an_app', 'enabled', 'no'
264
+        ));
265
+    }
266
+
267
+    public function testEnableAppForGroups(): void {
268
+        $group1 = $this->createMock(IGroup::class);
269
+        $group1->method('getGID')
270
+            ->willReturn('group1');
271
+        $group2 = $this->createMock(IGroup::class);
272
+        $group2->method('getGID')
273
+            ->willReturn('group2');
274
+
275
+        $groups = [$group1, $group2];
276
+
277
+        /** @var AppManager|MockObject $manager */
278
+        $manager = $this->getMockBuilder(AppManager::class)
279
+            ->setConstructorArgs([
280
+                $this->userSession,
281
+                $this->config,
282
+                $this->groupManager,
283
+                $this->cacheFactory,
284
+                $this->eventDispatcher,
285
+                $this->logger,
286
+                $this->serverVersion,
287
+            ])
288
+            ->onlyMethods([
289
+                'getAppPath',
290
+            ])
291
+            ->getMock();
292
+
293
+        $manager->expects($this->exactly(2))
294
+            ->method('getAppPath')
295
+            ->with('test')
296
+            ->willReturn('apps/test');
297
+
298
+        $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
299
+
300
+        $manager->enableAppForGroups('test', $groups);
301
+        $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
302
+    }
303
+
304
+    public static function dataEnableAppForGroupsAllowedTypes(): array {
305
+        return [
306
+            [[]],
307
+            [[
308
+                'types' => [],
309
+            ]],
310
+            [[
311
+                'types' => ['nickvergessen'],
312
+            ]],
313
+        ];
314
+    }
315
+
316
+    /**
317
+     * @dataProvider dataEnableAppForGroupsAllowedTypes
318
+     *
319
+     * @param array $appInfo
320
+     */
321
+    public function testEnableAppForGroupsAllowedTypes(array $appInfo): void {
322
+        $group1 = $this->createMock(IGroup::class);
323
+        $group1->method('getGID')
324
+            ->willReturn('group1');
325
+        $group2 = $this->createMock(IGroup::class);
326
+        $group2->method('getGID')
327
+            ->willReturn('group2');
328
+
329
+        $groups = [$group1, $group2];
330
+
331
+        /** @var AppManager|MockObject $manager */
332
+        $manager = $this->getMockBuilder(AppManager::class)
333
+            ->setConstructorArgs([
334
+                $this->userSession,
335
+                $this->config,
336
+                $this->groupManager,
337
+                $this->cacheFactory,
338
+                $this->eventDispatcher,
339
+                $this->logger,
340
+                $this->serverVersion,
341
+            ])
342
+            ->onlyMethods([
343
+                'getAppPath',
344
+                'getAppInfo',
345
+            ])
346
+            ->getMock();
347
+
348
+        $manager->expects($this->once())
349
+            ->method('getAppPath')
350
+            ->with('test')
351
+            ->willReturn('');
352
+
353
+        $manager->expects($this->once())
354
+            ->method('getAppInfo')
355
+            ->with('test')
356
+            ->willReturn($appInfo);
357
+
358
+        $this->eventDispatcher->expects($this->once())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
359
+
360
+        $manager->enableAppForGroups('test', $groups);
361
+        $this->assertEquals('["group1","group2"]', $this->appConfig->getValue('test', 'enabled', 'no'));
362
+    }
363
+
364
+    public static function dataEnableAppForGroupsForbiddenTypes(): array {
365
+        return [
366
+            ['filesystem'],
367
+            ['prelogin'],
368
+            ['authentication'],
369
+            ['logging'],
370
+            ['prevent_group_restriction'],
371
+        ];
372
+    }
373
+
374
+    /**
375
+     * @dataProvider dataEnableAppForGroupsForbiddenTypes
376
+     *
377
+     * @param string $type
378
+     *
379
+     */
380
+    public function testEnableAppForGroupsForbiddenTypes($type): void {
381
+        $this->expectException(\Exception::class);
382
+        $this->expectExceptionMessage('test can\'t be enabled for groups.');
383
+
384
+        $group1 = $this->createMock(IGroup::class);
385
+        $group1->method('getGID')
386
+            ->willReturn('group1');
387
+        $group2 = $this->createMock(IGroup::class);
388
+        $group2->method('getGID')
389
+            ->willReturn('group2');
390
+
391
+        $groups = [$group1, $group2];
392
+
393
+        /** @var AppManager|MockObject $manager */
394
+        $manager = $this->getMockBuilder(AppManager::class)
395
+            ->setConstructorArgs([
396
+                $this->userSession,
397
+                $this->config,
398
+                $this->groupManager,
399
+                $this->cacheFactory,
400
+                $this->eventDispatcher,
401
+                $this->logger,
402
+                $this->serverVersion,
403
+            ])
404
+            ->onlyMethods([
405
+                'getAppPath',
406
+                'getAppInfo',
407
+            ])
408
+            ->getMock();
409
+
410
+        $manager->expects($this->once())
411
+            ->method('getAppPath')
412
+            ->with('test')
413
+            ->willReturn('');
414
+
415
+        $manager->expects($this->once())
416
+            ->method('getAppInfo')
417
+            ->with('test')
418
+            ->willReturn([
419
+                'types' => [$type],
420
+            ]);
421
+
422
+        $this->eventDispatcher->expects($this->never())->method('dispatchTyped')->with(new AppEnableEvent('test', ['group1', 'group2']));
423
+
424
+        $manager->enableAppForGroups('test', $groups);
425
+    }
426
+
427
+    public function testIsInstalledEnabled(): void {
428
+        $this->appConfig->setValue('test', 'enabled', 'yes');
429
+        $this->assertTrue($this->manager->isEnabledForAnyone('test'));
430
+    }
431
+
432
+    public function testIsInstalledDisabled(): void {
433
+        $this->appConfig->setValue('test', 'enabled', 'no');
434
+        $this->assertFalse($this->manager->isEnabledForAnyone('test'));
435
+    }
436
+
437
+    public function testIsInstalledEnabledForGroups(): void {
438
+        $this->appConfig->setValue('test', 'enabled', '["foo"]');
439
+        $this->assertTrue($this->manager->isEnabledForAnyone('test'));
440
+    }
441
+
442
+    private function newUser($uid) {
443
+        $user = $this->createMock(IUser::class);
444
+        $user->method('getUID')
445
+            ->willReturn($uid);
446
+
447
+        return $user;
448
+    }
449
+
450
+    public function testIsEnabledForUserEnabled(): void {
451
+        $this->appConfig->setValue('test', 'enabled', 'yes');
452
+        $user = $this->newUser('user1');
453
+        $this->assertTrue($this->manager->isEnabledForUser('test', $user));
454
+    }
455
+
456
+    public function testIsEnabledForUserDisabled(): void {
457
+        $this->appConfig->setValue('test', 'enabled', 'no');
458
+        $user = $this->newUser('user1');
459
+        $this->assertFalse($this->manager->isEnabledForUser('test', $user));
460
+    }
461
+
462
+    public function testGetAppPath(): void {
463
+        $this->assertEquals(\OC::$SERVERROOT . '/apps/files', $this->manager->getAppPath('files'));
464
+    }
465
+
466
+    public function testGetAppPathSymlink(): void {
467
+        $fakeAppDirname = sha1(uniqid('test', true));
468
+        $fakeAppPath = sys_get_temp_dir() . '/' . $fakeAppDirname;
469
+        $fakeAppLink = \OC::$SERVERROOT . '/' . $fakeAppDirname;
470
+
471
+        mkdir($fakeAppPath);
472
+        if (symlink($fakeAppPath, $fakeAppLink) === false) {
473
+            $this->markTestSkipped('Failed to create symlink');
474
+        }
475
+
476
+        // Use the symlink as the app path
477
+        \OC::$APPSROOTS[] = [
478
+            'path' => $fakeAppLink,
479
+            'url' => \OC::$WEBROOT . '/' . $fakeAppDirname,
480
+            'writable' => false,
481
+        ];
482
+
483
+        $fakeTestAppPath = $fakeAppPath . '/' . 'test-test-app';
484
+        mkdir($fakeTestAppPath);
485
+
486
+        $generatedAppPath = $this->manager->getAppPath('test-test-app');
487
+
488
+        rmdir($fakeTestAppPath);
489
+        unlink($fakeAppLink);
490
+        rmdir($fakeAppPath);
491
+
492
+        $this->assertEquals($fakeAppLink . '/test-test-app', $generatedAppPath);
493
+    }
494
+
495
+    public function testGetAppPathFail(): void {
496
+        $this->expectException(AppPathNotFoundException::class);
497
+        $this->manager->getAppPath('testnotexisting');
498
+    }
499
+
500
+    public function testIsEnabledForUserEnabledForGroup(): void {
501
+        $user = $this->newUser('user1');
502
+        $this->groupManager->expects($this->once())
503
+            ->method('getUserGroupIds')
504
+            ->with($user)
505
+            ->willReturn(['foo', 'bar']);
506
+
507
+        $this->appConfig->setValue('test', 'enabled', '["foo"]');
508
+        $this->assertTrue($this->manager->isEnabledForUser('test', $user));
509
+    }
510
+
511
+    public function testIsEnabledForUserDisabledForGroup(): void {
512
+        $user = $this->newUser('user1');
513
+        $this->groupManager->expects($this->once())
514
+            ->method('getUserGroupIds')
515
+            ->with($user)
516
+            ->willReturn(['bar']);
517
+
518
+        $this->appConfig->setValue('test', 'enabled', '["foo"]');
519
+        $this->assertFalse($this->manager->isEnabledForUser('test', $user));
520
+    }
521
+
522
+    public function testIsEnabledForUserLoggedOut(): void {
523
+        $this->appConfig->setValue('test', 'enabled', '["foo"]');
524
+        $this->assertFalse($this->manager->isEnabledForUser('test'));
525
+    }
526
+
527
+    public function testIsEnabledForUserLoggedIn(): void {
528
+        $user = $this->newUser('user1');
529
+
530
+        $this->userSession->expects($this->once())
531
+            ->method('getUser')
532
+            ->willReturn($user);
533
+        $this->groupManager->expects($this->once())
534
+            ->method('getUserGroupIds')
535
+            ->with($user)
536
+            ->willReturn(['foo', 'bar']);
537
+
538
+        $this->appConfig->setValue('test', 'enabled', '["foo"]');
539
+        $this->assertTrue($this->manager->isEnabledForUser('test'));
540
+    }
541
+
542
+    public function testGetEnabledApps(): void {
543
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
544
+        $this->appConfig->setValue('test2', 'enabled', 'no');
545
+        $this->appConfig->setValue('test3', 'enabled', '["foo"]');
546
+        $apps = [
547
+            'cloud_federation_api',
548
+            'dav',
549
+            'federatedfilesharing',
550
+            'files',
551
+            'lookup_server_connector',
552
+            'oauth2',
553
+            'profile',
554
+            'provisioning_api',
555
+            'settings',
556
+            'test1',
557
+            'test3',
558
+            'theming',
559
+            'twofactor_backupcodes',
560
+            'viewer',
561
+            'workflowengine',
562
+        ];
563
+        $this->assertEquals($apps, $this->manager->getEnabledApps());
564
+    }
565
+
566
+    public function testGetAppsForUser(): void {
567
+        $user = $this->newUser('user1');
568
+        $this->groupManager->expects($this->any())
569
+            ->method('getUserGroupIds')
570
+            ->with($user)
571
+            ->willReturn(['foo', 'bar']);
572
+
573
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
574
+        $this->appConfig->setValue('test2', 'enabled', 'no');
575
+        $this->appConfig->setValue('test3', 'enabled', '["foo"]');
576
+        $this->appConfig->setValue('test4', 'enabled', '["asd"]');
577
+        $enabled = [
578
+            'cloud_federation_api',
579
+            'dav',
580
+            'federatedfilesharing',
581
+            'files',
582
+            'lookup_server_connector',
583
+            'oauth2',
584
+            'profile',
585
+            'provisioning_api',
586
+            'settings',
587
+            'test1',
588
+            'test3',
589
+            'theming',
590
+            'twofactor_backupcodes',
591
+            'viewer',
592
+            'workflowengine',
593
+        ];
594
+        $this->assertEquals($enabled, $this->manager->getEnabledAppsForUser($user));
595
+    }
596
+
597
+    public function testGetAppsNeedingUpgrade(): void {
598
+        /** @var AppManager|MockObject $manager */
599
+        $manager = $this->getMockBuilder(AppManager::class)
600
+            ->setConstructorArgs([
601
+                $this->userSession,
602
+                $this->config,
603
+                $this->groupManager,
604
+                $this->cacheFactory,
605
+                $this->eventDispatcher,
606
+                $this->logger,
607
+                $this->serverVersion,
608
+            ])
609
+            ->onlyMethods(['getAppInfo'])
610
+            ->getMock();
611
+
612
+        $appInfos = [
613
+            'cloud_federation_api' => ['id' => 'cloud_federation_api'],
614
+            'dav' => ['id' => 'dav'],
615
+            'files' => ['id' => 'files'],
616
+            'federatedfilesharing' => ['id' => 'federatedfilesharing'],
617
+            'profile' => ['id' => 'profile'],
618
+            'provisioning_api' => ['id' => 'provisioning_api'],
619
+            'lookup_server_connector' => ['id' => 'lookup_server_connector'],
620
+            'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '9.0.0'],
621
+            'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
622
+            'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
623
+            'test4' => ['id' => 'test4', 'version' => '3.0.0', 'requiremin' => '8.1.0'],
624
+            'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
625
+            'settings' => ['id' => 'settings'],
626
+            'theming' => ['id' => 'theming'],
627
+            'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
628
+            'viewer' => ['id' => 'viewer'],
629
+            'workflowengine' => ['id' => 'workflowengine'],
630
+            'oauth2' => ['id' => 'oauth2'],
631
+        ];
632
+
633
+        $manager->expects($this->any())
634
+            ->method('getAppInfo')
635
+            ->willReturnCallback(
636
+                function ($appId) use ($appInfos) {
637
+                    return $appInfos[$appId];
638
+                }
639
+            );
640
+
641
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
642
+        $this->appConfig->setValue('test1', 'installed_version', '1.0.0');
643
+        $this->appConfig->setValue('test2', 'enabled', 'yes');
644
+        $this->appConfig->setValue('test2', 'installed_version', '1.0.0');
645
+        $this->appConfig->setValue('test3', 'enabled', 'yes');
646
+        $this->appConfig->setValue('test3', 'installed_version', '1.0.0');
647
+        $this->appConfig->setValue('test4', 'enabled', 'yes');
648
+        $this->appConfig->setValue('test4', 'installed_version', '2.4.0');
649
+
650
+        $apps = $manager->getAppsNeedingUpgrade('8.2.0');
651
+
652
+        $this->assertCount(2, $apps);
653
+        $this->assertEquals('test1', $apps[0]['id']);
654
+        $this->assertEquals('test4', $apps[1]['id']);
655
+    }
656
+
657
+    public function testGetIncompatibleApps(): void {
658
+        /** @var AppManager|MockObject $manager */
659
+        $manager = $this->getMockBuilder(AppManager::class)
660
+            ->setConstructorArgs([
661
+                $this->userSession,
662
+                $this->config,
663
+                $this->groupManager,
664
+                $this->cacheFactory,
665
+                $this->eventDispatcher,
666
+                $this->logger,
667
+                $this->serverVersion,
668
+            ])
669
+            ->onlyMethods(['getAppInfo'])
670
+            ->getMock();
671
+
672
+        $appInfos = [
673
+            'cloud_federation_api' => ['id' => 'cloud_federation_api'],
674
+            'dav' => ['id' => 'dav'],
675
+            'files' => ['id' => 'files'],
676
+            'federatedfilesharing' => ['id' => 'federatedfilesharing'],
677
+            'profile' => ['id' => 'profile'],
678
+            'provisioning_api' => ['id' => 'provisioning_api'],
679
+            'lookup_server_connector' => ['id' => 'lookup_server_connector'],
680
+            'test1' => ['id' => 'test1', 'version' => '1.0.1', 'requiremax' => '8.0.0'],
681
+            'test2' => ['id' => 'test2', 'version' => '1.0.0', 'requiremin' => '8.2.0'],
682
+            'test3' => ['id' => 'test3', 'version' => '1.2.4', 'requiremin' => '9.0.0'],
683
+            'settings' => ['id' => 'settings'],
684
+            'testnoversion' => ['id' => 'testnoversion', 'requiremin' => '8.2.0'],
685
+            'theming' => ['id' => 'theming'],
686
+            'twofactor_backupcodes' => ['id' => 'twofactor_backupcodes'],
687
+            'workflowengine' => ['id' => 'workflowengine'],
688
+            'oauth2' => ['id' => 'oauth2'],
689
+            'viewer' => ['id' => 'viewer'],
690
+        ];
691
+
692
+        $manager->expects($this->any())
693
+            ->method('getAppInfo')
694
+            ->willReturnCallback(
695
+                function ($appId) use ($appInfos) {
696
+                    return $appInfos[$appId];
697
+                }
698
+            );
699
+
700
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
701
+        $this->appConfig->setValue('test2', 'enabled', 'yes');
702
+        $this->appConfig->setValue('test3', 'enabled', 'yes');
703
+
704
+        $apps = $manager->getIncompatibleApps('8.2.0');
705
+
706
+        $this->assertCount(2, $apps);
707
+        $this->assertEquals('test1', $apps[0]['id']);
708
+        $this->assertEquals('test3', $apps[1]['id']);
709
+    }
710
+
711
+    public function testGetEnabledAppsForGroup(): void {
712
+        $group = $this->createMock(IGroup::class);
713
+        $group->expects($this->any())
714
+            ->method('getGID')
715
+            ->willReturn('foo');
716
+
717
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
718
+        $this->appConfig->setValue('test2', 'enabled', 'no');
719
+        $this->appConfig->setValue('test3', 'enabled', '["foo"]');
720
+        $this->appConfig->setValue('test4', 'enabled', '["asd"]');
721
+        $enabled = [
722
+            'cloud_federation_api',
723
+            'dav',
724
+            'federatedfilesharing',
725
+            'files',
726
+            'lookup_server_connector',
727
+            'oauth2',
728
+            'profile',
729
+            'provisioning_api',
730
+            'settings',
731
+            'test1',
732
+            'test3',
733
+            'theming',
734
+            'twofactor_backupcodes',
735
+            'viewer',
736
+            'workflowengine',
737
+        ];
738
+        $this->assertEquals($enabled, $this->manager->getEnabledAppsForGroup($group));
739
+    }
740
+
741
+    public function testGetAppRestriction(): void {
742
+        $this->appConfig->setValue('test1', 'enabled', 'yes');
743
+        $this->appConfig->setValue('test2', 'enabled', 'no');
744
+        $this->appConfig->setValue('test3', 'enabled', '["foo"]');
745
+
746
+        $this->assertEquals([], $this->manager->getAppRestriction('test1'));
747
+        $this->assertEquals([], $this->manager->getAppRestriction('test2'));
748
+        $this->assertEquals(['foo'], $this->manager->getAppRestriction('test3'));
749
+    }
750
+
751
+    public static function isBackendRequiredDataProvider(): array {
752
+        return [
753
+            // backend available
754
+            [
755
+                'caldav',
756
+                ['app1' => ['caldav']],
757
+                true,
758
+            ],
759
+            [
760
+                'caldav',
761
+                ['app1' => [], 'app2' => ['foo'], 'app3' => ['caldav']],
762
+                true,
763
+            ],
764
+            // backend not available
765
+            [
766
+                'caldav',
767
+                ['app3' => [], 'app1' => ['foo'], 'app2' => ['bar', 'baz']],
768
+                false,
769
+            ],
770
+            // no app available
771
+            [
772
+                'caldav',
773
+                [],
774
+                false,
775
+            ],
776
+        ];
777
+    }
778
+
779
+    /**
780
+     * @dataProvider isBackendRequiredDataProvider
781
+     */
782
+    public function testIsBackendRequired(
783
+        string $backend,
784
+        array $appBackends,
785
+        bool $expected,
786
+    ): void {
787
+        $appInfoData = array_map(
788
+            static fn (array $backends) => ['dependencies' => ['backend' => $backends]],
789
+            $appBackends,
790
+        );
791
+
792
+        $reflection = new \ReflectionClass($this->manager);
793
+        $property = $reflection->getProperty('appInfos');
794
+        $property->setValue($this->manager, $appInfoData);
795
+
796
+        $this->assertEquals($expected, $this->manager->isBackendRequired($backend));
797
+    }
798
+
799
+    public function testGetAppVersion() {
800
+        $manager = $this->getMockBuilder(AppManager::class)
801
+            ->setConstructorArgs([
802
+                $this->userSession,
803
+                $this->config,
804
+                $this->groupManager,
805
+                $this->cacheFactory,
806
+                $this->eventDispatcher,
807
+                $this->logger,
808
+                $this->serverVersion,
809
+            ])
810
+            ->onlyMethods([
811
+                'getAppInfo',
812
+            ])
813
+            ->getMock();
814
+
815
+        $manager->expects(self::once())
816
+            ->method('getAppInfo')
817
+            ->with('myapp')
818
+            ->willReturn(['version' => '99.99.99-rc.99']);
819
+
820
+        $this->serverVersion
821
+            ->expects(self::never())
822
+            ->method('getVersionString');
823
+
824
+        $this->assertEquals(
825
+            '99.99.99-rc.99',
826
+            $manager->getAppVersion('myapp'),
827
+        );
828
+    }
829
+
830
+    public function testGetAppVersionCore() {
831
+        $manager = $this->getMockBuilder(AppManager::class)
832
+            ->setConstructorArgs([
833
+                $this->userSession,
834
+                $this->config,
835
+                $this->groupManager,
836
+                $this->cacheFactory,
837
+                $this->eventDispatcher,
838
+                $this->logger,
839
+                $this->serverVersion,
840
+            ])
841
+            ->onlyMethods([
842
+                'getAppInfo',
843
+            ])
844
+            ->getMock();
845
+
846
+        $manager->expects(self::never())
847
+            ->method('getAppInfo');
848
+
849
+        $this->serverVersion
850
+            ->expects(self::once())
851
+            ->method('getVersionString')
852
+            ->willReturn('1.2.3-beta.4');
853
+
854
+        $this->assertEquals(
855
+            '1.2.3-beta.4',
856
+            $manager->getAppVersion('core'),
857
+        );
858
+    }
859
+
860
+    public function testGetAppVersionUnknown() {
861
+        $manager = $this->getMockBuilder(AppManager::class)
862
+            ->setConstructorArgs([
863
+                $this->userSession,
864
+                $this->config,
865
+                $this->groupManager,
866
+                $this->cacheFactory,
867
+                $this->eventDispatcher,
868
+                $this->logger,
869
+                $this->serverVersion,
870
+            ])
871
+            ->onlyMethods([
872
+                'getAppInfo',
873
+            ])
874
+            ->getMock();
875
+
876
+        $manager->expects(self::once())
877
+            ->method('getAppInfo')
878
+            ->with('unknown')
879
+            ->willReturn(null);
880
+
881
+        $this->serverVersion
882
+            ->expects(self::never())
883
+            ->method('getVersionString');
884
+
885
+        $this->assertEquals(
886
+            '0',
887
+            $manager->getAppVersion('unknown'),
888
+        );
889
+    }
890 890
 
891 891
 }
Please login to merge, or discard this patch.