Completed
Push — master ( 158b3e...c62fa5 )
by Joas
29:53 queued 14s
created
tests/lib/Authentication/TwoFactorAuth/RegistryTest.php 2 patches
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -24,121 +24,121 @@
 block discarded – undo
24 24
 use Test\TestCase;
25 25
 
26 26
 class RegistryTest extends TestCase {
27
-	/** @var ProviderUserAssignmentDao|MockObject */
28
-	private $dao;
29
-
30
-	/** @var IEventDispatcher|MockObject */
31
-	private $dispatcher;
32
-
33
-	/** @var Registry */
34
-	private $registry;
35
-
36
-	protected function setUp(): void {
37
-		parent::setUp();
38
-
39
-		$this->dao = $this->createMock(ProviderUserAssignmentDao::class);
40
-		$this->dispatcher = $this->createMock(IEventDispatcher::class);
41
-
42
-		$this->registry = new Registry($this->dao, $this->dispatcher);
43
-	}
44
-
45
-	public function testGetProviderStates(): void {
46
-		$user = $this->createMock(IUser::class);
47
-		$user->expects($this->once())->method('getUID')->willReturn('user123');
48
-		$state = [
49
-			'twofactor_totp' => true,
50
-		];
51
-		$this->dao->expects($this->once())->method('getState')->willReturn($state);
52
-
53
-		$actual = $this->registry->getProviderStates($user);
54
-
55
-		$this->assertEquals($state, $actual);
56
-	}
57
-
58
-	public function testEnableProvider(): void {
59
-		$user = $this->createMock(IUser::class);
60
-		$provider = $this->createMock(IProvider::class);
61
-		$user->expects($this->once())->method('getUID')->willReturn('user123');
62
-		$provider->expects($this->once())->method('getId')->willReturn('p1');
63
-		$this->dao->expects($this->once())->method('persist')->with('p1', 'user123',
64
-			true);
65
-
66
-		$this->dispatcher->expects($this->once())
67
-			->method('dispatch')
68
-			->with(
69
-				$this->equalTo(IRegistry::EVENT_PROVIDER_ENABLED),
70
-				$this->callback(function (RegistryEvent $e) use ($user, $provider) {
71
-					return $e->getUser() === $user && $e->getProvider() === $provider;
72
-				})
73
-			);
74
-		$this->dispatcher->expects($this->once())
75
-			->method('dispatchTyped')
76
-			->with(new TwoFactorProviderForUserRegistered(
77
-				$user,
78
-				$provider,
79
-			));
80
-
81
-		$this->registry->enableProviderFor($provider, $user);
82
-	}
83
-
84
-	public function testDisableProvider(): void {
85
-		$user = $this->createMock(IUser::class);
86
-		$provider = $this->createMock(IProvider::class);
87
-		$user->expects($this->once())->method('getUID')->willReturn('user123');
88
-		$provider->expects($this->once())->method('getId')->willReturn('p1');
89
-		$this->dao->expects($this->once())->method('persist')->with('p1', 'user123',
90
-			false);
91
-
92
-
93
-		$this->dispatcher->expects($this->once())
94
-			->method('dispatch')
95
-			->with(
96
-				$this->equalTo(IRegistry::EVENT_PROVIDER_DISABLED),
97
-				$this->callback(function (RegistryEvent $e) use ($user, $provider) {
98
-					return $e->getUser() === $user && $e->getProvider() === $provider;
99
-				})
100
-			);
101
-		$this->dispatcher->expects($this->once())
102
-			->method('dispatchTyped')
103
-			->with(new TwoFactorProviderForUserUnregistered(
104
-				$user,
105
-				$provider,
106
-			));
107
-
108
-		$this->registry->disableProviderFor($provider, $user);
109
-	}
110
-
111
-	public function testDeleteUserData(): void {
112
-		$user = $this->createMock(IUser::class);
113
-		$user->expects($this->once())->method('getUID')->willReturn('user123');
114
-		$this->dao->expects($this->once())
115
-			->method('deleteByUser')
116
-			->with('user123')
117
-			->willReturn([
118
-				[
119
-					'provider_id' => 'twofactor_u2f',
120
-				]
121
-			]);
122
-
123
-		$calls = [
124
-			[new TwoFactorProviderDisabled('twofactor_u2f')],
125
-			[new TwoFactorProviderUserDeleted($user, 'twofactor_u2f')],
126
-		];
127
-		$this->dispatcher->expects($this->exactly(2))
128
-			->method('dispatchTyped')
129
-			->willReturnCallback(function () use (&$calls) {
130
-				$expected = array_shift($calls);
131
-				$this->assertEquals($expected, func_get_args());
132
-			});
133
-
134
-		$this->registry->deleteUserData($user);
135
-	}
136
-
137
-	public function testCleanUp(): void {
138
-		$this->dao->expects($this->once())
139
-			->method('deleteAll')
140
-			->with('twofactor_u2f');
141
-
142
-		$this->registry->cleanUp('twofactor_u2f');
143
-	}
27
+    /** @var ProviderUserAssignmentDao|MockObject */
28
+    private $dao;
29
+
30
+    /** @var IEventDispatcher|MockObject */
31
+    private $dispatcher;
32
+
33
+    /** @var Registry */
34
+    private $registry;
35
+
36
+    protected function setUp(): void {
37
+        parent::setUp();
38
+
39
+        $this->dao = $this->createMock(ProviderUserAssignmentDao::class);
40
+        $this->dispatcher = $this->createMock(IEventDispatcher::class);
41
+
42
+        $this->registry = new Registry($this->dao, $this->dispatcher);
43
+    }
44
+
45
+    public function testGetProviderStates(): void {
46
+        $user = $this->createMock(IUser::class);
47
+        $user->expects($this->once())->method('getUID')->willReturn('user123');
48
+        $state = [
49
+            'twofactor_totp' => true,
50
+        ];
51
+        $this->dao->expects($this->once())->method('getState')->willReturn($state);
52
+
53
+        $actual = $this->registry->getProviderStates($user);
54
+
55
+        $this->assertEquals($state, $actual);
56
+    }
57
+
58
+    public function testEnableProvider(): void {
59
+        $user = $this->createMock(IUser::class);
60
+        $provider = $this->createMock(IProvider::class);
61
+        $user->expects($this->once())->method('getUID')->willReturn('user123');
62
+        $provider->expects($this->once())->method('getId')->willReturn('p1');
63
+        $this->dao->expects($this->once())->method('persist')->with('p1', 'user123',
64
+            true);
65
+
66
+        $this->dispatcher->expects($this->once())
67
+            ->method('dispatch')
68
+            ->with(
69
+                $this->equalTo(IRegistry::EVENT_PROVIDER_ENABLED),
70
+                $this->callback(function (RegistryEvent $e) use ($user, $provider) {
71
+                    return $e->getUser() === $user && $e->getProvider() === $provider;
72
+                })
73
+            );
74
+        $this->dispatcher->expects($this->once())
75
+            ->method('dispatchTyped')
76
+            ->with(new TwoFactorProviderForUserRegistered(
77
+                $user,
78
+                $provider,
79
+            ));
80
+
81
+        $this->registry->enableProviderFor($provider, $user);
82
+    }
83
+
84
+    public function testDisableProvider(): void {
85
+        $user = $this->createMock(IUser::class);
86
+        $provider = $this->createMock(IProvider::class);
87
+        $user->expects($this->once())->method('getUID')->willReturn('user123');
88
+        $provider->expects($this->once())->method('getId')->willReturn('p1');
89
+        $this->dao->expects($this->once())->method('persist')->with('p1', 'user123',
90
+            false);
91
+
92
+
93
+        $this->dispatcher->expects($this->once())
94
+            ->method('dispatch')
95
+            ->with(
96
+                $this->equalTo(IRegistry::EVENT_PROVIDER_DISABLED),
97
+                $this->callback(function (RegistryEvent $e) use ($user, $provider) {
98
+                    return $e->getUser() === $user && $e->getProvider() === $provider;
99
+                })
100
+            );
101
+        $this->dispatcher->expects($this->once())
102
+            ->method('dispatchTyped')
103
+            ->with(new TwoFactorProviderForUserUnregistered(
104
+                $user,
105
+                $provider,
106
+            ));
107
+
108
+        $this->registry->disableProviderFor($provider, $user);
109
+    }
110
+
111
+    public function testDeleteUserData(): void {
112
+        $user = $this->createMock(IUser::class);
113
+        $user->expects($this->once())->method('getUID')->willReturn('user123');
114
+        $this->dao->expects($this->once())
115
+            ->method('deleteByUser')
116
+            ->with('user123')
117
+            ->willReturn([
118
+                [
119
+                    'provider_id' => 'twofactor_u2f',
120
+                ]
121
+            ]);
122
+
123
+        $calls = [
124
+            [new TwoFactorProviderDisabled('twofactor_u2f')],
125
+            [new TwoFactorProviderUserDeleted($user, 'twofactor_u2f')],
126
+        ];
127
+        $this->dispatcher->expects($this->exactly(2))
128
+            ->method('dispatchTyped')
129
+            ->willReturnCallback(function () use (&$calls) {
130
+                $expected = array_shift($calls);
131
+                $this->assertEquals($expected, func_get_args());
132
+            });
133
+
134
+        $this->registry->deleteUserData($user);
135
+    }
136
+
137
+    public function testCleanUp(): void {
138
+        $this->dao->expects($this->once())
139
+            ->method('deleteAll')
140
+            ->with('twofactor_u2f');
141
+
142
+        $this->registry->cleanUp('twofactor_u2f');
143
+    }
144 144
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
 			->method('dispatch')
68 68
 			->with(
69 69
 				$this->equalTo(IRegistry::EVENT_PROVIDER_ENABLED),
70
-				$this->callback(function (RegistryEvent $e) use ($user, $provider) {
70
+				$this->callback(function(RegistryEvent $e) use ($user, $provider) {
71 71
 					return $e->getUser() === $user && $e->getProvider() === $provider;
72 72
 				})
73 73
 			);
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 			->method('dispatch')
95 95
 			->with(
96 96
 				$this->equalTo(IRegistry::EVENT_PROVIDER_DISABLED),
97
-				$this->callback(function (RegistryEvent $e) use ($user, $provider) {
97
+				$this->callback(function(RegistryEvent $e) use ($user, $provider) {
98 98
 					return $e->getUser() === $user && $e->getProvider() === $provider;
99 99
 				})
100 100
 			);
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 		];
127 127
 		$this->dispatcher->expects($this->exactly(2))
128 128
 			->method('dispatchTyped')
129
-			->willReturnCallback(function () use (&$calls) {
129
+			->willReturnCallback(function() use (&$calls) {
130 130
 				$expected = array_shift($calls);
131 131
 				$this->assertEquals($expected, func_get_args());
132 132
 			});
Please login to merge, or discard this patch.
tests/lib/Authentication/TwoFactorAuth/ManagerTest.php 2 patches
Indentation   +762 added lines, -762 removed lines patch added patch discarded remove patch
@@ -30,766 +30,766 @@
 block discarded – undo
30 30
 use function reset;
31 31
 
32 32
 class ManagerTest extends TestCase {
33
-	/** @var IUser|MockObject */
34
-	private $user;
35
-
36
-	/** @var ProviderLoader|MockObject */
37
-	private $providerLoader;
38
-
39
-	/** @var IRegistry|MockObject */
40
-	private $providerRegistry;
41
-
42
-	/** @var MandatoryTwoFactor|MockObject */
43
-	private $mandatoryTwoFactor;
44
-
45
-	/** @var ISession|MockObject */
46
-	private $session;
47
-
48
-	/** @var Manager */
49
-	private $manager;
50
-
51
-	/** @var IConfig|MockObject */
52
-	private $config;
53
-
54
-	/** @var IManager|MockObject */
55
-	private $activityManager;
56
-
57
-	/** @var LoggerInterface|MockObject */
58
-	private $logger;
59
-
60
-	/** @var IProvider|MockObject */
61
-	private $fakeProvider;
62
-
63
-	/** @var IProvider|MockObject */
64
-	private $backupProvider;
65
-
66
-	/** @var TokenProvider|MockObject */
67
-	private $tokenProvider;
68
-
69
-	/** @var ITimeFactory|MockObject */
70
-	private $timeFactory;
71
-
72
-	/** @var IEventDispatcher|MockObject */
73
-	private $dispatcher;
74
-
75
-	protected function setUp(): void {
76
-		parent::setUp();
77
-
78
-		$this->user = $this->createMock(IUser::class);
79
-		$this->providerLoader = $this->createMock(ProviderLoader::class);
80
-		$this->providerRegistry = $this->createMock(IRegistry::class);
81
-		$this->mandatoryTwoFactor = $this->createMock(MandatoryTwoFactor::class);
82
-		$this->session = $this->createMock(ISession::class);
83
-		$this->config = $this->createMock(IConfig::class);
84
-		$this->activityManager = $this->createMock(IManager::class);
85
-		$this->logger = $this->createMock(LoggerInterface::class);
86
-		$this->tokenProvider = $this->createMock(TokenProvider::class);
87
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
88
-		$this->dispatcher = $this->createMock(IEventDispatcher::class);
89
-
90
-		$this->manager = new Manager(
91
-			$this->providerLoader,
92
-			$this->providerRegistry,
93
-			$this->mandatoryTwoFactor,
94
-			$this->session,
95
-			$this->config,
96
-			$this->activityManager,
97
-			$this->logger,
98
-			$this->tokenProvider,
99
-			$this->timeFactory,
100
-			$this->dispatcher,
101
-		);
102
-
103
-		$this->fakeProvider = $this->createMock(IProvider::class);
104
-		$this->fakeProvider->method('getId')->willReturn('email');
105
-
106
-		$this->backupProvider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider')->getMock();
107
-		$this->backupProvider->method('getId')->willReturn('backup_codes');
108
-		$this->backupProvider->method('isTwoFactorAuthEnabledForUser')->willReturn(true);
109
-	}
110
-
111
-	private function prepareNoProviders() {
112
-		$this->providerLoader->method('getProviders')
113
-			->with($this->user)
114
-			->willReturn([]);
115
-	}
116
-
117
-	private function prepareProviders() {
118
-		$this->providerRegistry->expects($this->once())
119
-			->method('getProviderStates')
120
-			->with($this->user)
121
-			->willReturn([
122
-				$this->fakeProvider->getId() => true,
123
-			]);
124
-		$this->providerLoader->expects($this->once())
125
-			->method('getProviders')
126
-			->with($this->user)
127
-			->willReturn([$this->fakeProvider]);
128
-	}
129
-
130
-	private function prepareProvidersWitBackupProvider() {
131
-		$this->providerLoader->method('getProviders')
132
-			->with($this->user)
133
-			->willReturn([
134
-				$this->fakeProvider,
135
-				$this->backupProvider,
136
-			]);
137
-	}
138
-
139
-	public function testIsTwoFactorAuthenticatedEnforced(): void {
140
-		$this->mandatoryTwoFactor->expects($this->once())
141
-			->method('isEnforcedFor')
142
-			->with($this->user)
143
-			->willReturn(true);
144
-
145
-		$enabled = $this->manager->isTwoFactorAuthenticated($this->user);
146
-
147
-		$this->assertTrue($enabled);
148
-	}
149
-
150
-	public function testIsTwoFactorAuthenticatedNoProviders(): void {
151
-		$this->mandatoryTwoFactor->expects($this->once())
152
-			->method('isEnforcedFor')
153
-			->with($this->user)
154
-			->willReturn(false);
155
-		$this->providerRegistry->expects($this->once())
156
-			->method('getProviderStates')
157
-			->willReturn([]); // No providers registered
158
-		$this->providerLoader->expects($this->once())
159
-			->method('getProviders')
160
-			->willReturn([]); // No providers loadable
161
-
162
-		$this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
163
-	}
164
-
165
-	public function testIsTwoFactorAuthenticatedOnlyBackupCodes(): void {
166
-		$this->mandatoryTwoFactor->expects($this->once())
167
-			->method('isEnforcedFor')
168
-			->with($this->user)
169
-			->willReturn(false);
170
-		$this->providerRegistry->expects($this->once())
171
-			->method('getProviderStates')
172
-			->willReturn([
173
-				'backup_codes' => true,
174
-			]);
175
-		$backupCodesProvider = $this->createMock(IProvider::class);
176
-		$backupCodesProvider
177
-			->method('getId')
178
-			->willReturn('backup_codes');
179
-		$this->providerLoader->expects($this->once())
180
-			->method('getProviders')
181
-			->willReturn([
182
-				$backupCodesProvider,
183
-			]);
184
-
185
-		$this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
186
-	}
187
-
188
-	public function testIsTwoFactorAuthenticatedFailingProviders(): void {
189
-		$this->mandatoryTwoFactor->expects($this->once())
190
-			->method('isEnforcedFor')
191
-			->with($this->user)
192
-			->willReturn(false);
193
-		$this->providerRegistry->expects($this->once())
194
-			->method('getProviderStates')
195
-			->willReturn([
196
-				'twofactor_totp' => true,
197
-				'twofactor_u2f' => false,
198
-			]); // Two providers registered, but …
199
-		$this->providerLoader->expects($this->once())
200
-			->method('getProviders')
201
-			->willReturn([]); // … none of them is able to load, however …
202
-
203
-		// … 2FA is still enforced
204
-		$this->assertTrue($this->manager->isTwoFactorAuthenticated($this->user));
205
-	}
206
-
207
-	public static function providerStatesFixData(): array {
208
-		return [
209
-			[false, false],
210
-			[true, true],
211
-		];
212
-	}
213
-
214
-	/**
215
-	 * If the 2FA registry has not been populated when a user logs in,
216
-	 * the 2FA manager has to first fix the state before it checks for
217
-	 * enabled providers.
218
-	 *
219
-	 * If any of these providers is active, 2FA is enabled
220
-	 *
221
-	 * @dataProvider providerStatesFixData
222
-	 */
223
-	public function testIsTwoFactorAuthenticatedFixesProviderStates(bool $providerEnabled, bool $expected): void {
224
-		$this->providerRegistry->expects($this->once())
225
-			->method('getProviderStates')
226
-			->willReturn([]); // Nothing registered yet
227
-		$this->providerLoader->expects($this->once())
228
-			->method('getProviders')
229
-			->willReturn([
230
-				$this->fakeProvider
231
-			]);
232
-		$this->fakeProvider->expects($this->once())
233
-			->method('isTwoFactorAuthEnabledForUser')
234
-			->with($this->user)
235
-			->willReturn($providerEnabled);
236
-		if ($providerEnabled) {
237
-			$this->providerRegistry->expects($this->once())
238
-				->method('enableProviderFor')
239
-				->with(
240
-					$this->fakeProvider,
241
-					$this->user
242
-				);
243
-		} else {
244
-			$this->providerRegistry->expects($this->once())
245
-				->method('disableProviderFor')
246
-				->with(
247
-					$this->fakeProvider,
248
-					$this->user
249
-				);
250
-		}
251
-
252
-		$this->assertEquals($expected, $this->manager->isTwoFactorAuthenticated($this->user));
253
-	}
254
-
255
-	public function testGetProvider(): void {
256
-		$this->providerRegistry->expects($this->once())
257
-			->method('getProviderStates')
258
-			->with($this->user)
259
-			->willReturn([
260
-				$this->fakeProvider->getId() => true,
261
-			]);
262
-		$this->providerLoader->expects($this->once())
263
-			->method('getProviders')
264
-			->with($this->user)
265
-			->willReturn([$this->fakeProvider]);
266
-
267
-		$provider = $this->manager->getProvider($this->user, $this->fakeProvider->getId());
268
-
269
-		$this->assertSame($this->fakeProvider, $provider);
270
-	}
271
-
272
-	public function testGetInvalidProvider(): void {
273
-		$this->providerRegistry->expects($this->once())
274
-			->method('getProviderStates')
275
-			->with($this->user)
276
-			->willReturn([]);
277
-		$this->providerLoader->expects($this->once())
278
-			->method('getProviders')
279
-			->with($this->user)
280
-			->willReturn([]);
281
-
282
-		$provider = $this->manager->getProvider($this->user, 'nonexistent');
283
-
284
-		$this->assertNull($provider);
285
-	}
286
-
287
-	public function testGetLoginSetupProviders(): void {
288
-		$provider1 = $this->createMock(IProvider::class);
289
-		$provider2 = $this->createMock(IActivatableAtLogin::class);
290
-		$this->providerLoader->expects($this->once())
291
-			->method('getProviders')
292
-			->with($this->user)
293
-			->willReturn([
294
-				$provider1,
295
-				$provider2,
296
-			]);
297
-
298
-		$providers = $this->manager->getLoginSetupProviders($this->user);
299
-
300
-		$this->assertCount(1, $providers);
301
-		$this->assertSame($provider2, reset($providers));
302
-	}
303
-
304
-	public function testGetProviders(): void {
305
-		$this->providerRegistry->expects($this->once())
306
-			->method('getProviderStates')
307
-			->with($this->user)
308
-			->willReturn([
309
-				$this->fakeProvider->getId() => true,
310
-			]);
311
-		$this->providerLoader->expects($this->once())
312
-			->method('getProviders')
313
-			->with($this->user)
314
-			->willReturn([$this->fakeProvider]);
315
-		$expectedProviders = [
316
-			'email' => $this->fakeProvider,
317
-		];
318
-
319
-		$providerSet = $this->manager->getProviderSet($this->user);
320
-		$providers = $providerSet->getProviders();
321
-
322
-		$this->assertEquals($expectedProviders, $providers);
323
-		$this->assertFalse($providerSet->isProviderMissing());
324
-	}
325
-
326
-	public function testGetProvidersOneMissing(): void {
327
-		$this->providerRegistry->expects($this->once())
328
-			->method('getProviderStates')
329
-			->with($this->user)
330
-			->willReturn([
331
-				$this->fakeProvider->getId() => true,
332
-			]);
333
-		$this->providerLoader->expects($this->once())
334
-			->method('getProviders')
335
-			->with($this->user)
336
-			->willReturn([]);
337
-		$expectedProviders = [
338
-			'email' => $this->fakeProvider,
339
-		];
340
-
341
-		$providerSet = $this->manager->getProviderSet($this->user);
342
-
343
-		$this->assertTrue($providerSet->isProviderMissing());
344
-	}
345
-
346
-	public function testVerifyChallenge(): void {
347
-		$this->prepareProviders();
348
-
349
-		$challenge = 'passme';
350
-		$event = $this->createMock(IEvent::class);
351
-		$this->fakeProvider->expects($this->once())
352
-			->method('verifyChallenge')
353
-			->with($this->user, $challenge)
354
-			->willReturn(true);
355
-		$this->session->expects($this->once())
356
-			->method('get')
357
-			->with('two_factor_remember_login')
358
-			->willReturn(false);
359
-
360
-		$calls = [
361
-			['two_factor_auth_uid'],
362
-			['two_factor_remember_login'],
363
-		];
364
-		$this->session->expects($this->exactly(2))
365
-			->method('remove')
366
-			->willReturnCallback(function () use (&$calls) {
367
-				$expected = array_shift($calls);
368
-				$this->assertEquals($expected, func_get_args());
369
-			});
370
-
371
-		$this->session->expects($this->once())
372
-			->method('set')
373
-			->with(Manager::SESSION_UID_DONE, 'jos');
374
-		$this->session->method('getId')
375
-			->willReturn('mysessionid');
376
-		$this->activityManager->expects($this->once())
377
-			->method('generateEvent')
378
-			->willReturn($event);
379
-		$this->user->expects($this->any())
380
-			->method('getUID')
381
-			->willReturn('jos');
382
-		$event->expects($this->once())
383
-			->method('setApp')
384
-			->with($this->equalTo('core'))
385
-			->willReturnSelf();
386
-		$event->expects($this->once())
387
-			->method('setType')
388
-			->with($this->equalTo('security'))
389
-			->willReturnSelf();
390
-		$event->expects($this->once())
391
-			->method('setAuthor')
392
-			->with($this->equalTo('jos'))
393
-			->willReturnSelf();
394
-		$event->expects($this->once())
395
-			->method('setAffectedUser')
396
-			->with($this->equalTo('jos'))
397
-			->willReturnSelf();
398
-		$this->fakeProvider
399
-			->method('getDisplayName')
400
-			->willReturn('Fake 2FA');
401
-		$event->expects($this->once())
402
-			->method('setSubject')
403
-			->with($this->equalTo('twofactor_success'), $this->equalTo([
404
-				'provider' => 'Fake 2FA',
405
-			]))
406
-			->willReturnSelf();
407
-		$token = $this->createMock(OC\Authentication\Token\IToken::class);
408
-		$this->tokenProvider->method('getToken')
409
-			->with('mysessionid')
410
-			->willReturn($token);
411
-		$token->method('getId')
412
-			->willReturn(42);
413
-		$this->config->expects($this->once())
414
-			->method('deleteUserValue')
415
-			->with('jos', 'login_token_2fa', '42');
416
-
417
-		$result = $this->manager->verifyChallenge('email', $this->user, $challenge);
418
-
419
-		$this->assertTrue($result);
420
-	}
421
-
422
-	public function testVerifyChallengeInvalidProviderId(): void {
423
-		$this->prepareProviders();
424
-
425
-		$challenge = 'passme';
426
-		$this->fakeProvider->expects($this->never())
427
-			->method('verifyChallenge')
428
-			->with($this->user, $challenge);
429
-		$this->session->expects($this->never())
430
-			->method('remove');
431
-
432
-		$this->assertFalse($this->manager->verifyChallenge('dontexist', $this->user, $challenge));
433
-	}
434
-
435
-	public function testVerifyInvalidChallenge(): void {
436
-		$this->prepareProviders();
437
-
438
-		$challenge = 'dontpassme';
439
-		$event = $this->createMock(IEvent::class);
440
-		$this->fakeProvider->expects($this->once())
441
-			->method('verifyChallenge')
442
-			->with($this->user, $challenge)
443
-			->willReturn(false);
444
-		$this->session->expects($this->never())
445
-			->method('remove');
446
-		$this->activityManager->expects($this->once())
447
-			->method('generateEvent')
448
-			->willReturn($event);
449
-		$this->user->expects($this->any())
450
-			->method('getUID')
451
-			->willReturn('jos');
452
-		$event->expects($this->once())
453
-			->method('setApp')
454
-			->with($this->equalTo('core'))
455
-			->willReturnSelf();
456
-		$event->expects($this->once())
457
-			->method('setType')
458
-			->with($this->equalTo('security'))
459
-			->willReturnSelf();
460
-		$event->expects($this->once())
461
-			->method('setAuthor')
462
-			->with($this->equalTo('jos'))
463
-			->willReturnSelf();
464
-		$event->expects($this->once())
465
-			->method('setAffectedUser')
466
-			->with($this->equalTo('jos'))
467
-			->willReturnSelf();
468
-		$this->fakeProvider
469
-			->method('getDisplayName')
470
-			->willReturn('Fake 2FA');
471
-		$event->expects($this->once())
472
-			->method('setSubject')
473
-			->with($this->equalTo('twofactor_failed'), $this->equalTo([
474
-				'provider' => 'Fake 2FA',
475
-			]))
476
-			->willReturnSelf();
477
-
478
-		$this->assertFalse($this->manager->verifyChallenge('email', $this->user, $challenge));
479
-	}
480
-
481
-	public function testNeedsSecondFactor(): void {
482
-		$user = $this->createMock(IUser::class);
483
-
484
-		$calls = [
485
-			['app_password'],
486
-			['two_factor_auth_uid'],
487
-			[Manager::SESSION_UID_DONE],
488
-		];
489
-		$this->session->expects($this->exactly(3))
490
-			->method('exists')
491
-			->willReturnCallback(function () use (&$calls) {
492
-				$expected = array_shift($calls);
493
-				$this->assertEquals($expected, func_get_args());
494
-				return false;
495
-			});
496
-
497
-		$this->session->method('getId')
498
-			->willReturn('mysessionid');
499
-		$token = $this->createMock(OC\Authentication\Token\IToken::class);
500
-		$this->tokenProvider->method('getToken')
501
-			->with('mysessionid')
502
-			->willReturn($token);
503
-		$token->method('getId')
504
-			->willReturn(42);
505
-
506
-		$user->method('getUID')
507
-			->willReturn('user');
508
-		$this->config->method('getUserKeys')
509
-			->with('user', 'login_token_2fa')
510
-			->willReturn([
511
-				'42'
512
-			]);
513
-
514
-		$manager = $this->getMockBuilder(Manager::class)
515
-			->setConstructorArgs([
516
-				$this->providerLoader,
517
-				$this->providerRegistry,
518
-				$this->mandatoryTwoFactor,
519
-				$this->session,
520
-				$this->config,
521
-				$this->activityManager,
522
-				$this->logger,
523
-				$this->tokenProvider,
524
-				$this->timeFactory,
525
-				$this->dispatcher,
526
-			])
527
-			->onlyMethods(['isTwoFactorAuthenticated'])// Do not actually load the apps
528
-			->getMock();
529
-
530
-		$manager->method('isTwoFactorAuthenticated')
531
-			->with($user)
532
-			->willReturn(true);
533
-
534
-		$this->assertTrue($manager->needsSecondFactor($user));
535
-	}
536
-
537
-	public function testNeedsSecondFactorUserIsNull(): void {
538
-		$user = null;
539
-		$this->session->expects($this->never())
540
-			->method('exists');
541
-
542
-		$this->assertFalse($this->manager->needsSecondFactor($user));
543
-	}
544
-
545
-	public function testNeedsSecondFactorWithNoProviderAvailableAnymore(): void {
546
-		$this->prepareNoProviders();
547
-
548
-		$user = null;
549
-		$this->session->expects($this->never())
550
-			->method('exists')
551
-			->with('two_factor_auth_uid')
552
-			->willReturn(true);
553
-		$this->session->expects($this->never())
554
-			->method('remove')
555
-			->with('two_factor_auth_uid');
556
-
557
-		$this->assertFalse($this->manager->needsSecondFactor($user));
558
-	}
559
-
560
-	public function testPrepareTwoFactorLogin(): void {
561
-		$this->user->method('getUID')
562
-			->willReturn('ferdinand');
563
-
564
-		$calls = [
565
-			['two_factor_auth_uid', 'ferdinand'],
566
-			['two_factor_remember_login', true],
567
-		];
568
-		$this->session->expects($this->exactly(2))
569
-			->method('set')
570
-			->willReturnCallback(function () use (&$calls) {
571
-				$expected = array_shift($calls);
572
-				$this->assertEquals($expected, func_get_args());
573
-			});
574
-
575
-		$this->session->method('getId')
576
-			->willReturn('mysessionid');
577
-		$token = $this->createMock(OC\Authentication\Token\IToken::class);
578
-		$this->tokenProvider->method('getToken')
579
-			->with('mysessionid')
580
-			->willReturn($token);
581
-		$token->method('getId')
582
-			->willReturn(42);
583
-
584
-		$this->timeFactory->method('getTime')
585
-			->willReturn(1337);
586
-
587
-		$this->config->method('setUserValue')
588
-			->with('ferdinand', 'login_token_2fa', '42', '1337');
589
-
590
-
591
-		$this->manager->prepareTwoFactorLogin($this->user, true);
592
-	}
593
-
594
-	public function testPrepareTwoFactorLoginDontRemember(): void {
595
-		$this->user->method('getUID')
596
-			->willReturn('ferdinand');
597
-
598
-		$calls = [
599
-			['two_factor_auth_uid', 'ferdinand'],
600
-			['two_factor_remember_login', false],
601
-		];
602
-		$this->session->expects($this->exactly(2))
603
-			->method('set')
604
-			->willReturnCallback(function () use (&$calls) {
605
-				$expected = array_shift($calls);
606
-				$this->assertEquals($expected, func_get_args());
607
-			});
608
-
609
-		$this->session->method('getId')
610
-			->willReturn('mysessionid');
611
-		$token = $this->createMock(OC\Authentication\Token\IToken::class);
612
-		$this->tokenProvider->method('getToken')
613
-			->with('mysessionid')
614
-			->willReturn($token);
615
-		$token->method('getId')
616
-			->willReturn(42);
617
-
618
-		$this->timeFactory->method('getTime')
619
-			->willReturn(1337);
620
-
621
-		$this->config->method('setUserValue')
622
-			->with('ferdinand', 'login_token_2fa', '42', '1337');
623
-
624
-		$this->manager->prepareTwoFactorLogin($this->user, false);
625
-	}
626
-
627
-	public function testNeedsSecondFactorSessionAuth(): void {
628
-		$user = $this->createMock(IUser::class);
629
-		$user->method('getUID')
630
-			->willReturn('user');
631
-
632
-		$this->session->method('exists')
633
-			->willReturnCallback(function ($var) {
634
-				if ($var === Manager::SESSION_UID_KEY) {
635
-					return false;
636
-				} elseif ($var === 'app_password') {
637
-					return false;
638
-				} elseif ($var === 'app_api') {
639
-					return false;
640
-				}
641
-				return true;
642
-			});
643
-		$this->session->method('get')
644
-			->willReturnCallback(function ($var) {
645
-				if ($var === Manager::SESSION_UID_KEY) {
646
-					return 'user';
647
-				} elseif ($var === 'app_api') {
648
-					return true;
649
-				}
650
-				return null;
651
-			});
652
-		$this->session->expects($this->once())
653
-			->method('get')
654
-			->willReturnMap([
655
-				[Manager::SESSION_UID_DONE, 'user'],
656
-				['app_api', true]
657
-			]);
658
-
659
-		$this->assertFalse($this->manager->needsSecondFactor($user));
660
-	}
661
-
662
-	public function testNeedsSecondFactorSessionAuthFailDBPass(): void {
663
-		$user = $this->createMock(IUser::class);
664
-		$user->method('getUID')
665
-			->willReturn('user');
666
-
667
-		$this->session->method('exists')
668
-			->willReturn(false);
669
-		$this->session->method('getId')
670
-			->willReturn('mysessionid');
671
-
672
-		$token = $this->createMock(OC\Authentication\Token\IToken::class);
673
-		$token->method('getId')
674
-			->willReturn(40);
675
-
676
-		$this->tokenProvider->method('getToken')
677
-			->with('mysessionid')
678
-			->willReturn($token);
679
-
680
-		$this->config->method('getUserKeys')
681
-			->with('user', 'login_token_2fa')
682
-			->willReturn([
683
-				'42', '43', '44'
684
-			]);
685
-
686
-		$this->session->expects($this->once())
687
-			->method('set')
688
-			->with(Manager::SESSION_UID_DONE, 'user');
689
-
690
-		$this->assertFalse($this->manager->needsSecondFactor($user));
691
-	}
692
-
693
-	public function testNeedsSecondFactorInvalidToken(): void {
694
-		$this->prepareNoProviders();
695
-
696
-		$user = $this->createMock(IUser::class);
697
-		$user->method('getUID')
698
-			->willReturn('user');
699
-
700
-		$this->session->method('exists')
701
-			->willReturn(false);
702
-		$this->session->method('getId')
703
-			->willReturn('mysessionid');
704
-
705
-		$this->tokenProvider->method('getToken')
706
-			->with('mysessionid')
707
-			->willThrowException(new OC\Authentication\Exceptions\InvalidTokenException());
708
-
709
-		$this->config->method('getUserKeys')->willReturn([]);
710
-
711
-		$this->assertFalse($this->manager->needsSecondFactor($user));
712
-	}
713
-
714
-	public function testNeedsSecondFactorAppPassword(): void {
715
-		$user = $this->createMock(IUser::class);
716
-		$this->session->method('exists')
717
-			->willReturnMap([
718
-				['app_password', true],
719
-				['app_api', true]
720
-			]);
721
-
722
-		$this->assertFalse($this->manager->needsSecondFactor($user));
723
-	}
724
-
725
-	public function testClearTwoFactorPending() {
726
-		$this->config->method('getUserKeys')
727
-			->with('theUserId', 'login_token_2fa')
728
-			->willReturn([
729
-				'42', '43', '44'
730
-			]);
731
-
732
-		$deleteUserValueCalls = [
733
-			['theUserId', 'login_token_2fa', '42'],
734
-			['theUserId', 'login_token_2fa', '43'],
735
-			['theUserId', 'login_token_2fa', '44'],
736
-		];
737
-		$this->config->expects($this->exactly(3))
738
-			->method('deleteUserValue')
739
-			->willReturnCallback(function () use (&$deleteUserValueCalls) {
740
-				$expected = array_shift($deleteUserValueCalls);
741
-				$this->assertEquals($expected, func_get_args());
742
-			});
743
-
744
-		$invalidateCalls = [
745
-			['theUserId', 42],
746
-			['theUserId', 43],
747
-			['theUserId', 44],
748
-		];
749
-		$this->tokenProvider->expects($this->exactly(3))
750
-			->method('invalidateTokenById')
751
-			->willReturnCallback(function () use (&$invalidateCalls) {
752
-				$expected = array_shift($invalidateCalls);
753
-				$this->assertEquals($expected, func_get_args());
754
-			});
755
-
756
-		$this->manager->clearTwoFactorPending('theUserId');
757
-	}
758
-
759
-	public function testClearTwoFactorPendingTokenDoesNotExist() {
760
-		$this->config->method('getUserKeys')
761
-			->with('theUserId', 'login_token_2fa')
762
-			->willReturn([
763
-				'42', '43', '44'
764
-			]);
765
-
766
-		$deleteUserValueCalls = [
767
-			['theUserId', 'login_token_2fa', '42'],
768
-			['theUserId', 'login_token_2fa', '43'],
769
-			['theUserId', 'login_token_2fa', '44'],
770
-		];
771
-		$this->config->expects($this->exactly(3))
772
-			->method('deleteUserValue')
773
-			->willReturnCallback(function () use (&$deleteUserValueCalls) {
774
-				$expected = array_shift($deleteUserValueCalls);
775
-				$this->assertEquals($expected, func_get_args());
776
-			});
777
-
778
-		$invalidateCalls = [
779
-			['theUserId', 42],
780
-			['theUserId', 43],
781
-			['theUserId', 44],
782
-		];
783
-		$this->tokenProvider->expects($this->exactly(3))
784
-			->method('invalidateTokenById')
785
-			->willReturnCallback(function ($user, $tokenId) use (&$invalidateCalls) {
786
-				$expected = array_shift($invalidateCalls);
787
-				$this->assertEquals($expected, func_get_args());
788
-				if ($tokenId === 43) {
789
-					throw new DoesNotExistException('token does not exist');
790
-				}
791
-			});
792
-
793
-		$this->manager->clearTwoFactorPending('theUserId');
794
-	}
33
+    /** @var IUser|MockObject */
34
+    private $user;
35
+
36
+    /** @var ProviderLoader|MockObject */
37
+    private $providerLoader;
38
+
39
+    /** @var IRegistry|MockObject */
40
+    private $providerRegistry;
41
+
42
+    /** @var MandatoryTwoFactor|MockObject */
43
+    private $mandatoryTwoFactor;
44
+
45
+    /** @var ISession|MockObject */
46
+    private $session;
47
+
48
+    /** @var Manager */
49
+    private $manager;
50
+
51
+    /** @var IConfig|MockObject */
52
+    private $config;
53
+
54
+    /** @var IManager|MockObject */
55
+    private $activityManager;
56
+
57
+    /** @var LoggerInterface|MockObject */
58
+    private $logger;
59
+
60
+    /** @var IProvider|MockObject */
61
+    private $fakeProvider;
62
+
63
+    /** @var IProvider|MockObject */
64
+    private $backupProvider;
65
+
66
+    /** @var TokenProvider|MockObject */
67
+    private $tokenProvider;
68
+
69
+    /** @var ITimeFactory|MockObject */
70
+    private $timeFactory;
71
+
72
+    /** @var IEventDispatcher|MockObject */
73
+    private $dispatcher;
74
+
75
+    protected function setUp(): void {
76
+        parent::setUp();
77
+
78
+        $this->user = $this->createMock(IUser::class);
79
+        $this->providerLoader = $this->createMock(ProviderLoader::class);
80
+        $this->providerRegistry = $this->createMock(IRegistry::class);
81
+        $this->mandatoryTwoFactor = $this->createMock(MandatoryTwoFactor::class);
82
+        $this->session = $this->createMock(ISession::class);
83
+        $this->config = $this->createMock(IConfig::class);
84
+        $this->activityManager = $this->createMock(IManager::class);
85
+        $this->logger = $this->createMock(LoggerInterface::class);
86
+        $this->tokenProvider = $this->createMock(TokenProvider::class);
87
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
88
+        $this->dispatcher = $this->createMock(IEventDispatcher::class);
89
+
90
+        $this->manager = new Manager(
91
+            $this->providerLoader,
92
+            $this->providerRegistry,
93
+            $this->mandatoryTwoFactor,
94
+            $this->session,
95
+            $this->config,
96
+            $this->activityManager,
97
+            $this->logger,
98
+            $this->tokenProvider,
99
+            $this->timeFactory,
100
+            $this->dispatcher,
101
+        );
102
+
103
+        $this->fakeProvider = $this->createMock(IProvider::class);
104
+        $this->fakeProvider->method('getId')->willReturn('email');
105
+
106
+        $this->backupProvider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider')->getMock();
107
+        $this->backupProvider->method('getId')->willReturn('backup_codes');
108
+        $this->backupProvider->method('isTwoFactorAuthEnabledForUser')->willReturn(true);
109
+    }
110
+
111
+    private function prepareNoProviders() {
112
+        $this->providerLoader->method('getProviders')
113
+            ->with($this->user)
114
+            ->willReturn([]);
115
+    }
116
+
117
+    private function prepareProviders() {
118
+        $this->providerRegistry->expects($this->once())
119
+            ->method('getProviderStates')
120
+            ->with($this->user)
121
+            ->willReturn([
122
+                $this->fakeProvider->getId() => true,
123
+            ]);
124
+        $this->providerLoader->expects($this->once())
125
+            ->method('getProviders')
126
+            ->with($this->user)
127
+            ->willReturn([$this->fakeProvider]);
128
+    }
129
+
130
+    private function prepareProvidersWitBackupProvider() {
131
+        $this->providerLoader->method('getProviders')
132
+            ->with($this->user)
133
+            ->willReturn([
134
+                $this->fakeProvider,
135
+                $this->backupProvider,
136
+            ]);
137
+    }
138
+
139
+    public function testIsTwoFactorAuthenticatedEnforced(): void {
140
+        $this->mandatoryTwoFactor->expects($this->once())
141
+            ->method('isEnforcedFor')
142
+            ->with($this->user)
143
+            ->willReturn(true);
144
+
145
+        $enabled = $this->manager->isTwoFactorAuthenticated($this->user);
146
+
147
+        $this->assertTrue($enabled);
148
+    }
149
+
150
+    public function testIsTwoFactorAuthenticatedNoProviders(): void {
151
+        $this->mandatoryTwoFactor->expects($this->once())
152
+            ->method('isEnforcedFor')
153
+            ->with($this->user)
154
+            ->willReturn(false);
155
+        $this->providerRegistry->expects($this->once())
156
+            ->method('getProviderStates')
157
+            ->willReturn([]); // No providers registered
158
+        $this->providerLoader->expects($this->once())
159
+            ->method('getProviders')
160
+            ->willReturn([]); // No providers loadable
161
+
162
+        $this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
163
+    }
164
+
165
+    public function testIsTwoFactorAuthenticatedOnlyBackupCodes(): void {
166
+        $this->mandatoryTwoFactor->expects($this->once())
167
+            ->method('isEnforcedFor')
168
+            ->with($this->user)
169
+            ->willReturn(false);
170
+        $this->providerRegistry->expects($this->once())
171
+            ->method('getProviderStates')
172
+            ->willReturn([
173
+                'backup_codes' => true,
174
+            ]);
175
+        $backupCodesProvider = $this->createMock(IProvider::class);
176
+        $backupCodesProvider
177
+            ->method('getId')
178
+            ->willReturn('backup_codes');
179
+        $this->providerLoader->expects($this->once())
180
+            ->method('getProviders')
181
+            ->willReturn([
182
+                $backupCodesProvider,
183
+            ]);
184
+
185
+        $this->assertFalse($this->manager->isTwoFactorAuthenticated($this->user));
186
+    }
187
+
188
+    public function testIsTwoFactorAuthenticatedFailingProviders(): void {
189
+        $this->mandatoryTwoFactor->expects($this->once())
190
+            ->method('isEnforcedFor')
191
+            ->with($this->user)
192
+            ->willReturn(false);
193
+        $this->providerRegistry->expects($this->once())
194
+            ->method('getProviderStates')
195
+            ->willReturn([
196
+                'twofactor_totp' => true,
197
+                'twofactor_u2f' => false,
198
+            ]); // Two providers registered, but …
199
+        $this->providerLoader->expects($this->once())
200
+            ->method('getProviders')
201
+            ->willReturn([]); // … none of them is able to load, however …
202
+
203
+        // … 2FA is still enforced
204
+        $this->assertTrue($this->manager->isTwoFactorAuthenticated($this->user));
205
+    }
206
+
207
+    public static function providerStatesFixData(): array {
208
+        return [
209
+            [false, false],
210
+            [true, true],
211
+        ];
212
+    }
213
+
214
+    /**
215
+     * If the 2FA registry has not been populated when a user logs in,
216
+     * the 2FA manager has to first fix the state before it checks for
217
+     * enabled providers.
218
+     *
219
+     * If any of these providers is active, 2FA is enabled
220
+     *
221
+     * @dataProvider providerStatesFixData
222
+     */
223
+    public function testIsTwoFactorAuthenticatedFixesProviderStates(bool $providerEnabled, bool $expected): void {
224
+        $this->providerRegistry->expects($this->once())
225
+            ->method('getProviderStates')
226
+            ->willReturn([]); // Nothing registered yet
227
+        $this->providerLoader->expects($this->once())
228
+            ->method('getProviders')
229
+            ->willReturn([
230
+                $this->fakeProvider
231
+            ]);
232
+        $this->fakeProvider->expects($this->once())
233
+            ->method('isTwoFactorAuthEnabledForUser')
234
+            ->with($this->user)
235
+            ->willReturn($providerEnabled);
236
+        if ($providerEnabled) {
237
+            $this->providerRegistry->expects($this->once())
238
+                ->method('enableProviderFor')
239
+                ->with(
240
+                    $this->fakeProvider,
241
+                    $this->user
242
+                );
243
+        } else {
244
+            $this->providerRegistry->expects($this->once())
245
+                ->method('disableProviderFor')
246
+                ->with(
247
+                    $this->fakeProvider,
248
+                    $this->user
249
+                );
250
+        }
251
+
252
+        $this->assertEquals($expected, $this->manager->isTwoFactorAuthenticated($this->user));
253
+    }
254
+
255
+    public function testGetProvider(): void {
256
+        $this->providerRegistry->expects($this->once())
257
+            ->method('getProviderStates')
258
+            ->with($this->user)
259
+            ->willReturn([
260
+                $this->fakeProvider->getId() => true,
261
+            ]);
262
+        $this->providerLoader->expects($this->once())
263
+            ->method('getProviders')
264
+            ->with($this->user)
265
+            ->willReturn([$this->fakeProvider]);
266
+
267
+        $provider = $this->manager->getProvider($this->user, $this->fakeProvider->getId());
268
+
269
+        $this->assertSame($this->fakeProvider, $provider);
270
+    }
271
+
272
+    public function testGetInvalidProvider(): void {
273
+        $this->providerRegistry->expects($this->once())
274
+            ->method('getProviderStates')
275
+            ->with($this->user)
276
+            ->willReturn([]);
277
+        $this->providerLoader->expects($this->once())
278
+            ->method('getProviders')
279
+            ->with($this->user)
280
+            ->willReturn([]);
281
+
282
+        $provider = $this->manager->getProvider($this->user, 'nonexistent');
283
+
284
+        $this->assertNull($provider);
285
+    }
286
+
287
+    public function testGetLoginSetupProviders(): void {
288
+        $provider1 = $this->createMock(IProvider::class);
289
+        $provider2 = $this->createMock(IActivatableAtLogin::class);
290
+        $this->providerLoader->expects($this->once())
291
+            ->method('getProviders')
292
+            ->with($this->user)
293
+            ->willReturn([
294
+                $provider1,
295
+                $provider2,
296
+            ]);
297
+
298
+        $providers = $this->manager->getLoginSetupProviders($this->user);
299
+
300
+        $this->assertCount(1, $providers);
301
+        $this->assertSame($provider2, reset($providers));
302
+    }
303
+
304
+    public function testGetProviders(): void {
305
+        $this->providerRegistry->expects($this->once())
306
+            ->method('getProviderStates')
307
+            ->with($this->user)
308
+            ->willReturn([
309
+                $this->fakeProvider->getId() => true,
310
+            ]);
311
+        $this->providerLoader->expects($this->once())
312
+            ->method('getProviders')
313
+            ->with($this->user)
314
+            ->willReturn([$this->fakeProvider]);
315
+        $expectedProviders = [
316
+            'email' => $this->fakeProvider,
317
+        ];
318
+
319
+        $providerSet = $this->manager->getProviderSet($this->user);
320
+        $providers = $providerSet->getProviders();
321
+
322
+        $this->assertEquals($expectedProviders, $providers);
323
+        $this->assertFalse($providerSet->isProviderMissing());
324
+    }
325
+
326
+    public function testGetProvidersOneMissing(): void {
327
+        $this->providerRegistry->expects($this->once())
328
+            ->method('getProviderStates')
329
+            ->with($this->user)
330
+            ->willReturn([
331
+                $this->fakeProvider->getId() => true,
332
+            ]);
333
+        $this->providerLoader->expects($this->once())
334
+            ->method('getProviders')
335
+            ->with($this->user)
336
+            ->willReturn([]);
337
+        $expectedProviders = [
338
+            'email' => $this->fakeProvider,
339
+        ];
340
+
341
+        $providerSet = $this->manager->getProviderSet($this->user);
342
+
343
+        $this->assertTrue($providerSet->isProviderMissing());
344
+    }
345
+
346
+    public function testVerifyChallenge(): void {
347
+        $this->prepareProviders();
348
+
349
+        $challenge = 'passme';
350
+        $event = $this->createMock(IEvent::class);
351
+        $this->fakeProvider->expects($this->once())
352
+            ->method('verifyChallenge')
353
+            ->with($this->user, $challenge)
354
+            ->willReturn(true);
355
+        $this->session->expects($this->once())
356
+            ->method('get')
357
+            ->with('two_factor_remember_login')
358
+            ->willReturn(false);
359
+
360
+        $calls = [
361
+            ['two_factor_auth_uid'],
362
+            ['two_factor_remember_login'],
363
+        ];
364
+        $this->session->expects($this->exactly(2))
365
+            ->method('remove')
366
+            ->willReturnCallback(function () use (&$calls) {
367
+                $expected = array_shift($calls);
368
+                $this->assertEquals($expected, func_get_args());
369
+            });
370
+
371
+        $this->session->expects($this->once())
372
+            ->method('set')
373
+            ->with(Manager::SESSION_UID_DONE, 'jos');
374
+        $this->session->method('getId')
375
+            ->willReturn('mysessionid');
376
+        $this->activityManager->expects($this->once())
377
+            ->method('generateEvent')
378
+            ->willReturn($event);
379
+        $this->user->expects($this->any())
380
+            ->method('getUID')
381
+            ->willReturn('jos');
382
+        $event->expects($this->once())
383
+            ->method('setApp')
384
+            ->with($this->equalTo('core'))
385
+            ->willReturnSelf();
386
+        $event->expects($this->once())
387
+            ->method('setType')
388
+            ->with($this->equalTo('security'))
389
+            ->willReturnSelf();
390
+        $event->expects($this->once())
391
+            ->method('setAuthor')
392
+            ->with($this->equalTo('jos'))
393
+            ->willReturnSelf();
394
+        $event->expects($this->once())
395
+            ->method('setAffectedUser')
396
+            ->with($this->equalTo('jos'))
397
+            ->willReturnSelf();
398
+        $this->fakeProvider
399
+            ->method('getDisplayName')
400
+            ->willReturn('Fake 2FA');
401
+        $event->expects($this->once())
402
+            ->method('setSubject')
403
+            ->with($this->equalTo('twofactor_success'), $this->equalTo([
404
+                'provider' => 'Fake 2FA',
405
+            ]))
406
+            ->willReturnSelf();
407
+        $token = $this->createMock(OC\Authentication\Token\IToken::class);
408
+        $this->tokenProvider->method('getToken')
409
+            ->with('mysessionid')
410
+            ->willReturn($token);
411
+        $token->method('getId')
412
+            ->willReturn(42);
413
+        $this->config->expects($this->once())
414
+            ->method('deleteUserValue')
415
+            ->with('jos', 'login_token_2fa', '42');
416
+
417
+        $result = $this->manager->verifyChallenge('email', $this->user, $challenge);
418
+
419
+        $this->assertTrue($result);
420
+    }
421
+
422
+    public function testVerifyChallengeInvalidProviderId(): void {
423
+        $this->prepareProviders();
424
+
425
+        $challenge = 'passme';
426
+        $this->fakeProvider->expects($this->never())
427
+            ->method('verifyChallenge')
428
+            ->with($this->user, $challenge);
429
+        $this->session->expects($this->never())
430
+            ->method('remove');
431
+
432
+        $this->assertFalse($this->manager->verifyChallenge('dontexist', $this->user, $challenge));
433
+    }
434
+
435
+    public function testVerifyInvalidChallenge(): void {
436
+        $this->prepareProviders();
437
+
438
+        $challenge = 'dontpassme';
439
+        $event = $this->createMock(IEvent::class);
440
+        $this->fakeProvider->expects($this->once())
441
+            ->method('verifyChallenge')
442
+            ->with($this->user, $challenge)
443
+            ->willReturn(false);
444
+        $this->session->expects($this->never())
445
+            ->method('remove');
446
+        $this->activityManager->expects($this->once())
447
+            ->method('generateEvent')
448
+            ->willReturn($event);
449
+        $this->user->expects($this->any())
450
+            ->method('getUID')
451
+            ->willReturn('jos');
452
+        $event->expects($this->once())
453
+            ->method('setApp')
454
+            ->with($this->equalTo('core'))
455
+            ->willReturnSelf();
456
+        $event->expects($this->once())
457
+            ->method('setType')
458
+            ->with($this->equalTo('security'))
459
+            ->willReturnSelf();
460
+        $event->expects($this->once())
461
+            ->method('setAuthor')
462
+            ->with($this->equalTo('jos'))
463
+            ->willReturnSelf();
464
+        $event->expects($this->once())
465
+            ->method('setAffectedUser')
466
+            ->with($this->equalTo('jos'))
467
+            ->willReturnSelf();
468
+        $this->fakeProvider
469
+            ->method('getDisplayName')
470
+            ->willReturn('Fake 2FA');
471
+        $event->expects($this->once())
472
+            ->method('setSubject')
473
+            ->with($this->equalTo('twofactor_failed'), $this->equalTo([
474
+                'provider' => 'Fake 2FA',
475
+            ]))
476
+            ->willReturnSelf();
477
+
478
+        $this->assertFalse($this->manager->verifyChallenge('email', $this->user, $challenge));
479
+    }
480
+
481
+    public function testNeedsSecondFactor(): void {
482
+        $user = $this->createMock(IUser::class);
483
+
484
+        $calls = [
485
+            ['app_password'],
486
+            ['two_factor_auth_uid'],
487
+            [Manager::SESSION_UID_DONE],
488
+        ];
489
+        $this->session->expects($this->exactly(3))
490
+            ->method('exists')
491
+            ->willReturnCallback(function () use (&$calls) {
492
+                $expected = array_shift($calls);
493
+                $this->assertEquals($expected, func_get_args());
494
+                return false;
495
+            });
496
+
497
+        $this->session->method('getId')
498
+            ->willReturn('mysessionid');
499
+        $token = $this->createMock(OC\Authentication\Token\IToken::class);
500
+        $this->tokenProvider->method('getToken')
501
+            ->with('mysessionid')
502
+            ->willReturn($token);
503
+        $token->method('getId')
504
+            ->willReturn(42);
505
+
506
+        $user->method('getUID')
507
+            ->willReturn('user');
508
+        $this->config->method('getUserKeys')
509
+            ->with('user', 'login_token_2fa')
510
+            ->willReturn([
511
+                '42'
512
+            ]);
513
+
514
+        $manager = $this->getMockBuilder(Manager::class)
515
+            ->setConstructorArgs([
516
+                $this->providerLoader,
517
+                $this->providerRegistry,
518
+                $this->mandatoryTwoFactor,
519
+                $this->session,
520
+                $this->config,
521
+                $this->activityManager,
522
+                $this->logger,
523
+                $this->tokenProvider,
524
+                $this->timeFactory,
525
+                $this->dispatcher,
526
+            ])
527
+            ->onlyMethods(['isTwoFactorAuthenticated'])// Do not actually load the apps
528
+            ->getMock();
529
+
530
+        $manager->method('isTwoFactorAuthenticated')
531
+            ->with($user)
532
+            ->willReturn(true);
533
+
534
+        $this->assertTrue($manager->needsSecondFactor($user));
535
+    }
536
+
537
+    public function testNeedsSecondFactorUserIsNull(): void {
538
+        $user = null;
539
+        $this->session->expects($this->never())
540
+            ->method('exists');
541
+
542
+        $this->assertFalse($this->manager->needsSecondFactor($user));
543
+    }
544
+
545
+    public function testNeedsSecondFactorWithNoProviderAvailableAnymore(): void {
546
+        $this->prepareNoProviders();
547
+
548
+        $user = null;
549
+        $this->session->expects($this->never())
550
+            ->method('exists')
551
+            ->with('two_factor_auth_uid')
552
+            ->willReturn(true);
553
+        $this->session->expects($this->never())
554
+            ->method('remove')
555
+            ->with('two_factor_auth_uid');
556
+
557
+        $this->assertFalse($this->manager->needsSecondFactor($user));
558
+    }
559
+
560
+    public function testPrepareTwoFactorLogin(): void {
561
+        $this->user->method('getUID')
562
+            ->willReturn('ferdinand');
563
+
564
+        $calls = [
565
+            ['two_factor_auth_uid', 'ferdinand'],
566
+            ['two_factor_remember_login', true],
567
+        ];
568
+        $this->session->expects($this->exactly(2))
569
+            ->method('set')
570
+            ->willReturnCallback(function () use (&$calls) {
571
+                $expected = array_shift($calls);
572
+                $this->assertEquals($expected, func_get_args());
573
+            });
574
+
575
+        $this->session->method('getId')
576
+            ->willReturn('mysessionid');
577
+        $token = $this->createMock(OC\Authentication\Token\IToken::class);
578
+        $this->tokenProvider->method('getToken')
579
+            ->with('mysessionid')
580
+            ->willReturn($token);
581
+        $token->method('getId')
582
+            ->willReturn(42);
583
+
584
+        $this->timeFactory->method('getTime')
585
+            ->willReturn(1337);
586
+
587
+        $this->config->method('setUserValue')
588
+            ->with('ferdinand', 'login_token_2fa', '42', '1337');
589
+
590
+
591
+        $this->manager->prepareTwoFactorLogin($this->user, true);
592
+    }
593
+
594
+    public function testPrepareTwoFactorLoginDontRemember(): void {
595
+        $this->user->method('getUID')
596
+            ->willReturn('ferdinand');
597
+
598
+        $calls = [
599
+            ['two_factor_auth_uid', 'ferdinand'],
600
+            ['two_factor_remember_login', false],
601
+        ];
602
+        $this->session->expects($this->exactly(2))
603
+            ->method('set')
604
+            ->willReturnCallback(function () use (&$calls) {
605
+                $expected = array_shift($calls);
606
+                $this->assertEquals($expected, func_get_args());
607
+            });
608
+
609
+        $this->session->method('getId')
610
+            ->willReturn('mysessionid');
611
+        $token = $this->createMock(OC\Authentication\Token\IToken::class);
612
+        $this->tokenProvider->method('getToken')
613
+            ->with('mysessionid')
614
+            ->willReturn($token);
615
+        $token->method('getId')
616
+            ->willReturn(42);
617
+
618
+        $this->timeFactory->method('getTime')
619
+            ->willReturn(1337);
620
+
621
+        $this->config->method('setUserValue')
622
+            ->with('ferdinand', 'login_token_2fa', '42', '1337');
623
+
624
+        $this->manager->prepareTwoFactorLogin($this->user, false);
625
+    }
626
+
627
+    public function testNeedsSecondFactorSessionAuth(): void {
628
+        $user = $this->createMock(IUser::class);
629
+        $user->method('getUID')
630
+            ->willReturn('user');
631
+
632
+        $this->session->method('exists')
633
+            ->willReturnCallback(function ($var) {
634
+                if ($var === Manager::SESSION_UID_KEY) {
635
+                    return false;
636
+                } elseif ($var === 'app_password') {
637
+                    return false;
638
+                } elseif ($var === 'app_api') {
639
+                    return false;
640
+                }
641
+                return true;
642
+            });
643
+        $this->session->method('get')
644
+            ->willReturnCallback(function ($var) {
645
+                if ($var === Manager::SESSION_UID_KEY) {
646
+                    return 'user';
647
+                } elseif ($var === 'app_api') {
648
+                    return true;
649
+                }
650
+                return null;
651
+            });
652
+        $this->session->expects($this->once())
653
+            ->method('get')
654
+            ->willReturnMap([
655
+                [Manager::SESSION_UID_DONE, 'user'],
656
+                ['app_api', true]
657
+            ]);
658
+
659
+        $this->assertFalse($this->manager->needsSecondFactor($user));
660
+    }
661
+
662
+    public function testNeedsSecondFactorSessionAuthFailDBPass(): void {
663
+        $user = $this->createMock(IUser::class);
664
+        $user->method('getUID')
665
+            ->willReturn('user');
666
+
667
+        $this->session->method('exists')
668
+            ->willReturn(false);
669
+        $this->session->method('getId')
670
+            ->willReturn('mysessionid');
671
+
672
+        $token = $this->createMock(OC\Authentication\Token\IToken::class);
673
+        $token->method('getId')
674
+            ->willReturn(40);
675
+
676
+        $this->tokenProvider->method('getToken')
677
+            ->with('mysessionid')
678
+            ->willReturn($token);
679
+
680
+        $this->config->method('getUserKeys')
681
+            ->with('user', 'login_token_2fa')
682
+            ->willReturn([
683
+                '42', '43', '44'
684
+            ]);
685
+
686
+        $this->session->expects($this->once())
687
+            ->method('set')
688
+            ->with(Manager::SESSION_UID_DONE, 'user');
689
+
690
+        $this->assertFalse($this->manager->needsSecondFactor($user));
691
+    }
692
+
693
+    public function testNeedsSecondFactorInvalidToken(): void {
694
+        $this->prepareNoProviders();
695
+
696
+        $user = $this->createMock(IUser::class);
697
+        $user->method('getUID')
698
+            ->willReturn('user');
699
+
700
+        $this->session->method('exists')
701
+            ->willReturn(false);
702
+        $this->session->method('getId')
703
+            ->willReturn('mysessionid');
704
+
705
+        $this->tokenProvider->method('getToken')
706
+            ->with('mysessionid')
707
+            ->willThrowException(new OC\Authentication\Exceptions\InvalidTokenException());
708
+
709
+        $this->config->method('getUserKeys')->willReturn([]);
710
+
711
+        $this->assertFalse($this->manager->needsSecondFactor($user));
712
+    }
713
+
714
+    public function testNeedsSecondFactorAppPassword(): void {
715
+        $user = $this->createMock(IUser::class);
716
+        $this->session->method('exists')
717
+            ->willReturnMap([
718
+                ['app_password', true],
719
+                ['app_api', true]
720
+            ]);
721
+
722
+        $this->assertFalse($this->manager->needsSecondFactor($user));
723
+    }
724
+
725
+    public function testClearTwoFactorPending() {
726
+        $this->config->method('getUserKeys')
727
+            ->with('theUserId', 'login_token_2fa')
728
+            ->willReturn([
729
+                '42', '43', '44'
730
+            ]);
731
+
732
+        $deleteUserValueCalls = [
733
+            ['theUserId', 'login_token_2fa', '42'],
734
+            ['theUserId', 'login_token_2fa', '43'],
735
+            ['theUserId', 'login_token_2fa', '44'],
736
+        ];
737
+        $this->config->expects($this->exactly(3))
738
+            ->method('deleteUserValue')
739
+            ->willReturnCallback(function () use (&$deleteUserValueCalls) {
740
+                $expected = array_shift($deleteUserValueCalls);
741
+                $this->assertEquals($expected, func_get_args());
742
+            });
743
+
744
+        $invalidateCalls = [
745
+            ['theUserId', 42],
746
+            ['theUserId', 43],
747
+            ['theUserId', 44],
748
+        ];
749
+        $this->tokenProvider->expects($this->exactly(3))
750
+            ->method('invalidateTokenById')
751
+            ->willReturnCallback(function () use (&$invalidateCalls) {
752
+                $expected = array_shift($invalidateCalls);
753
+                $this->assertEquals($expected, func_get_args());
754
+            });
755
+
756
+        $this->manager->clearTwoFactorPending('theUserId');
757
+    }
758
+
759
+    public function testClearTwoFactorPendingTokenDoesNotExist() {
760
+        $this->config->method('getUserKeys')
761
+            ->with('theUserId', 'login_token_2fa')
762
+            ->willReturn([
763
+                '42', '43', '44'
764
+            ]);
765
+
766
+        $deleteUserValueCalls = [
767
+            ['theUserId', 'login_token_2fa', '42'],
768
+            ['theUserId', 'login_token_2fa', '43'],
769
+            ['theUserId', 'login_token_2fa', '44'],
770
+        ];
771
+        $this->config->expects($this->exactly(3))
772
+            ->method('deleteUserValue')
773
+            ->willReturnCallback(function () use (&$deleteUserValueCalls) {
774
+                $expected = array_shift($deleteUserValueCalls);
775
+                $this->assertEquals($expected, func_get_args());
776
+            });
777
+
778
+        $invalidateCalls = [
779
+            ['theUserId', 42],
780
+            ['theUserId', 43],
781
+            ['theUserId', 44],
782
+        ];
783
+        $this->tokenProvider->expects($this->exactly(3))
784
+            ->method('invalidateTokenById')
785
+            ->willReturnCallback(function ($user, $tokenId) use (&$invalidateCalls) {
786
+                $expected = array_shift($invalidateCalls);
787
+                $this->assertEquals($expected, func_get_args());
788
+                if ($tokenId === 43) {
789
+                    throw new DoesNotExistException('token does not exist');
790
+                }
791
+            });
792
+
793
+        $this->manager->clearTwoFactorPending('theUserId');
794
+    }
795 795
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
 		];
364 364
 		$this->session->expects($this->exactly(2))
365 365
 			->method('remove')
366
-			->willReturnCallback(function () use (&$calls) {
366
+			->willReturnCallback(function() use (&$calls) {
367 367
 				$expected = array_shift($calls);
368 368
 				$this->assertEquals($expected, func_get_args());
369 369
 			});
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
 		];
489 489
 		$this->session->expects($this->exactly(3))
490 490
 			->method('exists')
491
-			->willReturnCallback(function () use (&$calls) {
491
+			->willReturnCallback(function() use (&$calls) {
492 492
 				$expected = array_shift($calls);
493 493
 				$this->assertEquals($expected, func_get_args());
494 494
 				return false;
@@ -567,7 +567,7 @@  discard block
 block discarded – undo
567 567
 		];
568 568
 		$this->session->expects($this->exactly(2))
569 569
 			->method('set')
570
-			->willReturnCallback(function () use (&$calls) {
570
+			->willReturnCallback(function() use (&$calls) {
571 571
 				$expected = array_shift($calls);
572 572
 				$this->assertEquals($expected, func_get_args());
573 573
 			});
@@ -601,7 +601,7 @@  discard block
 block discarded – undo
601 601
 		];
602 602
 		$this->session->expects($this->exactly(2))
603 603
 			->method('set')
604
-			->willReturnCallback(function () use (&$calls) {
604
+			->willReturnCallback(function() use (&$calls) {
605 605
 				$expected = array_shift($calls);
606 606
 				$this->assertEquals($expected, func_get_args());
607 607
 			});
@@ -630,7 +630,7 @@  discard block
 block discarded – undo
630 630
 			->willReturn('user');
631 631
 
632 632
 		$this->session->method('exists')
633
-			->willReturnCallback(function ($var) {
633
+			->willReturnCallback(function($var) {
634 634
 				if ($var === Manager::SESSION_UID_KEY) {
635 635
 					return false;
636 636
 				} elseif ($var === 'app_password') {
@@ -641,7 +641,7 @@  discard block
 block discarded – undo
641 641
 				return true;
642 642
 			});
643 643
 		$this->session->method('get')
644
-			->willReturnCallback(function ($var) {
644
+			->willReturnCallback(function($var) {
645 645
 				if ($var === Manager::SESSION_UID_KEY) {
646 646
 					return 'user';
647 647
 				} elseif ($var === 'app_api') {
@@ -736,7 +736,7 @@  discard block
 block discarded – undo
736 736
 		];
737 737
 		$this->config->expects($this->exactly(3))
738 738
 			->method('deleteUserValue')
739
-			->willReturnCallback(function () use (&$deleteUserValueCalls) {
739
+			->willReturnCallback(function() use (&$deleteUserValueCalls) {
740 740
 				$expected = array_shift($deleteUserValueCalls);
741 741
 				$this->assertEquals($expected, func_get_args());
742 742
 			});
@@ -748,7 +748,7 @@  discard block
 block discarded – undo
748 748
 		];
749 749
 		$this->tokenProvider->expects($this->exactly(3))
750 750
 			->method('invalidateTokenById')
751
-			->willReturnCallback(function () use (&$invalidateCalls) {
751
+			->willReturnCallback(function() use (&$invalidateCalls) {
752 752
 				$expected = array_shift($invalidateCalls);
753 753
 				$this->assertEquals($expected, func_get_args());
754 754
 			});
@@ -770,7 +770,7 @@  discard block
 block discarded – undo
770 770
 		];
771 771
 		$this->config->expects($this->exactly(3))
772 772
 			->method('deleteUserValue')
773
-			->willReturnCallback(function () use (&$deleteUserValueCalls) {
773
+			->willReturnCallback(function() use (&$deleteUserValueCalls) {
774 774
 				$expected = array_shift($deleteUserValueCalls);
775 775
 				$this->assertEquals($expected, func_get_args());
776 776
 			});
@@ -782,7 +782,7 @@  discard block
 block discarded – undo
782 782
 		];
783 783
 		$this->tokenProvider->expects($this->exactly(3))
784 784
 			->method('invalidateTokenById')
785
-			->willReturnCallback(function ($user, $tokenId) use (&$invalidateCalls) {
785
+			->willReturnCallback(function($user, $tokenId) use (&$invalidateCalls) {
786 786
 				$expected = array_shift($invalidateCalls);
787 787
 				$this->assertEquals($expected, func_get_args());
788 788
 				if ($tokenId === 43) {
Please login to merge, or discard this patch.
tests/lib/Federation/CloudIdTest.php 1 patch
Indentation   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -19,33 +19,33 @@
 block discarded – undo
19 19
  * @group DB
20 20
  */
21 21
 class CloudIdTest extends TestCase {
22
-	protected CloudIdManager&MockObject $cloudIdManager;
23
-
24
-	protected function setUp(): void {
25
-		parent::setUp();
26
-
27
-		$this->cloudIdManager = $this->createMock(CloudIdManager::class);
28
-		$this->overwriteService(ICloudIdManager::class, $this->cloudIdManager);
29
-	}
30
-
31
-	public static function dataGetDisplayCloudId(): array {
32
-		return [
33
-			['[email protected]', 'test', 'example.com', '[email protected]'],
34
-			['test@http://example.com', 'test', 'http://example.com', '[email protected]'],
35
-			['test@https://example.com', 'test', 'https://example.com', '[email protected]'],
36
-			['test@https://example.com', 'test', 'https://example.com', 'Beloved [email protected]', 'Beloved Amy'],
37
-		];
38
-	}
39
-
40
-	/**
41
-	 * @dataProvider dataGetDisplayCloudId
42
-	 */
43
-	public function testGetDisplayCloudId(string $id, string $user, string $remote, string $display, ?string $addressbookName = null): void {
44
-		$this->cloudIdManager->expects($this->once())
45
-			->method('getDisplayNameFromContact')
46
-			->willReturn($addressbookName);
47
-
48
-		$cloudId = new CloudId($id, $user, $remote);
49
-		$this->assertEquals($display, $cloudId->getDisplayId());
50
-	}
22
+    protected CloudIdManager&MockObject $cloudIdManager;
23
+
24
+    protected function setUp(): void {
25
+        parent::setUp();
26
+
27
+        $this->cloudIdManager = $this->createMock(CloudIdManager::class);
28
+        $this->overwriteService(ICloudIdManager::class, $this->cloudIdManager);
29
+    }
30
+
31
+    public static function dataGetDisplayCloudId(): array {
32
+        return [
33
+            ['[email protected]', 'test', 'example.com', '[email protected]'],
34
+            ['test@http://example.com', 'test', 'http://example.com', '[email protected]'],
35
+            ['test@https://example.com', 'test', 'https://example.com', '[email protected]'],
36
+            ['test@https://example.com', 'test', 'https://example.com', 'Beloved [email protected]', 'Beloved Amy'],
37
+        ];
38
+    }
39
+
40
+    /**
41
+     * @dataProvider dataGetDisplayCloudId
42
+     */
43
+    public function testGetDisplayCloudId(string $id, string $user, string $remote, string $display, ?string $addressbookName = null): void {
44
+        $this->cloudIdManager->expects($this->once())
45
+            ->method('getDisplayNameFromContact')
46
+            ->willReturn($addressbookName);
47
+
48
+        $cloudId = new CloudId($id, $user, $remote);
49
+        $this->assertEquals($display, $cloudId->getDisplayId());
50
+    }
51 51
 }
Please login to merge, or discard this patch.
tests/lib/Federation/CloudIdManagerTest.php 2 patches
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -23,161 +23,161 @@
 block discarded – undo
23 23
  * @group DB
24 24
  */
25 25
 class CloudIdManagerTest extends TestCase {
26
-	/** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
27
-	protected $contactsManager;
28
-	/** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
29
-	private $urlGenerator;
30
-	/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
31
-	private $userManager;
32
-	/** @var CloudIdManager */
33
-	private $cloudIdManager;
34
-	/** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */
35
-	private $cacheFactory;
36
-
37
-
38
-	protected function setUp(): void {
39
-		parent::setUp();
40
-
41
-		$this->contactsManager = $this->createMock(IManager::class);
42
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
43
-		$this->userManager = $this->createMock(IUserManager::class);
44
-
45
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
46
-		$this->cacheFactory->method('createDistributed')
47
-			->willReturn(new ArrayCache(''));
48
-
49
-		$this->cloudIdManager = new CloudIdManager(
50
-			$this->contactsManager,
51
-			$this->urlGenerator,
52
-			$this->userManager,
53
-			$this->cacheFactory,
54
-			$this->createMock(IEventDispatcher::class)
55
-		);
56
-		$this->overwriteService(ICloudIdManager::class, $this->cloudIdManager);
57
-	}
58
-
59
-	public static function dataGetDisplayNameFromContact(): array {
60
-		return [
61
-			['[email protected]', 'test', 'test'],
62
-			['[email protected]', null, null],
63
-			['[email protected]', 'test3@example', 'test3@example'],
64
-			['[email protected]', '[email protected]', null],
65
-		];
66
-	}
67
-
68
-	/**
69
-	 * @dataProvider dataGetDisplayNameFromContact
70
-	 */
71
-	public function testGetDisplayNameFromContact(string $cloudId, ?string $displayName, ?string $expected): void {
72
-		$returnedContact = [
73
-			'CLOUD' => [$cloudId],
74
-			'FN' => $expected,
75
-		];
76
-		if ($displayName === null) {
77
-			unset($returnedContact['FN']);
78
-		}
79
-		$this->contactsManager->method('search')
80
-			->with($cloudId, ['CLOUD'])
81
-			->willReturn([$returnedContact]);
82
-
83
-		$this->assertEquals($expected, $this->cloudIdManager->getDisplayNameFromContact($cloudId));
84
-		$this->assertEquals($expected, $this->cloudIdManager->getDisplayNameFromContact($cloudId));
85
-	}
86
-
87
-	public static function cloudIdProvider(): array {
88
-		return [
89
-			['[email protected]', 'test', 'example.com', '[email protected]'],
90
-			['[email protected]/cloud', 'test', 'example.com/cloud', '[email protected]/cloud'],
91
-			['[email protected]/cloud/', 'test', 'example.com/cloud', '[email protected]/cloud'],
92
-			['[email protected]/cloud/index.php', 'test', 'example.com/cloud', '[email protected]/cloud'],
93
-			['[email protected]@example.com', '[email protected]', 'example.com', '[email protected]@example.com'],
94
-
95
-			// Equal signs are not valid on Nextcloud side, but can be used by other federated OCM compatible servers
96
-			['[email protected]', 'test==', 'example.com', '[email protected]'],
97
-			['[email protected]', '==', 'example.com', '[email protected]'],
98
-		];
99
-	}
100
-
101
-	/**
102
-	 * @dataProvider cloudIdProvider
103
-	 */
104
-	public function testResolveCloudId(string $cloudId, string $user, string $noProtocolRemote, string $cleanId): void {
105
-		$displayName = 'Ample Ex';
106
-
107
-		$this->contactsManager->expects($this->any())
108
-			->method('search')
109
-			->with($cleanId, ['CLOUD'])
110
-			->willReturn([
111
-				[
112
-					'CLOUD' => [$cleanId],
113
-					'FN' => $displayName,
114
-				]
115
-			]);
116
-
117
-		$cloudId = $this->cloudIdManager->resolveCloudId($cloudId);
118
-
119
-		$this->assertEquals($user, $cloudId->getUser());
120
-		$this->assertEquals('https://' . $noProtocolRemote, $cloudId->getRemote());
121
-		$this->assertEquals($cleanId, $cloudId->getId());
122
-		$this->assertEquals($displayName . '@' . $noProtocolRemote, $cloudId->getDisplayId());
123
-	}
124
-
125
-	public static function invalidCloudIdProvider(): array {
126
-		return [
127
-			['example.com'],
128
-			['test:[email protected]'],
129
-			['test/[email protected]']
130
-		];
131
-	}
132
-
133
-	/**
134
-	 * @dataProvider invalidCloudIdProvider
135
-	 */
136
-	public function testInvalidCloudId(string $cloudId): void {
137
-		$this->expectException(\InvalidArgumentException::class);
138
-
139
-		$this->contactsManager->expects($this->never())
140
-			->method('search');
141
-
142
-		$this->cloudIdManager->resolveCloudId($cloudId);
143
-	}
144
-
145
-	public static function getCloudIdProvider(): array {
146
-		return [
147
-			['test', 'example.com', '[email protected]', null, 'https://example.com', 'https://example.com'],
148
-			['test', 'http://example.com', 'test@http://example.com', '[email protected]'],
149
-			['test', null, 'test@http://example.com', '[email protected]', 'http://example.com', 'http://example.com'],
150
-			['[email protected]', 'example.com', '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
151
-			['[email protected]', 'https://example.com', '[email protected]@example.com'],
152
-			['[email protected]', null, '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
153
-			['[email protected]', 'https://example.com/index.php/s/shareToken', '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
154
-		];
155
-	}
156
-
157
-	/**
158
-	 * @dataProvider getCloudIdProvider
159
-	 */
160
-	public function testGetCloudId(string $user, ?string $remote, string $id, ?string $searchCloudId = null, ?string $localHost = 'https://example.com', ?string $expectedRemoteId = null): void {
161
-		if ($remote !== null) {
162
-			$this->contactsManager->expects($this->any())
163
-				->method('search')
164
-				->with($searchCloudId ?? $id, ['CLOUD'])
165
-				->willReturn([
166
-					[
167
-						'CLOUD' => [$searchCloudId ?? $id],
168
-						'FN' => 'Ample Ex',
169
-					]
170
-				]);
171
-		} else {
172
-			$this->urlGenerator->expects(self::once())
173
-				->method('getAbsoluteUrl')
174
-				->willReturn($localHost);
175
-		}
176
-		$expectedRemoteId ??= $remote;
177
-
178
-		$cloudId = $this->cloudIdManager->getCloudId($user, $remote);
179
-
180
-		$this->assertEquals($id, $cloudId->getId(), 'Cloud ID');
181
-		$this->assertEquals($expectedRemoteId, $cloudId->getRemote(), 'Remote URL');
182
-	}
26
+    /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
27
+    protected $contactsManager;
28
+    /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
29
+    private $urlGenerator;
30
+    /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
31
+    private $userManager;
32
+    /** @var CloudIdManager */
33
+    private $cloudIdManager;
34
+    /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */
35
+    private $cacheFactory;
36
+
37
+
38
+    protected function setUp(): void {
39
+        parent::setUp();
40
+
41
+        $this->contactsManager = $this->createMock(IManager::class);
42
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
43
+        $this->userManager = $this->createMock(IUserManager::class);
44
+
45
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
46
+        $this->cacheFactory->method('createDistributed')
47
+            ->willReturn(new ArrayCache(''));
48
+
49
+        $this->cloudIdManager = new CloudIdManager(
50
+            $this->contactsManager,
51
+            $this->urlGenerator,
52
+            $this->userManager,
53
+            $this->cacheFactory,
54
+            $this->createMock(IEventDispatcher::class)
55
+        );
56
+        $this->overwriteService(ICloudIdManager::class, $this->cloudIdManager);
57
+    }
58
+
59
+    public static function dataGetDisplayNameFromContact(): array {
60
+        return [
61
+            ['[email protected]', 'test', 'test'],
62
+            ['[email protected]', null, null],
63
+            ['[email protected]', 'test3@example', 'test3@example'],
64
+            ['[email protected]', '[email protected]', null],
65
+        ];
66
+    }
67
+
68
+    /**
69
+     * @dataProvider dataGetDisplayNameFromContact
70
+     */
71
+    public function testGetDisplayNameFromContact(string $cloudId, ?string $displayName, ?string $expected): void {
72
+        $returnedContact = [
73
+            'CLOUD' => [$cloudId],
74
+            'FN' => $expected,
75
+        ];
76
+        if ($displayName === null) {
77
+            unset($returnedContact['FN']);
78
+        }
79
+        $this->contactsManager->method('search')
80
+            ->with($cloudId, ['CLOUD'])
81
+            ->willReturn([$returnedContact]);
82
+
83
+        $this->assertEquals($expected, $this->cloudIdManager->getDisplayNameFromContact($cloudId));
84
+        $this->assertEquals($expected, $this->cloudIdManager->getDisplayNameFromContact($cloudId));
85
+    }
86
+
87
+    public static function cloudIdProvider(): array {
88
+        return [
89
+            ['[email protected]', 'test', 'example.com', '[email protected]'],
90
+            ['[email protected]/cloud', 'test', 'example.com/cloud', '[email protected]/cloud'],
91
+            ['[email protected]/cloud/', 'test', 'example.com/cloud', '[email protected]/cloud'],
92
+            ['[email protected]/cloud/index.php', 'test', 'example.com/cloud', '[email protected]/cloud'],
93
+            ['[email protected]@example.com', '[email protected]', 'example.com', '[email protected]@example.com'],
94
+
95
+            // Equal signs are not valid on Nextcloud side, but can be used by other federated OCM compatible servers
96
+            ['[email protected]', 'test==', 'example.com', '[email protected]'],
97
+            ['[email protected]', '==', 'example.com', '[email protected]'],
98
+        ];
99
+    }
100
+
101
+    /**
102
+     * @dataProvider cloudIdProvider
103
+     */
104
+    public function testResolveCloudId(string $cloudId, string $user, string $noProtocolRemote, string $cleanId): void {
105
+        $displayName = 'Ample Ex';
106
+
107
+        $this->contactsManager->expects($this->any())
108
+            ->method('search')
109
+            ->with($cleanId, ['CLOUD'])
110
+            ->willReturn([
111
+                [
112
+                    'CLOUD' => [$cleanId],
113
+                    'FN' => $displayName,
114
+                ]
115
+            ]);
116
+
117
+        $cloudId = $this->cloudIdManager->resolveCloudId($cloudId);
118
+
119
+        $this->assertEquals($user, $cloudId->getUser());
120
+        $this->assertEquals('https://' . $noProtocolRemote, $cloudId->getRemote());
121
+        $this->assertEquals($cleanId, $cloudId->getId());
122
+        $this->assertEquals($displayName . '@' . $noProtocolRemote, $cloudId->getDisplayId());
123
+    }
124
+
125
+    public static function invalidCloudIdProvider(): array {
126
+        return [
127
+            ['example.com'],
128
+            ['test:[email protected]'],
129
+            ['test/[email protected]']
130
+        ];
131
+    }
132
+
133
+    /**
134
+     * @dataProvider invalidCloudIdProvider
135
+     */
136
+    public function testInvalidCloudId(string $cloudId): void {
137
+        $this->expectException(\InvalidArgumentException::class);
138
+
139
+        $this->contactsManager->expects($this->never())
140
+            ->method('search');
141
+
142
+        $this->cloudIdManager->resolveCloudId($cloudId);
143
+    }
144
+
145
+    public static function getCloudIdProvider(): array {
146
+        return [
147
+            ['test', 'example.com', '[email protected]', null, 'https://example.com', 'https://example.com'],
148
+            ['test', 'http://example.com', 'test@http://example.com', '[email protected]'],
149
+            ['test', null, 'test@http://example.com', '[email protected]', 'http://example.com', 'http://example.com'],
150
+            ['[email protected]', 'example.com', '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
151
+            ['[email protected]', 'https://example.com', '[email protected]@example.com'],
152
+            ['[email protected]', null, '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
153
+            ['[email protected]', 'https://example.com/index.php/s/shareToken', '[email protected]@example.com', null, 'https://example.com', 'https://example.com'],
154
+        ];
155
+    }
156
+
157
+    /**
158
+     * @dataProvider getCloudIdProvider
159
+     */
160
+    public function testGetCloudId(string $user, ?string $remote, string $id, ?string $searchCloudId = null, ?string $localHost = 'https://example.com', ?string $expectedRemoteId = null): void {
161
+        if ($remote !== null) {
162
+            $this->contactsManager->expects($this->any())
163
+                ->method('search')
164
+                ->with($searchCloudId ?? $id, ['CLOUD'])
165
+                ->willReturn([
166
+                    [
167
+                        'CLOUD' => [$searchCloudId ?? $id],
168
+                        'FN' => 'Ample Ex',
169
+                    ]
170
+                ]);
171
+        } else {
172
+            $this->urlGenerator->expects(self::once())
173
+                ->method('getAbsoluteUrl')
174
+                ->willReturn($localHost);
175
+        }
176
+        $expectedRemoteId ??= $remote;
177
+
178
+        $cloudId = $this->cloudIdManager->getCloudId($user, $remote);
179
+
180
+        $this->assertEquals($id, $cloudId->getId(), 'Cloud ID');
181
+        $this->assertEquals($expectedRemoteId, $cloudId->getRemote(), 'Remote URL');
182
+    }
183 183
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -117,9 +117,9 @@
 block discarded – undo
117 117
 		$cloudId = $this->cloudIdManager->resolveCloudId($cloudId);
118 118
 
119 119
 		$this->assertEquals($user, $cloudId->getUser());
120
-		$this->assertEquals('https://' . $noProtocolRemote, $cloudId->getRemote());
120
+		$this->assertEquals('https://'.$noProtocolRemote, $cloudId->getRemote());
121 121
 		$this->assertEquals($cleanId, $cloudId->getId());
122
-		$this->assertEquals($displayName . '@' . $noProtocolRemote, $cloudId->getDisplayId());
122
+		$this->assertEquals($displayName.'@'.$noProtocolRemote, $cloudId->getDisplayId());
123 123
 	}
124 124
 
125 125
 	public static function invalidCloudIdProvider(): array {
Please login to merge, or discard this patch.
tests/lib/Support/Subscription/RegistryTest.php 1 patch
Indentation   +178 added lines, -178 removed lines patch added patch discarded remove patch
@@ -21,182 +21,182 @@
 block discarded – undo
21 21
 use Test\TestCase;
22 22
 
23 23
 class RegistryTest extends TestCase {
24
-	private Registry $registry;
25
-
26
-	private MockObject&IConfig $config;
27
-	private MockObject&IServerContainer $serverContainer;
28
-	private MockObject&IUserManager $userManager;
29
-	private MockObject&IGroupManager $groupManager;
30
-	private MockObject&LoggerInterface $logger;
31
-	private MockObject&IManager $notificationManager;
32
-
33
-	protected function setUp(): void {
34
-		parent::setUp();
35
-
36
-		$this->config = $this->createMock(IConfig::class);
37
-		$this->serverContainer = $this->createMock(IServerContainer::class);
38
-		$this->userManager = $this->createMock(IUserManager::class);
39
-		$this->groupManager = $this->createMock(IGroupManager::class);
40
-		$this->logger = $this->createMock(LoggerInterface::class);
41
-		$this->notificationManager = $this->createMock(IManager::class);
42
-		$this->registry = new Registry(
43
-			$this->config,
44
-			$this->serverContainer,
45
-			$this->userManager,
46
-			$this->groupManager,
47
-			$this->logger
48
-		);
49
-	}
50
-
51
-	/**
52
-	 * Doesn't assert anything, just checks whether anything "explodes"
53
-	 */
54
-	public function testDelegateToNone(): void {
55
-		$this->registry->delegateHasValidSubscription();
56
-		$this->addToAssertionCount(1);
57
-	}
58
-
59
-
60
-	public function testDoubleRegistration(): void {
61
-		$this->expectException(\OCP\Support\Subscription\Exception\AlreadyRegisteredException::class);
62
-
63
-		/* @var ISubscription $subscription1 */
64
-		$subscription1 = $this->createMock(ISubscription::class);
65
-		/* @var ISubscription $subscription2 */
66
-		$subscription2 = $this->createMock(ISubscription::class);
67
-		$this->registry->register($subscription1);
68
-		$this->registry->register($subscription2);
69
-	}
70
-
71
-	public function testNoSupportApp(): void {
72
-		$this->assertSame([], $this->registry->delegateGetSupportedApps());
73
-		$this->assertSame(false, $this->registry->delegateHasValidSubscription());
74
-	}
75
-
76
-	public function testDelegateHasValidSubscription(): void {
77
-		/* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
78
-		$subscription = $this->createMock(ISubscription::class);
79
-		$subscription->expects($this->once())
80
-			->method('hasValidSubscription')
81
-			->willReturn(true);
82
-		$this->registry->register($subscription);
83
-
84
-		$this->assertSame(true, $this->registry->delegateHasValidSubscription());
85
-	}
86
-
87
-	public function testDelegateHasValidSubscriptionConfig(): void {
88
-		/* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
89
-		$this->config->expects($this->once())
90
-			->method('getSystemValueBool')
91
-			->with('has_valid_subscription')
92
-			->willReturn(true);
93
-
94
-		$this->assertSame(true, $this->registry->delegateHasValidSubscription());
95
-	}
96
-
97
-	public function testDelegateHasExtendedSupport(): void {
98
-		/* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
99
-		$subscription = $this->createMock(ISubscription::class);
100
-		$subscription->expects($this->once())
101
-			->method('hasExtendedSupport')
102
-			->willReturn(true);
103
-		$this->registry->register($subscription);
104
-
105
-		$this->assertSame(true, $this->registry->delegateHasExtendedSupport());
106
-	}
107
-
108
-
109
-	public function testDelegateGetSupportedApps(): void {
110
-		/* @var ISupportedApps|\PHPUnit\Framework\MockObject\MockObject $subscription */
111
-		$subscription = $this->createMock(ISupportedApps::class);
112
-		$subscription->expects($this->once())
113
-			->method('getSupportedApps')
114
-			->willReturn(['abc']);
115
-		$this->registry->register($subscription);
116
-
117
-		$this->assertSame(['abc'], $this->registry->delegateGetSupportedApps());
118
-	}
119
-
120
-	public function testSubscriptionService(): void {
121
-		$this->serverContainer->method('query')
122
-			->with(DummySubscription::class)
123
-			->willReturn(new DummySubscription(true, false, false));
124
-		$this->registry->registerService(DummySubscription::class);
125
-
126
-		$this->assertTrue($this->registry->delegateHasValidSubscription());
127
-		$this->assertFalse($this->registry->delegateHasExtendedSupport());
128
-	}
129
-
130
-	public function testDelegateIsHardUserLimitReached(): void {
131
-		/* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
132
-		$subscription = $this->createMock(ISubscription::class);
133
-		$subscription->expects($this->once())
134
-			->method('hasValidSubscription')
135
-			->willReturn(true);
136
-		$subscription->expects($this->once())
137
-			->method('isHardUserLimitReached')
138
-			->willReturn(true);
139
-		$this->registry->register($subscription);
140
-		$dummyGroup = $this->createMock(IGroup::class);
141
-		$dummyGroup->expects($this->once())
142
-			->method('getUsers')
143
-			->willReturn([]);
144
-		$this->groupManager->expects($this->once())
145
-			->method('get')
146
-			->willReturn($dummyGroup);
147
-
148
-		$this->assertSame(true, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
149
-	}
150
-
151
-	public function testDelegateIsHardUserLimitReachedWithoutSupportApp(): void {
152
-		$this->config->expects($this->once())
153
-			->method('getSystemValueBool')
154
-			->with('one-click-instance')
155
-			->willReturn(false);
156
-
157
-		$this->assertSame(false, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
158
-	}
159
-
160
-	public static function dataForUserLimitCheck(): array {
161
-		return [
162
-			// $userLimit, $userCount, $disabledUsers, $expectedResult
163
-			[35, 15, 2, false],
164
-			[35, 45, 15, false],
165
-			[35, 45, 5, true],
166
-			[35, 45, 55, false],
167
-		];
168
-	}
169
-
170
-	/**
171
-	 * @dataProvider dataForUserLimitCheck
172
-	 */
173
-	public function testDelegateIsHardUserLimitReachedWithoutSupportAppAndUserCount($userLimit, $userCount, $disabledUsers, $expectedResult): void {
174
-		$this->config->expects($this->once())
175
-			->method('getSystemValueBool')
176
-			->with('one-click-instance')
177
-			->willReturn(true);
178
-		$this->config->expects($this->once())
179
-			->method('getSystemValueInt')
180
-			->with('one-click-instance.user-limit')
181
-			->willReturn($userLimit);
182
-		$this->config->expects($this->once())
183
-			->method('getUsersForUserValue')
184
-			->with('core', 'enabled', 'false')
185
-			->willReturn(array_fill(0, $disabledUsers, ''));
186
-		$this->userManager->expects($this->once())
187
-			->method('countUsersTotal')
188
-			->willReturn($userCount);
189
-
190
-		if ($expectedResult) {
191
-			$dummyGroup = $this->createMock(IGroup::class);
192
-			$dummyGroup->expects($this->once())
193
-				->method('getUsers')
194
-				->willReturn([]);
195
-			$this->groupManager->expects($this->once())
196
-				->method('get')
197
-				->willReturn($dummyGroup);
198
-		}
199
-
200
-		$this->assertSame($expectedResult, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
201
-	}
24
+    private Registry $registry;
25
+
26
+    private MockObject&IConfig $config;
27
+    private MockObject&IServerContainer $serverContainer;
28
+    private MockObject&IUserManager $userManager;
29
+    private MockObject&IGroupManager $groupManager;
30
+    private MockObject&LoggerInterface $logger;
31
+    private MockObject&IManager $notificationManager;
32
+
33
+    protected function setUp(): void {
34
+        parent::setUp();
35
+
36
+        $this->config = $this->createMock(IConfig::class);
37
+        $this->serverContainer = $this->createMock(IServerContainer::class);
38
+        $this->userManager = $this->createMock(IUserManager::class);
39
+        $this->groupManager = $this->createMock(IGroupManager::class);
40
+        $this->logger = $this->createMock(LoggerInterface::class);
41
+        $this->notificationManager = $this->createMock(IManager::class);
42
+        $this->registry = new Registry(
43
+            $this->config,
44
+            $this->serverContainer,
45
+            $this->userManager,
46
+            $this->groupManager,
47
+            $this->logger
48
+        );
49
+    }
50
+
51
+    /**
52
+     * Doesn't assert anything, just checks whether anything "explodes"
53
+     */
54
+    public function testDelegateToNone(): void {
55
+        $this->registry->delegateHasValidSubscription();
56
+        $this->addToAssertionCount(1);
57
+    }
58
+
59
+
60
+    public function testDoubleRegistration(): void {
61
+        $this->expectException(\OCP\Support\Subscription\Exception\AlreadyRegisteredException::class);
62
+
63
+        /* @var ISubscription $subscription1 */
64
+        $subscription1 = $this->createMock(ISubscription::class);
65
+        /* @var ISubscription $subscription2 */
66
+        $subscription2 = $this->createMock(ISubscription::class);
67
+        $this->registry->register($subscription1);
68
+        $this->registry->register($subscription2);
69
+    }
70
+
71
+    public function testNoSupportApp(): void {
72
+        $this->assertSame([], $this->registry->delegateGetSupportedApps());
73
+        $this->assertSame(false, $this->registry->delegateHasValidSubscription());
74
+    }
75
+
76
+    public function testDelegateHasValidSubscription(): void {
77
+        /* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
78
+        $subscription = $this->createMock(ISubscription::class);
79
+        $subscription->expects($this->once())
80
+            ->method('hasValidSubscription')
81
+            ->willReturn(true);
82
+        $this->registry->register($subscription);
83
+
84
+        $this->assertSame(true, $this->registry->delegateHasValidSubscription());
85
+    }
86
+
87
+    public function testDelegateHasValidSubscriptionConfig(): void {
88
+        /* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
89
+        $this->config->expects($this->once())
90
+            ->method('getSystemValueBool')
91
+            ->with('has_valid_subscription')
92
+            ->willReturn(true);
93
+
94
+        $this->assertSame(true, $this->registry->delegateHasValidSubscription());
95
+    }
96
+
97
+    public function testDelegateHasExtendedSupport(): void {
98
+        /* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
99
+        $subscription = $this->createMock(ISubscription::class);
100
+        $subscription->expects($this->once())
101
+            ->method('hasExtendedSupport')
102
+            ->willReturn(true);
103
+        $this->registry->register($subscription);
104
+
105
+        $this->assertSame(true, $this->registry->delegateHasExtendedSupport());
106
+    }
107
+
108
+
109
+    public function testDelegateGetSupportedApps(): void {
110
+        /* @var ISupportedApps|\PHPUnit\Framework\MockObject\MockObject $subscription */
111
+        $subscription = $this->createMock(ISupportedApps::class);
112
+        $subscription->expects($this->once())
113
+            ->method('getSupportedApps')
114
+            ->willReturn(['abc']);
115
+        $this->registry->register($subscription);
116
+
117
+        $this->assertSame(['abc'], $this->registry->delegateGetSupportedApps());
118
+    }
119
+
120
+    public function testSubscriptionService(): void {
121
+        $this->serverContainer->method('query')
122
+            ->with(DummySubscription::class)
123
+            ->willReturn(new DummySubscription(true, false, false));
124
+        $this->registry->registerService(DummySubscription::class);
125
+
126
+        $this->assertTrue($this->registry->delegateHasValidSubscription());
127
+        $this->assertFalse($this->registry->delegateHasExtendedSupport());
128
+    }
129
+
130
+    public function testDelegateIsHardUserLimitReached(): void {
131
+        /* @var ISubscription|\PHPUnit\Framework\MockObject\MockObject $subscription */
132
+        $subscription = $this->createMock(ISubscription::class);
133
+        $subscription->expects($this->once())
134
+            ->method('hasValidSubscription')
135
+            ->willReturn(true);
136
+        $subscription->expects($this->once())
137
+            ->method('isHardUserLimitReached')
138
+            ->willReturn(true);
139
+        $this->registry->register($subscription);
140
+        $dummyGroup = $this->createMock(IGroup::class);
141
+        $dummyGroup->expects($this->once())
142
+            ->method('getUsers')
143
+            ->willReturn([]);
144
+        $this->groupManager->expects($this->once())
145
+            ->method('get')
146
+            ->willReturn($dummyGroup);
147
+
148
+        $this->assertSame(true, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
149
+    }
150
+
151
+    public function testDelegateIsHardUserLimitReachedWithoutSupportApp(): void {
152
+        $this->config->expects($this->once())
153
+            ->method('getSystemValueBool')
154
+            ->with('one-click-instance')
155
+            ->willReturn(false);
156
+
157
+        $this->assertSame(false, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
158
+    }
159
+
160
+    public static function dataForUserLimitCheck(): array {
161
+        return [
162
+            // $userLimit, $userCount, $disabledUsers, $expectedResult
163
+            [35, 15, 2, false],
164
+            [35, 45, 15, false],
165
+            [35, 45, 5, true],
166
+            [35, 45, 55, false],
167
+        ];
168
+    }
169
+
170
+    /**
171
+     * @dataProvider dataForUserLimitCheck
172
+     */
173
+    public function testDelegateIsHardUserLimitReachedWithoutSupportAppAndUserCount($userLimit, $userCount, $disabledUsers, $expectedResult): void {
174
+        $this->config->expects($this->once())
175
+            ->method('getSystemValueBool')
176
+            ->with('one-click-instance')
177
+            ->willReturn(true);
178
+        $this->config->expects($this->once())
179
+            ->method('getSystemValueInt')
180
+            ->with('one-click-instance.user-limit')
181
+            ->willReturn($userLimit);
182
+        $this->config->expects($this->once())
183
+            ->method('getUsersForUserValue')
184
+            ->with('core', 'enabled', 'false')
185
+            ->willReturn(array_fill(0, $disabledUsers, ''));
186
+        $this->userManager->expects($this->once())
187
+            ->method('countUsersTotal')
188
+            ->willReturn($userCount);
189
+
190
+        if ($expectedResult) {
191
+            $dummyGroup = $this->createMock(IGroup::class);
192
+            $dummyGroup->expects($this->once())
193
+                ->method('getUsers')
194
+                ->willReturn([]);
195
+            $this->groupManager->expects($this->once())
196
+                ->method('get')
197
+                ->willReturn($dummyGroup);
198
+        }
199
+
200
+        $this->assertSame($expectedResult, $this->registry->delegateIsHardUserLimitReached($this->notificationManager));
201
+    }
202 202
 }
Please login to merge, or discard this patch.
tests/lib/AppConfigTest.php 2 patches
Indentation   +1437 added lines, -1437 removed lines patch added patch discarded remove patch
@@ -24,1441 +24,1441 @@
 block discarded – undo
24 24
  * @package Test
25 25
  */
26 26
 class AppConfigTest extends TestCase {
27
-	protected IAppConfig $appConfig;
28
-	protected IDBConnection $connection;
29
-	private LoggerInterface $logger;
30
-	private ICrypto $crypto;
31
-
32
-	private array $originalConfig;
33
-
34
-	/**
35
-	 * @var array<string, array<string, array<string, string, int, bool, bool>>>
36
-	 *                                                                           [appId => [configKey, configValue, valueType, lazy, sensitive]]
37
-	 */
38
-	private static array $baseStruct =
39
-		[
40
-			'testapp' => [
41
-				'enabled' => ['enabled', 'true'],
42
-				'installed_version' => ['installed_version', '1.2.3'],
43
-				'depends_on' => ['depends_on', 'someapp'],
44
-				'deletethis' => ['deletethis', 'deletethis'],
45
-				'key' => ['key', 'value']
46
-			],
47
-			'someapp' => [
48
-				'key' => ['key', 'value'],
49
-				'otherkey' => ['otherkey', 'othervalue']
50
-			],
51
-			'123456' => [
52
-				'enabled' => ['enabled', 'true'],
53
-				'key' => ['key', 'value']
54
-			],
55
-			'anotherapp' => [
56
-				'enabled' => ['enabled', 'false'],
57
-				'key' => ['key', 'value']
58
-			],
59
-			'non-sensitive-app' => [
60
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, false],
61
-				'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, false],
62
-			],
63
-			'sensitive-app' => [
64
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, true],
65
-				'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, true],
66
-			],
67
-			'only-lazy' => [
68
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true]
69
-			],
70
-			'typed' => [
71
-				'mixed' => ['mixed', 'mix', IAppConfig::VALUE_MIXED],
72
-				'string' => ['string', 'value', IAppConfig::VALUE_STRING],
73
-				'int' => ['int', '42', IAppConfig::VALUE_INT],
74
-				'float' => ['float', '3.14', IAppConfig::VALUE_FLOAT],
75
-				'bool' => ['bool', '1', IAppConfig::VALUE_BOOL],
76
-				'array' => ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
77
-			],
78
-			'prefix-app' => [
79
-				'key1' => ['key1', 'value'],
80
-				'prefix1' => ['prefix1', 'value'],
81
-				'prefix-2' => ['prefix-2', 'value'],
82
-				'key-2' => ['key-2', 'value'],
83
-			]
84
-		];
85
-
86
-	protected function setUp(): void {
87
-		parent::setUp();
88
-
89
-		$this->connection = \OCP\Server::get(IDBConnection::class);
90
-		$this->logger = \OCP\Server::get(LoggerInterface::class);
91
-		$this->crypto = \OCP\Server::get(ICrypto::class);
92
-
93
-		// storing current config and emptying the data table
94
-		$sql = $this->connection->getQueryBuilder();
95
-		$sql->select('*')
96
-			->from('appconfig');
97
-		$result = $sql->executeQuery();
98
-		$this->originalConfig = $result->fetchAll();
99
-		$result->closeCursor();
100
-
101
-		$sql = $this->connection->getQueryBuilder();
102
-		$sql->delete('appconfig');
103
-		$sql->executeStatement();
104
-
105
-		$sql = $this->connection->getQueryBuilder();
106
-		$sql->insert('appconfig')
107
-			->values(
108
-				[
109
-					'appid' => $sql->createParameter('appid'),
110
-					'configkey' => $sql->createParameter('configkey'),
111
-					'configvalue' => $sql->createParameter('configvalue'),
112
-					'type' => $sql->createParameter('type'),
113
-					'lazy' => $sql->createParameter('lazy')
114
-				]
115
-			);
116
-
117
-		foreach (self::$baseStruct as $appId => $appData) {
118
-			foreach ($appData as $key => $row) {
119
-				$value = $row[1];
120
-				$type = $row[2] ?? IAppConfig::VALUE_MIXED;
121
-				if (($row[4] ?? false) === true) {
122
-					$type |= IAppConfig::VALUE_SENSITIVE;
123
-					$value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
124
-					self::$baseStruct[$appId][$key]['encrypted'] = $value;
125
-				}
126
-
127
-				$sql->setParameters(
128
-					[
129
-						'appid' => $appId,
130
-						'configkey' => $row[0],
131
-						'configvalue' => $value,
132
-						'type' => $type,
133
-						'lazy' => (($row[3] ?? false) === true) ? 1 : 0
134
-					]
135
-				)->executeStatement();
136
-			}
137
-		}
138
-	}
139
-
140
-	protected function tearDown(): void {
141
-		$sql = $this->connection->getQueryBuilder();
142
-		$sql->delete('appconfig');
143
-		$sql->executeStatement();
144
-
145
-		$sql = $this->connection->getQueryBuilder();
146
-		$sql->insert('appconfig')
147
-			->values(
148
-				[
149
-					'appid' => $sql->createParameter('appid'),
150
-					'configkey' => $sql->createParameter('configkey'),
151
-					'configvalue' => $sql->createParameter('configvalue'),
152
-					'lazy' => $sql->createParameter('lazy'),
153
-					'type' => $sql->createParameter('type'),
154
-				]
155
-			);
156
-
157
-		foreach ($this->originalConfig as $key => $configs) {
158
-			$sql->setParameter('appid', $configs['appid'])
159
-				->setParameter('configkey', $configs['configkey'])
160
-				->setParameter('configvalue', $configs['configvalue'])
161
-				->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
162
-				->setParameter('type', $configs['type']);
163
-			$sql->executeStatement();
164
-		}
165
-
166
-		//		$this->restoreService(AppConfig::class);
167
-		parent::tearDown();
168
-	}
169
-
170
-	/**
171
-	 * @param bool $preLoading TRUE will preload the 'fast' cache, which is the normal behavior of usual
172
-	 *                         IAppConfig
173
-	 *
174
-	 * @return IAppConfig
175
-	 */
176
-	private function generateAppConfig(bool $preLoading = true): IAppConfig {
177
-		/** @var AppConfig $config */
178
-		$config = new \OC\AppConfig(
179
-			$this->connection,
180
-			$this->logger,
181
-			$this->crypto,
182
-		);
183
-		$msg = ' generateAppConfig() failed to confirm cache status';
184
-
185
-		// confirm cache status
186
-		$status = $config->statusCache();
187
-		$this->assertSame(false, $status['fastLoaded'], $msg);
188
-		$this->assertSame(false, $status['lazyLoaded'], $msg);
189
-		$this->assertSame([], $status['fastCache'], $msg);
190
-		$this->assertSame([], $status['lazyCache'], $msg);
191
-		if ($preLoading) {
192
-			// simple way to initiate the load of non-lazy config values in cache
193
-			$config->getValueString('core', 'preload', '');
194
-
195
-			// confirm cache status
196
-			$status = $config->statusCache();
197
-			$this->assertSame(true, $status['fastLoaded'], $msg);
198
-			$this->assertSame(false, $status['lazyLoaded'], $msg);
199
-
200
-			$apps = array_values(array_diff(array_keys(self::$baseStruct), ['only-lazy']));
201
-			$this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache']), $msg);
202
-			$this->assertSame([], array_keys($status['lazyCache']), $msg);
203
-		}
204
-
205
-		return $config;
206
-	}
207
-
208
-	public function testGetApps(): void {
209
-		$config = $this->generateAppConfig(false);
210
-
211
-		$this->assertEqualsCanonicalizing(array_keys(self::$baseStruct), $config->getApps());
212
-	}
213
-
214
-	/**
215
-	 * returns list of app and their keys
216
-	 *
217
-	 * @return array<string, string[]> ['appId' => ['key1', 'key2', ]]
218
-	 * @see testGetKeys
219
-	 */
220
-	public static function providerGetAppKeys(): array {
221
-		$appKeys = [];
222
-		foreach (self::$baseStruct as $appId => $appData) {
223
-			$keys = [];
224
-			foreach ($appData as $row) {
225
-				$keys[] = $row[0];
226
-			}
227
-			$appKeys[] = [(string)$appId, $keys];
228
-		}
229
-
230
-		return $appKeys;
231
-	}
232
-
233
-	/**
234
-	 * returns list of config keys
235
-	 *
236
-	 * @return array<string, string, string, int, bool, bool> [appId, key, value, type, lazy, sensitive]
237
-	 * @see testIsSensitive
238
-	 * @see testIsLazy
239
-	 * @see testGetKeys
240
-	 */
241
-	public static function providerGetKeys(): array {
242
-		$appKeys = [];
243
-		foreach (self::$baseStruct as $appId => $appData) {
244
-			foreach ($appData as $row) {
245
-				$appKeys[] = [
246
-					(string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
247
-					$row[4] ?? false
248
-				];
249
-			}
250
-		}
251
-
252
-		return $appKeys;
253
-	}
254
-
255
-	/**
256
-	 * @dataProvider providerGetAppKeys
257
-	 *
258
-	 * @param string $appId
259
-	 * @param array $expectedKeys
260
-	 */
261
-	public function testGetKeys(string $appId, array $expectedKeys): void {
262
-		$config = $this->generateAppConfig();
263
-		$this->assertEqualsCanonicalizing($expectedKeys, $config->getKeys($appId));
264
-	}
265
-
266
-	public function testGetKeysOnUnknownAppShouldReturnsEmptyArray(): void {
267
-		$config = $this->generateAppConfig();
268
-		$this->assertEqualsCanonicalizing([], $config->getKeys('unknown-app'));
269
-	}
270
-
271
-	/**
272
-	 * @dataProvider providerGetKeys
273
-	 *
274
-	 * @param string $appId
275
-	 * @param string $configKey
276
-	 * @param string $value
277
-	 * @param bool $lazy
278
-	 */
279
-	public function testHasKey(string $appId, string $configKey, string $value, int $type, bool $lazy): void {
280
-		$config = $this->generateAppConfig();
281
-		$this->assertEquals(true, $config->hasKey($appId, $configKey, $lazy));
282
-	}
283
-
284
-	public function testHasKeyOnNonExistentKeyReturnsFalse(): void {
285
-		$config = $this->generateAppConfig();
286
-		$this->assertEquals(false, $config->hasKey(array_keys(self::$baseStruct)[0], 'inexistant-key'));
287
-	}
288
-
289
-	public function testHasKeyOnUnknownAppReturnsFalse(): void {
290
-		$config = $this->generateAppConfig();
291
-		$this->assertEquals(false, $config->hasKey('inexistant-app', 'inexistant-key'));
292
-	}
293
-
294
-	public function testHasKeyOnMistypedAsLazyReturnsFalse(): void {
295
-		$config = $this->generateAppConfig();
296
-		$this->assertSame(false, $config->hasKey('non-sensitive-app', 'non-lazy-key', true));
297
-	}
298
-
299
-	public function testHasKeyOnMistypeAsNonLazyReturnsFalse(): void {
300
-		$config = $this->generateAppConfig();
301
-		$this->assertSame(false, $config->hasKey('non-sensitive-app', 'lazy-key', false));
302
-	}
303
-
304
-	public function testHasKeyOnMistypeAsNonLazyReturnsTrueWithLazyArgumentIsNull(): void {
305
-		$config = $this->generateAppConfig();
306
-		$this->assertSame(true, $config->hasKey('non-sensitive-app', 'lazy-key', null));
307
-	}
308
-
309
-	/**
310
-	 * @dataProvider providerGetKeys
311
-	 */
312
-	public function testIsSensitive(
313
-		string $appId, string $configKey, string $configValue, int $type, bool $lazy, bool $sensitive,
314
-	): void {
315
-		$config = $this->generateAppConfig();
316
-		$this->assertEquals($sensitive, $config->isSensitive($appId, $configKey, $lazy));
317
-	}
318
-
319
-	public function testIsSensitiveOnNonExistentKeyThrowsException(): void {
320
-		$config = $this->generateAppConfig();
321
-		$this->expectException(AppConfigUnknownKeyException::class);
322
-		$config->isSensitive(array_keys(self::$baseStruct)[0], 'inexistant-key');
323
-	}
324
-
325
-	public function testIsSensitiveOnUnknownAppThrowsException(): void {
326
-		$config = $this->generateAppConfig();
327
-		$this->expectException(AppConfigUnknownKeyException::class);
328
-		$config->isSensitive('unknown-app', 'inexistant-key');
329
-	}
330
-
331
-	public function testIsSensitiveOnSensitiveMistypedAsLazy(): void {
332
-		$config = $this->generateAppConfig();
333
-		$this->assertSame(true, $config->isSensitive('sensitive-app', 'non-lazy-key', true));
334
-	}
335
-
336
-	public function testIsSensitiveOnNonSensitiveMistypedAsLazy(): void {
337
-		$config = $this->generateAppConfig();
338
-		$this->assertSame(false, $config->isSensitive('non-sensitive-app', 'non-lazy-key', true));
339
-	}
340
-
341
-	public function testIsSensitiveOnSensitiveMistypedAsNonLazyThrowsException(): void {
342
-		$config = $this->generateAppConfig();
343
-		$this->expectException(AppConfigUnknownKeyException::class);
344
-		$config->isSensitive('sensitive-app', 'lazy-key', false);
345
-	}
346
-
347
-	public function testIsSensitiveOnNonSensitiveMistypedAsNonLazyThrowsException(): void {
348
-		$config = $this->generateAppConfig();
349
-		$this->expectException(AppConfigUnknownKeyException::class);
350
-		$config->isSensitive('non-sensitive-app', 'lazy-key', false);
351
-	}
352
-
353
-	/**
354
-	 * @dataProvider providerGetKeys
355
-	 */
356
-	public function testIsLazy(string $appId, string $configKey, string $configValue, int $type, bool $lazy,
357
-	): void {
358
-		$config = $this->generateAppConfig();
359
-		$this->assertEquals($lazy, $config->isLazy($appId, $configKey));
360
-	}
361
-
362
-	public function testIsLazyOnNonExistentKeyThrowsException(): void {
363
-		$config = $this->generateAppConfig();
364
-		$this->expectException(AppConfigUnknownKeyException::class);
365
-		$config->isLazy(array_keys(self::$baseStruct)[0], 'inexistant-key');
366
-	}
367
-
368
-	public function testIsLazyOnUnknownAppThrowsException(): void {
369
-		$config = $this->generateAppConfig();
370
-		$this->expectException(AppConfigUnknownKeyException::class);
371
-		$config->isLazy('unknown-app', 'inexistant-key');
372
-	}
373
-
374
-	public function testGetAllValues(): void {
375
-		$config = $this->generateAppConfig();
376
-		$this->assertEquals(
377
-			[
378
-				'array' => ['test' => 1],
379
-				'bool' => true,
380
-				'float' => 3.14,
381
-				'int' => 42,
382
-				'mixed' => 'mix',
383
-				'string' => 'value',
384
-			],
385
-			$config->getAllValues('typed')
386
-		);
387
-	}
388
-
389
-	public function testGetAllValuesWithEmptyApp(): void {
390
-		$config = $this->generateAppConfig();
391
-		$this->expectException(InvalidArgumentException::class);
392
-		$config->getAllValues('');
393
-	}
394
-
395
-	/**
396
-	 * @dataProvider providerGetAppKeys
397
-	 *
398
-	 * @param string $appId
399
-	 * @param array $keys
400
-	 */
401
-	public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
402
-		$config = $this->generateAppConfig();
403
-		$this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
404
-	}
405
-
406
-	public function testGetAllValuesWithPrefix(): void {
407
-		$config = $this->generateAppConfig();
408
-		$this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
409
-	}
410
-
411
-	public function testSearchValues(): void {
412
-		$config = $this->generateAppConfig();
413
-		$this->assertEqualsCanonicalizing(['testapp' => 'true', '123456' => 'true', 'anotherapp' => 'false'], $config->searchValues('enabled'));
414
-	}
415
-
416
-	public function testGetValueString(): void {
417
-		$config = $this->generateAppConfig();
418
-		$this->assertSame('value', $config->getValueString('typed', 'string', ''));
419
-	}
420
-
421
-	public function testGetValueStringOnUnknownAppReturnsDefault(): void {
422
-		$config = $this->generateAppConfig();
423
-		$this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
424
-	}
425
-
426
-	public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
427
-		$config = $this->generateAppConfig();
428
-		$this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
429
-	}
430
-
431
-	public function testGetValueStringOnWrongType(): void {
432
-		$config = $this->generateAppConfig();
433
-		$this->expectException(AppConfigTypeConflictException::class);
434
-		$config->getValueString('typed', 'int');
435
-	}
436
-
437
-	public function testGetNonLazyValueStringAsLazy(): void {
438
-		$config = $this->generateAppConfig();
439
-		$this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
440
-	}
441
-
442
-	public function testGetValueInt(): void {
443
-		$config = $this->generateAppConfig();
444
-		$this->assertSame(42, $config->getValueInt('typed', 'int', 0));
445
-	}
446
-
447
-	public function testGetValueIntOnUnknownAppReturnsDefault(): void {
448
-		$config = $this->generateAppConfig();
449
-		$this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
450
-	}
451
-
452
-	public function testGetValueIntOnNonExistentKeyReturnsDefault(): void {
453
-		$config = $this->generateAppConfig();
454
-		$this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
455
-	}
456
-
457
-	public function testGetValueIntOnWrongType(): void {
458
-		$config = $this->generateAppConfig();
459
-		$this->expectException(AppConfigTypeConflictException::class);
460
-		$config->getValueInt('typed', 'float');
461
-	}
462
-
463
-	public function testGetValueFloat(): void {
464
-		$config = $this->generateAppConfig();
465
-		$this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
466
-	}
467
-
468
-	public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
469
-		$config = $this->generateAppConfig();
470
-		$this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
471
-	}
472
-
473
-	public function testGetValueFloatOnNonExistentKeyReturnsDefault(): void {
474
-		$config = $this->generateAppConfig();
475
-		$this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
476
-	}
477
-
478
-	public function testGetValueFloatOnWrongType(): void {
479
-		$config = $this->generateAppConfig();
480
-		$this->expectException(AppConfigTypeConflictException::class);
481
-		$config->getValueFloat('typed', 'bool');
482
-	}
483
-
484
-	public function testGetValueBool(): void {
485
-		$config = $this->generateAppConfig();
486
-		$this->assertSame(true, $config->getValueBool('typed', 'bool'));
487
-	}
488
-
489
-	public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
490
-		$config = $this->generateAppConfig();
491
-		$this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
492
-	}
493
-
494
-	public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
495
-		$config = $this->generateAppConfig();
496
-		$this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
497
-	}
498
-
499
-	public function testGetValueBoolOnWrongType(): void {
500
-		$config = $this->generateAppConfig();
501
-		$this->expectException(AppConfigTypeConflictException::class);
502
-		$config->getValueBool('typed', 'array');
503
-	}
504
-
505
-	public function testGetValueArray(): void {
506
-		$config = $this->generateAppConfig();
507
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
508
-	}
509
-
510
-	public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
511
-		$config = $this->generateAppConfig();
512
-		$this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
513
-	}
514
-
515
-	public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
516
-		$config = $this->generateAppConfig();
517
-		$this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
518
-	}
519
-
520
-	public function testGetValueArrayOnWrongType(): void {
521
-		$config = $this->generateAppConfig();
522
-		$this->expectException(AppConfigTypeConflictException::class);
523
-		$config->getValueArray('typed', 'string');
524
-	}
525
-
526
-
527
-	/**
528
-	 * @return array
529
-	 * @see testGetValueType
530
-	 *
531
-	 * @see testGetValueMixed
532
-	 */
533
-	public static function providerGetValueMixed(): array {
534
-		return [
535
-			// key, value, type
536
-			['mixed', 'mix', IAppConfig::VALUE_MIXED],
537
-			['string', 'value', IAppConfig::VALUE_STRING],
538
-			['int', '42', IAppConfig::VALUE_INT],
539
-			['float', '3.14', IAppConfig::VALUE_FLOAT],
540
-			['bool', '1', IAppConfig::VALUE_BOOL],
541
-			['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
542
-		];
543
-	}
544
-
545
-	/**
546
-	 * @dataProvider providerGetValueMixed
547
-	 *
548
-	 * @param string $key
549
-	 * @param string $value
550
-	 */
551
-	public function testGetValueMixed(string $key, string $value): void {
552
-		$config = $this->generateAppConfig();
553
-		$this->assertSame($value, $config->getValueMixed('typed', $key));
554
-	}
555
-
556
-	/**
557
-	 * @dataProvider providerGetValueMixed
558
-	 *
559
-	 * @param string $key
560
-	 * @param string $value
561
-	 * @param int $type
562
-	 */
563
-	public function testGetValueType(string $key, string $value, int $type): void {
564
-		$config = $this->generateAppConfig();
565
-		$this->assertSame($type, $config->getValueType('typed', $key));
566
-	}
567
-
568
-	public function testGetValueTypeOnUnknownApp(): void {
569
-		$config = $this->generateAppConfig();
570
-		$this->expectException(AppConfigUnknownKeyException::class);
571
-		$config->getValueType('typed-1', 'string');
572
-	}
573
-
574
-	public function testGetValueTypeOnNonExistentKey(): void {
575
-		$config = $this->generateAppConfig();
576
-		$this->expectException(AppConfigUnknownKeyException::class);
577
-		$config->getValueType('typed', 'string-2');
578
-	}
579
-
580
-	public function testSetValueString(): void {
581
-		$config = $this->generateAppConfig();
582
-		$config->setValueString('feed', 'string', 'value-1');
583
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
584
-	}
585
-
586
-	public function testSetValueStringCache(): void {
587
-		$config = $this->generateAppConfig();
588
-		$config->setValueString('feed', 'string', 'value-1');
589
-		$status = $config->statusCache();
590
-		$this->assertSame('value-1', $status['fastCache']['feed']['string']);
591
-	}
592
-
593
-	public function testSetValueStringDatabase(): void {
594
-		$config = $this->generateAppConfig();
595
-		$config->setValueString('feed', 'string', 'value-1');
596
-		$config->clearCache();
597
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
598
-	}
599
-
600
-	public function testSetValueStringIsUpdated(): void {
601
-		$config = $this->generateAppConfig();
602
-		$config->setValueString('feed', 'string', 'value-1');
603
-		$this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
604
-	}
605
-
606
-	public function testSetValueStringIsNotUpdated(): void {
607
-		$config = $this->generateAppConfig();
608
-		$config->setValueString('feed', 'string', 'value-1');
609
-		$this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
610
-	}
611
-
612
-	public function testSetValueStringIsUpdatedCache(): void {
613
-		$config = $this->generateAppConfig();
614
-		$config->setValueString('feed', 'string', 'value-1');
615
-		$config->setValueString('feed', 'string', 'value-2');
616
-		$status = $config->statusCache();
617
-		$this->assertSame('value-2', $status['fastCache']['feed']['string']);
618
-	}
619
-
620
-	public function testSetValueStringIsUpdatedDatabase(): void {
621
-		$config = $this->generateAppConfig();
622
-		$config->setValueString('feed', 'string', 'value-1');
623
-		$config->setValueString('feed', 'string', 'value-2');
624
-		$config->clearCache();
625
-		$this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
626
-	}
627
-
628
-	public function testSetValueInt(): void {
629
-		$config = $this->generateAppConfig();
630
-		$config->setValueInt('feed', 'int', 42);
631
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
632
-	}
633
-
634
-	public function testSetValueIntCache(): void {
635
-		$config = $this->generateAppConfig();
636
-		$config->setValueInt('feed', 'int', 42);
637
-		$status = $config->statusCache();
638
-		$this->assertSame('42', $status['fastCache']['feed']['int']);
639
-	}
640
-
641
-	public function testSetValueIntDatabase(): void {
642
-		$config = $this->generateAppConfig();
643
-		$config->setValueInt('feed', 'int', 42);
644
-		$config->clearCache();
645
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
646
-	}
647
-
648
-	public function testSetValueIntIsUpdated(): void {
649
-		$config = $this->generateAppConfig();
650
-		$config->setValueInt('feed', 'int', 42);
651
-		$this->assertSame(true, $config->setValueInt('feed', 'int', 17));
652
-	}
653
-
654
-	public function testSetValueIntIsNotUpdated(): void {
655
-		$config = $this->generateAppConfig();
656
-		$config->setValueInt('feed', 'int', 42);
657
-		$this->assertSame(false, $config->setValueInt('feed', 'int', 42));
658
-	}
659
-
660
-	public function testSetValueIntIsUpdatedCache(): void {
661
-		$config = $this->generateAppConfig();
662
-		$config->setValueInt('feed', 'int', 42);
663
-		$config->setValueInt('feed', 'int', 17);
664
-		$status = $config->statusCache();
665
-		$this->assertSame('17', $status['fastCache']['feed']['int']);
666
-	}
667
-
668
-	public function testSetValueIntIsUpdatedDatabase(): void {
669
-		$config = $this->generateAppConfig();
670
-		$config->setValueInt('feed', 'int', 42);
671
-		$config->setValueInt('feed', 'int', 17);
672
-		$config->clearCache();
673
-		$this->assertSame(17, $config->getValueInt('feed', 'int', 0));
674
-	}
675
-
676
-	public function testSetValueFloat(): void {
677
-		$config = $this->generateAppConfig();
678
-		$config->setValueFloat('feed', 'float', 3.14);
679
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
680
-	}
681
-
682
-	public function testSetValueFloatCache(): void {
683
-		$config = $this->generateAppConfig();
684
-		$config->setValueFloat('feed', 'float', 3.14);
685
-		$status = $config->statusCache();
686
-		$this->assertSame('3.14', $status['fastCache']['feed']['float']);
687
-	}
688
-
689
-	public function testSetValueFloatDatabase(): void {
690
-		$config = $this->generateAppConfig();
691
-		$config->setValueFloat('feed', 'float', 3.14);
692
-		$config->clearCache();
693
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
694
-	}
695
-
696
-	public function testSetValueFloatIsUpdated(): void {
697
-		$config = $this->generateAppConfig();
698
-		$config->setValueFloat('feed', 'float', 3.14);
699
-		$this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
700
-	}
701
-
702
-	public function testSetValueFloatIsNotUpdated(): void {
703
-		$config = $this->generateAppConfig();
704
-		$config->setValueFloat('feed', 'float', 3.14);
705
-		$this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
706
-	}
707
-
708
-	public function testSetValueFloatIsUpdatedCache(): void {
709
-		$config = $this->generateAppConfig();
710
-		$config->setValueFloat('feed', 'float', 3.14);
711
-		$config->setValueFloat('feed', 'float', 1.23);
712
-		$status = $config->statusCache();
713
-		$this->assertSame('1.23', $status['fastCache']['feed']['float']);
714
-	}
715
-
716
-	public function testSetValueFloatIsUpdatedDatabase(): void {
717
-		$config = $this->generateAppConfig();
718
-		$config->setValueFloat('feed', 'float', 3.14);
719
-		$config->setValueFloat('feed', 'float', 1.23);
720
-		$config->clearCache();
721
-		$this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
722
-	}
723
-
724
-	public function testSetValueBool(): void {
725
-		$config = $this->generateAppConfig();
726
-		$config->setValueBool('feed', 'bool', true);
727
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
728
-	}
729
-
730
-	public function testSetValueBoolCache(): void {
731
-		$config = $this->generateAppConfig();
732
-		$config->setValueBool('feed', 'bool', true);
733
-		$status = $config->statusCache();
734
-		$this->assertSame('1', $status['fastCache']['feed']['bool']);
735
-	}
736
-
737
-	public function testSetValueBoolDatabase(): void {
738
-		$config = $this->generateAppConfig();
739
-		$config->setValueBool('feed', 'bool', true);
740
-		$config->clearCache();
741
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
742
-	}
743
-
744
-	public function testSetValueBoolIsUpdated(): void {
745
-		$config = $this->generateAppConfig();
746
-		$config->setValueBool('feed', 'bool', true);
747
-		$this->assertSame(true, $config->setValueBool('feed', 'bool', false));
748
-	}
749
-
750
-	public function testSetValueBoolIsNotUpdated(): void {
751
-		$config = $this->generateAppConfig();
752
-		$config->setValueBool('feed', 'bool', true);
753
-		$this->assertSame(false, $config->setValueBool('feed', 'bool', true));
754
-	}
755
-
756
-	public function testSetValueBoolIsUpdatedCache(): void {
757
-		$config = $this->generateAppConfig();
758
-		$config->setValueBool('feed', 'bool', true);
759
-		$config->setValueBool('feed', 'bool', false);
760
-		$status = $config->statusCache();
761
-		$this->assertSame('0', $status['fastCache']['feed']['bool']);
762
-	}
763
-
764
-	public function testSetValueBoolIsUpdatedDatabase(): void {
765
-		$config = $this->generateAppConfig();
766
-		$config->setValueBool('feed', 'bool', true);
767
-		$config->setValueBool('feed', 'bool', false);
768
-		$config->clearCache();
769
-		$this->assertSame(false, $config->getValueBool('feed', 'bool', true));
770
-	}
771
-
772
-
773
-	public function testSetValueArray(): void {
774
-		$config = $this->generateAppConfig();
775
-		$config->setValueArray('feed', 'array', ['test' => 1]);
776
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
777
-	}
778
-
779
-	public function testSetValueArrayCache(): void {
780
-		$config = $this->generateAppConfig();
781
-		$config->setValueArray('feed', 'array', ['test' => 1]);
782
-		$status = $config->statusCache();
783
-		$this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
784
-	}
785
-
786
-	public function testSetValueArrayDatabase(): void {
787
-		$config = $this->generateAppConfig();
788
-		$config->setValueArray('feed', 'array', ['test' => 1]);
789
-		$config->clearCache();
790
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
791
-	}
792
-
793
-	public function testSetValueArrayIsUpdated(): void {
794
-		$config = $this->generateAppConfig();
795
-		$config->setValueArray('feed', 'array', ['test' => 1]);
796
-		$this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
797
-	}
798
-
799
-	public function testSetValueArrayIsNotUpdated(): void {
800
-		$config = $this->generateAppConfig();
801
-		$config->setValueArray('feed', 'array', ['test' => 1]);
802
-		$this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
803
-	}
804
-
805
-	public function testSetValueArrayIsUpdatedCache(): void {
806
-		$config = $this->generateAppConfig();
807
-		$config->setValueArray('feed', 'array', ['test' => 1]);
808
-		$config->setValueArray('feed', 'array', ['test' => 2]);
809
-		$status = $config->statusCache();
810
-		$this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
811
-	}
812
-
813
-	public function testSetValueArrayIsUpdatedDatabase(): void {
814
-		$config = $this->generateAppConfig();
815
-		$config->setValueArray('feed', 'array', ['test' => 1]);
816
-		$config->setValueArray('feed', 'array', ['test' => 2]);
817
-		$config->clearCache();
818
-		$this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
819
-	}
820
-
821
-	public function testSetLazyValueString(): void {
822
-		$config = $this->generateAppConfig();
823
-		$config->setValueString('feed', 'string', 'value-1', true);
824
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
825
-	}
826
-
827
-	public function testSetLazyValueStringCache(): void {
828
-		$config = $this->generateAppConfig();
829
-		$config->setValueString('feed', 'string', 'value-1', true);
830
-		$status = $config->statusCache();
831
-		$this->assertSame('value-1', $status['lazyCache']['feed']['string']);
832
-	}
833
-
834
-	public function testSetLazyValueStringDatabase(): void {
835
-		$config = $this->generateAppConfig();
836
-		$config->setValueString('feed', 'string', 'value-1', true);
837
-		$config->clearCache();
838
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
839
-	}
840
-
841
-	public function testSetLazyValueStringAsNonLazy(): void {
842
-		$config = $this->generateAppConfig();
843
-		$config->setValueString('feed', 'string', 'value-1', true);
844
-		$config->setValueString('feed', 'string', 'value-1', false);
845
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
846
-	}
847
-
848
-	public function testSetNonLazyValueStringAsLazy(): void {
849
-		$config = $this->generateAppConfig();
850
-		$config->setValueString('feed', 'string', 'value-1', false);
851
-		$config->setValueString('feed', 'string', 'value-1', true);
852
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
853
-	}
854
-
855
-	public function testSetSensitiveValueString(): void {
856
-		$config = $this->generateAppConfig();
857
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
858
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
859
-	}
860
-
861
-	public function testSetSensitiveValueStringCache(): void {
862
-		$config = $this->generateAppConfig();
863
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
864
-		$status = $config->statusCache();
865
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
866
-	}
867
-
868
-	public function testSetSensitiveValueStringDatabase(): void {
869
-		$config = $this->generateAppConfig();
870
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
871
-		$config->clearCache();
872
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
873
-	}
874
-
875
-	public function testSetNonSensitiveValueStringAsSensitive(): void {
876
-		$config = $this->generateAppConfig();
877
-		$config->setValueString('feed', 'string', 'value-1', sensitive: false);
878
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
879
-		$this->assertSame(true, $config->isSensitive('feed', 'string'));
880
-
881
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
882
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
883
-	}
884
-
885
-	public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
886
-		$config = $this->generateAppConfig();
887
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
888
-		$config->setValueString('feed', 'string', 'value-2', sensitive: false);
889
-		$this->assertSame(true, $config->isSensitive('feed', 'string'));
890
-
891
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
892
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
893
-	}
894
-
895
-	public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
896
-		$config = $this->generateAppConfig();
897
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
898
-		$config->setValueString('feed', 'string', 'value-2', sensitive: false);
899
-		$this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
900
-
901
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
902
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
903
-	}
904
-
905
-	public function testSetLazyValueInt(): void {
906
-		$config = $this->generateAppConfig();
907
-		$config->setValueInt('feed', 'int', 42, true);
908
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
909
-	}
910
-
911
-	public function testSetLazyValueIntCache(): void {
912
-		$config = $this->generateAppConfig();
913
-		$config->setValueInt('feed', 'int', 42, true);
914
-		$status = $config->statusCache();
915
-		$this->assertSame('42', $status['lazyCache']['feed']['int']);
916
-	}
917
-
918
-	public function testSetLazyValueIntDatabase(): void {
919
-		$config = $this->generateAppConfig();
920
-		$config->setValueInt('feed', 'int', 42, true);
921
-		$config->clearCache();
922
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
923
-	}
924
-
925
-	public function testSetLazyValueIntAsNonLazy(): void {
926
-		$config = $this->generateAppConfig();
927
-		$config->setValueInt('feed', 'int', 42, true);
928
-		$config->setValueInt('feed', 'int', 42, false);
929
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
930
-	}
931
-
932
-	public function testSetNonLazyValueIntAsLazy(): void {
933
-		$config = $this->generateAppConfig();
934
-		$config->setValueInt('feed', 'int', 42, false);
935
-		$config->setValueInt('feed', 'int', 42, true);
936
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
937
-	}
938
-
939
-	public function testSetSensitiveValueInt(): void {
940
-		$config = $this->generateAppConfig();
941
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
942
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
943
-	}
944
-
945
-	public function testSetSensitiveValueIntCache(): void {
946
-		$config = $this->generateAppConfig();
947
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
948
-		$status = $config->statusCache();
949
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
950
-	}
951
-
952
-	public function testSetSensitiveValueIntDatabase(): void {
953
-		$config = $this->generateAppConfig();
954
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
955
-		$config->clearCache();
956
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
957
-	}
958
-
959
-	public function testSetNonSensitiveValueIntAsSensitive(): void {
960
-		$config = $this->generateAppConfig();
961
-		$config->setValueInt('feed', 'int', 42);
962
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
963
-		$this->assertSame(true, $config->isSensitive('feed', 'int'));
964
-	}
965
-
966
-	public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
967
-		$config = $this->generateAppConfig();
968
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
969
-		$config->setValueInt('feed', 'int', 17);
970
-		$this->assertSame(true, $config->isSensitive('feed', 'int'));
971
-	}
972
-
973
-	public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
974
-		$config = $this->generateAppConfig();
975
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
976
-		$config->setValueInt('feed', 'int', 17);
977
-		$this->assertSame(17, $config->getValueInt('feed', 'int', 0));
978
-	}
979
-
980
-	public function testSetLazyValueFloat(): void {
981
-		$config = $this->generateAppConfig();
982
-		$config->setValueFloat('feed', 'float', 3.14, true);
983
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
984
-	}
985
-
986
-	public function testSetLazyValueFloatCache(): void {
987
-		$config = $this->generateAppConfig();
988
-		$config->setValueFloat('feed', 'float', 3.14, true);
989
-		$status = $config->statusCache();
990
-		$this->assertSame('3.14', $status['lazyCache']['feed']['float']);
991
-	}
992
-
993
-	public function testSetLazyValueFloatDatabase(): void {
994
-		$config = $this->generateAppConfig();
995
-		$config->setValueFloat('feed', 'float', 3.14, true);
996
-		$config->clearCache();
997
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
998
-	}
999
-
1000
-	public function testSetLazyValueFloatAsNonLazy(): void {
1001
-		$config = $this->generateAppConfig();
1002
-		$config->setValueFloat('feed', 'float', 3.14, true);
1003
-		$config->setValueFloat('feed', 'float', 3.14, false);
1004
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1005
-	}
1006
-
1007
-	public function testSetNonLazyValueFloatAsLazy(): void {
1008
-		$config = $this->generateAppConfig();
1009
-		$config->setValueFloat('feed', 'float', 3.14, false);
1010
-		$config->setValueFloat('feed', 'float', 3.14, true);
1011
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1012
-	}
1013
-
1014
-	public function testSetSensitiveValueFloat(): void {
1015
-		$config = $this->generateAppConfig();
1016
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1017
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1018
-	}
1019
-
1020
-	public function testSetSensitiveValueFloatCache(): void {
1021
-		$config = $this->generateAppConfig();
1022
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1023
-		$status = $config->statusCache();
1024
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
1025
-	}
1026
-
1027
-	public function testSetSensitiveValueFloatDatabase(): void {
1028
-		$config = $this->generateAppConfig();
1029
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1030
-		$config->clearCache();
1031
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1032
-	}
1033
-
1034
-	public function testSetNonSensitiveValueFloatAsSensitive(): void {
1035
-		$config = $this->generateAppConfig();
1036
-		$config->setValueFloat('feed', 'float', 3.14);
1037
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1038
-		$this->assertSame(true, $config->isSensitive('feed', 'float'));
1039
-	}
1040
-
1041
-	public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
1042
-		$config = $this->generateAppConfig();
1043
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1044
-		$config->setValueFloat('feed', 'float', 1.23);
1045
-		$this->assertSame(true, $config->isSensitive('feed', 'float'));
1046
-	}
1047
-
1048
-	public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
1049
-		$config = $this->generateAppConfig();
1050
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1051
-		$config->setValueFloat('feed', 'float', 1.23);
1052
-		$this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
1053
-	}
1054
-
1055
-	public function testSetLazyValueBool(): void {
1056
-		$config = $this->generateAppConfig();
1057
-		$config->setValueBool('feed', 'bool', true, true);
1058
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1059
-	}
1060
-
1061
-	public function testSetLazyValueBoolCache(): void {
1062
-		$config = $this->generateAppConfig();
1063
-		$config->setValueBool('feed', 'bool', true, true);
1064
-		$status = $config->statusCache();
1065
-		$this->assertSame('1', $status['lazyCache']['feed']['bool']);
1066
-	}
1067
-
1068
-	public function testSetLazyValueBoolDatabase(): void {
1069
-		$config = $this->generateAppConfig();
1070
-		$config->setValueBool('feed', 'bool', true, true);
1071
-		$config->clearCache();
1072
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1073
-	}
1074
-
1075
-	public function testSetLazyValueBoolAsNonLazy(): void {
1076
-		$config = $this->generateAppConfig();
1077
-		$config->setValueBool('feed', 'bool', true, true);
1078
-		$config->setValueBool('feed', 'bool', true, false);
1079
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
1080
-	}
1081
-
1082
-	public function testSetNonLazyValueBoolAsLazy(): void {
1083
-		$config = $this->generateAppConfig();
1084
-		$config->setValueBool('feed', 'bool', true, false);
1085
-		$config->setValueBool('feed', 'bool', true, true);
1086
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1087
-	}
1088
-
1089
-	public function testSetLazyValueArray(): void {
1090
-		$config = $this->generateAppConfig();
1091
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1092
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1093
-	}
1094
-
1095
-	public function testSetLazyValueArrayCache(): void {
1096
-		$config = $this->generateAppConfig();
1097
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1098
-		$status = $config->statusCache();
1099
-		$this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
1100
-	}
1101
-
1102
-	public function testSetLazyValueArrayDatabase(): void {
1103
-		$config = $this->generateAppConfig();
1104
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1105
-		$config->clearCache();
1106
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1107
-	}
1108
-
1109
-	public function testSetLazyValueArrayAsNonLazy(): void {
1110
-		$config = $this->generateAppConfig();
1111
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1112
-		$config->setValueArray('feed', 'array', ['test' => 1], false);
1113
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
1114
-	}
1115
-
1116
-	public function testSetNonLazyValueArrayAsLazy(): void {
1117
-		$config = $this->generateAppConfig();
1118
-		$config->setValueArray('feed', 'array', ['test' => 1], false);
1119
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1120
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1121
-	}
1122
-
1123
-
1124
-	public function testSetSensitiveValueArray(): void {
1125
-		$config = $this->generateAppConfig();
1126
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1127
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1128
-	}
1129
-
1130
-	public function testSetSensitiveValueArrayCache(): void {
1131
-		$config = $this->generateAppConfig();
1132
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1133
-		$status = $config->statusCache();
1134
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
1135
-	}
1136
-
1137
-	public function testSetSensitiveValueArrayDatabase(): void {
1138
-		$config = $this->generateAppConfig();
1139
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1140
-		$config->clearCache();
1141
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1142
-	}
1143
-
1144
-	public function testSetNonSensitiveValueArrayAsSensitive(): void {
1145
-		$config = $this->generateAppConfig();
1146
-		$config->setValueArray('feed', 'array', ['test' => 1]);
1147
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1148
-		$this->assertSame(true, $config->isSensitive('feed', 'array'));
1149
-	}
1150
-
1151
-	public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
1152
-		$config = $this->generateAppConfig();
1153
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1154
-		$config->setValueArray('feed', 'array', ['test' => 2]);
1155
-		$this->assertSame(true, $config->isSensitive('feed', 'array'));
1156
-	}
1157
-
1158
-	public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
1159
-		$config = $this->generateAppConfig();
1160
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1161
-		$config->setValueArray('feed', 'array', ['test' => 2]);
1162
-		$this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
1163
-	}
1164
-
1165
-	public function testUpdateNotSensitiveToSensitive(): void {
1166
-		$config = $this->generateAppConfig();
1167
-		$config->updateSensitive('non-sensitive-app', 'lazy-key', true);
1168
-		$this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
1169
-	}
1170
-
1171
-	public function testUpdateSensitiveToNotSensitive(): void {
1172
-		$config = $this->generateAppConfig();
1173
-		$config->updateSensitive('sensitive-app', 'lazy-key', false);
1174
-		$this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
1175
-	}
1176
-
1177
-	public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
1178
-		$config = $this->generateAppConfig();
1179
-		$this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
1180
-	}
1181
-
1182
-	public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
1183
-		$config = $this->generateAppConfig();
1184
-		$this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
1185
-	}
1186
-
1187
-	public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
1188
-		$config = $this->generateAppConfig();
1189
-		$this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
1190
-	}
1191
-
1192
-	public function testUpdateNotLazyToLazy(): void {
1193
-		$config = $this->generateAppConfig();
1194
-		$config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
1195
-		$this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
1196
-	}
1197
-
1198
-	public function testUpdateLazyToNotLazy(): void {
1199
-		$config = $this->generateAppConfig();
1200
-		$config->updateLazy('non-sensitive-app', 'lazy-key', false);
1201
-		$this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
1202
-	}
1203
-
1204
-	public function testUpdateLazyToLazyReturnsFalse(): void {
1205
-		$config = $this->generateAppConfig();
1206
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
1207
-	}
1208
-
1209
-	public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
1210
-		$config = $this->generateAppConfig();
1211
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
1212
-	}
1213
-
1214
-	public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
1215
-		$config = $this->generateAppConfig();
1216
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
1217
-	}
1218
-
1219
-	public function testGetDetails(): void {
1220
-		$config = $this->generateAppConfig();
1221
-		$this->assertEquals(
1222
-			[
1223
-				'app' => 'non-sensitive-app',
1224
-				'key' => 'lazy-key',
1225
-				'value' => 'value',
1226
-				'type' => 4,
1227
-				'lazy' => true,
1228
-				'typeString' => 'string',
1229
-				'sensitive' => false,
1230
-			],
1231
-			$config->getDetails('non-sensitive-app', 'lazy-key')
1232
-		);
1233
-	}
1234
-
1235
-	public function testGetDetailsSensitive(): void {
1236
-		$config = $this->generateAppConfig();
1237
-		$this->assertEquals(
1238
-			[
1239
-				'app' => 'sensitive-app',
1240
-				'key' => 'lazy-key',
1241
-				'value' => 'value',
1242
-				'type' => 4,
1243
-				'lazy' => true,
1244
-				'typeString' => 'string',
1245
-				'sensitive' => true,
1246
-			],
1247
-			$config->getDetails('sensitive-app', 'lazy-key')
1248
-		);
1249
-	}
1250
-
1251
-	public function testGetDetailsInt(): void {
1252
-		$config = $this->generateAppConfig();
1253
-		$this->assertEquals(
1254
-			[
1255
-				'app' => 'typed',
1256
-				'key' => 'int',
1257
-				'value' => '42',
1258
-				'type' => 8,
1259
-				'lazy' => false,
1260
-				'typeString' => 'integer',
1261
-				'sensitive' => false
1262
-			],
1263
-			$config->getDetails('typed', 'int')
1264
-		);
1265
-	}
1266
-
1267
-	public function testGetDetailsFloat(): void {
1268
-		$config = $this->generateAppConfig();
1269
-		$this->assertEquals(
1270
-			[
1271
-				'app' => 'typed',
1272
-				'key' => 'float',
1273
-				'value' => '3.14',
1274
-				'type' => 16,
1275
-				'lazy' => false,
1276
-				'typeString' => 'float',
1277
-				'sensitive' => false
1278
-			],
1279
-			$config->getDetails('typed', 'float')
1280
-		);
1281
-	}
1282
-
1283
-	public function testGetDetailsBool(): void {
1284
-		$config = $this->generateAppConfig();
1285
-		$this->assertEquals(
1286
-			[
1287
-				'app' => 'typed',
1288
-				'key' => 'bool',
1289
-				'value' => '1',
1290
-				'type' => 32,
1291
-				'lazy' => false,
1292
-				'typeString' => 'boolean',
1293
-				'sensitive' => false
1294
-			],
1295
-			$config->getDetails('typed', 'bool')
1296
-		);
1297
-	}
1298
-
1299
-	public function testGetDetailsArray(): void {
1300
-		$config = $this->generateAppConfig();
1301
-		$this->assertEquals(
1302
-			[
1303
-				'app' => 'typed',
1304
-				'key' => 'array',
1305
-				'value' => '{"test": 1}',
1306
-				'type' => 64,
1307
-				'lazy' => false,
1308
-				'typeString' => 'array',
1309
-				'sensitive' => false
1310
-			],
1311
-			$config->getDetails('typed', 'array')
1312
-		);
1313
-	}
1314
-
1315
-	public function testDeleteKey(): void {
1316
-		$config = $this->generateAppConfig();
1317
-		$config->deleteKey('anotherapp', 'key');
1318
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1319
-	}
1320
-
1321
-	public function testDeleteKeyCache(): void {
1322
-		$config = $this->generateAppConfig();
1323
-		$config->deleteKey('anotherapp', 'key');
1324
-		$status = $config->statusCache();
1325
-		$this->assertEqualsCanonicalizing(['enabled' => 'false'], $status['fastCache']['anotherapp']);
1326
-	}
1327
-
1328
-	public function testDeleteKeyDatabase(): void {
1329
-		$config = $this->generateAppConfig();
1330
-		$config->deleteKey('anotherapp', 'key');
1331
-		$config->clearCache();
1332
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1333
-	}
1334
-
1335
-	public function testDeleteApp(): void {
1336
-		$config = $this->generateAppConfig();
1337
-		$config->deleteApp('anotherapp');
1338
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1339
-		$this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1340
-	}
1341
-
1342
-	public function testDeleteAppCache(): void {
1343
-		$config = $this->generateAppConfig();
1344
-		$status = $config->statusCache();
1345
-		$this->assertSame(true, isset($status['fastCache']['anotherapp']));
1346
-		$config->deleteApp('anotherapp');
1347
-		$status = $config->statusCache();
1348
-		$this->assertSame(false, isset($status['fastCache']['anotherapp']));
1349
-	}
1350
-
1351
-	public function testDeleteAppDatabase(): void {
1352
-		$config = $this->generateAppConfig();
1353
-		$config->deleteApp('anotherapp');
1354
-		$config->clearCache();
1355
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1356
-		$this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1357
-	}
1358
-
1359
-	public function testClearCache(): void {
1360
-		$config = $this->generateAppConfig();
1361
-		$config->setValueString('feed', 'string', '123454');
1362
-		$config->clearCache();
1363
-		$status = $config->statusCache();
1364
-		$this->assertSame([], $status['fastCache']);
1365
-	}
1366
-
1367
-	public function testSensitiveValuesAreEncrypted(): void {
1368
-		$key = self::getUniqueID('secret');
1369
-
1370
-		$appConfig = $this->generateAppConfig();
1371
-		$secret = md5((string)time());
1372
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1373
-
1374
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1375
-
1376
-		// Can get in same run
1377
-		$actualSecret = $appConfig->getValueString('testapp', $key);
1378
-		$this->assertEquals($secret, $actualSecret);
1379
-
1380
-		// Can get freshly decrypted from DB
1381
-		$newAppConfig = $this->generateAppConfig();
1382
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1383
-		$this->assertEquals($secret, $actualSecret);
1384
-	}
1385
-
1386
-	public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
1387
-		$key = self::getUniqueID('secret');
1388
-		$appConfig = $this->generateAppConfig();
1389
-		$secret = sha1((string)time());
1390
-
1391
-		// Unencrypted
1392
-		$appConfig->setValueString('testapp', $key, $secret);
1393
-		$this->assertConfigKey('testapp', $key, $secret);
1394
-
1395
-		// Can get freshly decrypted from DB
1396
-		$newAppConfig = $this->generateAppConfig();
1397
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1398
-		$this->assertEquals($secret, $actualSecret);
1399
-
1400
-		// Encrypting on change
1401
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1402
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1403
-
1404
-		// Can get in same run
1405
-		$actualSecret = $appConfig->getValueString('testapp', $key);
1406
-		$this->assertEquals($secret, $actualSecret);
1407
-
1408
-		// Can get freshly decrypted from DB
1409
-		$newAppConfig = $this->generateAppConfig();
1410
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1411
-		$this->assertEquals($secret, $actualSecret);
1412
-	}
1413
-
1414
-	public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
1415
-		$key = self::getUniqueID('secret');
1416
-		$appConfig = $this->generateAppConfig();
1417
-		$secret = sha1((string)time());
1418
-
1419
-		// Encrypted
1420
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1421
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1422
-
1423
-		// Migrate to non-sensitive / non-encrypted
1424
-		$appConfig->updateSensitive('testapp', $key, false);
1425
-		$this->assertConfigKey('testapp', $key, $secret);
1426
-	}
1427
-
1428
-	public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
1429
-		$key = self::getUniqueID('secret');
1430
-		$appConfig = $this->generateAppConfig();
1431
-		$secret = sha1((string)time());
1432
-
1433
-		// Unencrypted
1434
-		$appConfig->setValueString('testapp', $key, $secret);
1435
-		$this->assertConfigKey('testapp', $key, $secret);
1436
-
1437
-		// Migrate to sensitive / encrypted
1438
-		$appConfig->updateSensitive('testapp', $key, true);
1439
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1440
-	}
1441
-
1442
-	protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
1443
-		$sql = $this->connection->getQueryBuilder();
1444
-		$sql->select('configvalue')
1445
-			->from('appconfig')
1446
-			->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
1447
-			->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
1448
-			->setParameter('appid', $app)
1449
-			->setParameter('configkey', $key);
1450
-		$query = $sql->executeQuery();
1451
-		$actual = $query->fetchOne();
1452
-		$query->closeCursor();
1453
-
1454
-		return $actual;
1455
-	}
1456
-
1457
-	protected function assertConfigKey(string $app, string $key, string|false $expected): void {
1458
-		$this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1459
-	}
1460
-
1461
-	protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
1462
-		$this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1463
-	}
27
+    protected IAppConfig $appConfig;
28
+    protected IDBConnection $connection;
29
+    private LoggerInterface $logger;
30
+    private ICrypto $crypto;
31
+
32
+    private array $originalConfig;
33
+
34
+    /**
35
+     * @var array<string, array<string, array<string, string, int, bool, bool>>>
36
+     *                                                                           [appId => [configKey, configValue, valueType, lazy, sensitive]]
37
+     */
38
+    private static array $baseStruct =
39
+        [
40
+            'testapp' => [
41
+                'enabled' => ['enabled', 'true'],
42
+                'installed_version' => ['installed_version', '1.2.3'],
43
+                'depends_on' => ['depends_on', 'someapp'],
44
+                'deletethis' => ['deletethis', 'deletethis'],
45
+                'key' => ['key', 'value']
46
+            ],
47
+            'someapp' => [
48
+                'key' => ['key', 'value'],
49
+                'otherkey' => ['otherkey', 'othervalue']
50
+            ],
51
+            '123456' => [
52
+                'enabled' => ['enabled', 'true'],
53
+                'key' => ['key', 'value']
54
+            ],
55
+            'anotherapp' => [
56
+                'enabled' => ['enabled', 'false'],
57
+                'key' => ['key', 'value']
58
+            ],
59
+            'non-sensitive-app' => [
60
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, false],
61
+                'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, false],
62
+            ],
63
+            'sensitive-app' => [
64
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, true],
65
+                'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, true],
66
+            ],
67
+            'only-lazy' => [
68
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true]
69
+            ],
70
+            'typed' => [
71
+                'mixed' => ['mixed', 'mix', IAppConfig::VALUE_MIXED],
72
+                'string' => ['string', 'value', IAppConfig::VALUE_STRING],
73
+                'int' => ['int', '42', IAppConfig::VALUE_INT],
74
+                'float' => ['float', '3.14', IAppConfig::VALUE_FLOAT],
75
+                'bool' => ['bool', '1', IAppConfig::VALUE_BOOL],
76
+                'array' => ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
77
+            ],
78
+            'prefix-app' => [
79
+                'key1' => ['key1', 'value'],
80
+                'prefix1' => ['prefix1', 'value'],
81
+                'prefix-2' => ['prefix-2', 'value'],
82
+                'key-2' => ['key-2', 'value'],
83
+            ]
84
+        ];
85
+
86
+    protected function setUp(): void {
87
+        parent::setUp();
88
+
89
+        $this->connection = \OCP\Server::get(IDBConnection::class);
90
+        $this->logger = \OCP\Server::get(LoggerInterface::class);
91
+        $this->crypto = \OCP\Server::get(ICrypto::class);
92
+
93
+        // storing current config and emptying the data table
94
+        $sql = $this->connection->getQueryBuilder();
95
+        $sql->select('*')
96
+            ->from('appconfig');
97
+        $result = $sql->executeQuery();
98
+        $this->originalConfig = $result->fetchAll();
99
+        $result->closeCursor();
100
+
101
+        $sql = $this->connection->getQueryBuilder();
102
+        $sql->delete('appconfig');
103
+        $sql->executeStatement();
104
+
105
+        $sql = $this->connection->getQueryBuilder();
106
+        $sql->insert('appconfig')
107
+            ->values(
108
+                [
109
+                    'appid' => $sql->createParameter('appid'),
110
+                    'configkey' => $sql->createParameter('configkey'),
111
+                    'configvalue' => $sql->createParameter('configvalue'),
112
+                    'type' => $sql->createParameter('type'),
113
+                    'lazy' => $sql->createParameter('lazy')
114
+                ]
115
+            );
116
+
117
+        foreach (self::$baseStruct as $appId => $appData) {
118
+            foreach ($appData as $key => $row) {
119
+                $value = $row[1];
120
+                $type = $row[2] ?? IAppConfig::VALUE_MIXED;
121
+                if (($row[4] ?? false) === true) {
122
+                    $type |= IAppConfig::VALUE_SENSITIVE;
123
+                    $value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
124
+                    self::$baseStruct[$appId][$key]['encrypted'] = $value;
125
+                }
126
+
127
+                $sql->setParameters(
128
+                    [
129
+                        'appid' => $appId,
130
+                        'configkey' => $row[0],
131
+                        'configvalue' => $value,
132
+                        'type' => $type,
133
+                        'lazy' => (($row[3] ?? false) === true) ? 1 : 0
134
+                    ]
135
+                )->executeStatement();
136
+            }
137
+        }
138
+    }
139
+
140
+    protected function tearDown(): void {
141
+        $sql = $this->connection->getQueryBuilder();
142
+        $sql->delete('appconfig');
143
+        $sql->executeStatement();
144
+
145
+        $sql = $this->connection->getQueryBuilder();
146
+        $sql->insert('appconfig')
147
+            ->values(
148
+                [
149
+                    'appid' => $sql->createParameter('appid'),
150
+                    'configkey' => $sql->createParameter('configkey'),
151
+                    'configvalue' => $sql->createParameter('configvalue'),
152
+                    'lazy' => $sql->createParameter('lazy'),
153
+                    'type' => $sql->createParameter('type'),
154
+                ]
155
+            );
156
+
157
+        foreach ($this->originalConfig as $key => $configs) {
158
+            $sql->setParameter('appid', $configs['appid'])
159
+                ->setParameter('configkey', $configs['configkey'])
160
+                ->setParameter('configvalue', $configs['configvalue'])
161
+                ->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
162
+                ->setParameter('type', $configs['type']);
163
+            $sql->executeStatement();
164
+        }
165
+
166
+        //		$this->restoreService(AppConfig::class);
167
+        parent::tearDown();
168
+    }
169
+
170
+    /**
171
+     * @param bool $preLoading TRUE will preload the 'fast' cache, which is the normal behavior of usual
172
+     *                         IAppConfig
173
+     *
174
+     * @return IAppConfig
175
+     */
176
+    private function generateAppConfig(bool $preLoading = true): IAppConfig {
177
+        /** @var AppConfig $config */
178
+        $config = new \OC\AppConfig(
179
+            $this->connection,
180
+            $this->logger,
181
+            $this->crypto,
182
+        );
183
+        $msg = ' generateAppConfig() failed to confirm cache status';
184
+
185
+        // confirm cache status
186
+        $status = $config->statusCache();
187
+        $this->assertSame(false, $status['fastLoaded'], $msg);
188
+        $this->assertSame(false, $status['lazyLoaded'], $msg);
189
+        $this->assertSame([], $status['fastCache'], $msg);
190
+        $this->assertSame([], $status['lazyCache'], $msg);
191
+        if ($preLoading) {
192
+            // simple way to initiate the load of non-lazy config values in cache
193
+            $config->getValueString('core', 'preload', '');
194
+
195
+            // confirm cache status
196
+            $status = $config->statusCache();
197
+            $this->assertSame(true, $status['fastLoaded'], $msg);
198
+            $this->assertSame(false, $status['lazyLoaded'], $msg);
199
+
200
+            $apps = array_values(array_diff(array_keys(self::$baseStruct), ['only-lazy']));
201
+            $this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache']), $msg);
202
+            $this->assertSame([], array_keys($status['lazyCache']), $msg);
203
+        }
204
+
205
+        return $config;
206
+    }
207
+
208
+    public function testGetApps(): void {
209
+        $config = $this->generateAppConfig(false);
210
+
211
+        $this->assertEqualsCanonicalizing(array_keys(self::$baseStruct), $config->getApps());
212
+    }
213
+
214
+    /**
215
+     * returns list of app and their keys
216
+     *
217
+     * @return array<string, string[]> ['appId' => ['key1', 'key2', ]]
218
+     * @see testGetKeys
219
+     */
220
+    public static function providerGetAppKeys(): array {
221
+        $appKeys = [];
222
+        foreach (self::$baseStruct as $appId => $appData) {
223
+            $keys = [];
224
+            foreach ($appData as $row) {
225
+                $keys[] = $row[0];
226
+            }
227
+            $appKeys[] = [(string)$appId, $keys];
228
+        }
229
+
230
+        return $appKeys;
231
+    }
232
+
233
+    /**
234
+     * returns list of config keys
235
+     *
236
+     * @return array<string, string, string, int, bool, bool> [appId, key, value, type, lazy, sensitive]
237
+     * @see testIsSensitive
238
+     * @see testIsLazy
239
+     * @see testGetKeys
240
+     */
241
+    public static function providerGetKeys(): array {
242
+        $appKeys = [];
243
+        foreach (self::$baseStruct as $appId => $appData) {
244
+            foreach ($appData as $row) {
245
+                $appKeys[] = [
246
+                    (string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
247
+                    $row[4] ?? false
248
+                ];
249
+            }
250
+        }
251
+
252
+        return $appKeys;
253
+    }
254
+
255
+    /**
256
+     * @dataProvider providerGetAppKeys
257
+     *
258
+     * @param string $appId
259
+     * @param array $expectedKeys
260
+     */
261
+    public function testGetKeys(string $appId, array $expectedKeys): void {
262
+        $config = $this->generateAppConfig();
263
+        $this->assertEqualsCanonicalizing($expectedKeys, $config->getKeys($appId));
264
+    }
265
+
266
+    public function testGetKeysOnUnknownAppShouldReturnsEmptyArray(): void {
267
+        $config = $this->generateAppConfig();
268
+        $this->assertEqualsCanonicalizing([], $config->getKeys('unknown-app'));
269
+    }
270
+
271
+    /**
272
+     * @dataProvider providerGetKeys
273
+     *
274
+     * @param string $appId
275
+     * @param string $configKey
276
+     * @param string $value
277
+     * @param bool $lazy
278
+     */
279
+    public function testHasKey(string $appId, string $configKey, string $value, int $type, bool $lazy): void {
280
+        $config = $this->generateAppConfig();
281
+        $this->assertEquals(true, $config->hasKey($appId, $configKey, $lazy));
282
+    }
283
+
284
+    public function testHasKeyOnNonExistentKeyReturnsFalse(): void {
285
+        $config = $this->generateAppConfig();
286
+        $this->assertEquals(false, $config->hasKey(array_keys(self::$baseStruct)[0], 'inexistant-key'));
287
+    }
288
+
289
+    public function testHasKeyOnUnknownAppReturnsFalse(): void {
290
+        $config = $this->generateAppConfig();
291
+        $this->assertEquals(false, $config->hasKey('inexistant-app', 'inexistant-key'));
292
+    }
293
+
294
+    public function testHasKeyOnMistypedAsLazyReturnsFalse(): void {
295
+        $config = $this->generateAppConfig();
296
+        $this->assertSame(false, $config->hasKey('non-sensitive-app', 'non-lazy-key', true));
297
+    }
298
+
299
+    public function testHasKeyOnMistypeAsNonLazyReturnsFalse(): void {
300
+        $config = $this->generateAppConfig();
301
+        $this->assertSame(false, $config->hasKey('non-sensitive-app', 'lazy-key', false));
302
+    }
303
+
304
+    public function testHasKeyOnMistypeAsNonLazyReturnsTrueWithLazyArgumentIsNull(): void {
305
+        $config = $this->generateAppConfig();
306
+        $this->assertSame(true, $config->hasKey('non-sensitive-app', 'lazy-key', null));
307
+    }
308
+
309
+    /**
310
+     * @dataProvider providerGetKeys
311
+     */
312
+    public function testIsSensitive(
313
+        string $appId, string $configKey, string $configValue, int $type, bool $lazy, bool $sensitive,
314
+    ): void {
315
+        $config = $this->generateAppConfig();
316
+        $this->assertEquals($sensitive, $config->isSensitive($appId, $configKey, $lazy));
317
+    }
318
+
319
+    public function testIsSensitiveOnNonExistentKeyThrowsException(): void {
320
+        $config = $this->generateAppConfig();
321
+        $this->expectException(AppConfigUnknownKeyException::class);
322
+        $config->isSensitive(array_keys(self::$baseStruct)[0], 'inexistant-key');
323
+    }
324
+
325
+    public function testIsSensitiveOnUnknownAppThrowsException(): void {
326
+        $config = $this->generateAppConfig();
327
+        $this->expectException(AppConfigUnknownKeyException::class);
328
+        $config->isSensitive('unknown-app', 'inexistant-key');
329
+    }
330
+
331
+    public function testIsSensitiveOnSensitiveMistypedAsLazy(): void {
332
+        $config = $this->generateAppConfig();
333
+        $this->assertSame(true, $config->isSensitive('sensitive-app', 'non-lazy-key', true));
334
+    }
335
+
336
+    public function testIsSensitiveOnNonSensitiveMistypedAsLazy(): void {
337
+        $config = $this->generateAppConfig();
338
+        $this->assertSame(false, $config->isSensitive('non-sensitive-app', 'non-lazy-key', true));
339
+    }
340
+
341
+    public function testIsSensitiveOnSensitiveMistypedAsNonLazyThrowsException(): void {
342
+        $config = $this->generateAppConfig();
343
+        $this->expectException(AppConfigUnknownKeyException::class);
344
+        $config->isSensitive('sensitive-app', 'lazy-key', false);
345
+    }
346
+
347
+    public function testIsSensitiveOnNonSensitiveMistypedAsNonLazyThrowsException(): void {
348
+        $config = $this->generateAppConfig();
349
+        $this->expectException(AppConfigUnknownKeyException::class);
350
+        $config->isSensitive('non-sensitive-app', 'lazy-key', false);
351
+    }
352
+
353
+    /**
354
+     * @dataProvider providerGetKeys
355
+     */
356
+    public function testIsLazy(string $appId, string $configKey, string $configValue, int $type, bool $lazy,
357
+    ): void {
358
+        $config = $this->generateAppConfig();
359
+        $this->assertEquals($lazy, $config->isLazy($appId, $configKey));
360
+    }
361
+
362
+    public function testIsLazyOnNonExistentKeyThrowsException(): void {
363
+        $config = $this->generateAppConfig();
364
+        $this->expectException(AppConfigUnknownKeyException::class);
365
+        $config->isLazy(array_keys(self::$baseStruct)[0], 'inexistant-key');
366
+    }
367
+
368
+    public function testIsLazyOnUnknownAppThrowsException(): void {
369
+        $config = $this->generateAppConfig();
370
+        $this->expectException(AppConfigUnknownKeyException::class);
371
+        $config->isLazy('unknown-app', 'inexistant-key');
372
+    }
373
+
374
+    public function testGetAllValues(): void {
375
+        $config = $this->generateAppConfig();
376
+        $this->assertEquals(
377
+            [
378
+                'array' => ['test' => 1],
379
+                'bool' => true,
380
+                'float' => 3.14,
381
+                'int' => 42,
382
+                'mixed' => 'mix',
383
+                'string' => 'value',
384
+            ],
385
+            $config->getAllValues('typed')
386
+        );
387
+    }
388
+
389
+    public function testGetAllValuesWithEmptyApp(): void {
390
+        $config = $this->generateAppConfig();
391
+        $this->expectException(InvalidArgumentException::class);
392
+        $config->getAllValues('');
393
+    }
394
+
395
+    /**
396
+     * @dataProvider providerGetAppKeys
397
+     *
398
+     * @param string $appId
399
+     * @param array $keys
400
+     */
401
+    public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
402
+        $config = $this->generateAppConfig();
403
+        $this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
404
+    }
405
+
406
+    public function testGetAllValuesWithPrefix(): void {
407
+        $config = $this->generateAppConfig();
408
+        $this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
409
+    }
410
+
411
+    public function testSearchValues(): void {
412
+        $config = $this->generateAppConfig();
413
+        $this->assertEqualsCanonicalizing(['testapp' => 'true', '123456' => 'true', 'anotherapp' => 'false'], $config->searchValues('enabled'));
414
+    }
415
+
416
+    public function testGetValueString(): void {
417
+        $config = $this->generateAppConfig();
418
+        $this->assertSame('value', $config->getValueString('typed', 'string', ''));
419
+    }
420
+
421
+    public function testGetValueStringOnUnknownAppReturnsDefault(): void {
422
+        $config = $this->generateAppConfig();
423
+        $this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
424
+    }
425
+
426
+    public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
427
+        $config = $this->generateAppConfig();
428
+        $this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
429
+    }
430
+
431
+    public function testGetValueStringOnWrongType(): void {
432
+        $config = $this->generateAppConfig();
433
+        $this->expectException(AppConfigTypeConflictException::class);
434
+        $config->getValueString('typed', 'int');
435
+    }
436
+
437
+    public function testGetNonLazyValueStringAsLazy(): void {
438
+        $config = $this->generateAppConfig();
439
+        $this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
440
+    }
441
+
442
+    public function testGetValueInt(): void {
443
+        $config = $this->generateAppConfig();
444
+        $this->assertSame(42, $config->getValueInt('typed', 'int', 0));
445
+    }
446
+
447
+    public function testGetValueIntOnUnknownAppReturnsDefault(): void {
448
+        $config = $this->generateAppConfig();
449
+        $this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
450
+    }
451
+
452
+    public function testGetValueIntOnNonExistentKeyReturnsDefault(): void {
453
+        $config = $this->generateAppConfig();
454
+        $this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
455
+    }
456
+
457
+    public function testGetValueIntOnWrongType(): void {
458
+        $config = $this->generateAppConfig();
459
+        $this->expectException(AppConfigTypeConflictException::class);
460
+        $config->getValueInt('typed', 'float');
461
+    }
462
+
463
+    public function testGetValueFloat(): void {
464
+        $config = $this->generateAppConfig();
465
+        $this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
466
+    }
467
+
468
+    public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
469
+        $config = $this->generateAppConfig();
470
+        $this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
471
+    }
472
+
473
+    public function testGetValueFloatOnNonExistentKeyReturnsDefault(): void {
474
+        $config = $this->generateAppConfig();
475
+        $this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
476
+    }
477
+
478
+    public function testGetValueFloatOnWrongType(): void {
479
+        $config = $this->generateAppConfig();
480
+        $this->expectException(AppConfigTypeConflictException::class);
481
+        $config->getValueFloat('typed', 'bool');
482
+    }
483
+
484
+    public function testGetValueBool(): void {
485
+        $config = $this->generateAppConfig();
486
+        $this->assertSame(true, $config->getValueBool('typed', 'bool'));
487
+    }
488
+
489
+    public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
490
+        $config = $this->generateAppConfig();
491
+        $this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
492
+    }
493
+
494
+    public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
495
+        $config = $this->generateAppConfig();
496
+        $this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
497
+    }
498
+
499
+    public function testGetValueBoolOnWrongType(): void {
500
+        $config = $this->generateAppConfig();
501
+        $this->expectException(AppConfigTypeConflictException::class);
502
+        $config->getValueBool('typed', 'array');
503
+    }
504
+
505
+    public function testGetValueArray(): void {
506
+        $config = $this->generateAppConfig();
507
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
508
+    }
509
+
510
+    public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
511
+        $config = $this->generateAppConfig();
512
+        $this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
513
+    }
514
+
515
+    public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
516
+        $config = $this->generateAppConfig();
517
+        $this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
518
+    }
519
+
520
+    public function testGetValueArrayOnWrongType(): void {
521
+        $config = $this->generateAppConfig();
522
+        $this->expectException(AppConfigTypeConflictException::class);
523
+        $config->getValueArray('typed', 'string');
524
+    }
525
+
526
+
527
+    /**
528
+     * @return array
529
+     * @see testGetValueType
530
+     *
531
+     * @see testGetValueMixed
532
+     */
533
+    public static function providerGetValueMixed(): array {
534
+        return [
535
+            // key, value, type
536
+            ['mixed', 'mix', IAppConfig::VALUE_MIXED],
537
+            ['string', 'value', IAppConfig::VALUE_STRING],
538
+            ['int', '42', IAppConfig::VALUE_INT],
539
+            ['float', '3.14', IAppConfig::VALUE_FLOAT],
540
+            ['bool', '1', IAppConfig::VALUE_BOOL],
541
+            ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
542
+        ];
543
+    }
544
+
545
+    /**
546
+     * @dataProvider providerGetValueMixed
547
+     *
548
+     * @param string $key
549
+     * @param string $value
550
+     */
551
+    public function testGetValueMixed(string $key, string $value): void {
552
+        $config = $this->generateAppConfig();
553
+        $this->assertSame($value, $config->getValueMixed('typed', $key));
554
+    }
555
+
556
+    /**
557
+     * @dataProvider providerGetValueMixed
558
+     *
559
+     * @param string $key
560
+     * @param string $value
561
+     * @param int $type
562
+     */
563
+    public function testGetValueType(string $key, string $value, int $type): void {
564
+        $config = $this->generateAppConfig();
565
+        $this->assertSame($type, $config->getValueType('typed', $key));
566
+    }
567
+
568
+    public function testGetValueTypeOnUnknownApp(): void {
569
+        $config = $this->generateAppConfig();
570
+        $this->expectException(AppConfigUnknownKeyException::class);
571
+        $config->getValueType('typed-1', 'string');
572
+    }
573
+
574
+    public function testGetValueTypeOnNonExistentKey(): void {
575
+        $config = $this->generateAppConfig();
576
+        $this->expectException(AppConfigUnknownKeyException::class);
577
+        $config->getValueType('typed', 'string-2');
578
+    }
579
+
580
+    public function testSetValueString(): void {
581
+        $config = $this->generateAppConfig();
582
+        $config->setValueString('feed', 'string', 'value-1');
583
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
584
+    }
585
+
586
+    public function testSetValueStringCache(): void {
587
+        $config = $this->generateAppConfig();
588
+        $config->setValueString('feed', 'string', 'value-1');
589
+        $status = $config->statusCache();
590
+        $this->assertSame('value-1', $status['fastCache']['feed']['string']);
591
+    }
592
+
593
+    public function testSetValueStringDatabase(): void {
594
+        $config = $this->generateAppConfig();
595
+        $config->setValueString('feed', 'string', 'value-1');
596
+        $config->clearCache();
597
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
598
+    }
599
+
600
+    public function testSetValueStringIsUpdated(): void {
601
+        $config = $this->generateAppConfig();
602
+        $config->setValueString('feed', 'string', 'value-1');
603
+        $this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
604
+    }
605
+
606
+    public function testSetValueStringIsNotUpdated(): void {
607
+        $config = $this->generateAppConfig();
608
+        $config->setValueString('feed', 'string', 'value-1');
609
+        $this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
610
+    }
611
+
612
+    public function testSetValueStringIsUpdatedCache(): void {
613
+        $config = $this->generateAppConfig();
614
+        $config->setValueString('feed', 'string', 'value-1');
615
+        $config->setValueString('feed', 'string', 'value-2');
616
+        $status = $config->statusCache();
617
+        $this->assertSame('value-2', $status['fastCache']['feed']['string']);
618
+    }
619
+
620
+    public function testSetValueStringIsUpdatedDatabase(): void {
621
+        $config = $this->generateAppConfig();
622
+        $config->setValueString('feed', 'string', 'value-1');
623
+        $config->setValueString('feed', 'string', 'value-2');
624
+        $config->clearCache();
625
+        $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
626
+    }
627
+
628
+    public function testSetValueInt(): void {
629
+        $config = $this->generateAppConfig();
630
+        $config->setValueInt('feed', 'int', 42);
631
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
632
+    }
633
+
634
+    public function testSetValueIntCache(): void {
635
+        $config = $this->generateAppConfig();
636
+        $config->setValueInt('feed', 'int', 42);
637
+        $status = $config->statusCache();
638
+        $this->assertSame('42', $status['fastCache']['feed']['int']);
639
+    }
640
+
641
+    public function testSetValueIntDatabase(): void {
642
+        $config = $this->generateAppConfig();
643
+        $config->setValueInt('feed', 'int', 42);
644
+        $config->clearCache();
645
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
646
+    }
647
+
648
+    public function testSetValueIntIsUpdated(): void {
649
+        $config = $this->generateAppConfig();
650
+        $config->setValueInt('feed', 'int', 42);
651
+        $this->assertSame(true, $config->setValueInt('feed', 'int', 17));
652
+    }
653
+
654
+    public function testSetValueIntIsNotUpdated(): void {
655
+        $config = $this->generateAppConfig();
656
+        $config->setValueInt('feed', 'int', 42);
657
+        $this->assertSame(false, $config->setValueInt('feed', 'int', 42));
658
+    }
659
+
660
+    public function testSetValueIntIsUpdatedCache(): void {
661
+        $config = $this->generateAppConfig();
662
+        $config->setValueInt('feed', 'int', 42);
663
+        $config->setValueInt('feed', 'int', 17);
664
+        $status = $config->statusCache();
665
+        $this->assertSame('17', $status['fastCache']['feed']['int']);
666
+    }
667
+
668
+    public function testSetValueIntIsUpdatedDatabase(): void {
669
+        $config = $this->generateAppConfig();
670
+        $config->setValueInt('feed', 'int', 42);
671
+        $config->setValueInt('feed', 'int', 17);
672
+        $config->clearCache();
673
+        $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
674
+    }
675
+
676
+    public function testSetValueFloat(): void {
677
+        $config = $this->generateAppConfig();
678
+        $config->setValueFloat('feed', 'float', 3.14);
679
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
680
+    }
681
+
682
+    public function testSetValueFloatCache(): void {
683
+        $config = $this->generateAppConfig();
684
+        $config->setValueFloat('feed', 'float', 3.14);
685
+        $status = $config->statusCache();
686
+        $this->assertSame('3.14', $status['fastCache']['feed']['float']);
687
+    }
688
+
689
+    public function testSetValueFloatDatabase(): void {
690
+        $config = $this->generateAppConfig();
691
+        $config->setValueFloat('feed', 'float', 3.14);
692
+        $config->clearCache();
693
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
694
+    }
695
+
696
+    public function testSetValueFloatIsUpdated(): void {
697
+        $config = $this->generateAppConfig();
698
+        $config->setValueFloat('feed', 'float', 3.14);
699
+        $this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
700
+    }
701
+
702
+    public function testSetValueFloatIsNotUpdated(): void {
703
+        $config = $this->generateAppConfig();
704
+        $config->setValueFloat('feed', 'float', 3.14);
705
+        $this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
706
+    }
707
+
708
+    public function testSetValueFloatIsUpdatedCache(): void {
709
+        $config = $this->generateAppConfig();
710
+        $config->setValueFloat('feed', 'float', 3.14);
711
+        $config->setValueFloat('feed', 'float', 1.23);
712
+        $status = $config->statusCache();
713
+        $this->assertSame('1.23', $status['fastCache']['feed']['float']);
714
+    }
715
+
716
+    public function testSetValueFloatIsUpdatedDatabase(): void {
717
+        $config = $this->generateAppConfig();
718
+        $config->setValueFloat('feed', 'float', 3.14);
719
+        $config->setValueFloat('feed', 'float', 1.23);
720
+        $config->clearCache();
721
+        $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
722
+    }
723
+
724
+    public function testSetValueBool(): void {
725
+        $config = $this->generateAppConfig();
726
+        $config->setValueBool('feed', 'bool', true);
727
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
728
+    }
729
+
730
+    public function testSetValueBoolCache(): void {
731
+        $config = $this->generateAppConfig();
732
+        $config->setValueBool('feed', 'bool', true);
733
+        $status = $config->statusCache();
734
+        $this->assertSame('1', $status['fastCache']['feed']['bool']);
735
+    }
736
+
737
+    public function testSetValueBoolDatabase(): void {
738
+        $config = $this->generateAppConfig();
739
+        $config->setValueBool('feed', 'bool', true);
740
+        $config->clearCache();
741
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
742
+    }
743
+
744
+    public function testSetValueBoolIsUpdated(): void {
745
+        $config = $this->generateAppConfig();
746
+        $config->setValueBool('feed', 'bool', true);
747
+        $this->assertSame(true, $config->setValueBool('feed', 'bool', false));
748
+    }
749
+
750
+    public function testSetValueBoolIsNotUpdated(): void {
751
+        $config = $this->generateAppConfig();
752
+        $config->setValueBool('feed', 'bool', true);
753
+        $this->assertSame(false, $config->setValueBool('feed', 'bool', true));
754
+    }
755
+
756
+    public function testSetValueBoolIsUpdatedCache(): void {
757
+        $config = $this->generateAppConfig();
758
+        $config->setValueBool('feed', 'bool', true);
759
+        $config->setValueBool('feed', 'bool', false);
760
+        $status = $config->statusCache();
761
+        $this->assertSame('0', $status['fastCache']['feed']['bool']);
762
+    }
763
+
764
+    public function testSetValueBoolIsUpdatedDatabase(): void {
765
+        $config = $this->generateAppConfig();
766
+        $config->setValueBool('feed', 'bool', true);
767
+        $config->setValueBool('feed', 'bool', false);
768
+        $config->clearCache();
769
+        $this->assertSame(false, $config->getValueBool('feed', 'bool', true));
770
+    }
771
+
772
+
773
+    public function testSetValueArray(): void {
774
+        $config = $this->generateAppConfig();
775
+        $config->setValueArray('feed', 'array', ['test' => 1]);
776
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
777
+    }
778
+
779
+    public function testSetValueArrayCache(): void {
780
+        $config = $this->generateAppConfig();
781
+        $config->setValueArray('feed', 'array', ['test' => 1]);
782
+        $status = $config->statusCache();
783
+        $this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
784
+    }
785
+
786
+    public function testSetValueArrayDatabase(): void {
787
+        $config = $this->generateAppConfig();
788
+        $config->setValueArray('feed', 'array', ['test' => 1]);
789
+        $config->clearCache();
790
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
791
+    }
792
+
793
+    public function testSetValueArrayIsUpdated(): void {
794
+        $config = $this->generateAppConfig();
795
+        $config->setValueArray('feed', 'array', ['test' => 1]);
796
+        $this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
797
+    }
798
+
799
+    public function testSetValueArrayIsNotUpdated(): void {
800
+        $config = $this->generateAppConfig();
801
+        $config->setValueArray('feed', 'array', ['test' => 1]);
802
+        $this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
803
+    }
804
+
805
+    public function testSetValueArrayIsUpdatedCache(): void {
806
+        $config = $this->generateAppConfig();
807
+        $config->setValueArray('feed', 'array', ['test' => 1]);
808
+        $config->setValueArray('feed', 'array', ['test' => 2]);
809
+        $status = $config->statusCache();
810
+        $this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
811
+    }
812
+
813
+    public function testSetValueArrayIsUpdatedDatabase(): void {
814
+        $config = $this->generateAppConfig();
815
+        $config->setValueArray('feed', 'array', ['test' => 1]);
816
+        $config->setValueArray('feed', 'array', ['test' => 2]);
817
+        $config->clearCache();
818
+        $this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
819
+    }
820
+
821
+    public function testSetLazyValueString(): void {
822
+        $config = $this->generateAppConfig();
823
+        $config->setValueString('feed', 'string', 'value-1', true);
824
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
825
+    }
826
+
827
+    public function testSetLazyValueStringCache(): void {
828
+        $config = $this->generateAppConfig();
829
+        $config->setValueString('feed', 'string', 'value-1', true);
830
+        $status = $config->statusCache();
831
+        $this->assertSame('value-1', $status['lazyCache']['feed']['string']);
832
+    }
833
+
834
+    public function testSetLazyValueStringDatabase(): void {
835
+        $config = $this->generateAppConfig();
836
+        $config->setValueString('feed', 'string', 'value-1', true);
837
+        $config->clearCache();
838
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
839
+    }
840
+
841
+    public function testSetLazyValueStringAsNonLazy(): void {
842
+        $config = $this->generateAppConfig();
843
+        $config->setValueString('feed', 'string', 'value-1', true);
844
+        $config->setValueString('feed', 'string', 'value-1', false);
845
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
846
+    }
847
+
848
+    public function testSetNonLazyValueStringAsLazy(): void {
849
+        $config = $this->generateAppConfig();
850
+        $config->setValueString('feed', 'string', 'value-1', false);
851
+        $config->setValueString('feed', 'string', 'value-1', true);
852
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
853
+    }
854
+
855
+    public function testSetSensitiveValueString(): void {
856
+        $config = $this->generateAppConfig();
857
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
858
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
859
+    }
860
+
861
+    public function testSetSensitiveValueStringCache(): void {
862
+        $config = $this->generateAppConfig();
863
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
864
+        $status = $config->statusCache();
865
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
866
+    }
867
+
868
+    public function testSetSensitiveValueStringDatabase(): void {
869
+        $config = $this->generateAppConfig();
870
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
871
+        $config->clearCache();
872
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
873
+    }
874
+
875
+    public function testSetNonSensitiveValueStringAsSensitive(): void {
876
+        $config = $this->generateAppConfig();
877
+        $config->setValueString('feed', 'string', 'value-1', sensitive: false);
878
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
879
+        $this->assertSame(true, $config->isSensitive('feed', 'string'));
880
+
881
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
882
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
883
+    }
884
+
885
+    public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
886
+        $config = $this->generateAppConfig();
887
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
888
+        $config->setValueString('feed', 'string', 'value-2', sensitive: false);
889
+        $this->assertSame(true, $config->isSensitive('feed', 'string'));
890
+
891
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
892
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
893
+    }
894
+
895
+    public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
896
+        $config = $this->generateAppConfig();
897
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
898
+        $config->setValueString('feed', 'string', 'value-2', sensitive: false);
899
+        $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
900
+
901
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
902
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
903
+    }
904
+
905
+    public function testSetLazyValueInt(): void {
906
+        $config = $this->generateAppConfig();
907
+        $config->setValueInt('feed', 'int', 42, true);
908
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
909
+    }
910
+
911
+    public function testSetLazyValueIntCache(): void {
912
+        $config = $this->generateAppConfig();
913
+        $config->setValueInt('feed', 'int', 42, true);
914
+        $status = $config->statusCache();
915
+        $this->assertSame('42', $status['lazyCache']['feed']['int']);
916
+    }
917
+
918
+    public function testSetLazyValueIntDatabase(): void {
919
+        $config = $this->generateAppConfig();
920
+        $config->setValueInt('feed', 'int', 42, true);
921
+        $config->clearCache();
922
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
923
+    }
924
+
925
+    public function testSetLazyValueIntAsNonLazy(): void {
926
+        $config = $this->generateAppConfig();
927
+        $config->setValueInt('feed', 'int', 42, true);
928
+        $config->setValueInt('feed', 'int', 42, false);
929
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
930
+    }
931
+
932
+    public function testSetNonLazyValueIntAsLazy(): void {
933
+        $config = $this->generateAppConfig();
934
+        $config->setValueInt('feed', 'int', 42, false);
935
+        $config->setValueInt('feed', 'int', 42, true);
936
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
937
+    }
938
+
939
+    public function testSetSensitiveValueInt(): void {
940
+        $config = $this->generateAppConfig();
941
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
942
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
943
+    }
944
+
945
+    public function testSetSensitiveValueIntCache(): void {
946
+        $config = $this->generateAppConfig();
947
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
948
+        $status = $config->statusCache();
949
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
950
+    }
951
+
952
+    public function testSetSensitiveValueIntDatabase(): void {
953
+        $config = $this->generateAppConfig();
954
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
955
+        $config->clearCache();
956
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
957
+    }
958
+
959
+    public function testSetNonSensitiveValueIntAsSensitive(): void {
960
+        $config = $this->generateAppConfig();
961
+        $config->setValueInt('feed', 'int', 42);
962
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
963
+        $this->assertSame(true, $config->isSensitive('feed', 'int'));
964
+    }
965
+
966
+    public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
967
+        $config = $this->generateAppConfig();
968
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
969
+        $config->setValueInt('feed', 'int', 17);
970
+        $this->assertSame(true, $config->isSensitive('feed', 'int'));
971
+    }
972
+
973
+    public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
974
+        $config = $this->generateAppConfig();
975
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
976
+        $config->setValueInt('feed', 'int', 17);
977
+        $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
978
+    }
979
+
980
+    public function testSetLazyValueFloat(): void {
981
+        $config = $this->generateAppConfig();
982
+        $config->setValueFloat('feed', 'float', 3.14, true);
983
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
984
+    }
985
+
986
+    public function testSetLazyValueFloatCache(): void {
987
+        $config = $this->generateAppConfig();
988
+        $config->setValueFloat('feed', 'float', 3.14, true);
989
+        $status = $config->statusCache();
990
+        $this->assertSame('3.14', $status['lazyCache']['feed']['float']);
991
+    }
992
+
993
+    public function testSetLazyValueFloatDatabase(): void {
994
+        $config = $this->generateAppConfig();
995
+        $config->setValueFloat('feed', 'float', 3.14, true);
996
+        $config->clearCache();
997
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
998
+    }
999
+
1000
+    public function testSetLazyValueFloatAsNonLazy(): void {
1001
+        $config = $this->generateAppConfig();
1002
+        $config->setValueFloat('feed', 'float', 3.14, true);
1003
+        $config->setValueFloat('feed', 'float', 3.14, false);
1004
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1005
+    }
1006
+
1007
+    public function testSetNonLazyValueFloatAsLazy(): void {
1008
+        $config = $this->generateAppConfig();
1009
+        $config->setValueFloat('feed', 'float', 3.14, false);
1010
+        $config->setValueFloat('feed', 'float', 3.14, true);
1011
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1012
+    }
1013
+
1014
+    public function testSetSensitiveValueFloat(): void {
1015
+        $config = $this->generateAppConfig();
1016
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1017
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1018
+    }
1019
+
1020
+    public function testSetSensitiveValueFloatCache(): void {
1021
+        $config = $this->generateAppConfig();
1022
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1023
+        $status = $config->statusCache();
1024
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
1025
+    }
1026
+
1027
+    public function testSetSensitiveValueFloatDatabase(): void {
1028
+        $config = $this->generateAppConfig();
1029
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1030
+        $config->clearCache();
1031
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1032
+    }
1033
+
1034
+    public function testSetNonSensitiveValueFloatAsSensitive(): void {
1035
+        $config = $this->generateAppConfig();
1036
+        $config->setValueFloat('feed', 'float', 3.14);
1037
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1038
+        $this->assertSame(true, $config->isSensitive('feed', 'float'));
1039
+    }
1040
+
1041
+    public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
1042
+        $config = $this->generateAppConfig();
1043
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1044
+        $config->setValueFloat('feed', 'float', 1.23);
1045
+        $this->assertSame(true, $config->isSensitive('feed', 'float'));
1046
+    }
1047
+
1048
+    public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
1049
+        $config = $this->generateAppConfig();
1050
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1051
+        $config->setValueFloat('feed', 'float', 1.23);
1052
+        $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
1053
+    }
1054
+
1055
+    public function testSetLazyValueBool(): void {
1056
+        $config = $this->generateAppConfig();
1057
+        $config->setValueBool('feed', 'bool', true, true);
1058
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1059
+    }
1060
+
1061
+    public function testSetLazyValueBoolCache(): void {
1062
+        $config = $this->generateAppConfig();
1063
+        $config->setValueBool('feed', 'bool', true, true);
1064
+        $status = $config->statusCache();
1065
+        $this->assertSame('1', $status['lazyCache']['feed']['bool']);
1066
+    }
1067
+
1068
+    public function testSetLazyValueBoolDatabase(): void {
1069
+        $config = $this->generateAppConfig();
1070
+        $config->setValueBool('feed', 'bool', true, true);
1071
+        $config->clearCache();
1072
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1073
+    }
1074
+
1075
+    public function testSetLazyValueBoolAsNonLazy(): void {
1076
+        $config = $this->generateAppConfig();
1077
+        $config->setValueBool('feed', 'bool', true, true);
1078
+        $config->setValueBool('feed', 'bool', true, false);
1079
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
1080
+    }
1081
+
1082
+    public function testSetNonLazyValueBoolAsLazy(): void {
1083
+        $config = $this->generateAppConfig();
1084
+        $config->setValueBool('feed', 'bool', true, false);
1085
+        $config->setValueBool('feed', 'bool', true, true);
1086
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1087
+    }
1088
+
1089
+    public function testSetLazyValueArray(): void {
1090
+        $config = $this->generateAppConfig();
1091
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1092
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1093
+    }
1094
+
1095
+    public function testSetLazyValueArrayCache(): void {
1096
+        $config = $this->generateAppConfig();
1097
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1098
+        $status = $config->statusCache();
1099
+        $this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
1100
+    }
1101
+
1102
+    public function testSetLazyValueArrayDatabase(): void {
1103
+        $config = $this->generateAppConfig();
1104
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1105
+        $config->clearCache();
1106
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1107
+    }
1108
+
1109
+    public function testSetLazyValueArrayAsNonLazy(): void {
1110
+        $config = $this->generateAppConfig();
1111
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1112
+        $config->setValueArray('feed', 'array', ['test' => 1], false);
1113
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
1114
+    }
1115
+
1116
+    public function testSetNonLazyValueArrayAsLazy(): void {
1117
+        $config = $this->generateAppConfig();
1118
+        $config->setValueArray('feed', 'array', ['test' => 1], false);
1119
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1120
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1121
+    }
1122
+
1123
+
1124
+    public function testSetSensitiveValueArray(): void {
1125
+        $config = $this->generateAppConfig();
1126
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1127
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1128
+    }
1129
+
1130
+    public function testSetSensitiveValueArrayCache(): void {
1131
+        $config = $this->generateAppConfig();
1132
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1133
+        $status = $config->statusCache();
1134
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
1135
+    }
1136
+
1137
+    public function testSetSensitiveValueArrayDatabase(): void {
1138
+        $config = $this->generateAppConfig();
1139
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1140
+        $config->clearCache();
1141
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1142
+    }
1143
+
1144
+    public function testSetNonSensitiveValueArrayAsSensitive(): void {
1145
+        $config = $this->generateAppConfig();
1146
+        $config->setValueArray('feed', 'array', ['test' => 1]);
1147
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1148
+        $this->assertSame(true, $config->isSensitive('feed', 'array'));
1149
+    }
1150
+
1151
+    public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
1152
+        $config = $this->generateAppConfig();
1153
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1154
+        $config->setValueArray('feed', 'array', ['test' => 2]);
1155
+        $this->assertSame(true, $config->isSensitive('feed', 'array'));
1156
+    }
1157
+
1158
+    public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
1159
+        $config = $this->generateAppConfig();
1160
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1161
+        $config->setValueArray('feed', 'array', ['test' => 2]);
1162
+        $this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
1163
+    }
1164
+
1165
+    public function testUpdateNotSensitiveToSensitive(): void {
1166
+        $config = $this->generateAppConfig();
1167
+        $config->updateSensitive('non-sensitive-app', 'lazy-key', true);
1168
+        $this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
1169
+    }
1170
+
1171
+    public function testUpdateSensitiveToNotSensitive(): void {
1172
+        $config = $this->generateAppConfig();
1173
+        $config->updateSensitive('sensitive-app', 'lazy-key', false);
1174
+        $this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
1175
+    }
1176
+
1177
+    public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
1178
+        $config = $this->generateAppConfig();
1179
+        $this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
1180
+    }
1181
+
1182
+    public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
1183
+        $config = $this->generateAppConfig();
1184
+        $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
1185
+    }
1186
+
1187
+    public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
1188
+        $config = $this->generateAppConfig();
1189
+        $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
1190
+    }
1191
+
1192
+    public function testUpdateNotLazyToLazy(): void {
1193
+        $config = $this->generateAppConfig();
1194
+        $config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
1195
+        $this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
1196
+    }
1197
+
1198
+    public function testUpdateLazyToNotLazy(): void {
1199
+        $config = $this->generateAppConfig();
1200
+        $config->updateLazy('non-sensitive-app', 'lazy-key', false);
1201
+        $this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
1202
+    }
1203
+
1204
+    public function testUpdateLazyToLazyReturnsFalse(): void {
1205
+        $config = $this->generateAppConfig();
1206
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
1207
+    }
1208
+
1209
+    public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
1210
+        $config = $this->generateAppConfig();
1211
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
1212
+    }
1213
+
1214
+    public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
1215
+        $config = $this->generateAppConfig();
1216
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
1217
+    }
1218
+
1219
+    public function testGetDetails(): void {
1220
+        $config = $this->generateAppConfig();
1221
+        $this->assertEquals(
1222
+            [
1223
+                'app' => 'non-sensitive-app',
1224
+                'key' => 'lazy-key',
1225
+                'value' => 'value',
1226
+                'type' => 4,
1227
+                'lazy' => true,
1228
+                'typeString' => 'string',
1229
+                'sensitive' => false,
1230
+            ],
1231
+            $config->getDetails('non-sensitive-app', 'lazy-key')
1232
+        );
1233
+    }
1234
+
1235
+    public function testGetDetailsSensitive(): void {
1236
+        $config = $this->generateAppConfig();
1237
+        $this->assertEquals(
1238
+            [
1239
+                'app' => 'sensitive-app',
1240
+                'key' => 'lazy-key',
1241
+                'value' => 'value',
1242
+                'type' => 4,
1243
+                'lazy' => true,
1244
+                'typeString' => 'string',
1245
+                'sensitive' => true,
1246
+            ],
1247
+            $config->getDetails('sensitive-app', 'lazy-key')
1248
+        );
1249
+    }
1250
+
1251
+    public function testGetDetailsInt(): void {
1252
+        $config = $this->generateAppConfig();
1253
+        $this->assertEquals(
1254
+            [
1255
+                'app' => 'typed',
1256
+                'key' => 'int',
1257
+                'value' => '42',
1258
+                'type' => 8,
1259
+                'lazy' => false,
1260
+                'typeString' => 'integer',
1261
+                'sensitive' => false
1262
+            ],
1263
+            $config->getDetails('typed', 'int')
1264
+        );
1265
+    }
1266
+
1267
+    public function testGetDetailsFloat(): void {
1268
+        $config = $this->generateAppConfig();
1269
+        $this->assertEquals(
1270
+            [
1271
+                'app' => 'typed',
1272
+                'key' => 'float',
1273
+                'value' => '3.14',
1274
+                'type' => 16,
1275
+                'lazy' => false,
1276
+                'typeString' => 'float',
1277
+                'sensitive' => false
1278
+            ],
1279
+            $config->getDetails('typed', 'float')
1280
+        );
1281
+    }
1282
+
1283
+    public function testGetDetailsBool(): void {
1284
+        $config = $this->generateAppConfig();
1285
+        $this->assertEquals(
1286
+            [
1287
+                'app' => 'typed',
1288
+                'key' => 'bool',
1289
+                'value' => '1',
1290
+                'type' => 32,
1291
+                'lazy' => false,
1292
+                'typeString' => 'boolean',
1293
+                'sensitive' => false
1294
+            ],
1295
+            $config->getDetails('typed', 'bool')
1296
+        );
1297
+    }
1298
+
1299
+    public function testGetDetailsArray(): void {
1300
+        $config = $this->generateAppConfig();
1301
+        $this->assertEquals(
1302
+            [
1303
+                'app' => 'typed',
1304
+                'key' => 'array',
1305
+                'value' => '{"test": 1}',
1306
+                'type' => 64,
1307
+                'lazy' => false,
1308
+                'typeString' => 'array',
1309
+                'sensitive' => false
1310
+            ],
1311
+            $config->getDetails('typed', 'array')
1312
+        );
1313
+    }
1314
+
1315
+    public function testDeleteKey(): void {
1316
+        $config = $this->generateAppConfig();
1317
+        $config->deleteKey('anotherapp', 'key');
1318
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1319
+    }
1320
+
1321
+    public function testDeleteKeyCache(): void {
1322
+        $config = $this->generateAppConfig();
1323
+        $config->deleteKey('anotherapp', 'key');
1324
+        $status = $config->statusCache();
1325
+        $this->assertEqualsCanonicalizing(['enabled' => 'false'], $status['fastCache']['anotherapp']);
1326
+    }
1327
+
1328
+    public function testDeleteKeyDatabase(): void {
1329
+        $config = $this->generateAppConfig();
1330
+        $config->deleteKey('anotherapp', 'key');
1331
+        $config->clearCache();
1332
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1333
+    }
1334
+
1335
+    public function testDeleteApp(): void {
1336
+        $config = $this->generateAppConfig();
1337
+        $config->deleteApp('anotherapp');
1338
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1339
+        $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1340
+    }
1341
+
1342
+    public function testDeleteAppCache(): void {
1343
+        $config = $this->generateAppConfig();
1344
+        $status = $config->statusCache();
1345
+        $this->assertSame(true, isset($status['fastCache']['anotherapp']));
1346
+        $config->deleteApp('anotherapp');
1347
+        $status = $config->statusCache();
1348
+        $this->assertSame(false, isset($status['fastCache']['anotherapp']));
1349
+    }
1350
+
1351
+    public function testDeleteAppDatabase(): void {
1352
+        $config = $this->generateAppConfig();
1353
+        $config->deleteApp('anotherapp');
1354
+        $config->clearCache();
1355
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1356
+        $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1357
+    }
1358
+
1359
+    public function testClearCache(): void {
1360
+        $config = $this->generateAppConfig();
1361
+        $config->setValueString('feed', 'string', '123454');
1362
+        $config->clearCache();
1363
+        $status = $config->statusCache();
1364
+        $this->assertSame([], $status['fastCache']);
1365
+    }
1366
+
1367
+    public function testSensitiveValuesAreEncrypted(): void {
1368
+        $key = self::getUniqueID('secret');
1369
+
1370
+        $appConfig = $this->generateAppConfig();
1371
+        $secret = md5((string)time());
1372
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1373
+
1374
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1375
+
1376
+        // Can get in same run
1377
+        $actualSecret = $appConfig->getValueString('testapp', $key);
1378
+        $this->assertEquals($secret, $actualSecret);
1379
+
1380
+        // Can get freshly decrypted from DB
1381
+        $newAppConfig = $this->generateAppConfig();
1382
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1383
+        $this->assertEquals($secret, $actualSecret);
1384
+    }
1385
+
1386
+    public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
1387
+        $key = self::getUniqueID('secret');
1388
+        $appConfig = $this->generateAppConfig();
1389
+        $secret = sha1((string)time());
1390
+
1391
+        // Unencrypted
1392
+        $appConfig->setValueString('testapp', $key, $secret);
1393
+        $this->assertConfigKey('testapp', $key, $secret);
1394
+
1395
+        // Can get freshly decrypted from DB
1396
+        $newAppConfig = $this->generateAppConfig();
1397
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1398
+        $this->assertEquals($secret, $actualSecret);
1399
+
1400
+        // Encrypting on change
1401
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1402
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1403
+
1404
+        // Can get in same run
1405
+        $actualSecret = $appConfig->getValueString('testapp', $key);
1406
+        $this->assertEquals($secret, $actualSecret);
1407
+
1408
+        // Can get freshly decrypted from DB
1409
+        $newAppConfig = $this->generateAppConfig();
1410
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1411
+        $this->assertEquals($secret, $actualSecret);
1412
+    }
1413
+
1414
+    public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
1415
+        $key = self::getUniqueID('secret');
1416
+        $appConfig = $this->generateAppConfig();
1417
+        $secret = sha1((string)time());
1418
+
1419
+        // Encrypted
1420
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1421
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1422
+
1423
+        // Migrate to non-sensitive / non-encrypted
1424
+        $appConfig->updateSensitive('testapp', $key, false);
1425
+        $this->assertConfigKey('testapp', $key, $secret);
1426
+    }
1427
+
1428
+    public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
1429
+        $key = self::getUniqueID('secret');
1430
+        $appConfig = $this->generateAppConfig();
1431
+        $secret = sha1((string)time());
1432
+
1433
+        // Unencrypted
1434
+        $appConfig->setValueString('testapp', $key, $secret);
1435
+        $this->assertConfigKey('testapp', $key, $secret);
1436
+
1437
+        // Migrate to sensitive / encrypted
1438
+        $appConfig->updateSensitive('testapp', $key, true);
1439
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1440
+    }
1441
+
1442
+    protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
1443
+        $sql = $this->connection->getQueryBuilder();
1444
+        $sql->select('configvalue')
1445
+            ->from('appconfig')
1446
+            ->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
1447
+            ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
1448
+            ->setParameter('appid', $app)
1449
+            ->setParameter('configkey', $key);
1450
+        $query = $sql->executeQuery();
1451
+        $actual = $query->fetchOne();
1452
+        $query->closeCursor();
1453
+
1454
+        return $actual;
1455
+    }
1456
+
1457
+    protected function assertConfigKey(string $app, string $key, string|false $expected): void {
1458
+        $this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1459
+    }
1460
+
1461
+    protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
1462
+        $this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1463
+    }
1464 1464
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
 				$type = $row[2] ?? IAppConfig::VALUE_MIXED;
