Completed
Push — master ( 36f793...6cdf09 )
by
unknown
42:22 queued 15:32
created
tests/lib/Files/Storage/Wrapper/EncryptionTest.php 1 patch
Indentation   +989 added lines, -989 removed lines patch added patch discarded remove patch
@@ -35,993 +35,993 @@
 block discarded – undo
35 35
 use Test\Files\Storage\Storage;
36 36
 
37 37
 class EncryptionTest extends Storage {
38
-	/**
39
-	 * block size will always be 8192 for a PHP stream
40
-	 * @see https://bugs.php.net/bug.php?id=21641
41
-	 */
42
-	protected int $headerSize = 8192;
43
-	private Temporary $sourceStorage;
44
-	/** @var Encryption&MockObject */
45
-	protected $instance;
46
-	private \OC\Encryption\Keys\Storage&MockObject $keyStore;
47
-	private Util&MockObject $util;
48
-	private \OC\Encryption\Manager&MockObject $encryptionManager;
49
-	private IEncryptionModule&MockObject $encryptionModule;
50
-	private Cache&MockObject $cache;
51
-	private LoggerInterface&MockObject $logger;
52
-	private File&MockObject $file;
53
-	private MountPoint&MockObject $mount;
54
-	private \OC\Files\Mount\Manager&MockObject $mountManager;
55
-	private \OC\Group\Manager&MockObject $groupManager;
56
-	private IConfig&MockObject $config;
57
-	private ArrayCache&MockObject $arrayCache;
58
-	/** dummy unencrypted size */
59
-	private int $dummySize = -1;
60
-
61
-	protected function setUp(): void {
62
-		parent::setUp();
63
-
64
-		$mockModule = $this->buildMockModule();
65
-		$this->encryptionManager = $this->getMockBuilder(\OC\Encryption\Manager::class)
66
-			->disableOriginalConstructor()
67
-			->onlyMethods(['getEncryptionModule', 'isEnabled'])
68
-			->getMock();
69
-		$this->encryptionManager->expects($this->any())
70
-			->method('getEncryptionModule')
71
-			->willReturn($mockModule);
72
-
73
-		$this->arrayCache = $this->createMock(ArrayCache::class);
74
-		$this->config = $this->getMockBuilder(IConfig::class)
75
-			->disableOriginalConstructor()
76
-			->getMock();
77
-		$this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
78
-			->disableOriginalConstructor()
79
-			->getMock();
80
-
81
-		$this->util = $this->getMockBuilder(Util::class)
82
-			->onlyMethods(['getUidAndFilename', 'isFile', 'isExcluded', 'stripPartialFileExtension'])
83
-			->setConstructorArgs([new View(), new Manager(
84
-				$this->config,
85
-				$this->createMock(ICacheFactory::class),
86
-				$this->createMock(IEventDispatcher::class),
87
-				$this->createMock(LoggerInterface::class),
88
-			), $this->groupManager, $this->config, $this->arrayCache])
89
-			->getMock();
90
-		$this->util->expects($this->any())
91
-			->method('getUidAndFilename')
92
-			->willReturnCallback(function ($path) {
93
-				return ['user1', $path];
94
-			});
95
-		$this->util->expects($this->any())
96
-			->method('stripPartialFileExtension')
97
-			->willReturnCallback(function ($path) {
98
-				return $path;
99
-			});
100
-
101
-		$this->file = $this->getMockBuilder(File::class)
102
-			->disableOriginalConstructor()
103
-			->onlyMethods(['getAccessList'])
104
-			->getMock();
105
-		$this->file->expects($this->any())->method('getAccessList')->willReturn([]);
106
-
107
-		$this->logger = $this->createMock(LoggerInterface::class);
108
-
109
-		$this->sourceStorage = new Temporary([]);
110
-
111
-		$this->keyStore = $this->createMock(\OC\Encryption\Keys\Storage::class);
112
-
113
-		$this->mount = $this->getMockBuilder(MountPoint::class)
114
-			->disableOriginalConstructor()
115
-			->onlyMethods(['getOption'])
116
-			->getMock();
117
-		$this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) {
118
-			if ($option === 'encrypt' && $default === true) {
119
-				global $mockedMountPointEncryptionEnabled;
120
-				if ($mockedMountPointEncryptionEnabled !== null) {
121
-					return $mockedMountPointEncryptionEnabled;
122
-				}
123
-			}
124
-			return true;
125
-		});
126
-
127
-		$this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
128
-			->disableOriginalConstructor()->getMock();
129
-		$this->cache->expects($this->any())
130
-			->method('get')
131
-			->willReturnCallback(function ($path) {
132
-				return ['encrypted' => false, 'path' => $path];
133
-			});
134
-
135
-		$this->mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
136
-		$this->mountManager->method('findByStorageId')
137
-			->willReturn([]);
138
-
139
-		$this->instance = $this->getMockBuilder(Encryption::class)
140
-			->setConstructorArgs(
141
-				[
142
-					[
143
-						'storage' => $this->sourceStorage,
144
-						'root' => 'foo',
145
-						'mountPoint' => '/',
146
-						'mount' => $this->mount
147
-					],
148
-					$this->encryptionManager,
149
-					$this->util,
150
-					$this->logger,
151
-					$this->file,
152
-					null,
153
-					$this->keyStore,
154
-					$this->mountManager,
155
-					$this->arrayCache
156
-				]
157
-			)
158
-			->onlyMethods(['getMetaData', 'getCache', 'getEncryptionModule'])
159
-			->getMock();
160
-
161
-		$this->instance->expects($this->any())
162
-			->method('getMetaData')
163
-			->willReturnCallback(function ($path) {
164
-				return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path];
165
-			});
166
-
167
-		$this->instance->expects($this->any())
168
-			->method('getCache')
169
-			->willReturn($this->cache);
170
-
171
-		$this->instance->expects($this->any())
172
-			->method('getEncryptionModule')
173
-			->willReturn($mockModule);
174
-	}
175
-
176
-	protected function buildMockModule(): IEncryptionModule&MockObject {
177
-		$this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
178
-			->disableOriginalConstructor()
179
-			->onlyMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList'])
180
-			->getMock();
181
-
182
-		$this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
183
-		$this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module');
184
-		$this->encryptionModule->expects($this->any())->method('begin')->willReturn([]);
185
-		$this->encryptionModule->expects($this->any())->method('end')->willReturn('');
186
-		$this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0);
187
-		$this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0);
188
-		$this->encryptionModule->expects($this->any())->method('update')->willReturn(true);
189
-		$this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true);
190
-		$this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192);
191
-		$this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
192
-		$this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false);
193
-		return $this->encryptionModule;
194
-	}
195
-
196
-	/**
197
-	 *
198
-	 * @param string $path
199
-	 * @param array $metaData
200
-	 * @param bool $encrypted
201
-	 * @param bool $unencryptedSizeSet
202
-	 * @param int $storedUnencryptedSize
203
-	 * @param array $expected
204
-	 */
205
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetMetaData')]
206
-	public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected): void {
207
-		$sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
208
-			->disableOriginalConstructor()->getMock();
209
-
210
-		$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
211
-			->disableOriginalConstructor()->getMock();
212
-		$cache->expects($this->any())
213
-			->method('get')
214
-			->willReturnCallback(
215
-				function ($path) use ($encrypted) {
216
-					return new CacheEntry(['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1]);
217
-				}
218
-			);
219
-
220
-		$this->instance = $this->getMockBuilder(Encryption::class)
221
-			->setConstructorArgs(
222
-				[
223
-					[
224
-						'storage' => $sourceStorage,
225
-						'root' => 'foo',
226
-						'mountPoint' => '/',
227
-						'mount' => $this->mount
228
-					],
229
-					$this->encryptionManager,
230
-					$this->util,
231
-					$this->logger,
232
-					$this->file,
233
-					null,
234
-					$this->keyStore,
235
-					$this->mountManager,
236
-					$this->arrayCache,
237
-				]
238
-			)
239
-			->onlyMethods(['getCache', 'verifyUnencryptedSize'])
240
-			->getMock();
241
-
242
-		if ($unencryptedSizeSet) {
243
-			$this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]);
244
-		}
245
-
246
-		$fileEntry = $this->getMockBuilder('\OC\Files\Cache\Cache')
247
-			->disableOriginalConstructor()->getMock();
248
-		$sourceStorage->expects($this->once())->method('getMetaData')->with($path)
249
-			->willReturn($metaData);
250
-		$sourceStorage->expects($this->any())
251
-			->method('getCache')
252
-			->with($path)
253
-			->willReturn($fileEntry);
254
-		if ($metaData !== null) {
255
-			$fileEntry->expects($this->any())
256
-				->method('get')
257
-				->with($metaData['fileid']);
258
-		}
259
-
260
-		$this->instance->expects($this->any())->method('getCache')->willReturn($cache);
261
-		if ($expected !== null) {
262
-			$this->instance->expects($this->any())->method('verifyUnencryptedSize')
263
-				->with($path, 0)->willReturn($expected['size']);
264
-		}
265
-
266
-		$result = $this->instance->getMetaData($path);
267
-		if (isset($expected['encrypted'])) {
268
-			$this->assertSame($expected['encrypted'], (bool)$result['encrypted']);
269
-
270
-			if (isset($expected['encryptedVersion'])) {
271
-				$this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']);
272
-			}
273
-		}
274
-
275
-		if ($expected !== null) {
276
-			$this->assertSame($expected['size'], $result['size']);
277
-		} else {
278
-			$this->assertSame(null, $result);
279
-		}
280
-	}
281
-
282
-	public static function dataTestGetMetaData(): array {
283
-		return [
284
-			['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]],
285
-			['/test.txt', null, true, true, 12, null],
286
-			['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]],
287
-			['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]]
288
-		];
289
-	}
290
-
291
-	public function testFilesize(): void {
292
-		$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
293
-			->disableOriginalConstructor()->getMock();
294
-		$cache->expects($this->any())
295
-			->method('get')
296
-			->willReturn(new CacheEntry(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1]));
297
-
298
-		$this->instance = $this->getMockBuilder(Encryption::class)
299
-			->setConstructorArgs(
300
-				[
301
-					[
302
-						'storage' => $this->sourceStorage,
303
-						'root' => 'foo',
304
-						'mountPoint' => '/',
305
-						'mount' => $this->mount
306
-					],
307
-					$this->encryptionManager,
308
-					$this->util,
309
-					$this->logger,
310
-					$this->file,
311
-					null,
312
-					$this->keyStore,
313
-					$this->mountManager,
314
-					$this->arrayCache,
315
-				]
316
-			)
317
-			->onlyMethods(['getCache', 'verifyUnencryptedSize'])
318
-			->getMock();
319
-
320
-		$this->instance->expects($this->any())->method('getCache')->willReturn($cache);
321
-		$this->instance->expects($this->any())->method('verifyUnencryptedSize')
322
-			->willReturn(42);
323
-
324
-
325
-		$this->assertSame(42,
326
-			$this->instance->filesize('/test.txt')
327
-		);
328
-	}
329
-
330
-	/**
331
-	 *
332
-	 * @param int $encryptedSize
333
-	 * @param int $unencryptedSize
334
-	 * @param bool $failure
335
-	 * @param int $expected
336
-	 */
337
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestVerifyUnencryptedSize')]
338
-	public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected): void {
339
-		$sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
340
-			->disableOriginalConstructor()->getMock();
341
-
342
-		$this->instance = $this->getMockBuilder(Encryption::class)
343
-			->setConstructorArgs(
344
-				[
345
-					[
346
-						'storage' => $sourceStorage,
347
-						'root' => 'foo',
348
-						'mountPoint' => '/',
349
-						'mount' => $this->mount
350
-					],
351
-					$this->encryptionManager,
352
-					$this->util,
353
-					$this->logger,
354
-					$this->file,
355
-					null,
356
-					$this->keyStore,
357
-					$this->mountManager,
358
-					$this->arrayCache,
359
-				]
360
-			)
361
-			->onlyMethods(['fixUnencryptedSize'])
362
-			->getMock();
363
-
364
-		$sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize);
365
-
366
-		$this->instance->expects($this->any())->method('fixUnencryptedSize')
367
-			->with('/test.txt', $encryptedSize, $unencryptedSize)
368
-			->willReturnCallback(
369
-				function () use ($failure, $expected) {
370
-					if ($failure) {
371
-						throw new Exception();
372
-					} else {
373
-						return $expected;
374
-					}
375
-				}
376
-			);
377
-
378
-		$this->assertSame(
379
-			$expected,
380
-			$this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize])
381
-		);
382
-	}
383
-
384
-	public static function dataTestVerifyUnencryptedSize(): array {
385
-		return [
386
-			[120, 80, false, 80],
387
-			[120, 120, false, 80],
388
-			[120, -1, false, 80],
389
-			[120, -1, true, -1]
390
-		];
391
-	}
392
-
393
-	/**
394
-	 *
395
-	 * @param string $source
396
-	 * @param string $target
397
-	 * @param $encryptionEnabled
398
-	 * @param boolean $renameKeysReturn
399
-	 */
400
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyAndRename')]
401
-	public function testRename($source,
402
-		$target,
403
-		$encryptionEnabled,
404
-		$renameKeysReturn): void {
405
-		if ($encryptionEnabled) {
406
-			$this->keyStore
407
-				->expects($this->once())
408
-				->method('renameKeys')
409
-				->willReturn($renameKeysReturn);
410
-		} else {
411
-			$this->keyStore
412
-				->expects($this->never())->method('renameKeys');
413
-		}
414
-		$this->util->expects($this->any())
415
-			->method('isFile')->willReturn(true);
416
-		$this->encryptionManager->expects($this->once())
417
-			->method('isEnabled')->willReturn($encryptionEnabled);
418
-
419
-		$this->instance->mkdir($source);
420
-		$this->instance->mkdir(dirname($target));
421
-		$this->instance->rename($source, $target);
422
-	}
423
-
424
-	public function testCopyEncryption(): void {
425
-		$this->instance->file_put_contents('source.txt', 'bar');
426
-		$this->instance->copy('source.txt', 'target.txt');
427
-		$this->assertSame('bar', $this->instance->file_get_contents('target.txt'));
428
-		$targetMeta = $this->instance->getMetaData('target.txt');
429
-		$sourceMeta = $this->instance->getMetaData('source.txt');
430
-		$this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']);
431
-		$this->assertSame($sourceMeta['size'], $targetMeta['size']);
432
-	}
433
-
434
-	/**
435
-	 * data provider for testCopyTesting() and dataTestCopyAndRename()
436
-	 *
437
-	 * @return array
438
-	 */
439
-	public static function dataTestCopyAndRename(): array {
440
-		return [
441
-			['source', 'target', true, false, false],
442
-			['source', 'target', true, true, false],
443
-			['source', '/subFolder/target', true, false, false],
444
-			['source', '/subFolder/target', true, true, true],
445
-			['source', '/subFolder/target', false, true, false],
446
-		];
447
-	}
448
-
449
-	public function testIsLocal(): void {
450
-		$this->encryptionManager->expects($this->once())
451
-			->method('isEnabled')->willReturn(true);
452
-		$this->assertFalse($this->instance->isLocal());
453
-	}
454
-
455
-	/**
456
-	 *
457
-	 * @param string $path
458
-	 * @param boolean $rmdirResult
459
-	 * @param boolean $isExcluded
460
-	 * @param boolean $encryptionEnabled
461
-	 */
462
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestRmdir')]
463
-	public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled): void {
464
-		$sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
465
-			->disableOriginalConstructor()->getMock();
466
-
467
-		$util = $this->getMockBuilder('\OC\Encryption\Util')->disableOriginalConstructor()->getMock();
468
-
469
-		$sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult);
470
-		$util->expects($this->any())->method('isExcluded')->willReturn($isExcluded);
471
-		$this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled);
472
-
473
-		$encryptionStorage = new Encryption(
474
-			[
475
-				'storage' => $sourceStorage,
476
-				'root' => 'foo',
477
-				'mountPoint' => '/mountPoint',
478
-				'mount' => $this->mount
479
-			],
480
-			$this->encryptionManager,
481
-			$util,
482
-			$this->logger,
483
-			$this->file,
484
-			null,
485
-			$this->keyStore,
486
-			$this->mountManager,
487
-			$this->arrayCache,
488
-		);
489
-
490
-
491
-		if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) {
492
-			$this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path);
493
-		} else {
494
-			$this->keyStore->expects($this->never())->method('deleteAllFileKeys');
495
-		}
496
-
497
-		$encryptionStorage->rmdir($path);
498
-	}
499
-
500
-	public static function dataTestRmdir(): array {
501
-		return [
502
-			['/file.txt', true, true, true],
503
-			['/file.txt', false, true, true],
504
-			['/file.txt', true, false, true],
505
-			['/file.txt', false, false, true],
506
-			['/file.txt', true, true, false],
507
-			['/file.txt', false, true, false],
508
-			['/file.txt', true, false, false],
509
-			['/file.txt', false, false, false],
510
-		];
511
-	}
512
-
513
-	/**
514
-	 *
515
-	 * @param boolean $excluded
516
-	 * @param boolean $expected
517
-	 */
518
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyKeys')]
519
-	public function testCopyKeys($excluded, $expected): void {
520
-		$this->util->expects($this->once())
521
-			->method('isExcluded')
522
-			->willReturn($excluded);
523
-
524
-		if ($excluded) {
525
-			$this->keyStore->expects($this->never())->method('copyKeys');
526
-		} else {
527
-			$this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true);
528
-		}
529
-
530
-		$this->assertSame($expected,
531
-			self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target'])
532
-		);
533
-	}
534
-
535
-	public static function dataTestCopyKeys(): array {
536
-		return [
537
-			[true, false],
538
-			[false, true],
539
-		];
540
-	}
541
-
542
-	/**
543
-	 *
544
-	 * @param string $path
545
-	 * @param bool $strippedPathExists
546
-	 * @param string $strippedPath
547
-	 */
548
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetHeader')]
549
-	public function testGetHeader($path, $strippedPathExists, $strippedPath): void {
550
-		$sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
551
-			->disableOriginalConstructor()->getMock();
552
-
553
-		$util = $this->getMockBuilder('\OC\Encryption\Util')
554
-			->setConstructorArgs(
555
-				[
556
-					new View(),
557
-					new Manager(
558
-						$this->config,
559
-						$this->createMock(ICacheFactory::class),
560
-						$this->createMock(IEventDispatcher::class),
561
-						$this->createMock(LoggerInterface::class),
562
-					),
563
-					$this->groupManager,
564
-					$this->config,
565
-					$this->arrayCache
566
-				]
567
-			)->getMock();
568
-
569
-		$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
570
-			->disableOriginalConstructor()->getMock();
571
-		$cache->expects($this->any())
572
-			->method('get')
573
-			->willReturnCallback(function ($path) {
574
-				return ['encrypted' => true, 'path' => $path];
575
-			});
576
-
577
-		$instance = $this->getMockBuilder(Encryption::class)
578
-			->setConstructorArgs(
579
-				[
580
-					[
581
-						'storage' => $sourceStorage,
582
-						'root' => 'foo',
583
-						'mountPoint' => '/',
584
-						'mount' => $this->mount
585
-					],
586
-					$this->encryptionManager,
587
-					$util,
588
-					$this->logger,
589
-					$this->file,
590
-					null,
591
-					$this->keyStore,
592
-					$this->mountManager,
593
-					$this->arrayCache,
594
-				]
595
-			)
596
-			->onlyMethods(['getCache', 'readFirstBlock'])
597
-			->getMock();
598
-
599
-		$instance->method('getCache')->willReturn($cache);
600
-
601
-		$util->method('parseRawHeader')
602
-			->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']);
603
-
604
-		if ($strippedPathExists) {
605
-			$instance->method('readFirstBlock')
606
-				->with($strippedPath)->willReturn('');
607
-		} else {
608
-			$instance->method('readFirstBlock')
609
-				->with($path)->willReturn('');
610
-		}
611
-
612
-		$util->expects($this->once())->method('stripPartialFileExtension')
613
-			->with($path)->willReturn($strippedPath);
614
-		$sourceStorage->expects($this->once())
615
-			->method('is_file')
616
-			->with($strippedPath)
617
-			->willReturn($strippedPathExists);
618
-
619
-		$this->invokePrivate($instance, 'getHeader', [$path]);
620
-	}
621
-
622
-	public static function dataTestGetHeader(): array {
623
-		return [
624
-			['/foo/bar.txt', false, '/foo/bar.txt'],
625
-			['/foo/bar.txt.part', false, '/foo/bar.txt'],
626
-			['/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'],
627
-			['/foo/bar.txt.part', true, '/foo/bar.txt'],
628
-			['/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'],
629
-		];
630
-	}
631
-
632
-	/**
633
-	 * test if getHeader adds the default module correctly to the header for
634
-	 * legacy files
635
-	 */
636
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetHeaderAddLegacyModule')]
637
-	public function testGetHeaderAddLegacyModule($header, $isEncrypted, $strippedPathExists, $expected): void {
638
-		$sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class)
639
-			->disableOriginalConstructor()->getMock();
640
-
641
-		$sourceStorage->expects($this->once())
642
-			->method('is_file')
643
-			->with('test.txt')
644
-			->willReturn($strippedPathExists);
645
-
646
-		$util = $this->getMockBuilder(Util::class)
647
-			->onlyMethods(['stripPartialFileExtension', 'parseRawHeader'])
648
-			->setConstructorArgs([new View(), new Manager(
649
-				$this->config,
650
-				$this->createMock(ICacheFactory::class),
651
-				$this->createMock(IEventDispatcher::class),
652
-				$this->createMock(LoggerInterface::class),
653
-			), $this->groupManager, $this->config, $this->arrayCache])
654
-			->getMock();
655
-		$util->expects($this->any())
656
-			->method('stripPartialFileExtension')
657
-			->willReturnCallback(function ($path) {
658
-				return $path;
659
-			});
660
-
661
-		$cache = $this->createMock(Cache::class);
662
-		$cache->expects($this->any())
663
-			->method('get')
664
-			->willReturnCallback(function ($path) use ($isEncrypted) {
665
-				return ['encrypted' => $isEncrypted, 'path' => $path];
666
-			});
667
-
668
-		$instance = $this->getMockBuilder(Encryption::class)
669
-			->setConstructorArgs(
670
-				[
671
-					[
672
-						'storage' => $sourceStorage,
673
-						'root' => 'foo',
674
-						'mountPoint' => '/',
675
-						'mount' => $this->mount
676
-					],
677
-					$this->encryptionManager,
678
-					$util,
679
-					$this->logger,
680
-					$this->file,
681
-					null,
682
-					$this->keyStore,
683
-					$this->mountManager,
684
-					$this->arrayCache,
685
-				]
686
-			)
687
-			->onlyMethods(['readFirstBlock', 'getCache'])
688
-			->getMock();
689
-
690
-		$instance->method('readFirstBlock')->willReturn('');
691
-
692
-		$util->method(('parseRawHeader'))->willReturn($header);
693
-		$instance->method('getCache')->willReturn($cache);
694
-
695
-		$result = $this->invokePrivate($instance, 'getHeader', ['test.txt']);
696
-		$this->assertSameSize($expected, $result);
697
-		foreach ($result as $key => $value) {
698
-			$this->assertArrayHasKey($key, $expected);
699
-			$this->assertSame($expected[$key], $value);
700
-		}
701
-	}
702
-
703
-	public static function dataTestGetHeaderAddLegacyModule(): array {
704
-		return [
705
-			[['cipher' => 'AES-128'], true, true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
706
-			[[], true, false, []],
707
-			[[], true, true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
708
-			[[], false, true, []],
709
-		];
710
-	}
711
-
712
-	public static function dataCopyBetweenStorage(): array {
713
-		return [
714
-			[true, true, true],
715
-			[true, false, false],
716
-			[false, true, false],
717
-			[false, false, false],
718
-		];
719
-	}
720
-
721
-	public function testCopyBetweenStorageMinimumEncryptedVersion(): void {
722
-		$storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
723
-
724
-		$sourceInternalPath = $targetInternalPath = 'file.txt';
725
-		$preserveMtime = $isRename = false;
726
-
727
-		$storage2->expects($this->any())
728
-			->method('fopen')
729
-			->willReturnCallback(function ($path, $mode) {
730
-				$temp = Server::get(ITempManager::class);
731
-				return fopen($temp->getTemporaryFile(), $mode);
732
-			});
733
-		$storage2->method('getId')
734
-			->willReturn('stroage2');
735
-		$cache = $this->createMock(ICache::class);
736
-		$cache->expects($this->once())
737
-			->method('get')
738
-			->with($sourceInternalPath)
739
-			->willReturn(['encryptedVersion' => 0]);
740
-		$storage2->expects($this->once())
741
-			->method('getCache')
742
-			->willReturn($cache);
743
-		$this->encryptionManager->expects($this->any())
744
-			->method('isEnabled')
745
-			->willReturn(true);
746
-		global $mockedMountPointEncryptionEnabled;
747
-		$mockedMountPointEncryptionEnabled = true;
748
-
749
-		$expectedCachePut = [
750
-			'encrypted' => true,
751
-		];
752
-		$expectedCachePut['encryptedVersion'] = 1;
753
-
754
-		$this->cache->expects($this->once())
755
-			->method('put')
756
-			->with($sourceInternalPath, $expectedCachePut);
757
-
758
-		$this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
759
-
760
-		$this->assertFalse(false);
761
-	}
762
-
763
-	/**
764
-	 *
765
-	 * @param bool $encryptionEnabled
766
-	 * @param bool $mountPointEncryptionEnabled
767
-	 * @param bool $expectedEncrypted
768
-	 */
769
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataCopyBetweenStorage')]
770
-	public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted): void {
771
-		$storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
772
-
773
-		$sourceInternalPath = $targetInternalPath = 'file.txt';
774
-		$preserveMtime = $isRename = false;
775
-
776
-		$storage2->expects($this->any())
777
-			->method('fopen')
778
-			->willReturnCallback(function ($path, $mode) {
779
-				$temp = Server::get(ITempManager::class);
780
-				return fopen($temp->getTemporaryFile(), $mode);
781
-			});
782
-		$storage2->method('getId')
783
-			->willReturn('stroage2');
784
-		if ($expectedEncrypted) {
785
-			$cache = $this->createMock(ICache::class);
786
-			$cache->expects($this->once())
787
-				->method('get')
788
-				->with($sourceInternalPath)
789
-				->willReturn(['encryptedVersion' => 12345]);
790
-			$storage2->expects($this->once())
791
-				->method('getCache')
792
-				->willReturn($cache);
793
-		}
794
-		$this->encryptionManager->expects($this->any())
795
-			->method('isEnabled')
796
-			->willReturn($encryptionEnabled);
797
-		// FIXME can not overwrite the return after definition
798
-		//		$this->mount->expects($this->at(0))
799
-		//			->method('getOption')
800
-		//			->with('encrypt', true)
801
-		//			->willReturn($mountPointEncryptionEnabled);
802
-		global $mockedMountPointEncryptionEnabled;
803
-		$mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled;
804
-
805
-		$expectedCachePut = [
806
-			'encrypted' => $expectedEncrypted,
807
-		];
808
-		if ($expectedEncrypted === true) {
809
-			$expectedCachePut['encryptedVersion'] = 1;
810
-		}
811
-
812
-		$this->arrayCache->expects($this->never())->method('set');
813
-
814
-		$this->cache->expects($this->once())
815
-			->method('put')
816
-			->with($sourceInternalPath, $expectedCachePut);
817
-
818
-		$this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
819
-
820
-		$this->assertFalse(false);
821
-	}
822
-
823
-	/**
824
-	 *
825
-	 * @param string $sourceInternalPath
826
-	 * @param string $targetInternalPath
827
-	 * @param bool $copyResult
828
-	 * @param bool $encrypted
829
-	 */
830
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyBetweenStorageVersions')]
831
-	public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted): void {
832
-		$sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class);
833
-
834
-		$targetStorage = $this->createMock(\OC\Files\Storage\Storage::class);
835
-
836
-		$cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
837
-			->disableOriginalConstructor()->getMock();
838
-
839
-		$mountPoint = '/mountPoint';
840
-
841
-		/** @var Encryption |MockObject $instance */
842
-		$instance = $this->getMockBuilder(Encryption::class)
843
-			->setConstructorArgs(
844
-				[
845
-					[
846
-						'storage' => $targetStorage,
847
-						'root' => 'foo',
848
-						'mountPoint' => $mountPoint,
849
-						'mount' => $this->mount
850
-					],
851
-					$this->encryptionManager,
852
-					$this->util,
853
-					$this->logger,
854
-					$this->file,
855
-					null,
856
-					$this->keyStore,
857
-					$this->mountManager,
858
-					$this->arrayCache
859
-				]
860
-			)
861
-			->onlyMethods(['updateUnencryptedSize', 'getCache'])
862
-			->getMock();
863
-
864
-		$targetStorage->expects($this->once())->method('copyFromStorage')
865
-			->with($sourceStorage, $sourceInternalPath, $targetInternalPath)
866
-			->willReturn($copyResult);
867
-
868
-		$instance->expects($this->any())->method('getCache')
869
-			->willReturn($cache);
870
-
871
-		$this->arrayCache->expects($this->once())->method('set')
872
-			->with('encryption_copy_version_' . $sourceInternalPath, true);
873
-
874
-		if ($copyResult) {
875
-			$cache->expects($this->once())->method('get')
876
-				->with($sourceInternalPath)
877
-				->willReturn(new CacheEntry(['encrypted' => $encrypted, 'size' => 42]));
878
-			if ($encrypted) {
879
-				$instance->expects($this->once())->method('updateUnencryptedSize')
880
-					->with($mountPoint . $targetInternalPath, 42);
881
-			} else {
882
-				$instance->expects($this->never())->method('updateUnencryptedSize');
883
-			}
884
-		} else {
885
-			$instance->expects($this->never())->method('updateUnencryptedSize');
886
-		}
887
-
888
-		$result = $this->invokePrivate(
889
-			$instance,
890
-			'copyBetweenStorage',
891
-			[
892
-				$sourceStorage,
893
-				$sourceInternalPath,
894
-				$targetInternalPath,
895
-				false,
896
-				false
897
-			]
898
-		);
899
-
900
-		$this->assertSame($copyResult, $result);
901
-	}
902
-
903
-	public static function dataTestCopyBetweenStorageVersions(): array {
904
-		return [
905
-			['/files/foo.txt', '/files_versions/foo.txt.768743', true, true],
906
-			['/files/foo.txt', '/files_versions/foo.txt.768743', true, false],
907
-			['/files/foo.txt', '/files_versions/foo.txt.768743', false, true],
908
-			['/files/foo.txt', '/files_versions/foo.txt.768743', false, false],
909
-			['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true],
910
-			['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false],
911
-			['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true],
912
-			['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false],
913
-
914
-		];
915
-	}
916
-
917
-	/**
918
-	 * @param string $path
919
-	 * @param bool $expected
920
-	 */
921
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsVersion')]
922
-	public function testIsVersion($path, $expected): void {
923
-		$this->assertSame($expected,
924
-			$this->invokePrivate($this->instance, 'isVersion', [$path])
925
-		);
926
-	}
927
-
928
-	public static function dataTestIsVersion(): array {
929
-		return [
930
-			['files_versions/foo', true],
931
-			['/files_versions/foo', true],
932
-			['//files_versions/foo', true],
933
-			['files/versions/foo', false],
934
-			['files/files_versions/foo', false],
935
-			['files_versions_test/foo', false],
936
-		];
937
-	}
938
-
939
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestShouldEncrypt')]
940
-	public function testShouldEncrypt(
941
-		bool $encryptionEnabled,
942
-		bool $encryptMountPoint,
943
-		?bool $encryptionModule,
944
-		bool $encryptionModuleShouldEncrypt,
945
-		bool $expected,
946
-	): void {
947
-		$encryptionManager = $this->createMock(\OC\Encryption\Manager::class);
948
-		$util = $this->createMock(Util::class);
949
-		$fileHelper = $this->createMock(IFile::class);
950
-		$keyStorage = $this->createMock(IStorage::class);
951
-		$mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
952
-		$mount = $this->createMock(IMountPoint::class);
953
-		$arrayCache = $this->createMock(ArrayCache::class);
954
-		$path = '/welcome.txt';
955
-		$fullPath = 'admin/files/welcome.txt';
956
-		$defaultEncryptionModule = $this->createMock(IEncryptionModule::class);
957
-
958
-		$wrapper = $this->getMockBuilder(Encryption::class)
959
-			->setConstructorArgs(
960
-				[
961
-					['mountPoint' => '', 'mount' => $mount, 'storage' => ''],
962
-					$encryptionManager,
963
-					$util,
964
-					$this->logger,
965
-					$fileHelper,
966
-					null,
967
-					$keyStorage,
968
-					$mountManager,
969
-					$arrayCache
970
-				]
971
-			)
972
-			->onlyMethods(['getFullPath', 'getEncryptionModule'])
973
-			->getMock();
974
-
975
-		$encryptionManager->method('isEnabled')->willReturn($encryptionEnabled);
976
-
977
-		if ($encryptionModule === true) {
978
-			/** @var IEncryptionModule|MockObject $encryptionModule */
979
-			$encryptionModule = $this->createMock(IEncryptionModule::class);
980
-		}
981
-
982
-		$wrapper->method('getFullPath')->with($path)->willReturn($fullPath);
983
-		$wrapper->expects(($encryptionEnabled && $encryptMountPoint) ? $this->once() : $this->never())
984
-			->method('getEncryptionModule')
985
-			->with($fullPath)
986
-			->willReturnCallback(
987
-				function () use ($encryptionModule) {
988
-					if ($encryptionModule === false) {
989
-						throw new ModuleDoesNotExistsException();
990
-					}
991
-					return $encryptionModule;
992
-				}
993
-			);
994
-		$mount->expects($encryptionEnabled ? $this->once() : $this->never())
995
-			->method('getOption')->with('encrypt', true)
996
-			->willReturn($encryptMountPoint);
997
-
998
-		if ($encryptionModule !== null && $encryptionModule !== false) {
999
-			$encryptionModule
1000
-				->method('shouldEncrypt')
1001
-				->with($fullPath)
1002
-				->willReturn($encryptionModuleShouldEncrypt);
1003
-		}
1004
-
1005
-		if ($encryptionModule === null) {
1006
-			$encryptionManager->expects($this->once())
1007
-				->method('getEncryptionModule')
1008
-				->willReturn($defaultEncryptionModule);
1009
-		}
1010
-		$defaultEncryptionModule->method('shouldEncrypt')->willReturn(true);
1011
-
1012
-		$result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]);
1013
-
1014
-		$this->assertSame($expected, $result);
1015
-	}
1016
-
1017
-	public static function dataTestShouldEncrypt(): array {
1018
-		return [
1019
-			[true, false, false, false, false],
1020
-			[true, true, false, false, false],
1021
-			[true, true, true, false, false],
1022
-			[true, true, true, true, true],
1023
-			[true, true, null, false, true],
1024
-			[false, true, true, true, false],
1025
-		];
1026
-	}
38
+    /**
39
+     * block size will always be 8192 for a PHP stream
40
+     * @see https://bugs.php.net/bug.php?id=21641
41
+     */
42
+    protected int $headerSize = 8192;
43
+    private Temporary $sourceStorage;
44
+    /** @var Encryption&MockObject */
45
+    protected $instance;
46
+    private \OC\Encryption\Keys\Storage&MockObject $keyStore;
47
+    private Util&MockObject $util;
48
+    private \OC\Encryption\Manager&MockObject $encryptionManager;
49
+    private IEncryptionModule&MockObject $encryptionModule;
50
+    private Cache&MockObject $cache;
51
+    private LoggerInterface&MockObject $logger;
52
+    private File&MockObject $file;
53
+    private MountPoint&MockObject $mount;
54
+    private \OC\Files\Mount\Manager&MockObject $mountManager;
55
+    private \OC\Group\Manager&MockObject $groupManager;
56
+    private IConfig&MockObject $config;
57
+    private ArrayCache&MockObject $arrayCache;
58
+    /** dummy unencrypted size */
59
+    private int $dummySize = -1;
60
+
61
+    protected function setUp(): void {
62
+        parent::setUp();
63
+
64
+        $mockModule = $this->buildMockModule();
65
+        $this->encryptionManager = $this->getMockBuilder(\OC\Encryption\Manager::class)
66
+            ->disableOriginalConstructor()
67
+            ->onlyMethods(['getEncryptionModule', 'isEnabled'])
68
+            ->getMock();
69
+        $this->encryptionManager->expects($this->any())
70
+            ->method('getEncryptionModule')
71
+            ->willReturn($mockModule);
72
+
73
+        $this->arrayCache = $this->createMock(ArrayCache::class);
74
+        $this->config = $this->getMockBuilder(IConfig::class)
75
+            ->disableOriginalConstructor()
76
+            ->getMock();
77
+        $this->groupManager = $this->getMockBuilder('\OC\Group\Manager')
78
+            ->disableOriginalConstructor()
79
+            ->getMock();
80
+
81
+        $this->util = $this->getMockBuilder(Util::class)
82
+            ->onlyMethods(['getUidAndFilename', 'isFile', 'isExcluded', 'stripPartialFileExtension'])
83
+            ->setConstructorArgs([new View(), new Manager(
84
+                $this->config,
85
+                $this->createMock(ICacheFactory::class),
86
+                $this->createMock(IEventDispatcher::class),
87
+                $this->createMock(LoggerInterface::class),
88
+            ), $this->groupManager, $this->config, $this->arrayCache])
89
+            ->getMock();
90
+        $this->util->expects($this->any())
91
+            ->method('getUidAndFilename')
92
+            ->willReturnCallback(function ($path) {
93
+                return ['user1', $path];
94
+            });
95
+        $this->util->expects($this->any())
96
+            ->method('stripPartialFileExtension')
97
+            ->willReturnCallback(function ($path) {
98
+                return $path;
99
+            });
100
+
101
+        $this->file = $this->getMockBuilder(File::class)
102
+            ->disableOriginalConstructor()
103
+            ->onlyMethods(['getAccessList'])
104
+            ->getMock();
105
+        $this->file->expects($this->any())->method('getAccessList')->willReturn([]);
106
+
107
+        $this->logger = $this->createMock(LoggerInterface::class);
108
+
109
+        $this->sourceStorage = new Temporary([]);
110
+
111
+        $this->keyStore = $this->createMock(\OC\Encryption\Keys\Storage::class);
112
+
113
+        $this->mount = $this->getMockBuilder(MountPoint::class)
114
+            ->disableOriginalConstructor()
115
+            ->onlyMethods(['getOption'])
116
+            ->getMock();
117
+        $this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) {
118
+            if ($option === 'encrypt' && $default === true) {
119
+                global $mockedMountPointEncryptionEnabled;
120
+                if ($mockedMountPointEncryptionEnabled !== null) {
121
+                    return $mockedMountPointEncryptionEnabled;
122
+                }
123
+            }
124
+            return true;
125
+        });
126
+
127
+        $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
128
+            ->disableOriginalConstructor()->getMock();
129
+        $this->cache->expects($this->any())
130
+            ->method('get')
131
+            ->willReturnCallback(function ($path) {
132
+                return ['encrypted' => false, 'path' => $path];
133
+            });
134
+
135
+        $this->mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
136
+        $this->mountManager->method('findByStorageId')
137
+            ->willReturn([]);
138
+
139
+        $this->instance = $this->getMockBuilder(Encryption::class)
140
+            ->setConstructorArgs(
141
+                [
142
+                    [
143
+                        'storage' => $this->sourceStorage,
144
+                        'root' => 'foo',
145
+                        'mountPoint' => '/',
146
+                        'mount' => $this->mount
147
+                    ],
148
+                    $this->encryptionManager,
149
+                    $this->util,
150
+                    $this->logger,
151
+                    $this->file,
152
+                    null,
153
+                    $this->keyStore,
154
+                    $this->mountManager,
155
+                    $this->arrayCache
156
+                ]
157
+            )
158
+            ->onlyMethods(['getMetaData', 'getCache', 'getEncryptionModule'])
159
+            ->getMock();
160
+
161
+        $this->instance->expects($this->any())
162
+            ->method('getMetaData')
163
+            ->willReturnCallback(function ($path) {
164
+                return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path];
165
+            });
166
+
167
+        $this->instance->expects($this->any())
168
+            ->method('getCache')
169
+            ->willReturn($this->cache);
170
+
171
+        $this->instance->expects($this->any())
172
+            ->method('getEncryptionModule')
173
+            ->willReturn($mockModule);
174
+    }
175
+
176
+    protected function buildMockModule(): IEncryptionModule&MockObject {
177
+        $this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule')
178
+            ->disableOriginalConstructor()
179
+            ->onlyMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser', 'needDetailedAccessList'])
180
+            ->getMock();
181
+
182
+        $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE');
183
+        $this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module');
184
+        $this->encryptionModule->expects($this->any())->method('begin')->willReturn([]);
185
+        $this->encryptionModule->expects($this->any())->method('end')->willReturn('');
186
+        $this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0);
187
+        $this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0);
188
+        $this->encryptionModule->expects($this->any())->method('update')->willReturn(true);
189
+        $this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true);
190
+        $this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192);
191
+        $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true);
192
+        $this->encryptionModule->expects($this->any())->method('needDetailedAccessList')->willReturn(false);
193
+        return $this->encryptionModule;
194
+    }
195
+
196
+    /**
197
+     *
198
+     * @param string $path
199
+     * @param array $metaData
200
+     * @param bool $encrypted
201
+     * @param bool $unencryptedSizeSet
202
+     * @param int $storedUnencryptedSize
203
+     * @param array $expected
204
+     */
205
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetMetaData')]
206
+    public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected): void {
207
+        $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
208
+            ->disableOriginalConstructor()->getMock();
209
+
210
+        $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
211
+            ->disableOriginalConstructor()->getMock();
212
+        $cache->expects($this->any())
213
+            ->method('get')
214
+            ->willReturnCallback(
215
+                function ($path) use ($encrypted) {
216
+                    return new CacheEntry(['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1]);
217
+                }
218
+            );
219
+
220
+        $this->instance = $this->getMockBuilder(Encryption::class)
221
+            ->setConstructorArgs(
222
+                [
223
+                    [
224
+                        'storage' => $sourceStorage,
225
+                        'root' => 'foo',
226
+                        'mountPoint' => '/',
227
+                        'mount' => $this->mount
228
+                    ],
229
+                    $this->encryptionManager,
230
+                    $this->util,
231
+                    $this->logger,
232
+                    $this->file,
233
+                    null,
234
+                    $this->keyStore,
235
+                    $this->mountManager,
236
+                    $this->arrayCache,
237
+                ]
238
+            )
239
+            ->onlyMethods(['getCache', 'verifyUnencryptedSize'])
240
+            ->getMock();
241
+
242
+        if ($unencryptedSizeSet) {
243
+            $this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]);
244
+        }
245
+
246
+        $fileEntry = $this->getMockBuilder('\OC\Files\Cache\Cache')
247
+            ->disableOriginalConstructor()->getMock();
248
+        $sourceStorage->expects($this->once())->method('getMetaData')->with($path)
249
+            ->willReturn($metaData);
250
+        $sourceStorage->expects($this->any())
251
+            ->method('getCache')
252
+            ->with($path)
253
+            ->willReturn($fileEntry);
254
+        if ($metaData !== null) {
255
+            $fileEntry->expects($this->any())
256
+                ->method('get')
257
+                ->with($metaData['fileid']);
258
+        }
259
+
260
+        $this->instance->expects($this->any())->method('getCache')->willReturn($cache);
261
+        if ($expected !== null) {
262
+            $this->instance->expects($this->any())->method('verifyUnencryptedSize')
263
+                ->with($path, 0)->willReturn($expected['size']);
264
+        }
265
+
266
+        $result = $this->instance->getMetaData($path);
267
+        if (isset($expected['encrypted'])) {
268
+            $this->assertSame($expected['encrypted'], (bool)$result['encrypted']);
269
+
270
+            if (isset($expected['encryptedVersion'])) {
271
+                $this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']);
272
+            }
273
+        }
274
+
275
+        if ($expected !== null) {
276
+            $this->assertSame($expected['size'], $result['size']);
277
+        } else {
278
+            $this->assertSame(null, $result);
279
+        }
280
+    }
281
+
282
+    public static function dataTestGetMetaData(): array {
283
+        return [
284
+            ['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]],
285
+            ['/test.txt', null, true, true, 12, null],
286
+            ['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]],
287
+            ['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]]
288
+        ];
289
+    }
290
+
291
+    public function testFilesize(): void {
292
+        $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
293
+            ->disableOriginalConstructor()->getMock();
294
+        $cache->expects($this->any())
295
+            ->method('get')
296
+            ->willReturn(new CacheEntry(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1]));
297
+
298
+        $this->instance = $this->getMockBuilder(Encryption::class)
299
+            ->setConstructorArgs(
300
+                [
301
+                    [
302
+                        'storage' => $this->sourceStorage,
303
+                        'root' => 'foo',
304
+                        'mountPoint' => '/',
305
+                        'mount' => $this->mount
306
+                    ],
307
+                    $this->encryptionManager,
308
+                    $this->util,
309
+                    $this->logger,
310
+                    $this->file,
311
+                    null,
312
+                    $this->keyStore,
313
+                    $this->mountManager,
314
+                    $this->arrayCache,
315
+                ]
316
+            )
317
+            ->onlyMethods(['getCache', 'verifyUnencryptedSize'])
318
+            ->getMock();
319
+
320
+        $this->instance->expects($this->any())->method('getCache')->willReturn($cache);
321
+        $this->instance->expects($this->any())->method('verifyUnencryptedSize')
322
+            ->willReturn(42);
323
+
324
+
325
+        $this->assertSame(42,
326
+            $this->instance->filesize('/test.txt')
327
+        );
328
+    }
329
+
330
+    /**
331
+     *
332
+     * @param int $encryptedSize
333
+     * @param int $unencryptedSize
334
+     * @param bool $failure
335
+     * @param int $expected
336
+     */
337
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestVerifyUnencryptedSize')]
338
+    public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected): void {
339
+        $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
340
+            ->disableOriginalConstructor()->getMock();
341
+
342
+        $this->instance = $this->getMockBuilder(Encryption::class)
343
+            ->setConstructorArgs(
344
+                [
345
+                    [
346
+                        'storage' => $sourceStorage,
347
+                        'root' => 'foo',
348
+                        'mountPoint' => '/',
349
+                        'mount' => $this->mount
350
+                    ],
351
+                    $this->encryptionManager,
352
+                    $this->util,
353
+                    $this->logger,
354
+                    $this->file,
355
+                    null,
356
+                    $this->keyStore,
357
+                    $this->mountManager,
358
+                    $this->arrayCache,
359
+                ]
360
+            )
361
+            ->onlyMethods(['fixUnencryptedSize'])
362
+            ->getMock();
363
+
364
+        $sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize);
365
+
366
+        $this->instance->expects($this->any())->method('fixUnencryptedSize')
367
+            ->with('/test.txt', $encryptedSize, $unencryptedSize)
368
+            ->willReturnCallback(
369
+                function () use ($failure, $expected) {
370
+                    if ($failure) {
371
+                        throw new Exception();
372
+                    } else {
373
+                        return $expected;
374
+                    }
375
+                }
376
+            );
377
+
378
+        $this->assertSame(
379
+            $expected,
380
+            $this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize])
381
+        );
382
+    }
383
+
384
+    public static function dataTestVerifyUnencryptedSize(): array {
385
+        return [
386
+            [120, 80, false, 80],
387
+            [120, 120, false, 80],
388
+            [120, -1, false, 80],
389
+            [120, -1, true, -1]
390
+        ];
391
+    }
392
+
393
+    /**
394
+     *
395
+     * @param string $source
396
+     * @param string $target
397
+     * @param $encryptionEnabled
398
+     * @param boolean $renameKeysReturn
399
+     */
400
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyAndRename')]
401
+    public function testRename($source,
402
+        $target,
403
+        $encryptionEnabled,
404
+        $renameKeysReturn): void {
405
+        if ($encryptionEnabled) {
406
+            $this->keyStore
407
+                ->expects($this->once())
408
+                ->method('renameKeys')
409
+                ->willReturn($renameKeysReturn);
410
+        } else {
411
+            $this->keyStore
412
+                ->expects($this->never())->method('renameKeys');
413
+        }
414
+        $this->util->expects($this->any())
415
+            ->method('isFile')->willReturn(true);
416
+        $this->encryptionManager->expects($this->once())
417
+            ->method('isEnabled')->willReturn($encryptionEnabled);
418
+
419
+        $this->instance->mkdir($source);
420
+        $this->instance->mkdir(dirname($target));
421
+        $this->instance->rename($source, $target);
422
+    }
423
+
424
+    public function testCopyEncryption(): void {
425
+        $this->instance->file_put_contents('source.txt', 'bar');
426
+        $this->instance->copy('source.txt', 'target.txt');
427
+        $this->assertSame('bar', $this->instance->file_get_contents('target.txt'));
428
+        $targetMeta = $this->instance->getMetaData('target.txt');
429
+        $sourceMeta = $this->instance->getMetaData('source.txt');
430
+        $this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']);
431
+        $this->assertSame($sourceMeta['size'], $targetMeta['size']);
432
+    }
433
+
434
+    /**
435
+     * data provider for testCopyTesting() and dataTestCopyAndRename()
436
+     *
437
+     * @return array
438
+     */
439
+    public static function dataTestCopyAndRename(): array {
440
+        return [
441
+            ['source', 'target', true, false, false],
442
+            ['source', 'target', true, true, false],
443
+            ['source', '/subFolder/target', true, false, false],
444
+            ['source', '/subFolder/target', true, true, true],
445
+            ['source', '/subFolder/target', false, true, false],
446
+        ];
447
+    }
448
+
449
+    public function testIsLocal(): void {
450
+        $this->encryptionManager->expects($this->once())
451
+            ->method('isEnabled')->willReturn(true);
452
+        $this->assertFalse($this->instance->isLocal());
453
+    }
454
+
455
+    /**
456
+     *
457
+     * @param string $path
458
+     * @param boolean $rmdirResult
459
+     * @param boolean $isExcluded
460
+     * @param boolean $encryptionEnabled
461
+     */
462
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestRmdir')]
463
+    public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled): void {
464
+        $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
465
+            ->disableOriginalConstructor()->getMock();
466
+
467
+        $util = $this->getMockBuilder('\OC\Encryption\Util')->disableOriginalConstructor()->getMock();
468
+
469
+        $sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult);
470
+        $util->expects($this->any())->method('isExcluded')->willReturn($isExcluded);
471
+        $this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled);
472
+
473
+        $encryptionStorage = new Encryption(
474
+            [
475
+                'storage' => $sourceStorage,
476
+                'root' => 'foo',
477
+                'mountPoint' => '/mountPoint',
478
+                'mount' => $this->mount
479
+            ],
480
+            $this->encryptionManager,
481
+            $util,
482
+            $this->logger,
483
+            $this->file,
484
+            null,
485
+            $this->keyStore,
486
+            $this->mountManager,
487
+            $this->arrayCache,
488
+        );
489
+
490
+
491
+        if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) {
492
+            $this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path);
493
+        } else {
494
+            $this->keyStore->expects($this->never())->method('deleteAllFileKeys');
495
+        }
496
+
497
+        $encryptionStorage->rmdir($path);
498
+    }
499
+
500
+    public static function dataTestRmdir(): array {
501
+        return [
502
+            ['/file.txt', true, true, true],
503
+            ['/file.txt', false, true, true],
504
+            ['/file.txt', true, false, true],
505
+            ['/file.txt', false, false, true],
506
+            ['/file.txt', true, true, false],
507
+            ['/file.txt', false, true, false],
508
+            ['/file.txt', true, false, false],
509
+            ['/file.txt', false, false, false],
510
+        ];
511
+    }
512
+
513
+    /**
514
+     *
515
+     * @param boolean $excluded
516
+     * @param boolean $expected
517
+     */
518
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyKeys')]
519
+    public function testCopyKeys($excluded, $expected): void {
520
+        $this->util->expects($this->once())
521
+            ->method('isExcluded')
522
+            ->willReturn($excluded);
523
+
524
+        if ($excluded) {
525
+            $this->keyStore->expects($this->never())->method('copyKeys');
526
+        } else {
527
+            $this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true);
528
+        }
529
+
530
+        $this->assertSame($expected,
531
+            self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target'])
532
+        );
533
+    }
534
+
535
+    public static function dataTestCopyKeys(): array {
536
+        return [
537
+            [true, false],
538
+            [false, true],
539
+        ];
540
+    }
541
+
542
+    /**
543
+     *
544
+     * @param string $path
545
+     * @param bool $strippedPathExists
546
+     * @param string $strippedPath
547
+     */
548
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetHeader')]
549
+    public function testGetHeader($path, $strippedPathExists, $strippedPath): void {
550
+        $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage')
551
+            ->disableOriginalConstructor()->getMock();
552
+
553
+        $util = $this->getMockBuilder('\OC\Encryption\Util')
554
+            ->setConstructorArgs(
555
+                [
556
+                    new View(),
557
+                    new Manager(
558
+                        $this->config,
559
+                        $this->createMock(ICacheFactory::class),
560
+                        $this->createMock(IEventDispatcher::class),
561
+                        $this->createMock(LoggerInterface::class),
562
+                    ),
563
+                    $this->groupManager,
564
+                    $this->config,
565
+                    $this->arrayCache
566
+                ]
567
+            )->getMock();
568
+
569
+        $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
570
+            ->disableOriginalConstructor()->getMock();
571
+        $cache->expects($this->any())
572
+            ->method('get')
573
+            ->willReturnCallback(function ($path) {
574
+                return ['encrypted' => true, 'path' => $path];
575
+            });
576
+
577
+        $instance = $this->getMockBuilder(Encryption::class)
578
+            ->setConstructorArgs(
579
+                [
580
+                    [
581
+                        'storage' => $sourceStorage,
582
+                        'root' => 'foo',
583
+                        'mountPoint' => '/',
584
+                        'mount' => $this->mount
585
+                    ],
586
+                    $this->encryptionManager,
587
+                    $util,
588
+                    $this->logger,
589
+                    $this->file,
590
+                    null,
591
+                    $this->keyStore,
592
+                    $this->mountManager,
593
+                    $this->arrayCache,
594
+                ]
595
+            )
596
+            ->onlyMethods(['getCache', 'readFirstBlock'])
597
+            ->getMock();
598
+
599
+        $instance->method('getCache')->willReturn($cache);
600
+
601
+        $util->method('parseRawHeader')
602
+            ->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']);
603
+
604
+        if ($strippedPathExists) {
605
+            $instance->method('readFirstBlock')
606
+                ->with($strippedPath)->willReturn('');
607
+        } else {
608
+            $instance->method('readFirstBlock')
609
+                ->with($path)->willReturn('');
610
+        }
611
+
612
+        $util->expects($this->once())->method('stripPartialFileExtension')
613
+            ->with($path)->willReturn($strippedPath);
614
+        $sourceStorage->expects($this->once())
615
+            ->method('is_file')
616
+            ->with($strippedPath)
617
+            ->willReturn($strippedPathExists);
618
+
619
+        $this->invokePrivate($instance, 'getHeader', [$path]);
620
+    }
621
+
622
+    public static function dataTestGetHeader(): array {
623
+        return [
624
+            ['/foo/bar.txt', false, '/foo/bar.txt'],
625
+            ['/foo/bar.txt.part', false, '/foo/bar.txt'],
626
+            ['/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'],
627
+            ['/foo/bar.txt.part', true, '/foo/bar.txt'],
628
+            ['/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'],
629
+        ];
630
+    }
631
+
632
+    /**
633
+     * test if getHeader adds the default module correctly to the header for
634
+     * legacy files
635
+     */
636
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetHeaderAddLegacyModule')]
637
+    public function testGetHeaderAddLegacyModule($header, $isEncrypted, $strippedPathExists, $expected): void {
638
+        $sourceStorage = $this->getMockBuilder(\OC\Files\Storage\Storage::class)
639
+            ->disableOriginalConstructor()->getMock();
640
+
641
+        $sourceStorage->expects($this->once())
642
+            ->method('is_file')
643
+            ->with('test.txt')
644
+            ->willReturn($strippedPathExists);
645
+
646
+        $util = $this->getMockBuilder(Util::class)
647
+            ->onlyMethods(['stripPartialFileExtension', 'parseRawHeader'])
648
+            ->setConstructorArgs([new View(), new Manager(
649
+                $this->config,
650
+                $this->createMock(ICacheFactory::class),
651
+                $this->createMock(IEventDispatcher::class),
652
+                $this->createMock(LoggerInterface::class),
653
+            ), $this->groupManager, $this->config, $this->arrayCache])
654
+            ->getMock();
655
+        $util->expects($this->any())
656
+            ->method('stripPartialFileExtension')
657
+            ->willReturnCallback(function ($path) {
658
+                return $path;
659
+            });
660
+
661
+        $cache = $this->createMock(Cache::class);
662
+        $cache->expects($this->any())
663
+            ->method('get')
664
+            ->willReturnCallback(function ($path) use ($isEncrypted) {
665
+                return ['encrypted' => $isEncrypted, 'path' => $path];
666
+            });
667
+
668
+        $instance = $this->getMockBuilder(Encryption::class)
669
+            ->setConstructorArgs(
670
+                [
671
+                    [
672
+                        'storage' => $sourceStorage,
673
+                        'root' => 'foo',
674
+                        'mountPoint' => '/',
675
+                        'mount' => $this->mount
676
+                    ],
677
+                    $this->encryptionManager,
678
+                    $util,
679
+                    $this->logger,
680
+                    $this->file,
681
+                    null,
682
+                    $this->keyStore,
683
+                    $this->mountManager,
684
+                    $this->arrayCache,
685
+                ]
686
+            )
687
+            ->onlyMethods(['readFirstBlock', 'getCache'])
688
+            ->getMock();
689
+
690
+        $instance->method('readFirstBlock')->willReturn('');
691
+
692
+        $util->method(('parseRawHeader'))->willReturn($header);
693
+        $instance->method('getCache')->willReturn($cache);
694
+
695
+        $result = $this->invokePrivate($instance, 'getHeader', ['test.txt']);
696
+        $this->assertSameSize($expected, $result);
697
+        foreach ($result as $key => $value) {
698
+            $this->assertArrayHasKey($key, $expected);
699
+            $this->assertSame($expected[$key], $value);
700
+        }
701
+    }
702
+
703
+    public static function dataTestGetHeaderAddLegacyModule(): array {
704
+        return [
705
+            [['cipher' => 'AES-128'], true, true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
706
+            [[], true, false, []],
707
+            [[], true, true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']],
708
+            [[], false, true, []],
709
+        ];
710
+    }
711
+
712
+    public static function dataCopyBetweenStorage(): array {
713
+        return [
714
+            [true, true, true],
715
+            [true, false, false],
716
+            [false, true, false],
717
+            [false, false, false],
718
+        ];
719
+    }
720
+
721
+    public function testCopyBetweenStorageMinimumEncryptedVersion(): void {
722
+        $storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
723
+
724
+        $sourceInternalPath = $targetInternalPath = 'file.txt';
725
+        $preserveMtime = $isRename = false;
726
+
727
+        $storage2->expects($this->any())
728
+            ->method('fopen')
729
+            ->willReturnCallback(function ($path, $mode) {
730
+                $temp = Server::get(ITempManager::class);
731
+                return fopen($temp->getTemporaryFile(), $mode);
732
+            });
733
+        $storage2->method('getId')
734
+            ->willReturn('stroage2');
735
+        $cache = $this->createMock(ICache::class);
736
+        $cache->expects($this->once())
737
+            ->method('get')
738
+            ->with($sourceInternalPath)
739
+            ->willReturn(['encryptedVersion' => 0]);
740
+        $storage2->expects($this->once())
741
+            ->method('getCache')
742
+            ->willReturn($cache);
743
+        $this->encryptionManager->expects($this->any())
744
+            ->method('isEnabled')
745
+            ->willReturn(true);
746
+        global $mockedMountPointEncryptionEnabled;
747
+        $mockedMountPointEncryptionEnabled = true;
748
+
749
+        $expectedCachePut = [
750
+            'encrypted' => true,
751
+        ];
752
+        $expectedCachePut['encryptedVersion'] = 1;
753
+
754
+        $this->cache->expects($this->once())
755
+            ->method('put')
756
+            ->with($sourceInternalPath, $expectedCachePut);
757
+
758
+        $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
759
+
760
+        $this->assertFalse(false);
761
+    }
762
+
763
+    /**
764
+     *
765
+     * @param bool $encryptionEnabled
766
+     * @param bool $mountPointEncryptionEnabled
767
+     * @param bool $expectedEncrypted
768
+     */
769
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataCopyBetweenStorage')]
770
+    public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted): void {
771
+        $storage2 = $this->createMock(\OC\Files\Storage\Storage::class);
772
+
773
+        $sourceInternalPath = $targetInternalPath = 'file.txt';
774
+        $preserveMtime = $isRename = false;
775
+
776
+        $storage2->expects($this->any())
777
+            ->method('fopen')
778
+            ->willReturnCallback(function ($path, $mode) {
779
+                $temp = Server::get(ITempManager::class);
780
+                return fopen($temp->getTemporaryFile(), $mode);
781
+            });
782
+        $storage2->method('getId')
783
+            ->willReturn('stroage2');
784
+        if ($expectedEncrypted) {
785
+            $cache = $this->createMock(ICache::class);
786
+            $cache->expects($this->once())
787
+                ->method('get')
788
+                ->with($sourceInternalPath)
789
+                ->willReturn(['encryptedVersion' => 12345]);
790
+            $storage2->expects($this->once())
791
+                ->method('getCache')
792
+                ->willReturn($cache);
793
+        }
794
+        $this->encryptionManager->expects($this->any())
795
+            ->method('isEnabled')
796
+            ->willReturn($encryptionEnabled);
797
+        // FIXME can not overwrite the return after definition
798
+        //		$this->mount->expects($this->at(0))
799
+        //			->method('getOption')
800
+        //			->with('encrypt', true)
801
+        //			->willReturn($mountPointEncryptionEnabled);
802
+        global $mockedMountPointEncryptionEnabled;
803
+        $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled;
804
+
805
+        $expectedCachePut = [
806
+            'encrypted' => $expectedEncrypted,
807
+        ];
808
+        if ($expectedEncrypted === true) {
809
+            $expectedCachePut['encryptedVersion'] = 1;
810
+        }
811
+
812
+        $this->arrayCache->expects($this->never())->method('set');
813
+
814
+        $this->cache->expects($this->once())
815
+            ->method('put')
816
+            ->with($sourceInternalPath, $expectedCachePut);
817
+
818
+        $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]);
819
+
820
+        $this->assertFalse(false);
821
+    }
822
+
823
+    /**
824
+     *
825
+     * @param string $sourceInternalPath
826
+     * @param string $targetInternalPath
827
+     * @param bool $copyResult
828
+     * @param bool $encrypted
829
+     */
830
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCopyBetweenStorageVersions')]
831
+    public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted): void {
832
+        $sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class);
833
+
834
+        $targetStorage = $this->createMock(\OC\Files\Storage\Storage::class);
835
+
836
+        $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
837
+            ->disableOriginalConstructor()->getMock();
838
+
839
+        $mountPoint = '/mountPoint';
840
+
841
+        /** @var Encryption |MockObject $instance */
842
+        $instance = $this->getMockBuilder(Encryption::class)
843
+            ->setConstructorArgs(
844
+                [
845
+                    [
846
+                        'storage' => $targetStorage,
847
+                        'root' => 'foo',
848
+                        'mountPoint' => $mountPoint,
849
+                        'mount' => $this->mount
850
+                    ],
851
+                    $this->encryptionManager,
852
+                    $this->util,
853
+                    $this->logger,
854
+                    $this->file,
855
+                    null,
856
+                    $this->keyStore,
857
+                    $this->mountManager,
858
+                    $this->arrayCache
859
+                ]
860
+            )
861
+            ->onlyMethods(['updateUnencryptedSize', 'getCache'])
862
+            ->getMock();
863
+
864
+        $targetStorage->expects($this->once())->method('copyFromStorage')
865
+            ->with($sourceStorage, $sourceInternalPath, $targetInternalPath)
866
+            ->willReturn($copyResult);
867
+
868
+        $instance->expects($this->any())->method('getCache')
869
+            ->willReturn($cache);
870
+
871
+        $this->arrayCache->expects($this->once())->method('set')
872
+            ->with('encryption_copy_version_' . $sourceInternalPath, true);
873
+
874
+        if ($copyResult) {
875
+            $cache->expects($this->once())->method('get')
876
+                ->with($sourceInternalPath)
877
+                ->willReturn(new CacheEntry(['encrypted' => $encrypted, 'size' => 42]));
878
+            if ($encrypted) {
879
+                $instance->expects($this->once())->method('updateUnencryptedSize')
880
+                    ->with($mountPoint . $targetInternalPath, 42);
881
+            } else {
882
+                $instance->expects($this->never())->method('updateUnencryptedSize');
883
+            }
884
+        } else {
885
+            $instance->expects($this->never())->method('updateUnencryptedSize');
886
+        }
887
+
888
+        $result = $this->invokePrivate(
889
+            $instance,
890
+            'copyBetweenStorage',
891
+            [
892
+                $sourceStorage,
893
+                $sourceInternalPath,
894
+                $targetInternalPath,
895
+                false,
896
+                false
897
+            ]
898
+        );
899
+
900
+        $this->assertSame($copyResult, $result);
901
+    }
902
+
903
+    public static function dataTestCopyBetweenStorageVersions(): array {
904
+        return [
905
+            ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true],
906
+            ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false],
907
+            ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true],
908
+            ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false],
909
+            ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true],
910
+            ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false],
911
+            ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true],
912
+            ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false],
913
+
914
+        ];
915
+    }
916
+
917
+    /**
918
+     * @param string $path
919
+     * @param bool $expected
920
+     */
921
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsVersion')]
922
+    public function testIsVersion($path, $expected): void {
923
+        $this->assertSame($expected,
924
+            $this->invokePrivate($this->instance, 'isVersion', [$path])
925
+        );
926
+    }
927
+
928
+    public static function dataTestIsVersion(): array {
929
+        return [
930
+            ['files_versions/foo', true],
931
+            ['/files_versions/foo', true],
932
+            ['//files_versions/foo', true],
933
+            ['files/versions/foo', false],
934
+            ['files/files_versions/foo', false],
935
+            ['files_versions_test/foo', false],
936
+        ];
937
+    }
938
+
939
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestShouldEncrypt')]
940
+    public function testShouldEncrypt(
941
+        bool $encryptionEnabled,
942
+        bool $encryptMountPoint,
943
+        ?bool $encryptionModule,
944
+        bool $encryptionModuleShouldEncrypt,
945
+        bool $expected,
946
+    ): void {
947
+        $encryptionManager = $this->createMock(\OC\Encryption\Manager::class);
948
+        $util = $this->createMock(Util::class);
949
+        $fileHelper = $this->createMock(IFile::class);
950
+        $keyStorage = $this->createMock(IStorage::class);
951
+        $mountManager = $this->createMock(\OC\Files\Mount\Manager::class);
952
+        $mount = $this->createMock(IMountPoint::class);
953
+        $arrayCache = $this->createMock(ArrayCache::class);
954
+        $path = '/welcome.txt';
955
+        $fullPath = 'admin/files/welcome.txt';
956
+        $defaultEncryptionModule = $this->createMock(IEncryptionModule::class);
957
+
958
+        $wrapper = $this->getMockBuilder(Encryption::class)
959
+            ->setConstructorArgs(
960
+                [
961
+                    ['mountPoint' => '', 'mount' => $mount, 'storage' => ''],
962
+                    $encryptionManager,
963
+                    $util,
964
+                    $this->logger,
965
+                    $fileHelper,
966
+                    null,
967
+                    $keyStorage,
968
+                    $mountManager,
969
+                    $arrayCache
970
+                ]
971
+            )
972
+            ->onlyMethods(['getFullPath', 'getEncryptionModule'])
973
+            ->getMock();
974
+
975
+        $encryptionManager->method('isEnabled')->willReturn($encryptionEnabled);
976
+
977
+        if ($encryptionModule === true) {
978
+            /** @var IEncryptionModule|MockObject $encryptionModule */
979
+            $encryptionModule = $this->createMock(IEncryptionModule::class);
980
+        }
981
+
982
+        $wrapper->method('getFullPath')->with($path)->willReturn($fullPath);
983
+        $wrapper->expects(($encryptionEnabled && $encryptMountPoint) ? $this->once() : $this->never())
984
+            ->method('getEncryptionModule')
985
+            ->with($fullPath)
986
+            ->willReturnCallback(
987
+                function () use ($encryptionModule) {
988
+                    if ($encryptionModule === false) {
989
+                        throw new ModuleDoesNotExistsException();
990
+                    }
991
+                    return $encryptionModule;
992
+                }
993
+            );
994
+        $mount->expects($encryptionEnabled ? $this->once() : $this->never())
995
+            ->method('getOption')->with('encrypt', true)
996
+            ->willReturn($encryptMountPoint);
997
+
998
+        if ($encryptionModule !== null && $encryptionModule !== false) {
999
+            $encryptionModule
1000
+                ->method('shouldEncrypt')
1001
+                ->with($fullPath)
1002
+                ->willReturn($encryptionModuleShouldEncrypt);
1003
+        }
1004
+
1005
+        if ($encryptionModule === null) {
1006
+            $encryptionManager->expects($this->once())
1007
+                ->method('getEncryptionModule')
1008
+                ->willReturn($defaultEncryptionModule);
1009
+        }
1010
+        $defaultEncryptionModule->method('shouldEncrypt')->willReturn(true);
1011
+
1012
+        $result = $this->invokePrivate($wrapper, 'shouldEncrypt', [$path]);
1013
+
1014
+        $this->assertSame($expected, $result);
1015
+    }
1016
+
1017
+    public static function dataTestShouldEncrypt(): array {
1018
+        return [
1019
+            [true, false, false, false, false],
1020
+            [true, true, false, false, false],
1021
+            [true, true, true, false, false],
1022
+            [true, true, true, true, true],
1023
+            [true, true, null, false, true],
1024
+            [false, true, true, true, false],
1025
+        ];
1026
+    }
1027 1027
 }
