Completed
Push — master ( 81d0c7...618175 )
by
unknown
26:17
created
tests/lib/TestCase.php 2 patches
Indentation   +593 added lines, -593 removed lines patch added patch discarded remove patch
@@ -37,601 +37,601 @@
 block discarded – undo
37 37
 use PHPUnit\Framework\Attributes\Group;
38 38
 
39 39
 if (version_compare(\PHPUnit\Runner\Version::id(), 10, '>=')) {
40
-	trait OnNotSuccessfulTestTrait {
41
-		protected function onNotSuccessfulTest(\Throwable $t): never {
42
-			$this->restoreAllServices();
43
-
44
-			// restore database connection
45
-			if (!$this->IsDatabaseAccessAllowed()) {
46
-				\OC::$server->registerService(IDBConnection::class, function () {
47
-					return self::$realDatabase;
48
-				});
49
-			}
50
-
51
-			parent::onNotSuccessfulTest($t);
52
-		}
53
-	}
40
+    trait OnNotSuccessfulTestTrait {
41
+        protected function onNotSuccessfulTest(\Throwable $t): never {
42
+            $this->restoreAllServices();
43
+
44
+            // restore database connection
45
+            if (!$this->IsDatabaseAccessAllowed()) {
46
+                \OC::$server->registerService(IDBConnection::class, function () {
47
+                    return self::$realDatabase;
48
+                });
49
+            }
50
+
51
+            parent::onNotSuccessfulTest($t);
52
+        }
53
+    }
54 54
 } else {
55
-	trait OnNotSuccessfulTestTrait {
56
-		protected function onNotSuccessfulTest(\Throwable $t): void {
57
-			$this->restoreAllServices();
58
-
59
-			// restore database connection
60
-			if (!$this->IsDatabaseAccessAllowed()) {
61
-				\OC::$server->registerService(IDBConnection::class, function () {
62
-					return self::$realDatabase;
63
-				});
64
-			}
65
-
66
-			parent::onNotSuccessfulTest($t);
67
-		}
68
-	}
55
+    trait OnNotSuccessfulTestTrait {
56
+        protected function onNotSuccessfulTest(\Throwable $t): void {
57
+            $this->restoreAllServices();
58
+
59
+            // restore database connection
60
+            if (!$this->IsDatabaseAccessAllowed()) {
61
+                \OC::$server->registerService(IDBConnection::class, function () {
62
+                    return self::$realDatabase;
63
+                });
64
+            }
65
+
66
+            parent::onNotSuccessfulTest($t);
67
+        }
68
+    }
69 69
 }
70 70
 