121 121
 				if (($row[4] ?? false) === true) {
122 122
 					$type |= IAppConfig::VALUE_SENSITIVE;
123
-					$value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
123
+					$value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX').$this->crypto->encrypt($value);
124 124
 					self::$baseStruct[$appId][$key]['encrypted'] = $value;
125 125
 				}
126 126
 
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 			foreach ($appData as $row) {
225 225
 				$keys[] = $row[0];
226 226
 			}
227
-			$appKeys[] = [(string)$appId, $keys];
227
+			$appKeys[] = [(string) $appId, $keys];
228 228
 		}
229 229
 
230 230
 		return $appKeys;
@@ -243,7 +243,7 @@  discard block
 block discarded – undo
243 243
 		foreach (self::$baseStruct as $appId => $appData) {
244 244
 			foreach ($appData as $row) {
245 245
 				$appKeys[] = [
246
-					(string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
246
+					(string) $appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
247 247
 					$row[4] ?? false
248 248
 				];
249 249
 			}
@@ -1368,7 +1368,7 @@  discard block
 block discarded – undo
1368 1368
 		$key = self::getUniqueID('secret');
1369 1369
 
1370 1370
 		$appConfig = $this->generateAppConfig();
1371
-		$secret = md5((string)time());
1371
+		$secret = md5((string) time());
1372 1372
 		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1373 1373
 
1374 1374
 		$this->assertConfigValueNotEquals('testapp', $key, $secret);
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
 	public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
1387 1387
 		$key = self::getUniqueID('secret');
1388 1388
 		$appConfig = $this->generateAppConfig();
1389
-		$secret = sha1((string)time());
1389
+		$secret = sha1((string) time());
1390 1390
 
1391 1391
 		// Unencrypted
1392 1392
 		$appConfig->setValueString('testapp', $key, $secret);
@@ -1414,7 +1414,7 @@  discard block
 block discarded – undo
1414 1414
 	public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
1415 1415
 		$key = self::getUniqueID('secret');
1416 1416
 		$appConfig = $this->generateAppConfig();
1417
-		$secret = sha1((string)time());
1417
+		$secret = sha1((string) time());
1418 1418
 
1419 1419
 		// Encrypted
1420 1420
 		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
@@ -1428,7 +1428,7 @@  discard block
 block discarded – undo
1428 1428
 	public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
1429 1429
 		$key = self::getUniqueID('secret');
1430 1430
 		$appConfig = $this->generateAppConfig();
1431
-		$secret = sha1((string)time());
1431
+		$secret = sha1((string) time());
1432 1432
 
1433 1433
 		// Unencrypted
1434 1434
 		$appConfig->setValueString('testapp', $key, $secret);
@@ -1439,7 +1439,7 @@  discard block
 block discarded – undo
1439 1439
 		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1440 1440
 	}
1441 1441
 
1442
-	protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
1442
+	protected function loadConfigValueFromDatabase(string $app, string $key): string | false {
1443 1443
 		$sql = $this->connection->getQueryBuilder();
1444 1444
 		$sql->select('configvalue')
1445 1445
 			->from('appconfig')
@@ -1454,11 +1454,11 @@  discard block
 block discarded – undo
1454 1454
 		return $actual;
1455 1455
 	}
1456 1456
 
1457
-	protected function assertConfigKey(string $app, string $key, string|false $expected): void {
1457
+	protected function assertConfigKey(string $app, string $key, string | false $expected): void {
1458 1458
 		$this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1459 1459
 	}
1460 1460
 
1461
-	protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
1461
+	protected function assertConfigValueNotEquals(string $app, string $key, string | false $expected): void {
1462 1462
 		$this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1463 1463
 	}
1464 1464
 }
Please login to merge, or discard this patch.
tests/lib/NaturalSortTest.php 1 patch
Indentation   +252 added lines, -252 removed lines patch added patch discarded remove patch
@@ -8,259 +8,259 @@
 block discarded – undo
8 8
 namespace Test;
9 9
 
10 10
 class NaturalSortTest extends \Test\TestCase {
11
-	/**
12
-	 * @dataProvider naturalSortDataProvider
13
-	 */
14
-	public function testNaturalSortCompare($array, $sorted): void {
15
-		if (!class_exists('Collator')) {
16
-			$this->markTestSkipped('The intl module is not available, natural sorting might not work as expected.');
17
-			return;
18
-		}
19
-		$comparator = \OC\NaturalSort::getInstance();
20
-		usort($array, [$comparator, 'compare']);
21
-		$this->assertEquals($sorted, $array);
22
-	}
11
+    /**
12
+     * @dataProvider naturalSortDataProvider
13
+     */
14
+    public function testNaturalSortCompare($array, $sorted): void {
15
+        if (!class_exists('Collator')) {
16
+            $this->markTestSkipped('The intl module is not available, natural sorting might not work as expected.');
17
+            return;
18
+        }
19
+        $comparator = \OC\NaturalSort::getInstance();
20
+        usort($array, [$comparator, 'compare']);
21
+        $this->assertEquals($sorted, $array);
22
+    }
23 23
 
24
-	/**
25
-	 * @dataProvider defaultCollatorDataProvider
26
-	 */
27
-	public function testDefaultCollatorCompare($array, $sorted): void {
28
-		$comparator = new \OC\NaturalSort(new \OC\NaturalSort_DefaultCollator());
29
-		usort($array, [$comparator, 'compare']);
30
-		$this->assertEquals($sorted, $array);
31
-	}
24
+    /**
25
+     * @dataProvider defaultCollatorDataProvider
26
+     */
27
+    public function testDefaultCollatorCompare($array, $sorted): void {
28
+        $comparator = new \OC\NaturalSort(new \OC\NaturalSort_DefaultCollator());
29
+        usort($array, [$comparator, 'compare']);
30
+        $this->assertEquals($sorted, $array);
31
+    }
32 32
 
33
-	/**
34
-	 * Data provider for natural sorting with php5-intl's Collator.
35
-	 * Must provide the same result as in core/js/tests/specs/coreSpec.js
36
-	 * @return array test cases
37
-	 */
38
-	public static function naturalSortDataProvider(): array {
39
-		return [
40
-			// different casing
41
-			[
42
-				// unsorted
43
-				[
44
-					'aaa',
45
-					'bbb',
46
-					'BBB',
47
-					'AAA'
48
-				],
49
-				// sorted
50
-				[
51
-					'aaa',
52
-					'AAA',
53
-					'bbb',
54
-					'BBB'
55
-				]
56
-			],
57
-			// numbers
58
-			[
59
-				// unsorted
60
-				[
61
-					'124.txt',
62
-					'abc1',
63
-					'123.txt',
64
-					'abc',
65
-					'abc2',
66
-					'def (2).txt',
67
-					'ghi 10.txt',
68
-					'abc12',
69
-					'def.txt',
70
-					'def (1).txt',
71
-					'ghi 2.txt',
72
-					'def (10).txt',
73
-					'abc10',
74
-					'def (12).txt',
75
-					'z',
76
-					'ghi.txt',
77
-					'za',
78
-					'ghi 1.txt',
79
-					'ghi 12.txt',
80
-					'zz',
81
-					'15.txt',
82
-					'15b.txt',
83
-				],
84
-				// sorted
85
-				[
86
-					'15.txt',
87
-					'15b.txt',
88
-					'123.txt',
89
-					'124.txt',
90
-					'abc',
91
-					'abc1',
92
-					'abc2',
93
-					'abc10',
94
-					'abc12',
95
-					'def.txt',
96
-					'def (1).txt',
97
-					'def (2).txt',
98
-					'def (10).txt',
99
-					'def (12).txt',
100
-					'ghi.txt',
101
-					'ghi 1.txt',
102
-					'ghi 2.txt',
103
-					'ghi 10.txt',
104
-					'ghi 12.txt',
105
-					'z',
106
-					'za',
107
-					'zz',
108
-				]
109
-			],
110
-			// chinese characters
111
-			[
112
-				// unsorted
113
-				[
114
-					'十.txt',
115
-					'一.txt',
116
-					'二.txt',
117
-					'十 2.txt',
118
-					'三.txt',
119
-					'四.txt',
120
-					'abc.txt',
121
-					'五.txt',
122
-					'七.txt',
123
-					'八.txt',
124
-					'九.txt',
125
-					'六.txt',
126
-					'十一.txt',
127
-					'波.txt',
128
-					'破.txt',
129
-					'莫.txt',
130
-					'啊.txt',
131
-					'123.txt',
132
-				],
133
-				// sorted
134
-				[
135
-					'123.txt',
136
-					'abc.txt',
137
-					'一.txt',
138
-					'七.txt',
139
-					'三.txt',
140
-					'九.txt',
141
-					'二.txt',
142
-					'五.txt',
143
-					'八.txt',
144
-					'六.txt',
145
-					'十.txt',
146
-					'十 2.txt',
147
-					'十一.txt',
148
-					'啊.txt',
149
-					'四.txt',
150
-					'波.txt',
151
-					'破.txt',
152
-					'莫.txt',
153
-				]
154
-			],
155
-			// with umlauts
156
-			[
157
-				// unsorted
158
-				[
159
-					'öh.txt',
160
-					'Äh.txt',
161
-					'oh.txt',
162
-					'Üh 2.txt',
163
-					'Üh.txt',
164
-					'ah.txt',
165
-					'Öh.txt',
166
-					'uh.txt',
167
-					'üh.txt',
168
-					'äh.txt',
169
-				],
170
-				// sorted
171
-				[
172
-					'ah.txt',
173
-					'äh.txt',
174
-					'Äh.txt',
175
-					'oh.txt',
176
-					'öh.txt',
177
-					'Öh.txt',
178
-					'uh.txt',
179
-					'üh.txt',
180
-					'Üh.txt',
181
-					'Üh 2.txt',
182
-				]
183
-			],
184
-		];
185
-	}
33
+    /**
34
+     * Data provider for natural sorting with php5-intl's Collator.
35
+     * Must provide the same result as in core/js/tests/specs/coreSpec.js
36
+     * @return array test cases
37
+     */
38
+    public static function naturalSortDataProvider(): array {
39
+        return [
40
+            // different casing
41
+            [
42
+                // unsorted
43
+                [
44
+                    'aaa',
45
+                    'bbb',
46
+                    'BBB',
47
+                    'AAA'
48
+                ],
49
+                // sorted
50
+                [
51
+                    'aaa',
52
+                    'AAA',
53
+                    'bbb',
54
+                    'BBB'
55
+                ]
56
+            ],
57
+            // numbers
58
+            [
59
+                // unsorted
60
+                [
61
+                    '124.txt',
62
+                    'abc1',
63
+                    '123.txt',
64
+                    'abc',
65
+                    'abc2',
66
+                    'def (2).txt',
67
+                    'ghi 10.txt',
68
+                    'abc12',
69
+                    'def.txt',
70
+                    'def (1).txt',
71
+                    'ghi 2.txt',
72
+                    'def (10).txt',
73
+                    'abc10',
74
+                    'def (12).txt',
75
+                    'z',
76
+                    'ghi.txt',
77
+                    'za',
78
+                    'ghi 1.txt',
79
+                    'ghi 12.txt',
80
+                    'zz',
81
+                    '15.txt',
82
+                    '15b.txt',
83
+                ],
84
+                // sorted
85
+                [
86
+                    '15.txt',
87
+                    '15b.txt',
88
+                    '123.txt',
89
+                    '124.txt',
90
+                    'abc',
91
+                    'abc1',
92
+                    'abc2',
93
+                    'abc10',
94
+                    'abc12',
95
+                    'def.txt',
96
+                    'def (1).txt',
97
+                    'def (2).txt',
98
+                    'def (10).txt',
99
+                    'def (12).txt',
100
+                    'ghi.txt',
101
+                    'ghi 1.txt',
102
+                    'ghi 2.txt',
103
+                    'ghi 10.txt',
104
+                    'ghi 12.txt',
105
+                    'z',
106
+                    'za',
107
+                    'zz',
108
+                ]
109
+            ],
110
+            // chinese characters
111
+            [
112
+                // unsorted
113
+                [
114
+                    '十.txt',
115
+                    '一.txt',
116
+                    '二.txt',
117
+                    '十 2.txt',
118
+                    '三.txt',
119
+                    '四.txt',
120
+                    'abc.txt',
121
+                    '五.txt',
122
+                    '七.txt',
123
+                    '八.txt',
124
+                    '九.txt',
125
+                    '六.txt',
126
+                    '十一.txt',
127
+                    '波.txt',
128
+                    '破.txt',
129
+                    '莫.txt',
130
+                    '啊.txt',
131
+                    '123.txt',
132
+                ],
133
+                // sorted
134
+                [
135
+                    '123.txt',
136
+                    'abc.txt',
137
+                    '一.txt',
138
+                    '七.txt',
139
+                    '三.txt',
140
+                    '九.txt',
141
+                    '二.txt',
142
+                    '五.txt',
143
+                    '八.txt',
144
+                    '六.txt',
145
+                    '十.txt',
146
+                    '十 2.txt',
147
+                    '十一.txt',
148
+                    '啊.txt',
149
+                    '四.txt',
150
+                    '波.txt',
151
+                    '破.txt',
152
+                    '莫.txt',
153
+                ]
154
+            ],
155
+            // with umlauts
156
+            [
157
+                // unsorted
158
+                [
159
+                    'öh.txt',
160
+                    'Äh.txt',
161
+                    'oh.txt',
162
+                    'Üh 2.txt',
163
+                    'Üh.txt',
164
+                    'ah.txt',
165
+                    'Öh.txt',
166
+                    'uh.txt',
167
+                    'üh.txt',
168
+                    'äh.txt',
169
+                ],
170
+                // sorted
171
+                [
172
+                    'ah.txt',
173
+                    'äh.txt',
174
+                    'Äh.txt',
175
+                    'oh.txt',
176
+                    'öh.txt',
177
+                    'Öh.txt',
178
+                    'uh.txt',
179
+                    'üh.txt',
180
+                    'Üh.txt',
181
+                    'Üh 2.txt',
182
+                ]
183
+            ],
184
+        ];
185
+    }
186 186
 
187
-	/**
188
-	 * Data provider for natural sorting with \OC\NaturalSort_DefaultCollator.
189
-	 * Must provide the same result as in core/js/tests/specs/coreSpec.js
190
-	 * @return array test cases
191
-	 */
192
-	public static function defaultCollatorDataProvider(): array {
193
-		return [
194
-			// different casing
195
-			[
196
-				// unsorted
197
-				[
198
-					'aaa',
199
-					'bbb',
200
-					'BBB',
201
-					'AAA'
202
-				],
203
-				// sorted
204
-				[
205
-					'aaa',
206
-					'AAA',
207
-					'bbb',
208
-					'BBB'
209
-				]
210
-			],
211
-			// numbers
212
-			[
213
-				// unsorted
214
-				[
215
-					'124.txt',
216
-					'abc1',
217
-					'123.txt',
218
-					'abc',
219
-					'abc2',
220
-					'def (2).txt',
221
-					'ghi 10.txt',
222
-					'abc12',
223
-					'def.txt',
224
-					'def (1).txt',
225
-					'ghi 2.txt',
226
-					'def (10).txt',
227
-					'abc10',
228
-					'def (12).txt',
229
-					'z',
230
-					'ghi.txt',
231
-					'za',
232
-					'ghi 1.txt',
233
-					'ghi 12.txt',
234
-					'zz',
235
-					'15.txt',
236
-					'15b.txt',
237
-				],
238
-				// sorted
239
-				[
240
-					'15.txt',
241
-					'15b.txt',
242
-					'123.txt',
243
-					'124.txt',
244
-					'abc',
245
-					'abc1',
246
-					'abc2',
247
-					'abc10',
248
-					'abc12',
249
-					'def.txt',
250
-					'def (1).txt',
251
-					'def (2).txt',
252
-					'def (10).txt',
253
-					'def (12).txt',
254
-					'ghi.txt',
255
-					'ghi 1.txt',
256
-					'ghi 2.txt',
257
-					'ghi 10.txt',
258
-					'ghi 12.txt',
259
-					'z',
260
-					'za',
261
-					'zz',
262
-				]
263
-			],
264
-		];
265
-	}
187
+    /**
188
+     * Data provider for natural sorting with \OC\NaturalSort_DefaultCollator.
189
+     * Must provide the same result as in core/js/tests/specs/coreSpec.js
190
+     * @return array test cases
191
+     */
192
+    public static function defaultCollatorDataProvider(): array {
193
+        return [
194
+            // different casing
195
+            [
196
+                // unsorted
197
+                [
198
+                    'aaa',
199
+                    'bbb',
200
+                    'BBB',
201
+                    'AAA'
202
+                ],
203
+                // sorted
204
+                [
205
+                    'aaa',
206
+                    'AAA',
207
+                    'bbb',
208
+                    'BBB'
209
+                ]
210
+            ],
211
+            // numbers
212
+            [
213
+                // unsorted
214
+                [
215
+                    '124.txt',
216
+                    'abc1',
217
+                    '123.txt',
218
+                    'abc',
219
+                    'abc2',
220
+                    'def (2).txt',
221
+                    'ghi 10.txt',
222
+                    'abc12',
223
+                    'def.txt',
224
+                    'def (1).txt',
225
+                    'ghi 2.txt',
226
+                    'def (10).txt',
227
+                    'abc10',
228
+                    'def (12).txt',
229
+                    'z',
230
+                    'ghi.txt',
231
+                    'za',
232
+                    'ghi 1.txt',
233
+                    'ghi 12.txt',
234
+                    'zz',
235
+                    '15.txt',
236
+                    '15b.txt',
237
+                ],
238
+                // sorted
239
+                [
240
+                    '15.txt',
241
+                    '15b.txt',
242
+                    '123.txt',
243
+                    '124.txt',
244
+                    'abc',
245
+                    'abc1',
246
+                    'abc2',
247
+                    'abc10',
248
+                    'abc12',
249
+                    'def.txt',
250
+                    'def (1).txt',
251
+                    'def (2).txt',
252
+                    'def (10).txt',
253
+                    'def (12).txt',
254
+                    'ghi.txt',
255
+                    'ghi 1.txt',
256
+                    'ghi 2.txt',
257
+                    'ghi 10.txt',
258
+                    'ghi 12.txt',
259
+                    'z',
260
+                    'za',
261
+                    'zz',
262
+                ]
263
+            ],
264
+        ];
265
+    }
266 266
 }
Please login to merge, or discard this patch.
tests/lib/ErrorHandlerTest.php 1 patch
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -16,62 +16,62 @@
 block discarded – undo
16 16
 use Psr\Log\LoggerInterface;
17 17
 
18 18
 class ErrorHandlerTest extends TestCase {
19
-	private LoggerInterface&MockObject $logger;
20
-	private ErrorHandler $errorHandler;
21
-	private int $errorReporting;
19
+    private LoggerInterface&MockObject $logger;
20
+    private ErrorHandler $errorHandler;
21
+    private int $errorReporting;
22 22
 
23
-	protected function setUp(): void {
24
-		parent::setUp();
23
+    protected function setUp(): void {
24
+        parent::setUp();
25 25
 
26
-		$this->logger = $this->createMock(LoggerInterface::class);
27
-		$this->errorHandler = new ErrorHandler(
28
-			$this->logger
29
-		);
26
+        $this->logger = $this->createMock(LoggerInterface::class);
27
+        $this->errorHandler = new ErrorHandler(
28
+            $this->logger
29
+        );
30 30
 
31
-		$this->errorReporting = error_reporting(E_ALL);
32
-	}
31
+        $this->errorReporting = error_reporting(E_ALL);
32
+    }
33 33
 
34
-	protected function tearDown(): void {
35
-		error_reporting($this->errorReporting);
36
-		parent::tearDown();
37
-	}
34
+    protected function tearDown(): void {
35
+        error_reporting($this->errorReporting);
36
+        parent::tearDown();
37
+    }
38 38
 
39
-	/**
40
-	 * provide username, password combinations for testRemovePassword
41
-	 * @return array
42
-	 */
43
-	public static function passwordProvider(): array {
44
-		return [
45
-			['us:er', 'pass@word'],
46
-			['us:er', 'password'],
47
-			['user', '-C:R,w)@6*}'],
48
-			['user', 'pass:word'],
49
-			['user', 'pass@word'],
50
-			['user', 'password'],
51
-			['user:test@cloud', 'password'],
52
-			['[email protected]', 'password'],
53
-			['user@[email protected]', 'password'],
54
-		];
55
-	}
39
+    /**
40
+     * provide username, password combinations for testRemovePassword
41
+     * @return array
42
+     */
43
+    public static function passwordProvider(): array {
44
+        return [
45
+            ['us:er', 'pass@word'],
46
+            ['us:er', 'password'],
47
+            ['user', '-C:R,w)@6*}'],
48
+            ['user', 'pass:word'],
49
+            ['user', 'pass@word'],
50
+            ['user', 'password'],
51
+            ['user:test@cloud', 'password'],
52
+            ['[email protected]', 'password'],
53
+            ['user@[email protected]', 'password'],
54
+        ];
55
+    }
56 56
 
57
-	/**
58
-	 * @dataProvider passwordProvider
59
-	 * @param string $username
60
-	 * @param string $password
61
-	 */
62
-	public function testRemovePasswordFromError($username, $password): void {
63
-		$url = 'http://' . $username . ':' . $password . '@owncloud.org';
64
-		$expectedResult = 'http://xxx:[email protected]';
65
-		$this->logger->expects(self::once())
66
-			->method('log')
67
-			->with(
68
-				ILogger::ERROR,
69
-				'Could not reach ' . $expectedResult . ' at file#4',
70
-				['app' => 'PHP'],
71
-			);
57
+    /**
58
+     * @dataProvider passwordProvider
59
+     * @param string $username
60
+     * @param string $password
61
+     */
62
+    public function testRemovePasswordFromError($username, $password): void {
63
+        $url = 'http://' . $username . ':' . $password . '@owncloud.org';
64
+        $expectedResult = 'http://xxx:[email protected]';
65
+        $this->logger->expects(self::once())
66
+            ->method('log')
67
+            ->with(
68
+                ILogger::ERROR,
69
+                'Could not reach ' . $expectedResult . ' at file#4',
70
+                ['app' => 'PHP'],
71
+            );
72 72
 
73
-		$result = $this->errorHandler->onError(E_USER_ERROR, 'Could not reach ' . $url, 'file', 4);
73
+        $result = $this->errorHandler->onError(E_USER_ERROR, 'Could not reach ' . $url, 'file', 4);
74 74
 
75
-		self::assertTrue($result);
76
-	}
75
+        self::assertTrue($result);
76
+    }
77 77
 }
Please login to merge, or discard this patch.
tests/lib/InstallerTest.php 1 patch
Indentation   +448 added lines, -448 removed lines patch added patch discarded remove patch
@@ -24,151 +24,151 @@  discard block
 block discarded – undo
24 24
  * @group DB
25 25
  */
26 26
 class InstallerTest extends TestCase {
27
-	private static $appid = 'testapp';
28
-	private $appstore;
29
-	/** @var AppFetcher|\PHPUnit\Framework\MockObject\MockObject */
30
-	private $appFetcher;
31
-	/** @var IClientService|\PHPUnit\Framework\MockObject\MockObject */
32
-	private $clientService;
33
-	/** @var ITempManager|\PHPUnit\Framework\MockObject\MockObject */
34
-	private $tempManager;
35
-	/** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
36
-	private $logger;
37
-	/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
38
-	private $config;
39
-
40
-	protected function setUp(): void {
41
-		parent::setUp();
42
-
43
-		$this->appFetcher = $this->createMock(AppFetcher::class);
44
-		$this->clientService = $this->createMock(IClientService::class);
45
-		$this->tempManager = $this->createMock(ITempManager::class);
46
-		$this->logger = $this->createMock(LoggerInterface::class);
47
-		$this->config = $this->createMock(IConfig::class);
48
-
49
-		$config = \OC::$server->getConfig();
50
-		$this->appstore = $config->setSystemValue('appstoreenabled', true);
51
-		$config->setSystemValue('appstoreenabled', true);
52
-		$installer = new Installer(
53
-			\OC::$server->get(AppFetcher::class),
54
-			\OC::$server->get(IClientService::class),
55
-			\OC::$server->getTempManager(),
56
-			\OC::$server->get(LoggerInterface::class),
57
-			$config,
58
-			false
59
-		);
60
-		$installer->removeApp(self::$appid);
61
-	}
62
-
63
-	protected function getInstaller() {
64
-		return new Installer(
65
-			$this->appFetcher,
66
-			$this->clientService,
67
-			$this->tempManager,
68
-			$this->logger,
69
-			$this->config,
70
-			false
71
-		);
72
-	}
73
-
74
-	protected function tearDown(): void {
75
-		$installer = new Installer(
76
-			\OC::$server->get(AppFetcher::class),
77
-			\OC::$server->get(IClientService::class),
78
-			\OC::$server->getTempManager(),
79
-			\OC::$server->get(LoggerInterface::class),
80
-			\OC::$server->getConfig(),
81
-			false
82
-		);
83
-		$installer->removeApp(self::$appid);
84
-		\OC::$server->getConfig()->setSystemValue('appstoreenabled', $this->appstore);
85
-
86
-		parent::tearDown();
87
-	}
88
-
89
-	public function testInstallApp(): void {
90
-		// Read the current version of the app to check for bug #2572
91
-		\OCP\Server::get(IAppManager::class)->getAppVersion('testapp', true);
92
-
93
-		// Extract app
94
-		$pathOfTestApp = __DIR__ . '/../data/testapp.zip';
95
-		$tar = new ZIP($pathOfTestApp);
96
-		$tar->extract(\OC_App::getInstallPath());
97
-
98
-		// Install app
99
-		$installer = new Installer(
100
-			\OC::$server->get(AppFetcher::class),
101
-			\OC::$server->get(IClientService::class),
102
-			\OC::$server->getTempManager(),
103
-			\OC::$server->get(LoggerInterface::class),
104
-			\OC::$server->getConfig(),
105
-			false
106
-		);
107
-		$this->assertNull(\OC::$server->getConfig()->getAppValue('testapp', 'enabled', null), 'Check that the app is not listed before installation');
108
-		$this->assertSame('testapp', $installer->installApp(self::$appid));
109
-		$this->assertSame('no', \OC::$server->getConfig()->getAppValue('testapp', 'enabled', null), 'Check that the app is listed after installation');
110
-		$this->assertSame('0.9', \OC::$server->getConfig()->getAppValue('testapp', 'installed_version'));
111
-		$installer->removeApp(self::$appid);
112
-	}
113
-
114
-	public static function updateArrayProvider(): array {
115
-		return [
116
-			// Update available
117
-			[
118
-				[
119
-					[
120
-						'id' => 'files',
121
-						'releases' => [
122
-							[
123
-								'version' => '1111.0'
124
-							],
125
-						],
126
-					],
127
-				],
128
-				'1111.0',
129
-			],
130
-			// No update available
131
-			[
132
-				[
133
-					[
134
-						'id' => 'files',
135
-						'releases' => [
136
-							[
137
-								'version' => '1.0'
138
-							],
139
-						],
140
-					],
141
-				],
142
-				false,
143
-			],
144
-		];
145
-	}
146
-
147
-	/**
148
-	 * @dataProvider updateArrayProvider
149
-	 * @param array $appArray
150
-	 * @param string|bool $updateAvailable
151
-	 */
152
-	public function testIsUpdateAvailable(array $appArray, $updateAvailable): void {
153
-		$this->appFetcher
154
-			->expects($this->once())
155
-			->method('get')
156
-			->willReturn($appArray);
157
-
158
-		$installer = $this->getInstaller();
159
-		$this->assertSame($updateAvailable, $installer->isUpdateAvailable('files'));
160
-		$this->assertSame($updateAvailable, $installer->isUpdateAvailable('files'), 'Cached result should be returned and fetcher should be only called once');
161
-	}
162
-
163
-
164
-	public function testDownloadAppWithRevokedCertificate(): void {
165
-		$this->expectException(\Exception::class);
166
-		$this->expectExceptionMessage('Certificate "4112" has been revoked');
167
-
168
-		$appArray = [
169
-			[
170
-				'id' => 'news',
171
-				'certificate' => '-----BEGIN CERTIFICATE-----
27
+    private static $appid = 'testapp';
28
+    private $appstore;
29
+    /** @var AppFetcher|\PHPUnit\Framework\MockObject\MockObject */
30
+    private $appFetcher;
31
+    /** @var IClientService|\PHPUnit\Framework\MockObject\MockObject */
32
+    private $clientService;
33
+    /** @var ITempManager|\PHPUnit\Framework\MockObject\MockObject */
34
+    private $tempManager;
35
+    /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
36
+    private $logger;
37
+    /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
38
+    private $config;
39
+
40
+    protected function setUp(): void {
41
+        parent::setUp();
42
+
43
+        $this->appFetcher = $this->createMock(AppFetcher::class);
44
+        $this->clientService = $this->createMock(IClientService::class);
45
+        $this->tempManager = $this->createMock(ITempManager::class);
46
+        $this->logger = $this->createMock(LoggerInterface::class);
47
+        $this->config = $this->createMock(IConfig::class);
48
+
49
+        $config = \OC::$server->getConfig();
50
+        $this->appstore = $config->setSystemValue('appstoreenabled', true);
51
+        $config->setSystemValue('appstoreenabled', true);
52
+        $installer = new Installer(
53
+            \OC::$server->get(AppFetcher::class),
54
+            \OC::$server->get(IClientService::class),
55
+            \OC::$server->getTempManager(),
56
+            \OC::$server->get(LoggerInterface::class),
57
+            $config,
58
+            false
59
+        );
60
+        $installer->removeApp(self::$appid);
61
+    }
62
+
63
+    protected function getInstaller() {
64
+        return new Installer(
65
+            $this->appFetcher,
66
+            $this->clientService,
67
+            $this->tempManager,
68
+            $this->logger,
69
+            $this->config,
70
+            false
71
+        );
72
+    }
73
+
74
+    protected function tearDown(): void {
75
+        $installer = new Installer(
76
+            \OC::$server->get(AppFetcher::class),
77
+            \OC::$server->get(IClientService::class),
78
+            \OC::$server->getTempManager(),
79
+            \OC::$server->get(LoggerInterface::class),
80
+            \OC::$server->getConfig(),
81
+            false
82
+        );
83
+        $installer->removeApp(self::$appid);
84
+        \OC::$server->getConfig()->setSystemValue('appstoreenabled', $this->appstore);
85
+
86
+        parent::tearDown();
87
+    }
88
+
89
+    public function testInstallApp(): void {
90
+        // Read the current version of the app to check for bug #2572
91
+        \OCP\Server::get(IAppManager::class)->getAppVersion('testapp', true);
92
+
93
+        // Extract app
94
+        $pathOfTestApp = __DIR__ . '/../data/testapp.zip';
95
+        $tar = new ZIP($pathOfTestApp);
96
+        $tar->extract(\OC_App::getInstallPath());
97
+
98
+        // Install app
99
+        $installer = new Installer(
100
+            \OC::$server->get(AppFetcher::class),
101
+            \OC::$server->get(IClientService::class),
102
+            \OC::$server->getTempManager(),
103
+            \OC::$server->get(LoggerInterface::class),
104
+            \OC::$server->getConfig(),
105
+            false
106
+        );
107
+        $this->assertNull(\OC::$server->getConfig()->getAppValue('testapp', 'enabled', null), 'Check that the app is not listed before installation');
108
+        $this->assertSame('testapp', $installer->installApp(self::$appid));
109
+        $this->assertSame('no', \OC::$server->getConfig()->getAppValue('testapp', 'enabled', null), 'Check that the app is listed after installation');
110
+        $this->assertSame('0.9', \OC::$server->getConfig()->getAppValue('testapp', 'installed_version'));
111
+        $installer->removeApp(self::$appid);
112
+    }
113
+
114
+    public static function updateArrayProvider(): array {
115
+        return [
116
+            // Update available
117
+            [
118
+                [
119
+                    [
120
+                        'id' => 'files',
121
+                        'releases' => [
122
+                            [
123
+                                'version' => '1111.0'
124
+                            ],
125
+                        ],
126
+                    ],
127
+                ],
128
+                '1111.0',
129
+            ],
130
+            // No update available
131
+            [
132
+                [
133
+                    [
134
+                        'id' => 'files',
135
+                        'releases' => [
136
+                            [
137
+                                'version' => '1.0'
138
+                            ],
139
+                        ],
140
+                    ],
141
+                ],
142
+                false,
143
+            ],
144
+        ];
145
+    }
146
+
147
+    /**
148
+     * @dataProvider updateArrayProvider
149
+     * @param array $appArray
150
+     * @param string|bool $updateAvailable
151
+     */
152
+    public function testIsUpdateAvailable(array $appArray, $updateAvailable): void {
153
+        $this->appFetcher
154
+            ->expects($this->once())
155
+            ->method('get')
156
+            ->willReturn($appArray);
157
+
158
+        $installer = $this->getInstaller();
159
+        $this->assertSame($updateAvailable, $installer->isUpdateAvailable('files'));
160
+        $this->assertSame($updateAvailable, $installer->isUpdateAvailable('files'), 'Cached result should be returned and fetcher should be only called once');
161
+    }
162
+
163
+
164
+    public function testDownloadAppWithRevokedCertificate(): void {
165
+        $this->expectException(\Exception::class);
166
+        $this->expectExceptionMessage('Certificate "4112" has been revoked');
167
+
168
+        $appArray = [
169
+            [
170
+                'id' => 'news',
171
+                'certificate' => '-----BEGIN CERTIFICATE-----
172 172
 MIIEAjCCAuoCAhAQMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
173 173
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
174 174
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -192,27 +192,27 @@  discard block
 block discarded – undo
192 192
 tczQMzLtVdTg5z8XMi//6TkAPxRPjYi8Vef/s2mLo7KystTmofxI/HZePSieJ9tj
193 193
 gLgK8d8sKL60JMmKHN3boHrsThKBVA==
194 194
 -----END CERTIFICATE-----',
195
-			],
196
-		];
197
-		$this->appFetcher
198
-			->expects($this->once())
199
-			->method('get')
200
-			->willReturn($appArray);
195
+            ],
196
+        ];
197
+        $this->appFetcher
198
+            ->expects($this->once())
199
+            ->method('get')
200
+            ->willReturn($appArray);
201 201
 
202 202
 
203
-		$installer = $this->getInstaller();
204
-		$installer->downloadApp('news');
205
-	}
203
+        $installer = $this->getInstaller();
204
+        $installer->downloadApp('news');
205
+    }
206 206
 
207 207
 
208
-	public function testDownloadAppWithNotNextcloudCertificate(): void {
209
-		$this->expectException(\Exception::class);
210
-		$this->expectExceptionMessage('App with id news has a certificate not issued by a trusted Code Signing Authority');
208
+    public function testDownloadAppWithNotNextcloudCertificate(): void {
209
+        $this->expectException(\Exception::class);
210
+        $this->expectExceptionMessage('App with id news has a certificate not issued by a trusted Code Signing Authority');
211 211
 
212
-		$appArray = [
213
-			[
214
-				'id' => 'news',
215
-				'certificate' => '-----BEGIN CERTIFICATE-----
212
+        $appArray = [
213
+            [
214
+                'id' => 'news',
215
+                'certificate' => '-----BEGIN CERTIFICATE-----
216 216
 MIID8TCCAdkCAhAAMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNVBAYTAlVTMQ8wDQYD
217 217
 VQQIDAZCb3N0b24xFjAUBgNVBAoMDW93bkNsb3VkIEluYy4xNTAzBgNVBAMMLG93
218 218
 bkNsb3VkIENvZGUgU2lnbmluZyBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MB4XDTE2
@@ -236,26 +236,26 @@  discard block
 block discarded – undo
236 236
 crl5lBlKjXh2GP0+omSO3x1jX4+iQPCW2TWoyKkUdLu/hGHG2w8RrTeme+kATECH
237 237
 YSu356M=
238 238
 -----END CERTIFICATE-----',
239
-			],
240
-		];
241
-		$this->appFetcher
242
-			->expects($this->once())
243
-			->method('get')
244
-			->willReturn($appArray);
245
-
246
-		$installer = $this->getInstaller();
247
-		$installer->downloadApp('news');
248
-	}
249
-
250
-
251
-	public function testDownloadAppWithDifferentCN(): void {
252
-		$this->expectException(\Exception::class);
253
-		$this->expectExceptionMessage('App with id news has a cert issued to passman');
254
-
255
-		$appArray = [
256
-			[
257
-				'id' => 'news',
258
-				'certificate' => '-----BEGIN CERTIFICATE-----
239
+            ],
240
+        ];
241
+        $this->appFetcher
242
+            ->expects($this->once())
243
+            ->method('get')
244
+            ->willReturn($appArray);
245
+
246
+        $installer = $this->getInstaller();
247
+        $installer->downloadApp('news');
248
+    }
249
+
250
+
251
+    public function testDownloadAppWithDifferentCN(): void {
252
+        $this->expectException(\Exception::class);
253
+        $this->expectExceptionMessage('App with id news has a cert issued to passman');
254
+
255
+        $appArray = [
256
+            [
257
+                'id' => 'news',
258
+                'certificate' => '-----BEGIN CERTIFICATE-----
259 259
 MIIEAjCCAuoCAhDUMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
260 260
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
261 261
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -279,26 +279,26 @@  discard block
 block discarded – undo
279 279
 u/spPSSVhaun5BA1FlphB2TkgnzlCmxJa63nFY045e/Jq+IKMcqqZl/092gbI2EQ
280 280
 5EpZaQ1l6H5DBXwrz58a8WTPC2Mu8g==
281 281
 -----END CERTIFICATE-----',
282
-			],
283
-		];
284
-		$this->appFetcher
285
-			->expects($this->once())
286
-			->method('get')
287
-			->willReturn($appArray);
288
-
289
-		$installer = $this->getInstaller();
290
-		$installer->downloadApp('news');
291
-	}
292
-
293
-
294
-	public function testDownloadAppWithInvalidSignature(): void {
295
-		$this->expectException(\Exception::class);
296
-		$this->expectExceptionMessage('App with id passman has invalid signature');
297
-
298
-		$appArray = [
299
-			[
300
-				'id' => 'passman',
301
-				'certificate' => '-----BEGIN CERTIFICATE-----
282
+            ],
283
+        ];
284
+        $this->appFetcher
285
+            ->expects($this->once())
286
+            ->method('get')
287
+            ->willReturn($appArray);
288
+
289
+        $installer = $this->getInstaller();
290
+        $installer->downloadApp('news');
291
+    }
292
+
293
+
294
+    public function testDownloadAppWithInvalidSignature(): void {
295
+        $this->expectException(\Exception::class);
296
+        $this->expectExceptionMessage('App with id passman has invalid signature');
297
+
298
+        $appArray = [
299
+            [
300
+                'id' => 'passman',
301
+                'certificate' => '-----BEGIN CERTIFICATE-----
302 302
 MIIEAjCCAuoCAhDUMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
303 303
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
304 304
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -322,51 +322,51 @@  discard block
 block discarded – undo
322 322
 u/spPSSVhaun5BA1FlphB2TkgnzlCmxJa63nFY045e/Jq+IKMcqqZl/092gbI2EQ
323 323
 5EpZaQ1l6H5DBXwrz58a8WTPC2Mu8g==
324 324
 -----END CERTIFICATE-----',
325
-				'releases' => [
326
-					[
327
-						'download' => 'https://example.com',
328
-						'signature' => 'MySignature',
329
-					],
330
-					[
331
-						'download' => 'https://nextcloud.com',
332
-					],
333
-				],
334
-			],
335
-		];
336
-		$this->appFetcher
337
-			->expects($this->once())
338
-			->method('get')
339
-			->willReturn($appArray);
340
-		$realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
341
-		copy(__DIR__ . '/../data/testapp.tar.gz', $realTmpFile);
342
-		$this->tempManager
343
-			->expects($this->once())
344
-			->method('getTemporaryFile')
345
-			->with('.tar.gz')
346
-			->willReturn($realTmpFile);
347
-		$client = $this->createMock(IClient::class);
348
-		$client
349
-			->expects($this->once())
350
-			->method('get')
351
-			->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
352
-		$this->clientService
353
-			->expects($this->once())
354
-			->method('newClient')
355
-			->willReturn($client);
356
-
357
-		$installer = $this->getInstaller();
358
-		$installer->downloadApp('passman');
359
-	}
360
-
361
-
362
-	public function testDownloadAppWithMoreThanOneFolderDownloaded(): void {
363
-		$this->expectException(\Exception::class);
364
-		$this->expectExceptionMessage('Extracted app testapp has more than 1 folder');
365
-
366
-		$appArray = [
367
-			[
368
-				'id' => 'testapp',
369
-				'certificate' => '-----BEGIN CERTIFICATE-----
325
+                'releases' => [
326
+                    [
327
+                        'download' => 'https://example.com',
328
+                        'signature' => 'MySignature',
329
+                    ],
330
+                    [
331
+                        'download' => 'https://nextcloud.com',
332
+                    ],
333
+                ],
334
+            ],
335
+        ];
336
+        $this->appFetcher
337
+            ->expects($this->once())
338
+            ->method('get')
339
+            ->willReturn($appArray);
340
+        $realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
341
+        copy(__DIR__ . '/../data/testapp.tar.gz', $realTmpFile);
342
+        $this->tempManager
343
+            ->expects($this->once())
344
+            ->method('getTemporaryFile')
345
+            ->with('.tar.gz')
346
+            ->willReturn($realTmpFile);
347
+        $client = $this->createMock(IClient::class);
348
+        $client
349
+            ->expects($this->once())
350
+            ->method('get')
351
+            ->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
352
+        $this->clientService
353
+            ->expects($this->once())
354
+            ->method('newClient')
355
+            ->willReturn($client);
356
+
357
+        $installer = $this->getInstaller();
358
+        $installer->downloadApp('passman');
359
+    }
360
+
361
+
362
+    public function testDownloadAppWithMoreThanOneFolderDownloaded(): void {
363
+        $this->expectException(\Exception::class);
364
+        $this->expectExceptionMessage('Extracted app testapp has more than 1 folder');
365
+
366
+        $appArray = [
367
+            [
368
+                'id' => 'testapp',
369
+                'certificate' => '-----BEGIN CERTIFICATE-----
370 370
 MIIEAjCCAuoCAhAbMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
371 371
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
372 372
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -390,10 +390,10 @@  discard block
 block discarded – undo
390 390
 Zh8Xg8UMNrOtXc1Wx1Wmjaa4ZE9dY6/KkU2ny2UWyDHKU/9VE8QQ4HN93gxU4+H7
391 391
 cUg0V1uAxqUvKytKkMfcyPWsz/AINA==
392 392
 -----END CERTIFICATE-----',
393
-				'releases' => [
394
-					[
395
-						'download' => 'https://example.com',
396
-						'signature' => 'h8H3tUy2dDlwrV/hY/ZxqYqe8Vue+IINluLtAt1HxX2cjz3vdoVHJRINRkMYYcdz
393
+                'releases' => [
394
+                    [
395
+                        'download' => 'https://example.com',
396
+                        'signature' => 'h8H3tUy2dDlwrV/hY/ZxqYqe8Vue+IINluLtAt1HxX2cjz3vdoVHJRINRkMYYcdz
397 397
 VlndvHyKdqJHDAACphR8tVV6EFrPermn7gEgWk7a51LbUM7sAN7RV7ijEooUo+TQ
398 398
 jNW9Ch48Wg3jvebMwWNr5t5U4MEXTP5f0YX/kxvkJoUrG3a3spt7ziEuHaq8IPvt
399 399
 Jj/JSDFhvRNpom7yNNcI1Ijoq8yC11sg7RJBNfrHdGPHPZVz2SyBiY9OcvgGSpUU
@@ -404,53 +404,53 @@  discard block
 block discarded – undo
404 404
 GqEhdDmOHsxNaeJ08Hlptq5yLv3+0wEdtriVjgAZNVduHG1F1FkhPIrDHaB6pd67
405 405
 0AFvO/pZgMSHDRHD+safBgaLb5dBZ895Qvudbq3RQevVnO+YZQYZkpmjoF/+TQ7/
406 406
 YwDVP+QmNRzx72jtqAN/Kc3CvQ9nkgYhU65B95aX0xA=',
407
-					],
408
-					[
409
-						'download' => 'https://nextcloud.com',
410
-					],
411
-				],
412
-			],
413
-		];
414
-		$this->appFetcher
415
-			->expects($this->once())
416
-			->method('get')
417
-			->willReturn($appArray);
418
-		$realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
419
-		copy(__DIR__ . '/../data/testapp1.tar.gz', $realTmpFile);
420
-		$this->tempManager
421
-			->expects($this->once())
422
-			->method('getTemporaryFile')
423
-			->with('.tar.gz')
424
-			->willReturn($realTmpFile);
425
-		$realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
426
-		mkdir($realTmpFolder . '/testfolder');
427
-		$this->tempManager
428
-			->expects($this->once())
429
-			->method('getTemporaryFolder')
430
-			->willReturn($realTmpFolder);
431
-		$client = $this->createMock(IClient::class);
432
-		$client
433
-			->expects($this->once())
434
-			->method('get')
435
-			->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
436
-		$this->clientService
437
-			->expects($this->once())
438
-			->method('newClient')
439
-			->willReturn($client);
440
-
441
-		$installer = $this->getInstaller();
442
-		$installer->downloadApp('testapp');
443
-	}
444
-
445
-
446
-	public function testDownloadAppWithMismatchingIdentifier(): void {
447
-		$this->expectException(\Exception::class);
448
-		$this->expectExceptionMessage('App for id testapp has a wrong app ID in info.xml: testapp1');
449
-
450
-		$appArray = [
451
-			[
452
-				'id' => 'testapp',
453
-				'certificate' => '-----BEGIN CERTIFICATE-----
407
+                    ],
408
+                    [
409
+                        'download' => 'https://nextcloud.com',
410
+                    ],
411
+                ],
412
+            ],
413
+        ];
414
+        $this->appFetcher
415
+            ->expects($this->once())
416
+            ->method('get')
417
+            ->willReturn($appArray);
418
+        $realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
419
+        copy(__DIR__ . '/../data/testapp1.tar.gz', $realTmpFile);
420
+        $this->tempManager
421
+            ->expects($this->once())
422
+            ->method('getTemporaryFile')
423
+            ->with('.tar.gz')
424
+            ->willReturn($realTmpFile);
425
+        $realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
426
+        mkdir($realTmpFolder . '/testfolder');
427
+        $this->tempManager
428
+            ->expects($this->once())
429
+            ->method('getTemporaryFolder')
430
+            ->willReturn($realTmpFolder);
431
+        $client = $this->createMock(IClient::class);
432
+        $client
433
+            ->expects($this->once())
434
+            ->method('get')
435
+            ->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
436
+        $this->clientService
437
+            ->expects($this->once())
438
+            ->method('newClient')
439
+            ->willReturn($client);
440
+
441
+        $installer = $this->getInstaller();
442
+        $installer->downloadApp('testapp');
443
+    }
444
+
445
+
446
+    public function testDownloadAppWithMismatchingIdentifier(): void {
447
+        $this->expectException(\Exception::class);
448
+        $this->expectExceptionMessage('App for id testapp has a wrong app ID in info.xml: testapp1');
449
+
450
+        $appArray = [
451
+            [
452
+                'id' => 'testapp',
453
+                'certificate' => '-----BEGIN CERTIFICATE-----
454 454
 MIIEAjCCAuoCAhAbMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
455 455
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
456 456
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -474,10 +474,10 @@  discard block
 block discarded – undo
474 474
 Zh8Xg8UMNrOtXc1Wx1Wmjaa4ZE9dY6/KkU2ny2UWyDHKU/9VE8QQ4HN93gxU4+H7
475 475
 cUg0V1uAxqUvKytKkMfcyPWsz/AINA==
476 476
 -----END CERTIFICATE-----',
477
-				'releases' => [
478
-					[
479
-						'download' => 'https://example.com',
480
-						'signature' => 'h8H3tUy2dDlwrV/hY/ZxqYqe8Vue+IINluLtAt1HxX2cjz3vdoVHJRINRkMYYcdz
477
+                'releases' => [
478
+                    [
479
+                        'download' => 'https://example.com',
480
+                        'signature' => 'h8H3tUy2dDlwrV/hY/ZxqYqe8Vue+IINluLtAt1HxX2cjz3vdoVHJRINRkMYYcdz
481 481
 VlndvHyKdqJHDAACphR8tVV6EFrPermn7gEgWk7a51LbUM7sAN7RV7ijEooUo+TQ
482 482
 jNW9Ch48Wg3jvebMwWNr5t5U4MEXTP5f0YX/kxvkJoUrG3a3spt7ziEuHaq8IPvt
483 483
 Jj/JSDFhvRNpom7yNNcI1Ijoq8yC11sg7RJBNfrHdGPHPZVz2SyBiY9OcvgGSpUU
@@ -488,48 +488,48 @@  discard block
 block discarded – undo
488 488
 GqEhdDmOHsxNaeJ08Hlptq5yLv3+0wEdtriVjgAZNVduHG1F1FkhPIrDHaB6pd67
489 489
 0AFvO/pZgMSHDRHD+safBgaLb5dBZ895Qvudbq3RQevVnO+YZQYZkpmjoF/+TQ7/
490 490
 YwDVP+QmNRzx72jtqAN/Kc3CvQ9nkgYhU65B95aX0xA=',
491
-					],
492
-					[
493
-						'download' => 'https://nextcloud.com',
494
-					],
495
-				],
496
-			],
497
-		];
498
-		$this->appFetcher
499
-			->expects($this->once())
500
-			->method('get')
501
-			->willReturn($appArray);
502
-		$realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
503
-		copy(__DIR__ . '/../data/testapp1.tar.gz', $realTmpFile);
504
-		$this->tempManager
505
-			->expects($this->once())
506
-			->method('getTemporaryFile')
507
-			->with('.tar.gz')
508
-			->willReturn($realTmpFile);
509
-		$realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
510
-		$this->tempManager
511
-			->expects($this->once())
512
-			->method('getTemporaryFolder')
513
-			->willReturn($realTmpFolder);
514
-		$client = $this->createMock(IClient::class);
515
-		$client
516
-			->expects($this->once())
517
-			->method('get')
518
-			->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
519
-		$this->clientService
520
-			->expects($this->once())
521
-			->method('newClient')
522
-			->willReturn($client);
523
-
524
-		$installer = $this->getInstaller();
525
-		$installer->downloadApp('testapp');
526
-	}
527
-
528
-	public function testDownloadAppSuccessful(): void {
529
-		$appArray = [
530
-			[
531
-				'id' => 'testapp',
532
-				'certificate' => '-----BEGIN CERTIFICATE-----
491
+                    ],
492
+                    [
493
+                        'download' => 'https://nextcloud.com',
494
+                    ],
495
+                ],
496
+            ],
497
+        ];
498
+        $this->appFetcher
499
+            ->expects($this->once())
500
+            ->method('get')
501
+            ->willReturn($appArray);
502
+        $realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
503
+        copy(__DIR__ . '/../data/testapp1.tar.gz', $realTmpFile);
504
+        $this->tempManager
505
+            ->expects($this->once())
506
+            ->method('getTemporaryFile')
507
+            ->with('.tar.gz')
508
+            ->willReturn($realTmpFile);
509
+        $realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
510
+        $this->tempManager
511
+            ->expects($this->once())
512
+            ->method('getTemporaryFolder')
513
+            ->willReturn($realTmpFolder);
514
+        $client = $this->createMock(IClient::class);
515
+        $client
516
+            ->expects($this->once())
517
+            ->method('get')
518
+            ->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
519
+        $this->clientService
520
+            ->expects($this->once())
521
+            ->method('newClient')
522
+            ->willReturn($client);
523
+
524
+        $installer = $this->getInstaller();
525
+        $installer->downloadApp('testapp');
526
+    }
527
+
528
+    public function testDownloadAppSuccessful(): void {
529
+        $appArray = [
530
+            [
531
+                'id' => 'testapp',
532
+                'certificate' => '-----BEGIN CERTIFICATE-----
533 533
 MIIEAjCCAuoCAhAbMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
534 534
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
535 535
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -553,10 +553,10 @@  discard block
 block discarded – undo
553 553
 Zh8Xg8UMNrOtXc1Wx1Wmjaa4ZE9dY6/KkU2ny2UWyDHKU/9VE8QQ4HN93gxU4+H7
554 554
 cUg0V1uAxqUvKytKkMfcyPWsz/AINA==
555 555
 -----END CERTIFICATE-----',
556
-				'releases' => [
557
-					[
558
-						'download' => 'https://example.com',
559
-						'signature' => 'O5UWFRnSx4mSdEX83Uh9u7KW+Gl1OWU4uaFg6aYY19zc+lWP4rKCbAUH7Jo1Bohf
556
+                'releases' => [
557
+                    [
558
+                        'download' => 'https://example.com',
559
+                        'signature' => 'O5UWFRnSx4mSdEX83Uh9u7KW+Gl1OWU4uaFg6aYY19zc+lWP4rKCbAUH7Jo1Bohf
560 560
 qxQbhXs4cMqGmoL8dW4zeFUqSJCRk52LA+ciLezjPFv275q+BxEgyWOylLnbhBaz
561 561
 +v6lXLaeG0J/ry8wEdg+rwP8FCYPsvKlXSVbFjgubvCR/owKJJf5iL0B93noBwBN
562 562
 jfbcxi7Kh16HAKy6f/gVZ6hf/4Uo7iEFMCPEHjidope+ejUpqbd8XhQg5/yh7TQ7
@@ -567,63 +567,63 @@  discard block
 block discarded – undo
567 567
 7yQWrsV7QvAzygAOFsC0TlSNJbmMCljouUk9di4CUZ+xsQ6n6TZtE7gsdljlKjPS
568 568
 3Ys+e3V1HUaVzv8SaSmKwjRoQxQxHWLtXpJS2Yq+i+gq7LuC+aStzxAzV/h2plDW
569 569
 358picx/PobNDi71Q97+/CAOq+4wDOwhKwls7lwudIs=',
570
-					],
571
-					[
572
-						'download' => 'https://nextcloud.com',
573
-					],
574
-				],
575
-			],
576
-		];
577
-		$this->appFetcher
578
-			->expects($this->once())
579
-			->method('get')
580
-			->willReturn($appArray);
581
-		$realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
582
-		copy(__DIR__ . '/../data/testapp.tar.gz', $realTmpFile);
583
-		$this->tempManager
584
-			->expects($this->once())
585
-			->method('getTemporaryFile')
586
-			->with('.tar.gz')
587
-			->willReturn($realTmpFile);
588
-		$realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
589
-		$this->tempManager
590
-			->expects($this->once())
591
-			->method('getTemporaryFolder')
592
-			->willReturn($realTmpFolder);
593
-		$client = $this->createMock(IClient::class);
594
-		$client
595
-			->expects($this->once())
596
-			->method('get')
597
-			->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
598
-		$this->clientService
599
-			->expects($this->once())
600
-			->method('newClient')
601
-			->willReturn($client);
602
-
603
-		$installer = $this->getInstaller();
604
-		$installer->downloadApp('testapp');
605
-
606
-		$this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
607
-		$this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
608
-	}
609
-
610
-
611
-	public function testDownloadAppWithDowngrade(): void {
612
-		// Use previous test to download the application in version 0.9
613
-		$this->testDownloadAppSuccessful();
614
-
615
-		// Reset mocks
616
-		$this->appFetcher = $this->createMock(AppFetcher::class);
617
-		$this->clientService = $this->createMock(IClientService::class);
618
-		$this->tempManager = $this->createMock(ITempManager::class);
619
-
620
-		$this->expectException(\Exception::class);
621
-		$this->expectExceptionMessage('App for id testapp has version 0.9 and tried to update to lower version 0.8');
622
-
623
-		$appArray = [
624
-			[
625
-				'id' => 'testapp',
626
-				'certificate' => '-----BEGIN CERTIFICATE-----
570
+                    ],
571
+                    [
572
+                        'download' => 'https://nextcloud.com',
573
+                    ],
574
+                ],
575
+            ],
576
+        ];
577
+        $this->appFetcher
578
+            ->expects($this->once())
579
+            ->method('get')
580
+            ->willReturn($appArray);
581
+        $realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
582
+        copy(__DIR__ . '/../data/testapp.tar.gz', $realTmpFile);
583
+        $this->tempManager
584
+            ->expects($this->once())
585
+            ->method('getTemporaryFile')
586
+            ->with('.tar.gz')
587
+            ->willReturn($realTmpFile);
588
+        $realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
589
+        $this->tempManager
590
+            ->expects($this->once())
591
+            ->method('getTemporaryFolder')
592
+            ->willReturn($realTmpFolder);
593
+        $client = $this->createMock(IClient::class);
594
+        $client
595
+            ->expects($this->once())
596
+            ->method('get')
597
+            ->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
598
+        $this->clientService
599
+            ->expects($this->once())
600
+            ->method('newClient')
601
+            ->willReturn($client);
602
+
603
+        $installer = $this->getInstaller();
604
+        $installer->downloadApp('testapp');
605
+
606
+        $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
607
+        $this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
608
+    }
609
+
610
+
611
+    public function testDownloadAppWithDowngrade(): void {
612
+        // Use previous test to download the application in version 0.9
613
+        $this->testDownloadAppSuccessful();
614
+
615
+        // Reset mocks
616
+        $this->appFetcher = $this->createMock(AppFetcher::class);
617
+        $this->clientService = $this->createMock(IClientService::class);
618
+        $this->tempManager = $this->createMock(ITempManager::class);
619
+
620
+        $this->expectException(\Exception::class);
621
+        $this->expectExceptionMessage('App for id testapp has version 0.9 and tried to update to lower version 0.8');
622
+
623
+        $appArray = [
624
+            [
625
+                'id' => 'testapp',
626
+                'certificate' => '-----BEGIN CERTIFICATE-----
627 627
 MIIEAjCCAuoCAhAbMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD
628 628
 VQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI
629 629
 MTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB
@@ -647,10 +647,10 @@  discard block
 block discarded – undo
647 647
 Zh8Xg8UMNrOtXc1Wx1Wmjaa4ZE9dY6/KkU2ny2UWyDHKU/9VE8QQ4HN93gxU4+H7
648 648
 cUg0V1uAxqUvKytKkMfcyPWsz/AINA==
649 649
 -----END CERTIFICATE-----',
650
-				'releases' => [
651
-					[
652
-						'download' => 'https://example.com',
653
-						'signature' => 'KMSao4cKdMIYxeT8Bm4lrmSeIQnk7YzJZh+Vz+4LVSBwF+OMmcujryQuWLXmbPfg
650
+                'releases' => [
651
+                    [
652
+                        'download' => 'https://example.com',
653
+                        'signature' => 'KMSao4cKdMIYxeT8Bm4lrmSeIQnk7YzJZh+Vz+4LVSBwF+OMmcujryQuWLXmbPfg
654 654
 4hGI9zS025469VNjUoCprn01H8NBq3O1cXz+ewG1oxYWMMQFZDkOtUQ+XZ27b91t
655 655
 y0l45H6C8j0sTeSrUb/LCjrdm+buUygkhC2RZxCI6tLi4rYWj0MiqDz98XkbB3te
656 656
 pW3ZND6mG6Jxn1fnd35paqZ/+URMftoLQ4K+6vJoBVGnug9nk1RpGLouICI0zCrz
@@ -661,44 +661,44 @@  discard block
 block discarded – undo
661 661
 9WfeKJ/mavrSLVa7QqZ4RCcMigmijT1kdqbaEh05IZNrzs6VDcS2EIrbDX8SGXUk
662 662
 uDDkPXZEXqNDEjyONfDXVRLiqDa52Gg+I4vW/l/4ZOFgAWdZkqPPuZFaqzZpsJXm
663 663
 JXhrdaWDZ8fzpUjugrtC3qslsqL0dzgU37anS3HwrT8=',
664
-					],
665
-					[
666
-						'download' => 'https://nextcloud.com',
667
-					],
668
-				],
669
-			],
670
-		];
671
-		$this->appFetcher
672
-			->expects($this->once())
673
-			->method('get')
674
-			->willReturn($appArray);
675
-		$realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
676
-		copy(__DIR__ . '/../data/testapp.0.8.tar.gz', $realTmpFile);
677
-		$this->tempManager
678
-			->expects($this->once())
679
-			->method('getTemporaryFile')
680
-			->with('.tar.gz')
681
-			->willReturn($realTmpFile);
682
-		$realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
683
-		$this->tempManager
684
-			->expects($this->once())
685
-			->method('getTemporaryFolder')
686
-			->willReturn($realTmpFolder);
687
-		$client = $this->createMock(IClient::class);
688
-		$client
689
-			->expects($this->once())
690
-			->method('get')
691
-			->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
692
-		$this->clientService
693
-			->expects($this->once())
694
-			->method('newClient')
695
-			->willReturn($client);
696
-		$this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
697
-		$this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
698
-
699
-		$installer = $this->getInstaller();
700
-		$installer->downloadApp('testapp');
701
-		$this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
702
-		$this->assertEquals('0.8', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
703
-	}
664
+                    ],
665
+                    [
666
+                        'download' => 'https://nextcloud.com',
667
+                    ],
668
+                ],
669
+            ],
670
+        ];
671
+        $this->appFetcher
672
+            ->expects($this->once())
673
+            ->method('get')
674
+            ->willReturn($appArray);
675
+        $realTmpFile = \OC::$server->getTempManager()->getTemporaryFile('.tar.gz');
676
+        copy(__DIR__ . '/../data/testapp.0.8.tar.gz', $realTmpFile);
677
+        $this->tempManager
678
+            ->expects($this->once())
679
+            ->method('getTemporaryFile')
680
+            ->with('.tar.gz')
681
+            ->willReturn($realTmpFile);
682
+        $realTmpFolder = \OC::$server->getTempManager()->getTemporaryFolder();
683
+        $this->tempManager
684
+            ->expects($this->once())
685
+            ->method('getTemporaryFolder')
686
+            ->willReturn($realTmpFolder);
687
+        $client = $this->createMock(IClient::class);
688
+        $client
689
+            ->expects($this->once())
690
+            ->method('get')
691
+            ->with('https://example.com', ['sink' => $realTmpFile, 'timeout' => 120]);
692
+        $this->clientService
693
+            ->expects($this->once())
694
+            ->method('newClient')
695
+            ->willReturn($client);
696
+        $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
697
+        $this->assertEquals('0.9', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
698
+
699
+        $installer = $this->getInstaller();
700
+        $installer->downloadApp('testapp');
701
+        $this->assertTrue(file_exists(__DIR__ . '/../../apps/testapp/appinfo/info.xml'));
702
+        $this->assertEquals('0.8', \OC_App::getAppVersionByPath(__DIR__ . '/../../apps/testapp/'));
703
+    }
704 704
 }
Please login to merge, or discard this patch.