Please login to merge, or discard this patch.
build/integration/features/bootstrap/CommandLine.php 2 patches
Indentation   +141 added lines, -141 removed lines patch added patch discarded remove patch
@@ -10,145 +10,145 @@
 block discarded – undo
10 10
 require __DIR__ . '/../../vendor/autoload.php';
11 11
 
12 12
 trait CommandLine {
13
-	/** @var int return code of last command */
14
-	private $lastCode;
15
-	/** @var string stdout of last command */
16
-	private $lastStdOut;
17
-	/** @var string stderr of last command */
18
-	private $lastStdErr;
19
-
20
-	/** @var string */
21
-	protected $ocPath = '../..';
22
-
23
-	/**
24
-	 * Invokes an OCC command
25
-	 *
26
-	 * @param []string $args OCC command, the part behind "occ". For example: "files:transfer-ownership"
27
-	 * @return int exit code
28
-	 */
29
-	public function runOcc($args = [], string $inputString = '') {
30
-		$args = array_map(function ($arg) {
31
-			return escapeshellarg($arg);
32
-		}, $args);
33
-		$args[] = '--no-ansi';
34
-		$args = implode(' ', $args);
35
-
36
-		$descriptor = [
37
-			0 => ['pipe', 'r'],
38
-			1 => ['pipe', 'w'],
39
-			2 => ['pipe', 'w'],
40
-		];
41
-		$process = proc_open('php console.php ' . $args, $descriptor, $pipes, $this->ocPath);
42
-		if ($inputString !== '') {
43
-			fwrite($pipes[0], $inputString . "\n");
44
-			fclose($pipes[0]);
45
-		}
46
-		$this->lastStdOut = stream_get_contents($pipes[1]);
47
-		$this->lastStdErr = stream_get_contents($pipes[2]);
48
-		$this->lastCode = proc_close($process);
49
-
50
-		// Clean opcode cache
51
-		$client = new GuzzleHttp\Client();
52
-		$client->request('GET', 'http://localhost:8080/apps/testing/clean_opcode_cache.php');
53
-
54
-		return $this->lastCode;
55
-	}
56
-
57
-	/**
58
-	 * @Given /^invoking occ with "([^"]*)"$/
59
-	 */
60
-	public function invokingTheCommand($cmd) {
61
-		$args = explode(' ', $cmd);
62
-		$this->runOcc($args);
63
-	}
64
-
65
-	/**
66
-	 * @Given /^invoking occ with "([^"]*)" with input "([^"]+)"$/
67
-	 */
68
-	public function invokingTheCommandWith($cmd, $inputString) {
69
-		$args = explode(' ', $cmd);
70
-		$this->runOcc($args, $inputString);
71
-	}
72
-
73
-	/**
74
-	 * Find exception texts in stderr
75
-	 */
76
-	public function findExceptions() {
77
-		$exceptions = [];
78
-		$captureNext = false;
79
-		// the exception text usually appears after an "[Exception"] row
80
-		foreach (explode("\n", $this->lastStdErr) as $line) {
81
-			if (preg_match('/\[Exception\]/', $line)) {
82
-				$captureNext = true;
83
-				continue;
84
-			}
85
-			if ($captureNext) {
86
-				$exceptions[] = trim($line);
87
-				$captureNext = false;
88
-			}
89
-		}
90
-
91
-		return $exceptions;
92
-	}
93
-
94
-	/**
95
-	 * @Then /^the command was successful$/
96
-	 */
97
-	public function theCommandWasSuccessful() {
98
-		$exceptions = $this->findExceptions();
99
-		if ($this->lastCode !== 0) {
100
-			$msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
101
-			if (!empty($exceptions)) {
102
-				$msg .= ' Exceptions: ' . implode(', ', $exceptions);
103
-			}
104
-			throw new \Exception($msg);
105
-		} elseif (!empty($exceptions)) {
106
-			$msg = 'The command was successful but triggered exceptions: ' . implode(', ', $exceptions);
107
-			throw new \Exception($msg);
108
-		}
109
-	}
110
-
111
-	/**
112
-	 * @Then /^the command failed with exit code ([0-9]+)$/
113
-	 */
114
-	public function theCommandFailedWithExitCode($exitCode) {
115
-		if ($this->lastCode !== (int)$exitCode) {
116
-			throw new \Exception('The command was expected to fail with exit code ' . $exitCode . ' but got ' . $this->lastCode);
117
-		}
118
-	}
119
-
120
-	/**
121
-	 * @Then /^the command failed with exception text "([^"]*)"$/
122
-	 */
123
-	public function theCommandFailedWithException($exceptionText) {
124
-		$exceptions = $this->findExceptions();
125
-		if (empty($exceptions)) {
126
-			throw new \Exception('The command did not throw any exceptions');
127
-		}
128
-
129
-		if (!in_array($exceptionText, $exceptions)) {
130
-			throw new \Exception('The command did not throw any exception with the text "' . $exceptionText . '"');
131
-		}
132
-	}
133
-
134
-	/**
135
-	 * @Then /^the command output contains the text "([^"]*)"$/
136
-	 */
137
-	public function theCommandOutputContainsTheText($text) {
138
-		Assert::assertStringContainsString($text, $this->lastStdOut, 'The command did not output the expected text on stdout');
139
-	}
140
-
141
-	/**
142
-	 * @Then /^the command output does not contain the text "([^"]*)"$/
143
-	 */
144
-	public function theCommandOutputDoesNotContainTheText($text) {
145
-		Assert::assertStringNotContainsString($text, $this->lastStdOut, 'The command did output the not expected text on stdout');
146
-	}
147
-
148
-	/**
149
-	 * @Then /^the command error output contains the text "([^"]*)"$/
150
-	 */
151
-	public function theCommandErrorOutputContainsTheText($text) {
152
-		Assert::assertStringContainsString($text, $this->lastStdErr, 'The command did not output the expected text on stderr');
153
-	}
13
+    /** @var int return code of last command */
14
+    private $lastCode;
15
+    /** @var string stdout of last command */
16
+    private $lastStdOut;
17
+    /** @var string stderr of last command */
18
+    private $lastStdErr;
19
+
20
+    /** @var string */
21
+    protected $ocPath = '../..';
22
+
23
+    /**
24
+     * Invokes an OCC command
25
+     *
26
+     * @param []string $args OCC command, the part behind "occ". For example: "files:transfer-ownership"
27
+     * @return int exit code
28
+     */
29
+    public function runOcc($args = [], string $inputString = '') {
30
+        $args = array_map(function ($arg) {
31
+            return escapeshellarg($arg);
32
+        }, $args);
33
+        $args[] = '--no-ansi';
34
+        $args = implode(' ', $args);
35
+
36
+        $descriptor = [
37
+            0 => ['pipe', 'r'],
38
+            1 => ['pipe', 'w'],
39
+            2 => ['pipe', 'w'],
40
+        ];
41
+        $process = proc_open('php console.php ' . $args, $descriptor, $pipes, $this->ocPath);
42
+        if ($inputString !== '') {
43
+            fwrite($pipes[0], $inputString . "\n");
44
+            fclose($pipes[0]);
45
+        }
46
+        $this->lastStdOut = stream_get_contents($pipes[1]);
47
+        $this->lastStdErr = stream_get_contents($pipes[2]);
48
+        $this->lastCode = proc_close($process);
49
+
50
+        // Clean opcode cache
51
+        $client = new GuzzleHttp\Client();
52
+        $client->request('GET', 'http://localhost:8080/apps/testing/clean_opcode_cache.php');
53
+
54
+        return $this->lastCode;
55
+    }
56
+
57
+    /**
58
+     * @Given /^invoking occ with "([^"]*)"$/
59
+     */
60
+    public function invokingTheCommand($cmd) {
61
+        $args = explode(' ', $cmd);
62
+        $this->runOcc($args);
63
+    }
64
+
65
+    /**
66
+     * @Given /^invoking occ with "([^"]*)" with input "([^"]+)"$/
67
+     */
68
+    public function invokingTheCommandWith($cmd, $inputString) {
69
+        $args = explode(' ', $cmd);
70
+        $this->runOcc($args, $inputString);
71
+    }
72
+
73
+    /**
74
+     * Find exception texts in stderr
75
+     */
76
+    public function findExceptions() {
77
+        $exceptions = [];
78
+        $captureNext = false;
79
+        // the exception text usually appears after an "[Exception"] row
80
+        foreach (explode("\n", $this->lastStdErr) as $line) {
81
+            if (preg_match('/\[Exception\]/', $line)) {
82
+                $captureNext = true;
83
+                continue;
84
+            }
85
+            if ($captureNext) {
86
+                $exceptions[] = trim($line);
87
+                $captureNext = false;
88
+            }
89
+        }
90
+
91
+        return $exceptions;
92
+    }
93
+
94
+    /**
95
+     * @Then /^the command was successful$/
96
+     */
97
+    public function theCommandWasSuccessful() {
98
+        $exceptions = $this->findExceptions();
99
+        if ($this->lastCode !== 0) {
100
+            $msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
101
+            if (!empty($exceptions)) {
102
+                $msg .= ' Exceptions: ' . implode(', ', $exceptions);
103
+            }
104
+            throw new \Exception($msg);
105
+        } elseif (!empty($exceptions)) {
106
+            $msg = 'The command was successful but triggered exceptions: ' . implode(', ', $exceptions);
107
+            throw new \Exception($msg);
108
+        }
109
+    }
110
+
111
+    /**
112
+     * @Then /^the command failed with exit code ([0-9]+)$/
113
+     */
114
+    public function theCommandFailedWithExitCode($exitCode) {
115
+        if ($this->lastCode !== (int)$exitCode) {
116
+            throw new \Exception('The command was expected to fail with exit code ' . $exitCode . ' but got ' . $this->lastCode);
117
+        }
118
+    }
119
+
120
+    /**
121
+     * @Then /^the command failed with exception text "([^"]*)"$/
122
+     */
123
+    public function theCommandFailedWithException($exceptionText) {
124
+        $exceptions = $this->findExceptions();
125
+        if (empty($exceptions)) {
126
+            throw new \Exception('The command did not throw any exceptions');
127
+        }
128
+
129
+        if (!in_array($exceptionText, $exceptions)) {
130
+            throw new \Exception('The command did not throw any exception with the text "' . $exceptionText . '"');
131
+        }
132
+    }
133
+
134
+    /**
135
+     * @Then /^the command output contains the text "([^"]*)"$/
136
+     */
137
+    public function theCommandOutputContainsTheText($text) {
138
+        Assert::assertStringContainsString($text, $this->lastStdOut, 'The command did not output the expected text on stdout');
139
+    }
140
+
141
+    /**
142
+     * @Then /^the command output does not contain the text "([^"]*)"$/
143
+     */
144
+    public function theCommandOutputDoesNotContainTheText($text) {
145
+        Assert::assertStringNotContainsString($text, $this->lastStdOut, 'The command did output the not expected text on stdout');
146
+    }
147
+
148
+    /**
149
+     * @Then /^the command error output contains the text "([^"]*)"$/
150
+     */
151
+    public function theCommandErrorOutputContainsTheText($text) {
152
+        Assert::assertStringContainsString($text, $this->lastStdErr, 'The command did not output the expected text on stderr');
153
+    }
154 154
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@  discard block
 block discarded – undo
7 7
  */
8 8
 use PHPUnit\Framework\Assert;
9 9
 
10
-require __DIR__ . '/../../vendor/autoload.php';
10
+require __DIR__.'/../../vendor/autoload.php';
11 11
 
12 12
 trait CommandLine {
13 13
 	/** @var int return code of last command */
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
 	 * @return int exit code
28 28
 	 */
29 29
 	public function runOcc($args = [], string $inputString = '') {
30
-		$args = array_map(function ($arg) {
30
+		$args = array_map(function($arg) {
31 31
 			return escapeshellarg($arg);
32 32
 		}, $args);
33 33
 		$args[] = '--no-ansi';
@@ -38,9 +38,9 @@  discard block
 block discarded – undo
38 38
 			1 => ['pipe', 'w'],
39 39
 			2 => ['pipe', 'w'],
40 40
 		];
41
-		$process = proc_open('php console.php ' . $args, $descriptor, $pipes, $this->ocPath);
41
+		$process = proc_open('php console.php '.$args, $descriptor, $pipes, $this->ocPath);
42 42
 		if ($inputString !== '') {
43
-			fwrite($pipes[0], $inputString . "\n");
43
+			fwrite($pipes[0], $inputString."\n");
44 44
 			fclose($pipes[0]);
45 45
 		}
46 46
 		$this->lastStdOut = stream_get_contents($pipes[1]);
@@ -97,13 +97,13 @@  discard block
 block discarded – undo
97 97
 	public function theCommandWasSuccessful() {
98 98
 		$exceptions = $this->findExceptions();
99 99
 		if ($this->lastCode !== 0) {
100
-			$msg = 'The command was not successful, exit code was ' . $this->lastCode . '.';
100
+			$msg = 'The command was not successful, exit code was '.$this->lastCode.'.';
101 101
 			if (!empty($exceptions)) {
102
-				$msg .= ' Exceptions: ' . implode(', ', $exceptions);
102
+				$msg .= ' Exceptions: '.implode(', ', $exceptions);
103 103
 			}
104 104
 			throw new \Exception($msg);
105 105
 		} elseif (!empty($exceptions)) {
106
-			$msg = 'The command was successful but triggered exceptions: ' . implode(', ', $exceptions);
106
+			$msg = 'The command was successful but triggered exceptions: '.implode(', ', $exceptions);
107 107
 			throw new \Exception($msg);
108 108
 		}
109 109
 	}
@@ -112,8 +112,8 @@  discard block
 block discarded – undo
112 112
 	 * @Then /^the command failed with exit code ([0-9]+)$/
113 113
 	 */
114 114
 	public function theCommandFailedWithExitCode($exitCode) {
115
-		if ($this->lastCode !== (int)$exitCode) {
116
-			throw new \Exception('The command was expected to fail with exit code ' . $exitCode . ' but got ' . $this->lastCode);
115
+		if ($this->lastCode !== (int) $exitCode) {
116
+			throw new \Exception('The command was expected to fail with exit code '.$exitCode.' but got '.$this->lastCode);
117 117
 		}
118 118
 	}
119 119
 
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
 		}
128 128
 
129 129
 		if (!in_array($exceptionText, $exceptions)) {
130
-			throw new \Exception('The command did not throw any exception with the text "' . $exceptionText . '"');
130
+			throw new \Exception('The command did not throw any exception with the text "'.$exceptionText.'"');
131 131
 		}
132 132
 	}
133 133
 
Please login to merge, or discard this patch.