71 71
 abstract class TestCase extends \PHPUnit\Framework\TestCase {
72
-	/** @var \OC\Command\QueueBus */
73
-	private $commandBus;
74
-
75
-	/** @var IDBConnection */
76
-	protected static $realDatabase = null;
77
-
78
-	/** @var bool */
79
-	private static $wasDatabaseAllowed = false;
80
-
81
-	/** @var array */
82
-	protected $services = [];
83
-
84
-	use OnNotSuccessfulTestTrait;
85
-
86
-	/**
87
-	 * @param string $name
88
-	 * @param mixed $newService
89
-	 * @return bool
90
-	 */
91
-	public function overwriteService(string $name, $newService): bool {
92
-		if (isset($this->services[$name])) {
93
-			return false;
94
-		}
95
-
96
-		try {
97
-			$this->services[$name] = Server::get($name);
98
-		} catch (QueryException $e) {
99
-			$this->services[$name] = false;
100
-		}
101
-		$container = \OC::$server->getAppContainerForService($name);
102
-		$container = $container ?? \OC::$server;
103
-
104
-		$container->registerService($name, function () use ($newService) {
105
-			return $newService;
106
-		});
107
-
108
-		return true;
109
-	}
110
-
111
-	/**
112
-	 * @param string $name
113
-	 * @return bool
114
-	 */
115
-	public function restoreService(string $name): bool {
116
-		if (isset($this->services[$name])) {
117
-			$oldService = $this->services[$name];
118
-
119
-			$container = \OC::$server->getAppContainerForService($name);
120
-			$container = $container ?? \OC::$server;
121
-
122
-			if ($oldService !== false) {
123
-				$container->registerService($name, function () use ($oldService) {
124
-					return $oldService;
125
-				});
126
-			} else {
127
-				unset($container[$oldService]);
128
-			}
129
-
130
-
131
-			unset($this->services[$name]);
132
-			return true;
133
-		}
134
-
135
-		return false;
136
-	}
137
-
138
-	public function restoreAllServices() {
139
-		if (!empty($this->services)) {
140
-			if (!empty($this->services)) {
141
-				foreach ($this->services as $name => $service) {
142
-					$this->restoreService($name);
143
-				}
144
-			}
145
-		}
146
-	}
147
-
148
-	protected function getTestTraits() {
149
-		$traits = [];
150
-		$class = $this;
151
-		do {
152
-			$traits = array_merge(class_uses($class), $traits);
153
-		} while ($class = get_parent_class($class));
154
-		foreach ($traits as $trait => $same) {
155
-			$traits = array_merge(class_uses($trait), $traits);
156
-		}
157
-		$traits = array_unique($traits);
158
-		return array_filter($traits, function ($trait) {
159
-			return substr($trait, 0, 5) === 'Test\\';
160
-		});
161
-	}
162
-
163
-	protected function setUp(): void {
164
-		// overwrite the command bus with one we can run ourselves
165
-		$this->commandBus = new QueueBus();
166
-		$this->overwriteService('AsyncCommandBus', $this->commandBus);
167
-		$this->overwriteService(IBus::class, $this->commandBus);
168
-
169
-		// detect database access
170
-		self::$wasDatabaseAllowed = true;
171
-		if (!$this->IsDatabaseAccessAllowed()) {
172
-			self::$wasDatabaseAllowed = false;
173
-			if (is_null(self::$realDatabase)) {
174
-				self::$realDatabase = Server::get(IDBConnection::class);
175
-			}
176
-			\OC::$server->registerService(IDBConnection::class, function (): void {
177
-				$this->fail('Your test case is not allowed to access the database.');
178
-			});
179
-		}
180
-
181
-		$traits = $this->getTestTraits();
182
-		foreach ($traits as $trait) {
183
-			$methodName = 'setUp' . basename(str_replace('\\', '/', $trait));
184
-			if (method_exists($this, $methodName)) {
185
-				call_user_func([$this, $methodName]);
186
-			}
187
-		}
188
-	}
189
-
190
-	protected function tearDown(): void {
191
-		$this->restoreAllServices();
192
-
193
-		// restore database connection
194
-		if (!$this->IsDatabaseAccessAllowed()) {
195
-			\OC::$server->registerService(IDBConnection::class, function () {
196
-				return self::$realDatabase;
197
-			});
198
-		}
199
-
200
-		// further cleanup
201
-		$hookExceptions = \OC_Hook::$thrownExceptions;
202
-		\OC_Hook::$thrownExceptions = [];
203
-		Server::get(ILockingProvider::class)->releaseAll();
204
-		if (!empty($hookExceptions)) {
205
-			throw $hookExceptions[0];
206
-		}
207
-
208
-		// fail hard if xml errors have not been cleaned up
209
-		$errors = libxml_get_errors();
210
-		libxml_clear_errors();
211
-		if (!empty($errors)) {
212
-			self::assertEquals([], $errors, 'There have been xml parsing errors');
213
-		}
214
-
215
-		if ($this->IsDatabaseAccessAllowed()) {
216
-			Storage::getGlobalCache()->clearCache();
217
-		}
218
-
219
-		// tearDown the traits
220
-		$traits = $this->getTestTraits();
221
-		foreach ($traits as $trait) {
222
-			$methodName = 'tearDown' . basename(str_replace('\\', '/', $trait));
223
-			if (method_exists($this, $methodName)) {
224
-				call_user_func([$this, $methodName]);
225
-			}
226
-		}
227
-	}
228
-
229
-	/**
230
-	 * Allows us to test private methods/properties
231
-	 *
232
-	 * @param $object
233
-	 * @param $methodName
234
-	 * @param array $parameters
235
-	 * @return mixed
236
-	 */
237
-	protected static function invokePrivate($object, $methodName, array $parameters = []) {
238
-		if (is_string($object)) {
239
-			$className = $object;
240
-		} else {
241
-			$className = get_class($object);
242
-		}
243
-		$reflection = new \ReflectionClass($className);
244
-
245
-		if ($reflection->hasMethod($methodName)) {
246
-			$method = $reflection->getMethod($methodName);
247
-
248
-			$method->setAccessible(true);
249
-
250
-			return $method->invokeArgs($object, $parameters);
251
-		} elseif ($reflection->hasProperty($methodName)) {
252
-			$property = $reflection->getProperty($methodName);
253
-
254
-			$property->setAccessible(true);
255
-
256
-			if (!empty($parameters)) {
257
-				if ($property->isStatic()) {
258
-					$property->setValue(null, array_pop($parameters));
259
-				} else {
260
-					$property->setValue($object, array_pop($parameters));
261
-				}
262
-			}
263
-
264
-			if (is_object($object)) {
265
-				return $property->getValue($object);
266
-			}
267
-
268
-			return $property->getValue();
269
-		} elseif ($reflection->hasConstant($methodName)) {
270
-			return $reflection->getConstant($methodName);
271
-		}
272
-
273
-		return false;
274
-	}
275
-
276
-	/**
277
-	 * Returns a unique identifier as uniqid() is not reliable sometimes
278
-	 *
279
-	 * @param string $prefix
280
-	 * @param int $length
281
-	 * @return string
282
-	 */
283
-	protected static function getUniqueID($prefix = '', $length = 13) {
284
-		return $prefix . Server::get(ISecureRandom::class)->generate(
285
-			$length,
286
-			// Do not use dots and slashes as we use the value for file names
287
-			ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
288
-		);
289
-	}
290
-
291
-	/**
292
-	 * Filter methods
293
-	 *
294
-	 * Returns all methods of the given class,
295
-	 * that are public or abstract and not in the ignoreMethods list,
296
-	 * to be able to fill onlyMethods() with an inverted list.
297
-	 *
298
-	 * @param string $className
299
-	 * @param string[] $filterMethods
300
-	 * @return string[]
301
-	 */
302
-	public function filterClassMethods(string $className, array $filterMethods): array {
303
-		$class = new \ReflectionClass($className);
304
-
305
-		$methods = [];
306
-		foreach ($class->getMethods() as $method) {
307
-			if (($method->isPublic() || $method->isAbstract()) && !in_array($method->getName(), $filterMethods, true)) {
308
-				$methods[] = $method->getName();
309
-			}
310
-		}
311
-
312
-		return $methods;
313
-	}
314
-
315
-	public static function tearDownAfterClass(): void {
316
-		if (!self::$wasDatabaseAllowed && self::$realDatabase !== null) {
317
-			// in case an error is thrown in a test, PHPUnit jumps straight to tearDownAfterClass,
318
-			// so we need the database again
319
-			\OC::$server->registerService(IDBConnection::class, function () {
320
-				return self::$realDatabase;
321
-			});
322
-		}
323
-		$dataDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data-autotest');
324
-		if (self::$wasDatabaseAllowed && Server::get(IDBConnection::class)) {
325
-			$db = Server::get(IDBConnection::class);
326
-			if ($db->inTransaction()) {
327
-				$db->rollBack();
328
-				throw new \Exception('There was a transaction still in progress and needed to be rolled back. Please fix this in your test.');
329
-			}
330
-			$queryBuilder = $db->getQueryBuilder();
331
-
332
-			self::tearDownAfterClassCleanShares($queryBuilder);
333
-			self::tearDownAfterClassCleanStorages($queryBuilder);
334
-			self::tearDownAfterClassCleanFileCache($queryBuilder);
335
-		}
336
-		self::tearDownAfterClassCleanStrayDataFiles($dataDir);
337
-		self::tearDownAfterClassCleanStrayHooks();
338
-		self::tearDownAfterClassCleanStrayLocks();
339
-
340
-		/** @var SetupManager $setupManager */
341
-		$setupManager = Server::get(SetupManager::class);
342
-		$setupManager->tearDown();
343
-
344
-		/** @var MountProviderCollection $mountProviderCollection */
345
-		$mountProviderCollection = Server::get(MountProviderCollection::class);
346
-		$mountProviderCollection->clearProviders();
347
-
348
-		/** @var IConfig $config */
349
-		$config = Server::get(IConfig::class);
350
-		$mountProviderCollection->registerProvider(new CacheMountProvider($config));
351
-		$mountProviderCollection->registerHomeProvider(new LocalHomeMountProvider());
352
-		$objectStoreConfig = Server::get(PrimaryObjectStoreConfig::class);
353
-		$mountProviderCollection->registerRootProvider(new RootMountProvider($objectStoreConfig, $config));
354
-
355
-		$setupManager->setupRoot();
356
-
357
-		parent::tearDownAfterClass();
358
-	}
359
-
360
-	/**
361
-	 * Remove all entries from the share table
362
-	 *
363
-	 * @param IQueryBuilder $queryBuilder
364
-	 */
365
-	protected static function tearDownAfterClassCleanShares(IQueryBuilder $queryBuilder) {
366
-		$queryBuilder->delete('share')
367
-			->executeStatement();
368
-	}
369
-
370
-	/**
371
-	 * Remove all entries from the storages table
372
-	 *
373
-	 * @param IQueryBuilder $queryBuilder
374
-	 */
375
-	protected static function tearDownAfterClassCleanStorages(IQueryBuilder $queryBuilder) {
376
-		$queryBuilder->delete('storages')
377
-			->executeStatement();
378
-	}
379
-
380
-	/**
381
-	 * Remove all entries from the filecache table
382
-	 *
383
-	 * @param IQueryBuilder $queryBuilder
384
-	 */
385
-	protected static function tearDownAfterClassCleanFileCache(IQueryBuilder $queryBuilder) {
386
-		$queryBuilder->delete('filecache')
387
-			->runAcrossAllShards()
388
-			->executeStatement();
389
-	}
390
-
391
-	/**
392
-	 * Remove all unused files from the data dir
393
-	 *
394
-	 * @param string $dataDir
395
-	 */
396
-	protected static function tearDownAfterClassCleanStrayDataFiles($dataDir) {
397
-		$knownEntries = [
398
-			'nextcloud.log' => true,
399
-			'audit.log' => true,
400
-			'owncloud.db' => true,
401
-			'.ocdata' => true,
402
-			'..' => true,
403
-			'.' => true,
404
-		];
405
-
406
-		if ($dh = opendir($dataDir)) {
407
-			while (($file = readdir($dh)) !== false) {
408
-				if (!isset($knownEntries[$file])) {
409
-					self::tearDownAfterClassCleanStrayDataUnlinkDir($dataDir . '/' . $file);
410
-				}
411
-			}
412
-			closedir($dh);
413
-		}
414
-	}
415
-
416
-	/**
417
-	 * Recursive delete files and folders from a given directory
418
-	 *
419
-	 * @param string $dir
420
-	 */
421
-	protected static function tearDownAfterClassCleanStrayDataUnlinkDir($dir) {
422
-		if ($dh = @opendir($dir)) {
423
-			while (($file = readdir($dh)) !== false) {
424
-				if (Filesystem::isIgnoredDir($file)) {
425
-					continue;
426
-				}
427
-				$path = $dir . '/' . $file;
428
-				if (is_dir($path)) {
429
-					self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
430
-				} else {
431
-					@unlink($path);
432
-				}
433
-			}
434
-			closedir($dh);
435
-		}
436
-		@rmdir($dir);
437
-	}
438
-
439
-	/**
440
-	 * Clean up the list of hooks
441
-	 */
442
-	protected static function tearDownAfterClassCleanStrayHooks() {
443
-		\OC_Hook::clear();
444
-	}
445
-
446
-	/**
447
-	 * Clean up the list of locks
448
-	 */
449
-	protected static function tearDownAfterClassCleanStrayLocks() {
450
-		Server::get(ILockingProvider::class)->releaseAll();
451
-	}
452
-
453
-	/**
454
-	 * Login and setup FS as a given user,
455
-	 * sets the given user as the current user.
456
-	 *
457
-	 * @param string $user user id or empty for a generic FS
458
-	 */
459
-	protected static function loginAsUser($user = '') {
460
-		self::logout();
461
-		Filesystem::tearDown();
462
-		\OC_User::setUserId($user);
463
-		$userObject = Server::get(IUserManager::class)->get($user);
464
-		if (!is_null($userObject)) {
465
-			$userObject->updateLastLoginTimestamp();
466
-		}
467
-		\OC_Util::setupFS($user);
468
-		if (Server::get(IUserManager::class)->userExists($user)) {
469
-			\OC::$server->getUserFolder($user);
470
-		}
471
-	}
472
-
473
-	/**
474
-	 * Logout the current user and tear down the filesystem.
475
-	 */
476
-	protected static function logout() {
477
-		\OC_Util::tearDownFS();
478
-		\OC_User::setUserId('');
479
-		// needed for fully logout
480
-		Server::get(IUserSession::class)->setUser(null);
481
-	}
482
-
483
-	/**
484
-	 * Run all commands pushed to the bus
485
-	 */
486
-	protected function runCommands() {
487
-		// get the user for which the fs is setup
488
-		$view = Filesystem::getView();
489
-		if ($view) {
490
-			[, $user] = explode('/', $view->getRoot());
491
-		} else {
492
-			$user = null;
493
-		}
494
-
495
-		\OC_Util::tearDownFS(); // command can't reply on the fs being setup
496
-		$this->commandBus->run();
497
-		\OC_Util::tearDownFS();
498
-
499
-		if ($user) {
500
-			\OC_Util::setupFS($user);
501
-		}
502
-	}
503
-
504
-	/**
505
-	 * Check if the given path is locked with a given type
506
-	 *
507
-	 * @param View $view view
508
-	 * @param string $path path to check
509
-	 * @param int $type lock type
510
-	 * @param bool $onMountPoint true to check the mount point instead of the
511
-	 *                           mounted storage
512
-	 *
513
-	 * @return boolean true if the file is locked with the
514
-	 *                 given type, false otherwise
515
-	 */
516
-	protected function isFileLocked($view, $path, $type, $onMountPoint = false) {
517
-		// Note: this seems convoluted but is necessary because
518
-		// the format of the lock key depends on the storage implementation
519
-		// (in our case mostly md5)
520
-
521
-		if ($type === ILockingProvider::LOCK_SHARED) {
522
-			// to check if the file has a shared lock, try acquiring an exclusive lock
523
-			$checkType = ILockingProvider::LOCK_EXCLUSIVE;
524
-		} else {
525
-			// a shared lock cannot be set if exclusive lock is in place
526
-			$checkType = ILockingProvider::LOCK_SHARED;
527
-		}
528
-		try {
529
-			$view->lockFile($path, $checkType, $onMountPoint);
530
-			// no exception, which means the lock of $type is not set
531
-			// clean up
532
-			$view->unlockFile($path, $checkType, $onMountPoint);
533
-			return false;
534
-		} catch (LockedException $e) {
535
-			// we could not acquire the counter-lock, which means
536
-			// the lock of $type was in place
537
-			return true;
538
-		}
539
-	}
540
-
541
-	protected function getGroupAnnotations(): array {
542
-		if (method_exists($this, 'getAnnotations')) {
543
-			$annotations = $this->getAnnotations();
544
-			return $annotations['class']['group'] ?? [];
545
-		}
546
-
547
-		$r = new \ReflectionClass($this);
548
-		$doc = $r->getDocComment();
549
-
550
-		if (class_exists(Group::class)) {
551
-			$attributes = array_map(function (\ReflectionAttribute $attribute) {
552
-				/** @var Group $group */
553
-				$group = $attribute->newInstance();
554
-				return $group->name();
555
-			}, $r->getAttributes(Group::class));
556
-			if (count($attributes) > 0) {
557
-				return $attributes;
558
-			}
559
-		}
560
-		preg_match_all('#@group\s+(.*?)\n#s', $doc, $annotations);
561
-		return $annotations[1] ?? [];
562
-	}
563
-
564
-	protected function IsDatabaseAccessAllowed(): bool {
565
-		$annotations = $this->getGroupAnnotations();
566
-		if (isset($annotations)) {
567
-			if (in_array('DB', $annotations) || in_array('SLOWDB', $annotations)) {
568
-				return true;
569
-			}
570
-		}
571
-
572
-		return false;
573
-	}
574
-
575
-	/**
576
-	 * @param string $expectedHtml
577
-	 * @param string $template
578
-	 * @param array $vars
579
-	 */
580
-	protected function assertTemplate($expectedHtml, $template, $vars = []) {
581
-		$requestToken = 12345;
582
-		/** @var Defaults|\PHPUnit\Framework\MockObject\MockObject $l10n */
583
-		$theme = $this->getMockBuilder('\OCP\Defaults')
584
-			->disableOriginalConstructor()->getMock();
585
-		$theme->expects($this->any())
586
-			->method('getName')
587
-			->willReturn('Nextcloud');
588
-		/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject $l10n */
589
-		$l10n = $this->getMockBuilder(IL10N::class)
590
-			->disableOriginalConstructor()->getMock();
591
-		$l10n
592
-			->expects($this->any())
593
-			->method('t')
594
-			->willReturnCallback(function ($text, $parameters = []) {
595
-				return vsprintf($text, $parameters);
596
-			});
597
-
598
-		$t = new Base($template, $requestToken, $l10n, $theme);
599
-		$buf = $t->fetchPage($vars);
600
-		$this->assertHtmlStringEqualsHtmlString($expectedHtml, $buf);
601
-	}
602
-
603
-	/**
604
-	 * @param string $expectedHtml
605
-	 * @param string $actualHtml
606
-	 * @param string $message
607
-	 */
608
-	protected function assertHtmlStringEqualsHtmlString($expectedHtml, $actualHtml, $message = '') {
609
-		$expected = new DOMDocument();
610
-		$expected->preserveWhiteSpace = false;
611
-		$expected->formatOutput = true;
612
-		$expected->loadHTML($expectedHtml);
613
-
614
-		$actual = new DOMDocument();
615
-		$actual->preserveWhiteSpace = false;
616
-		$actual->formatOutput = true;
617
-		$actual->loadHTML($actualHtml);
618
-		$this->removeWhitespaces($actual);
619
-
620
-		$expectedHtml1 = $expected->saveHTML();
621
-		$actualHtml1 = $actual->saveHTML();
622
-		self::assertEquals($expectedHtml1, $actualHtml1, $message);
623
-	}
624
-
625
-
626
-	private function removeWhitespaces(DOMNode $domNode) {
627
-		foreach ($domNode->childNodes as $node) {
628
-			if ($node->hasChildNodes()) {
629
-				$this->removeWhitespaces($node);
630
-			} else {
631
-				if ($node instanceof \DOMText && $node->isWhitespaceInElementContent()) {
632
-					$domNode->removeChild($node);
633
-				}
634
-			}
635
-		}
636
-	}
72
+    /** @var \OC\Command\QueueBus */
73
+    private $commandBus;
74
+
75
+    /** @var IDBConnection */
76
+    protected static $realDatabase = null;
77
+
78
+    /** @var bool */
79
+    private static $wasDatabaseAllowed = false;
80
+
81
+    /** @var array */
82
+    protected $services = [];
83
+
84
+    use OnNotSuccessfulTestTrait;
85
+
86
+    /**
87
+     * @param string $name
88
+     * @param mixed $newService
89
+     * @return bool
90
+     */
91
+    public function overwriteService(string $name, $newService): bool {
92
+        if (isset($this->services[$name])) {
93
+            return false;
94
+        }
95
+
96
+        try {
97
+            $this->services[$name] = Server::get($name);
98
+        } catch (QueryException $e) {
99
+            $this->services[$name] = false;
100
+        }
101
+        $container = \OC::$server->getAppContainerForService($name);
102
+        $container = $container ?? \OC::$server;
103
+
104
+        $container->registerService($name, function () use ($newService) {
105
+            return $newService;
106
+        });
107
+
108
+        return true;
109
+    }
110
+
111
+    /**
112
+     * @param string $name
113
+     * @return bool
114
+     */
115
+    public function restoreService(string $name): bool {
116
+        if (isset($this->services[$name])) {
117
+            $oldService = $this->services[$name];
118
+
119
+            $container = \OC::$server->getAppContainerForService($name);
120
+            $container = $container ?? \OC::$server;
121
+
122
+            if ($oldService !== false) {
123
+                $container->registerService($name, function () use ($oldService) {
124
+                    return $oldService;
125
+                });
126
+            } else {
127
+                unset($container[$oldService]);
128
+            }
129
+
130
+
131
+            unset($this->services[$name]);
132
+            return true;
133
+        }
134
+
135
+        return false;
136
+    }
137
+
138
+    public function restoreAllServices() {
139
+        if (!empty($this->services)) {
140
+            if (!empty($this->services)) {
141
+                foreach ($this->services as $name => $service) {
142
+                    $this->restoreService($name);
143
+                }
144
+            }
145
+        }
146
+    }
147
+
148
+    protected function getTestTraits() {
149
+        $traits = [];
150
+        $class = $this;
151
+        do {
152
+            $traits = array_merge(class_uses($class), $traits);
153
+        } while ($class = get_parent_class($class));
154
+        foreach ($traits as $trait => $same) {
155
+            $traits = array_merge(class_uses($trait), $traits);
156
+        }
157
+        $traits = array_unique($traits);
158
+        return array_filter($traits, function ($trait) {
159
+            return substr($trait, 0, 5) === 'Test\\';
160
+        });
161
+    }
162
+
163
+    protected function setUp(): void {
164
+        // overwrite the command bus with one we can run ourselves
165
+        $this->commandBus = new QueueBus();
166
+        $this->overwriteService('AsyncCommandBus', $this->commandBus);
167
+        $this->overwriteService(IBus::class, $this->commandBus);
168
+
169
+        // detect database access
170
+        self::$wasDatabaseAllowed = true;
171
+        if (!$this->IsDatabaseAccessAllowed()) {
172
+            self::$wasDatabaseAllowed = false;
173
+            if (is_null(self::$realDatabase)) {
174
+                self::$realDatabase = Server::get(IDBConnection::class);
175
+            }
176
+            \OC::$server->registerService(IDBConnection::class, function (): void {
177
+                $this->fail('Your test case is not allowed to access the database.');
178
+            });
179
+        }
180
+
181
+        $traits = $this->getTestTraits();
182
+        foreach ($traits as $trait) {
183
+            $methodName = 'setUp' . basename(str_replace('\\', '/', $trait));
184
+            if (method_exists($this, $methodName)) {
185
+                call_user_func([$this, $methodName]);
186
+            }
187
+        }
188
+    }
189
+
190
+    protected function tearDown(): void {
191
+        $this->restoreAllServices();
192
+
193
+        // restore database connection
194
+        if (!$this->IsDatabaseAccessAllowed()) {
195
+            \OC::$server->registerService(IDBConnection::class, function () {
196
+                return self::$realDatabase;
197
+            });
198
+        }
199
+
200
+        // further cleanup
201
+        $hookExceptions = \OC_Hook::$thrownExceptions;
202
+        \OC_Hook::$thrownExceptions = [];
203
+        Server::get(ILockingProvider::class)->releaseAll();
204
+        if (!empty($hookExceptions)) {
205
+            throw $hookExceptions[0];
206
+        }
207
+
208
+        // fail hard if xml errors have not been cleaned up
209
+        $errors = libxml_get_errors();
210
+        libxml_clear_errors();
211
+        if (!empty($errors)) {
212
+            self::assertEquals([], $errors, 'There have been xml parsing errors');
213
+        }
214
+
215
+        if ($this->IsDatabaseAccessAllowed()) {
216
+            Storage::getGlobalCache()->clearCache();
217
+        }
218
+
219
+        // tearDown the traits
220
+        $traits = $this->getTestTraits();
221
+        foreach ($traits as $trait) {
222
+            $methodName = 'tearDown' . basename(str_replace('\\', '/', $trait));
223
+            if (method_exists($this, $methodName)) {
224
+                call_user_func([$this, $methodName]);
225
+            }
226
+        }
227
+    }
228
+
229
+    /**
230
+     * Allows us to test private methods/properties
231
+     *
232
+     * @param $object
233
+     * @param $methodName
234
+     * @param array $parameters
235
+     * @return mixed
236
+     */
237
+    protected static function invokePrivate($object, $methodName, array $parameters = []) {
238
+        if (is_string($object)) {
239
+            $className = $object;
240
+        } else {
241
+            $className = get_class($object);
242
+        }
243
+        $reflection = new \ReflectionClass($className);
244
+
245
+        if ($reflection->hasMethod($methodName)) {
246
+            $method = $reflection->getMethod($methodName);
247
+
248
+            $method->setAccessible(true);
249
+
250
+            return $method->invokeArgs($object, $parameters);
251
+        } elseif ($reflection->hasProperty($methodName)) {
252
+            $property = $reflection->getProperty($methodName);
253
+
254
+            $property->setAccessible(true);
255
+
256
+            if (!empty($parameters)) {
257
+                if ($property->isStatic()) {
258
+                    $property->setValue(null, array_pop($parameters));
259
+                } else {
260
+                    $property->setValue($object, array_pop($parameters));
261
+                }
262
+            }
263
+
264
+            if (is_object($object)) {
265
+                return $property->getValue($object);
266
+            }
267
+
268
+            return $property->getValue();
269
+        } elseif ($reflection->hasConstant($methodName)) {
270
+            return $reflection->getConstant($methodName);
271
+        }
272
+
273
+        return false;
274
+    }
275
+
276
+    /**
277
+     * Returns a unique identifier as uniqid() is not reliable sometimes
278
+     *
279
+     * @param string $prefix
280
+     * @param int $length
281
+     * @return string
282
+     */
283
+    protected static function getUniqueID($prefix = '', $length = 13) {
284
+        return $prefix . Server::get(ISecureRandom::class)->generate(
285
+            $length,
286
+            // Do not use dots and slashes as we use the value for file names
287
+            ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
288
+        );
289
+    }
290
+
291
+    /**
292
+     * Filter methods
293
+     *
294
+     * Returns all methods of the given class,
295
+     * that are public or abstract and not in the ignoreMethods list,
296
+     * to be able to fill onlyMethods() with an inverted list.
297
+     *
298
+     * @param string $className
299
+     * @param string[] $filterMethods
300
+     * @return string[]
301
+     */
302
+    public function filterClassMethods(string $className, array $filterMethods): array {
303
+        $class = new \ReflectionClass($className);
304
+
305
+        $methods = [];
306
+        foreach ($class->getMethods() as $method) {
307
+            if (($method->isPublic() || $method->isAbstract()) && !in_array($method->getName(), $filterMethods, true)) {
308
+                $methods[] = $method->getName();
309
+            }
310
+        }
311
+
312
+        return $methods;
313
+    }
314
+
315
+    public static function tearDownAfterClass(): void {
316
+        if (!self::$wasDatabaseAllowed && self::$realDatabase !== null) {
317
+            // in case an error is thrown in a test, PHPUnit jumps straight to tearDownAfterClass,
318
+            // so we need the database again
319
+            \OC::$server->registerService(IDBConnection::class, function () {
320
+                return self::$realDatabase;
321
+            });
322
+        }
323
+        $dataDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data-autotest');
324
+        if (self::$wasDatabaseAllowed && Server::get(IDBConnection::class)) {
325
+            $db = Server::get(IDBConnection::class);
326
+            if ($db->inTransaction()) {
327
+                $db->rollBack();
328
+                throw new \Exception('There was a transaction still in progress and needed to be rolled back. Please fix this in your test.');
329
+            }
330
+            $queryBuilder = $db->getQueryBuilder();
331
+
332
+            self::tearDownAfterClassCleanShares($queryBuilder);
333
+            self::tearDownAfterClassCleanStorages($queryBuilder);
334
+            self::tearDownAfterClassCleanFileCache($queryBuilder);
335
+        }
336
+        self::tearDownAfterClassCleanStrayDataFiles($dataDir);
337
+        self::tearDownAfterClassCleanStrayHooks();
338
+        self::tearDownAfterClassCleanStrayLocks();
339
+
340
+        /** @var SetupManager $setupManager */
341
+        $setupManager = Server::get(SetupManager::class);
342
+        $setupManager->tearDown();
343
+
344
+        /** @var MountProviderCollection $mountProviderCollection */
345
+        $mountProviderCollection = Server::get(MountProviderCollection::class);
346
+        $mountProviderCollection->clearProviders();
347
+
348
+        /** @var IConfig $config */
349
+        $config = Server::get(IConfig::class);
350
+        $mountProviderCollection->registerProvider(new CacheMountProvider($config));
351
+        $mountProviderCollection->registerHomeProvider(new LocalHomeMountProvider());
352
+        $objectStoreConfig = Server::get(PrimaryObjectStoreConfig::class);
353
+        $mountProviderCollection->registerRootProvider(new RootMountProvider($objectStoreConfig, $config));
354
+
355
+        $setupManager->setupRoot();
356
+
357
+        parent::tearDownAfterClass();
358
+    }
359
+
360
+    /**
361
+     * Remove all entries from the share table
362
+     *
363
+     * @param IQueryBuilder $queryBuilder
364
+     */
365
+    protected static function tearDownAfterClassCleanShares(IQueryBuilder $queryBuilder) {
366
+        $queryBuilder->delete('share')
367
+            ->executeStatement();
368
+    }
369
+
370
+    /**
371
+     * Remove all entries from the storages table
372
+     *
373
+     * @param IQueryBuilder $queryBuilder
374
+     */
375
+    protected static function tearDownAfterClassCleanStorages(IQueryBuilder $queryBuilder) {
376
+        $queryBuilder->delete('storages')
377
+            ->executeStatement();
378
+    }
379
+
380
+    /**
381
+     * Remove all entries from the filecache table
382
+     *
383
+     * @param IQueryBuilder $queryBuilder
384
+     */
385
+    protected static function tearDownAfterClassCleanFileCache(IQueryBuilder $queryBuilder) {
386
+        $queryBuilder->delete('filecache')
387
+            ->runAcrossAllShards()
388
+            ->executeStatement();
389
+    }
390
+
391
+    /**
392
+     * Remove all unused files from the data dir
393
+     *
394
+     * @param string $dataDir
395
+     */
396
+    protected static function tearDownAfterClassCleanStrayDataFiles($dataDir) {
397
+        $knownEntries = [
398
+            'nextcloud.log' => true,
399
+            'audit.log' => true,
400
+            'owncloud.db' => true,
401
+            '.ocdata' => true,
402
+            '..' => true,
403
+            '.' => true,
404
+        ];
405
+
406
+        if ($dh = opendir($dataDir)) {
407
+            while (($file = readdir($dh)) !== false) {
408
+                if (!isset($knownEntries[$file])) {
409
+                    self::tearDownAfterClassCleanStrayDataUnlinkDir($dataDir . '/' . $file);
410
+                }
411
+            }
412
+            closedir($dh);
413
+        }
414
+    }
415
+
416
+    /**
417
+     * Recursive delete files and folders from a given directory
418
+     *
419
+     * @param string $dir
420
+     */
421
+    protected static function tearDownAfterClassCleanStrayDataUnlinkDir($dir) {
422
+        if ($dh = @opendir($dir)) {
423
+            while (($file = readdir($dh)) !== false) {
424
+                if (Filesystem::isIgnoredDir($file)) {
425
+                    continue;
426
+                }
427
+                $path = $dir . '/' . $file;
428
+                if (is_dir($path)) {
429
+                    self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
430
+                } else {
431
+                    @unlink($path);
432
+                }
433
+            }
434
+            closedir($dh);
435
+        }
436
+        @rmdir($dir);
437
+    }
438
+
439
+    /**
440
+     * Clean up the list of hooks
441
+     */
442
+    protected static function tearDownAfterClassCleanStrayHooks() {
443
+        \OC_Hook::clear();
444
+    }
445
+
446
+    /**
447
+     * Clean up the list of locks
448
+     */
449
+    protected static function tearDownAfterClassCleanStrayLocks() {
450
+        Server::get(ILockingProvider::class)->releaseAll();
451
+    }
452
+
453
+    /**
454
+     * Login and setup FS as a given user,
455
+     * sets the given user as the current user.
456
+     *
457
+     * @param string $user user id or empty for a generic FS
458
+     */
459
+    protected static function loginAsUser($user = '') {
460
+        self::logout();
461
+        Filesystem::tearDown();
462
+        \OC_User::setUserId($user);
463
+        $userObject = Server::get(IUserManager::class)->get($user);
464
+        if (!is_null($userObject)) {
465
+            $userObject->updateLastLoginTimestamp();
466
+        }
467
+        \OC_Util::setupFS($user);
468
+        if (Server::get(IUserManager::class)->userExists($user)) {
469
+            \OC::$server->getUserFolder($user);
470
+        }
471
+    }
472
+
473
+    /**
474
+     * Logout the current user and tear down the filesystem.
475
+     */
476
+    protected static function logout() {
477
+        \OC_Util::tearDownFS();
478
+        \OC_User::setUserId('');
479
+        // needed for fully logout
480
+        Server::get(IUserSession::class)->setUser(null);
481
+    }
482
+
483
+    /**
484
+     * Run all commands pushed to the bus
485
+     */
486
+    protected function runCommands() {
487
+        // get the user for which the fs is setup
488
+        $view = Filesystem::getView();
489
+        if ($view) {
490
+            [, $user] = explode('/', $view->getRoot());
491
+        } else {
492
+            $user = null;
493
+        }
494
+
495
+        \OC_Util::tearDownFS(); // command can't reply on the fs being setup
496
+        $this->commandBus->run();
497
+        \OC_Util::tearDownFS();
498
+
499
+        if ($user) {
500
+            \OC_Util::setupFS($user);
501
+        }
502
+    }
503
+
504
+    /**
505
+     * Check if the given path is locked with a given type
506
+     *
507
+     * @param View $view view
508
+     * @param string $path path to check
509
+     * @param int $type lock type
510
+     * @param bool $onMountPoint true to check the mount point instead of the
511
+     *                           mounted storage
512
+     *
513
+     * @return boolean true if the file is locked with the
514
+     *                 given type, false otherwise
515
+     */
516
+    protected function isFileLocked($view, $path, $type, $onMountPoint = false) {
517
+        // Note: this seems convoluted but is necessary because
518
+        // the format of the lock key depends on the storage implementation
519
+        // (in our case mostly md5)
520
+
521
+        if ($type === ILockingProvider::LOCK_SHARED) {
522
+            // to check if the file has a shared lock, try acquiring an exclusive lock
523
+            $checkType = ILockingProvider::LOCK_EXCLUSIVE;
524
+        } else {
525
+            // a shared lock cannot be set if exclusive lock is in place
526
+            $checkType = ILockingProvider::LOCK_SHARED;
527
+        }
528
+        try {
529
+            $view->lockFile($path, $checkType, $onMountPoint);
530
+            // no exception, which means the lock of $type is not set
531
+            // clean up
532
+            $view->unlockFile($path, $checkType, $onMountPoint);
533
+            return false;
534
+        } catch (LockedException $e) {
535
+            // we could not acquire the counter-lock, which means
536
+            // the lock of $type was in place
537
+            return true;
538
+        }
539
+    }
540
+
541
+    protected function getGroupAnnotations(): array {
542
+        if (method_exists($this, 'getAnnotations')) {
543
+            $annotations = $this->getAnnotations();
544
+            return $annotations['class']['group'] ?? [];
545
+        }
546
+
547
+        $r = new \ReflectionClass($this);
548
+        $doc = $r->getDocComment();
549
+
550
+        if (class_exists(Group::class)) {
551
+            $attributes = array_map(function (\ReflectionAttribute $attribute) {
552
+                /** @var Group $group */
553
+                $group = $attribute->newInstance();
554
+                return $group->name();
555
+            }, $r->getAttributes(Group::class));
556
+            if (count($attributes) > 0) {
557
+                return $attributes;
558
+            }
559
+        }
560
+        preg_match_all('#@group\s+(.*?)\n#s', $doc, $annotations);
561
+        return $annotations[1] ?? [];
562
+    }
563
+
564
+    protected function IsDatabaseAccessAllowed(): bool {
565
+        $annotations = $this->getGroupAnnotations();
566
+        if (isset($annotations)) {
567
+            if (in_array('DB', $annotations) || in_array('SLOWDB', $annotations)) {
568
+                return true;
569
+            }
570
+        }
571
+
572
+        return false;
573
+    }
574
+
575
+    /**
576
+     * @param string $expectedHtml
577
+     * @param string $template
578
+     * @param array $vars
579
+     */
580
+    protected function assertTemplate($expectedHtml, $template, $vars = []) {
581
+        $requestToken = 12345;
582
+        /** @var Defaults|\PHPUnit\Framework\MockObject\MockObject $l10n */
583
+        $theme = $this->getMockBuilder('\OCP\Defaults')
584
+            ->disableOriginalConstructor()->getMock();
585
+        $theme->expects($this->any())
586
+            ->method('getName')
587
+            ->willReturn('Nextcloud');
588
+        /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject $l10n */
589
+        $l10n = $this->getMockBuilder(IL10N::class)
590
+            ->disableOriginalConstructor()->getMock();
591
+        $l10n
592
+            ->expects($this->any())
593
+            ->method('t')
594
+            ->willReturnCallback(function ($text, $parameters = []) {
595
+                return vsprintf($text, $parameters);
596
+            });
597
+
598
+        $t = new Base($template, $requestToken, $l10n, $theme);
599
+        $buf = $t->fetchPage($vars);
600
+        $this->assertHtmlStringEqualsHtmlString($expectedHtml, $buf);
601
+    }
602
+
603
+    /**
604
+     * @param string $expectedHtml
605
+     * @param string $actualHtml
606
+     * @param string $message
607
+     */
608
+    protected function assertHtmlStringEqualsHtmlString($expectedHtml, $actualHtml, $message = '') {
609
+        $expected = new DOMDocument();
610
+        $expected->preserveWhiteSpace = false;
611
+        $expected->formatOutput = true;
612
+        $expected->loadHTML($expectedHtml);
613
+
614
+        $actual = new DOMDocument();
615
+        $actual->preserveWhiteSpace = false;
616
+        $actual->formatOutput = true;
617
+        $actual->loadHTML($actualHtml);
618
+        $this->removeWhitespaces($actual);
619
+
620
+        $expectedHtml1 = $expected->saveHTML();
621
+        $actualHtml1 = $actual->saveHTML();
622
+        self::assertEquals($expectedHtml1, $actualHtml1, $message);
623
+    }
624
+
625
+
626
+    private function removeWhitespaces(DOMNode $domNode) {
627
+        foreach ($domNode->childNodes as $node) {
628
+            if ($node->hasChildNodes()) {
629
+                $this->removeWhitespaces($node);
630
+            } else {
631
+                if ($node instanceof \DOMText && $node->isWhitespaceInElementContent()) {
632
+                    $domNode->removeChild($node);
633
+                }
634
+            }
635
+        }
636
+    }
637 637
 }
Please login to merge, or discard this patch.
Spacing   +17 added lines, -17 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
 
44 44
 			// restore database connection
45 45
 			if (!$this->IsDatabaseAccessAllowed()) {
46
-				\OC::$server->registerService(IDBConnection::class, function () {
46
+				\OC::$server->registerService(IDBConnection::class, function() {
47 47
 					return self::$realDatabase;
48 48
 				});
49 49
 			}
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
 
59 59
 			// restore database connection
60 60
 			if (!$this->IsDatabaseAccessAllowed()) {
61
-				\OC::$server->registerService(IDBConnection::class, function () {
61
+				\OC::$server->registerService(IDBConnection::class, function() {
62 62
 					return self::$realDatabase;
63 63
 				});
64 64
 			}
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		$container = \OC::$server->getAppContainerForService($name);
102 102
 		$container = $container ?? \OC::$server;
103 103
 
104
-		$container->registerService($name, function () use ($newService) {
104
+		$container->registerService($name, function() use ($newService) {
105 105
 			return $newService;
106 106
 		});
107 107
 
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
 			$container = $container ?? \OC::$server;
121 121
 
122 122
 			if ($oldService !== false) {
123
-				$container->registerService($name, function () use ($oldService) {
123
+				$container->registerService($name, function() use ($oldService) {
124 124
 					return $oldService;
125 125
 				});
126 126
 			} else {
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 			$traits = array_merge(class_uses($trait), $traits);
156 156
 		}
157 157
 		$traits = array_unique($traits);
158
-		return array_filter($traits, function ($trait) {
158
+		return array_filter($traits, function($trait) {
159 159
 			return substr($trait, 0, 5) === 'Test\\';
160 160
 		});
161 161
 	}
@@ -173,14 +173,14 @@  discard block
 block discarded – undo
173 173
 			if (is_null(self::$realDatabase)) {
174 174
 				self::$realDatabase = Server::get(IDBConnection::class);
175 175
 			}
176
-			\OC::$server->registerService(IDBConnection::class, function (): void {
176
+			\OC::$server->registerService(IDBConnection::class, function(): void {
177 177
 				$this->fail('Your test case is not allowed to access the database.');
178 178
 			});
179 179
 		}
180 180
 
181 181
 		$traits = $this->getTestTraits();
182 182
 		foreach ($traits as $trait) {
183
-			$methodName = 'setUp' . basename(str_replace('\\', '/', $trait));
183
+			$methodName = 'setUp'.basename(str_replace('\\', '/', $trait));
184 184
 			if (method_exists($this, $methodName)) {
185 185
 				call_user_func([$this, $methodName]);
186 186
 			}
@@ -192,7 +192,7 @@  discard block
 block discarded – undo
192 192
 
193 193
 		// restore database connection
194 194
 		if (!$this->IsDatabaseAccessAllowed()) {
195
-			\OC::$server->registerService(IDBConnection::class, function () {
195
+			\OC::$server->registerService(IDBConnection::class, function() {
196 196
 				return self::$realDatabase;
197 197
 			});
198 198
 		}
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
 		// tearDown the traits
220 220
 		$traits = $this->getTestTraits();
221 221
 		foreach ($traits as $trait) {
222
-			$methodName = 'tearDown' . basename(str_replace('\\', '/', $trait));
222
+			$methodName = 'tearDown'.basename(str_replace('\\', '/', $trait));
223 223
 			if (method_exists($this, $methodName)) {
224 224
 				call_user_func([$this, $methodName]);
225 225
 			}
@@ -281,10 +281,10 @@  discard block
 block discarded – undo
281 281
 	 * @return string
282 282
 	 */
283 283
 	protected static function getUniqueID($prefix = '', $length = 13) {
284
-		return $prefix . Server::get(ISecureRandom::class)->generate(
284
+		return $prefix.Server::get(ISecureRandom::class)->generate(
285 285
 			$length,
286 286
 			// Do not use dots and slashes as we use the value for file names
287
-			ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER
287
+			ISecureRandom::CHAR_DIGITS.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER
288 288
 		);
289 289
 	}
290 290
 
@@ -316,11 +316,11 @@  discard block
 block discarded – undo
316 316
 		if (!self::$wasDatabaseAllowed && self::$realDatabase !== null) {
317 317
 			// in case an error is thrown in a test, PHPUnit jumps straight to tearDownAfterClass,
318 318
 			// so we need the database again
319
-			\OC::$server->registerService(IDBConnection::class, function () {
319
+			\OC::$server->registerService(IDBConnection::class, function() {
320 320
 				return self::$realDatabase;
321 321
 			});
322 322
 		}
323
-		$dataDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data-autotest');
323
+		$dataDir = Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT.'/data-autotest');
324 324
 		if (self::$wasDatabaseAllowed && Server::get(IDBConnection::class)) {
325 325
 			$db = Server::get(IDBConnection::class);
326 326
 			if ($db->inTransaction()) {
@@ -406,7 +406,7 @@  discard block
 block discarded – undo
406 406
 		if ($dh = opendir($dataDir)) {
407 407
 			while (($file = readdir($dh)) !== false) {
408 408
 				if (!isset($knownEntries[$file])) {
409
-					self::tearDownAfterClassCleanStrayDataUnlinkDir($dataDir . '/' . $file);
409
+					self::tearDownAfterClassCleanStrayDataUnlinkDir($dataDir.'/'.$file);
410 410
 				}
411 411
 			}
412 412
 			closedir($dh);
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
 				if (Filesystem::isIgnoredDir($file)) {
425 425
 					continue;
426 426
 				}
427
-				$path = $dir . '/' . $file;
427
+				$path = $dir.'/'.$file;
428 428
 				if (is_dir($path)) {
429 429
 					self::tearDownAfterClassCleanStrayDataUnlinkDir($path);
430 430
 				} else {
@@ -548,7 +548,7 @@  discard block
 block discarded – undo
548 548
 		$doc = $r->getDocComment();
549 549
 
550 550
 		if (class_exists(Group::class)) {
551
-			$attributes = array_map(function (\ReflectionAttribute $attribute) {
551
+			$attributes = array_map(function(\ReflectionAttribute $attribute) {
552 552
 				/** @var Group $group */
553 553
 				$group = $attribute->newInstance();
554 554
 				return $group->name();
@@ -591,7 +591,7 @@  discard block
 block discarded – undo
591 591
 		$l10n
592 592
 			->expects($this->any())
593 593
 			->method('t')
594
-			->willReturnCallback(function ($text, $parameters = []) {
594
+			->willReturnCallback(function($text, $parameters = []) {
595 595
 				return vsprintf($text, $parameters);
596 596
 			});
597 597
 
Please login to merge, or discard this patch.