Completed
Push — master ( ca1fc2...aba39c )
by Joas
31:19 queued 16s
created
tests/lib/Files/Mount/ObjectHomeMountProviderTest.php 1 patch
Indentation   +223 added lines, -223 removed lines patch added patch discarded remove patch
@@ -12,232 +12,232 @@
 block discarded – undo
12 12
 use OCP\IUser;
13 13
 
14 14
 class ObjectHomeMountProviderTest extends \Test\TestCase {
15
-	/** @var ObjectHomeMountProvider */
16
-	protected $provider;
17
-
18
-	/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
19
-	protected $config;
20
-
21
-	/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
22
-	protected $user;
23
-
24
-	/** @var IStorageFactory|\PHPUnit\Framework\MockObject\MockObject */
25
-	protected $loader;
26
-
27
-	protected function setUp(): void {
28
-		parent::setUp();
29
-
30
-		$this->config = $this->createMock(IConfig::class);
31
-		$this->user = $this->createMock(IUser::class);
32
-		$this->loader = $this->createMock(IStorageFactory::class);
33
-
34
-		$this->provider = new ObjectHomeMountProvider($this->config);
35
-	}
36
-
37
-	public function testSingleBucket(): void {
38
-		$this->config->expects($this->once())
39
-			->method('getSystemValue')
40
-			->with($this->equalTo('objectstore'), '')
41
-			->willReturn([
42
-				'class' => 'Test\Files\Mount\FakeObjectStore',
43
-			]);
44
-
45
-		$this->user->expects($this->never())->method($this->anything());
46
-		$this->loader->expects($this->never())->method($this->anything());
47
-
48
-		$config = $this->invokePrivate($this->provider, 'getSingleBucketObjectStoreConfig', [$this->user, $this->loader]);
49
-
50
-		$this->assertArrayHasKey('class', $config);
51
-		$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
52
-		$this->assertArrayHasKey('arguments', $config);
53
-		$this->assertArrayHasKey('user', $config['arguments']);
54
-		$this->assertSame($this->user, $config['arguments']['user']);
55
-		$this->assertArrayHasKey('objectstore', $config['arguments']);
56
-		$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
57
-	}
58
-
59
-	public function testMultiBucket(): void {
60
-		$this->config->expects($this->exactly(2))
61
-			->method('getSystemValue')
62
-			->with($this->equalTo('objectstore_multibucket'), '')
63
-			->willReturn([
64
-				'class' => 'Test\Files\Mount\FakeObjectStore',
65
-			]);
66
-
67
-		$this->user->method('getUID')
68
-			->willReturn('uid');
69
-		$this->loader->expects($this->never())->method($this->anything());
70
-
71
-		$this->config->expects($this->once())
72
-			->method('getUserValue')
73
-			->with(
74
-				$this->equalTo('uid'),
75
-				$this->equalTo('homeobjectstore'),
76
-				$this->equalTo('bucket'),
77
-				$this->equalTo(null)
78
-			)->willReturn(null);
79
-
80
-		$this->config->expects($this->once())
81
-			->method('setUserValue')
82
-			->with(
83
-				$this->equalTo('uid'),
84
-				$this->equalTo('homeobjectstore'),
85
-				$this->equalTo('bucket'),
86
-				$this->equalTo('49'),
87
-				$this->equalTo(null)
88
-			);
89
-
90
-		$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
91
-
92
-		$this->assertArrayHasKey('class', $config);
93
-		$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
94
-		$this->assertArrayHasKey('arguments', $config);
95
-		$this->assertArrayHasKey('user', $config['arguments']);
96
-		$this->assertSame($this->user, $config['arguments']['user']);
97
-		$this->assertArrayHasKey('objectstore', $config['arguments']);
98
-		$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
99
-		$this->assertArrayHasKey('bucket', $config['arguments']);
100
-		$this->assertEquals('49', $config['arguments']['bucket']);
101
-	}
102
-
103
-	public function testMultiBucketWithPrefix(): void {
104
-		$this->config->expects($this->exactly(2))
105
-			->method('getSystemValue')
106
-			->with('objectstore_multibucket')
107
-			->willReturn([
108
-				'class' => 'Test\Files\Mount\FakeObjectStore',
109
-				'arguments' => [
110
-					'bucket' => 'myBucketPrefix',
111
-				],
112
-			]);
113
-
114
-		$this->user->method('getUID')
115
-			->willReturn('uid');
116
-		$this->loader->expects($this->never())->method($this->anything());
117
-
118
-		$this->config->expects($this->once())
119
-			->method('getUserValue')
120
-			->with(
121
-				$this->equalTo('uid'),
122
-				$this->equalTo('homeobjectstore'),
123
-				$this->equalTo('bucket'),
124
-				$this->equalTo(null)
125
-			)->willReturn(null);
126
-
127
-		$this->config->expects($this->once())
128
-			->method('setUserValue')
129
-			->with(
130
-				$this->equalTo('uid'),
131
-				$this->equalTo('homeobjectstore'),
132
-				$this->equalTo('bucket'),
133
-				$this->equalTo('myBucketPrefix49'),
134
-				$this->equalTo(null)
135
-			);
136
-
137
-		$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
138
-
139
-		$this->assertArrayHasKey('class', $config);
140
-		$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
141
-		$this->assertArrayHasKey('arguments', $config);
142
-		$this->assertArrayHasKey('user', $config['arguments']);
143
-		$this->assertSame($this->user, $config['arguments']['user']);
144
-		$this->assertArrayHasKey('objectstore', $config['arguments']);
145
-		$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
146
-		$this->assertArrayHasKey('bucket', $config['arguments']);
147
-		$this->assertEquals('myBucketPrefix49', $config['arguments']['bucket']);
148
-	}
149
-
150
-	public function testMultiBucketBucketAlreadySet(): void {
151
-		$this->config->expects($this->once())
152
-			->method('getSystemValue')
153
-			->with('objectstore_multibucket')
154
-			->willReturn([
155
-				'class' => 'Test\Files\Mount\FakeObjectStore',
156
-				'arguments' => [
157
-					'bucket' => 'myBucketPrefix',
158
-				],
159
-			]);
160
-
161
-		$this->user->method('getUID')
162
-			->willReturn('uid');
163
-		$this->loader->expects($this->never())->method($this->anything());
164
-
165
-		$this->config->expects($this->once())
166
-			->method('getUserValue')
167
-			->with(
168
-				$this->equalTo('uid'),
169
-				$this->equalTo('homeobjectstore'),
170
-				$this->equalTo('bucket'),
171
-				$this->equalTo(null)
172
-			)->willReturn('awesomeBucket1');
173
-
174
-		$this->config->expects($this->never())
175
-			->method('setUserValue');
176
-
177
-		$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
178
-
179
-		$this->assertArrayHasKey('class', $config);
180
-		$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
181
-		$this->assertArrayHasKey('arguments', $config);
182
-		$this->assertArrayHasKey('user', $config['arguments']);
183
-		$this->assertSame($this->user, $config['arguments']['user']);
184
-		$this->assertArrayHasKey('objectstore', $config['arguments']);
185
-		$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
186
-		$this->assertArrayHasKey('bucket', $config['arguments']);
187
-		$this->assertEquals('awesomeBucket1', $config['arguments']['bucket']);
188
-	}
189
-
190
-	public function testMultiBucketConfigFirst(): void {
191
-		$this->config->expects($this->exactly(2))
192
-			->method('getSystemValue')
193
-			->with('objectstore_multibucket')
194
-			->willReturn([
195
-				'class' => 'Test\Files\Mount\FakeObjectStore',
196
-			]);
197
-
198
-		$this->user->method('getUID')
199
-			->willReturn('uid');
200
-		$this->loader->expects($this->never())->method($this->anything());
201
-
202
-		$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
203
-		$this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount);
204
-	}
205
-
206
-	public function testMultiBucketConfigFirstFallBackSingle(): void {
207
-		$this->config->expects($this->exactly(2))
208
-			->method('getSystemValue')->willReturnMap([
209
-				['objectstore_multibucket', '', ''],
210
-				['objectstore', '', [
211
-					'class' => 'Test\Files\Mount\FakeObjectStore',
212
-				]],
213
-			]);
214
-
215
-		$this->user->method('getUID')
216
-			->willReturn('uid');
217
-		$this->loader->expects($this->never())->method($this->anything());
218
-
219
-		$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
220
-		$this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount);
221
-	}
222
-
223
-	public function testNoObjectStore(): void {
224
-		$this->config->expects($this->exactly(2))
225
-			->method('getSystemValue')
226
-			->willReturn('');
227
-
228
-		$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
229
-		$this->assertNull($mount);
230
-	}
15
+    /** @var ObjectHomeMountProvider */
16
+    protected $provider;
17
+
18
+    /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
19
+    protected $config;
20
+
21
+    /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
22
+    protected $user;
23
+
24
+    /** @var IStorageFactory|\PHPUnit\Framework\MockObject\MockObject */
25
+    protected $loader;
26
+
27
+    protected function setUp(): void {
28
+        parent::setUp();
29
+
30
+        $this->config = $this->createMock(IConfig::class);
31
+        $this->user = $this->createMock(IUser::class);
32
+        $this->loader = $this->createMock(IStorageFactory::class);
33
+
34
+        $this->provider = new ObjectHomeMountProvider($this->config);
35
+    }
36
+
37
+    public function testSingleBucket(): void {
38
+        $this->config->expects($this->once())
39
+            ->method('getSystemValue')
40
+            ->with($this->equalTo('objectstore'), '')
41
+            ->willReturn([
42
+                'class' => 'Test\Files\Mount\FakeObjectStore',
43
+            ]);
44
+
45
+        $this->user->expects($this->never())->method($this->anything());
46
+        $this->loader->expects($this->never())->method($this->anything());
47
+
48
+        $config = $this->invokePrivate($this->provider, 'getSingleBucketObjectStoreConfig', [$this->user, $this->loader]);
49
+
50
+        $this->assertArrayHasKey('class', $config);
51
+        $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
52
+        $this->assertArrayHasKey('arguments', $config);
53
+        $this->assertArrayHasKey('user', $config['arguments']);
54
+        $this->assertSame($this->user, $config['arguments']['user']);
55
+        $this->assertArrayHasKey('objectstore', $config['arguments']);
56
+        $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
57
+    }
58
+
59
+    public function testMultiBucket(): void {
60
+        $this->config->expects($this->exactly(2))
61
+            ->method('getSystemValue')
62
+            ->with($this->equalTo('objectstore_multibucket'), '')
63
+            ->willReturn([
64
+                'class' => 'Test\Files\Mount\FakeObjectStore',
65
+            ]);
66
+
67
+        $this->user->method('getUID')
68
+            ->willReturn('uid');
69
+        $this->loader->expects($this->never())->method($this->anything());
70
+
71
+        $this->config->expects($this->once())
72
+            ->method('getUserValue')
73
+            ->with(
74
+                $this->equalTo('uid'),
75
+                $this->equalTo('homeobjectstore'),
76
+                $this->equalTo('bucket'),
77
+                $this->equalTo(null)
78
+            )->willReturn(null);
79
+
80
+        $this->config->expects($this->once())
81
+            ->method('setUserValue')
82
+            ->with(
83
+                $this->equalTo('uid'),
84
+                $this->equalTo('homeobjectstore'),
85
+                $this->equalTo('bucket'),
86
+                $this->equalTo('49'),
87
+                $this->equalTo(null)
88
+            );
89
+
90
+        $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
91
+
92
+        $this->assertArrayHasKey('class', $config);
93
+        $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
94
+        $this->assertArrayHasKey('arguments', $config);
95
+        $this->assertArrayHasKey('user', $config['arguments']);
96
+        $this->assertSame($this->user, $config['arguments']['user']);
97
+        $this->assertArrayHasKey('objectstore', $config['arguments']);
98
+        $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
99
+        $this->assertArrayHasKey('bucket', $config['arguments']);
100
+        $this->assertEquals('49', $config['arguments']['bucket']);
101
+    }
102
+
103
+    public function testMultiBucketWithPrefix(): void {
104
+        $this->config->expects($this->exactly(2))
105
+            ->method('getSystemValue')
106
+            ->with('objectstore_multibucket')
107
+            ->willReturn([
108
+                'class' => 'Test\Files\Mount\FakeObjectStore',
109
+                'arguments' => [
110
+                    'bucket' => 'myBucketPrefix',
111
+                ],
112
+            ]);
113
+
114
+        $this->user->method('getUID')
115
+            ->willReturn('uid');
116
+        $this->loader->expects($this->never())->method($this->anything());
117
+
118
+        $this->config->expects($this->once())
119
+            ->method('getUserValue')
120
+            ->with(
121
+                $this->equalTo('uid'),
122
+                $this->equalTo('homeobjectstore'),
123
+                $this->equalTo('bucket'),
124
+                $this->equalTo(null)
125
+            )->willReturn(null);
126
+
127
+        $this->config->expects($this->once())
128
+            ->method('setUserValue')
129
+            ->with(
130
+                $this->equalTo('uid'),
131
+                $this->equalTo('homeobjectstore'),
132
+                $this->equalTo('bucket'),
133
+                $this->equalTo('myBucketPrefix49'),
134
+                $this->equalTo(null)
135
+            );
136
+
137
+        $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
138
+
139
+        $this->assertArrayHasKey('class', $config);
140
+        $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
141
+        $this->assertArrayHasKey('arguments', $config);
142
+        $this->assertArrayHasKey('user', $config['arguments']);
143
+        $this->assertSame($this->user, $config['arguments']['user']);
144
+        $this->assertArrayHasKey('objectstore', $config['arguments']);
145
+        $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
146
+        $this->assertArrayHasKey('bucket', $config['arguments']);
147
+        $this->assertEquals('myBucketPrefix49', $config['arguments']['bucket']);
148
+    }
149
+
150
+    public function testMultiBucketBucketAlreadySet(): void {
151
+        $this->config->expects($this->once())
152
+            ->method('getSystemValue')
153
+            ->with('objectstore_multibucket')
154
+            ->willReturn([
155
+                'class' => 'Test\Files\Mount\FakeObjectStore',
156
+                'arguments' => [
157
+                    'bucket' => 'myBucketPrefix',
158
+                ],
159
+            ]);
160
+
161
+        $this->user->method('getUID')
162
+            ->willReturn('uid');
163
+        $this->loader->expects($this->never())->method($this->anything());
164
+
165
+        $this->config->expects($this->once())
166
+            ->method('getUserValue')
167
+            ->with(
168
+                $this->equalTo('uid'),
169
+                $this->equalTo('homeobjectstore'),
170
+                $this->equalTo('bucket'),
171
+                $this->equalTo(null)
172
+            )->willReturn('awesomeBucket1');
173
+
174
+        $this->config->expects($this->never())
175
+            ->method('setUserValue');
176
+
177
+        $config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
178
+
179
+        $this->assertArrayHasKey('class', $config);
180
+        $this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
181
+        $this->assertArrayHasKey('arguments', $config);
182
+        $this->assertArrayHasKey('user', $config['arguments']);
183
+        $this->assertSame($this->user, $config['arguments']['user']);
184
+        $this->assertArrayHasKey('objectstore', $config['arguments']);
185
+        $this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
186
+        $this->assertArrayHasKey('bucket', $config['arguments']);
187
+        $this->assertEquals('awesomeBucket1', $config['arguments']['bucket']);
188
+    }
189
+
190
+    public function testMultiBucketConfigFirst(): void {
191
+        $this->config->expects($this->exactly(2))
192
+            ->method('getSystemValue')
193
+            ->with('objectstore_multibucket')
194
+            ->willReturn([
195
+                'class' => 'Test\Files\Mount\FakeObjectStore',
196
+            ]);
197
+
198
+        $this->user->method('getUID')
199
+            ->willReturn('uid');
200
+        $this->loader->expects($this->never())->method($this->anything());
201
+
202
+        $mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
203
+        $this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount);
204
+    }
205
+
206
+    public function testMultiBucketConfigFirstFallBackSingle(): void {
207
+        $this->config->expects($this->exactly(2))
208
+            ->method('getSystemValue')->willReturnMap([
209
+                ['objectstore_multibucket', '', ''],
210
+                ['objectstore', '', [
211
+                    'class' => 'Test\Files\Mount\FakeObjectStore',
212
+                ]],
213
+            ]);
214
+
215
+        $this->user->method('getUID')
216
+            ->willReturn('uid');
217
+        $this->loader->expects($this->never())->method($this->anything());
218
+
219
+        $mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
220
+        $this->assertInstanceOf('OC\Files\Mount\MountPoint', $mount);
221
+    }
222
+
223
+    public function testNoObjectStore(): void {
224
+        $this->config->expects($this->exactly(2))
225
+            ->method('getSystemValue')
226
+            ->willReturn('');
227
+
228
+        $mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
229
+        $this->assertNull($mount);
230
+    }
231 231
 }
232 232
 
233 233
 class FakeObjectStore {
234
-	private $arguments;
234
+    private $arguments;
235 235
 
236
-	public function __construct(array $arguments) {
237
-		$this->arguments = $arguments;
238
-	}
236
+    public function __construct(array $arguments) {
237
+        $this->arguments = $arguments;
238
+    }
239 239
 
240
-	public function getArguments() {
241
-		return $this->arguments;
242
-	}
240
+    public function getArguments() {
241
+        return $this->arguments;
242
+    }
243 243
 }
Please login to merge, or discard this patch.
tests/lib/Files/ViewTest.php 2 patches
Indentation   +2819 added lines, -2819 removed lines patch added patch discarded remove patch
@@ -39,40 +39,40 @@  discard block
 block discarded – undo
39 39
 use Test\Traits\UserTrait;
40 40
 
41 41
 class TemporaryNoTouch extends Temporary {
42
-	public function touch(string $path, ?int $mtime = null): bool {
43
-		return false;
44
-	}
42
+    public function touch(string $path, ?int $mtime = null): bool {
43
+        return false;
44
+    }
45 45
 }
46 46
 
47 47
 class TemporaryNoCross extends Temporary {
48
-	public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath, bool $preserveMtime = false): bool {
49
-		return Common::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime);
50
-	}
48
+    public function copyFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath, bool $preserveMtime = false): bool {
49
+        return Common::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime);
50
+    }
51 51
 
52
-	public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
53
-		return Common::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
54
-	}
52
+    public function moveFromStorage(IStorage $sourceStorage, string $sourceInternalPath, string $targetInternalPath): bool {
53
+        return Common::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
54
+    }
55 55
 }
56 56
 
57 57
 class TemporaryNoLocal extends Temporary {
58
-	public function instanceOfStorage(string $class): bool {
59
-		if ($class === '\OC\Files\Storage\Local') {
60
-			return false;
61
-		} else {
62
-			return parent::instanceOfStorage($class);
63
-		}
64
-	}
58
+    public function instanceOfStorage(string $class): bool {
59
+        if ($class === '\OC\Files\Storage\Local') {
60
+            return false;
61
+        } else {
62
+            return parent::instanceOfStorage($class);
63
+        }
64
+    }
65 65
 }
66 66
 
67 67
 class TestEventHandler {
68
-	public function umount() {
69
-	}
70
-	public function post_umount() {
71
-	}
72
-	public function preCallback() {
73
-	}
74
-	public function postCallback() {
75
-	}
68
+    public function umount() {
69
+    }
70
+    public function post_umount() {
71
+    }
72
+    public function preCallback() {
73
+    }
74
+    public function postCallback() {
75
+    }
76 76
 }
77 77
 
78 78
 /**
@@ -83,2802 +83,2802 @@  discard block
 block discarded – undo
83 83
  * @package Test\Files
84 84
  */
85 85
 class ViewTest extends \Test\TestCase {
86
-	use UserTrait;
87
-
88
-	/**
89
-	 * @var \OC\Files\Storage\Storage[] $storages
90
-	 */
91
-	private $storages = [];
92
-
93
-	/**
94
-	 * @var string
95
-	 */
96
-	private $user;
97
-
98
-	/**
99
-	 * @var \OCP\IUser
100
-	 */
101
-	private $userObject;
102
-
103
-	/**
104
-	 * @var \OCP\IGroup
105
-	 */
106
-	private $groupObject;
107
-
108
-	/** @var \OC\Files\Storage\Storage */
109
-	private $tempStorage;
110
-
111
-	protected function setUp(): void {
112
-		parent::setUp();
113
-		\OC_Hook::clear();
114
-
115
-		Server::get(IUserManager::class)->clearBackends();
116
-		Server::get(IUserManager::class)->registerBackend(new \Test\Util\User\Dummy());
117
-
118
-		//login
119
-		$userManager = \OC::$server->getUserManager();
120
-		$groupManager = \OC::$server->getGroupManager();
121
-		$this->user = 'test';
122
-		$this->userObject = $userManager->createUser('test', 'test');
123
-
124
-		$this->groupObject = $groupManager->createGroup('group1');
125
-		$this->groupObject->addUser($this->userObject);
126
-
127
-		self::loginAsUser($this->user);
128
-
129
-		/** @var IMountManager $manager */
130
-		$manager = \OC::$server->get(IMountManager::class);
131
-		$manager->removeMount('/test');
132
-
133
-		$this->tempStorage = null;
134
-	}
135
-
136
-	protected function tearDown(): void {
137
-		\OC_User::setUserId($this->user);
138
-		foreach ($this->storages as $storage) {
139
-			$cache = $storage->getCache();
140
-			$ids = $cache->getAll();
141
-			$cache->clear();
142
-		}
143
-
144
-		if ($this->tempStorage) {
145
-			system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
146
-		}
147
-
148
-		self::logout();
149
-
150
-		/** @var SetupManager $setupManager */
151
-		$setupManager = \OC::$server->get(SetupManager::class);
152
-		$setupManager->setupRoot();
153
-
154
-		$this->userObject->delete();
155
-		$this->groupObject->delete();
156
-
157
-		$mountProviderCollection = \OC::$server->getMountProviderCollection();
158
-		self::invokePrivate($mountProviderCollection, 'providers', [[]]);
159
-
160
-		parent::tearDown();
161
-	}
162
-
163
-	/**
164
-	 * @medium
165
-	 */
166
-	public function testCacheAPI(): void {
167
-		$storage1 = $this->getTestStorage();
168
-		$storage2 = $this->getTestStorage();
169
-		$storage3 = $this->getTestStorage();
170
-		$root = self::getUniqueID('/');
171
-		Filesystem::mount($storage1, [], $root . '/');
172
-		Filesystem::mount($storage2, [], $root . '/substorage');
173
-		Filesystem::mount($storage3, [], $root . '/folder/anotherstorage');
174
-		$textSize = strlen("dummy file data\n");
175
-		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo/logo.png');
176
-		$storageSize = $textSize * 2 + $imageSize;
177
-
178
-		$storageInfo = $storage3->getCache()->get('');
179
-		$this->assertEquals($storageSize, $storageInfo['size']);
180
-
181
-		$rootView = new View($root);
182
-
183
-		$cachedData = $rootView->getFileInfo('/foo.txt');
184
-		$this->assertEquals($textSize, $cachedData['size']);
185
-		$this->assertEquals('text/plain', $cachedData['mimetype']);
186
-		$this->assertNotEquals(-1, $cachedData['permissions']);
187
-
188
-		$cachedData = $rootView->getFileInfo('/');
189
-		$this->assertEquals($storageSize * 3, $cachedData['size']);
190
-		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
191
-
192
-		// get cached data excluding mount points
193
-		$cachedData = $rootView->getFileInfo('/', false);
194
-		$this->assertEquals($storageSize, $cachedData['size']);
195
-		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
196
-
197
-		$cachedData = $rootView->getFileInfo('/folder');
198
-		$this->assertEquals($storageSize + $textSize, $cachedData['size']);
199
-		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
200
-
201
-		$folderData = $rootView->getDirectoryContent('/');
202
-		/**
203
-		 * expected entries:
204
-		 * folder
205
-		 * foo.png
206
-		 * foo.txt
207
-		 * substorage
208
-		 */
209
-		$this->assertCount(4, $folderData);
210
-		$this->assertEquals('folder', $folderData[0]['name']);
211
-		$this->assertEquals('foo.png', $folderData[1]['name']);
212
-		$this->assertEquals('foo.txt', $folderData[2]['name']);
213
-		$this->assertEquals('substorage', $folderData[3]['name']);
214
-
215
-		$this->assertEquals($storageSize + $textSize, $folderData[0]['size']);
216
-		$this->assertEquals($imageSize, $folderData[1]['size']);
217
-		$this->assertEquals($textSize, $folderData[2]['size']);
218
-		$this->assertEquals($storageSize, $folderData[3]['size']);
219
-
220
-		$folderData = $rootView->getDirectoryContent('/substorage');
221
-		/**
222
-		 * expected entries:
223
-		 * folder
224
-		 * foo.png
225
-		 * foo.txt
226
-		 */
227
-		$this->assertCount(3, $folderData);
228
-		$this->assertEquals('folder', $folderData[0]['name']);
229
-		$this->assertEquals('foo.png', $folderData[1]['name']);
230
-		$this->assertEquals('foo.txt', $folderData[2]['name']);
231
-
232
-		$folderView = new View($root . '/folder');
233
-		$this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
234
-
235
-		$cachedData = $rootView->getFileInfo('/foo.txt');
236
-		$this->assertFalse($cachedData['encrypted']);
237
-		$id = $rootView->putFileInfo('/foo.txt', ['encrypted' => true]);
238
-		$cachedData = $rootView->getFileInfo('/foo.txt');
239
-		$this->assertTrue($cachedData['encrypted']);
240
-		$this->assertEquals($cachedData['fileid'], $id);
241
-
242
-		$this->assertFalse($rootView->getFileInfo('/non/existing'));
243
-		$this->assertEquals([], $rootView->getDirectoryContent('/non/existing'));
244
-	}
245
-
246
-	/**
247
-	 * @medium
248
-	 */
249
-	public function testGetPath(): void {
250
-		$storage1 = $this->getTestStorage();
251
-		$storage2 = $this->getTestStorage();
252
-		$storage3 = $this->getTestStorage();
253
-
254
-		Filesystem::mount($storage1, [], '/');
255
-		Filesystem::mount($storage2, [], '/substorage');
256
-		Filesystem::mount($storage3, [], '/folder/anotherstorage');
257
-
258
-		$rootView = new View('');
259
-
260
-
261
-		$cachedData = $rootView->getFileInfo('/foo.txt');
262
-		/** @var int $id1 */
263
-		$id1 = $cachedData['fileid'];
264
-		$this->assertEquals('/foo.txt', $rootView->getPath($id1));
265
-
266
-		$cachedData = $rootView->getFileInfo('/substorage/foo.txt');
267
-		/** @var int $id2 */
268
-		$id2 = $cachedData['fileid'];
269
-		$this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2));
270
-
271
-		$folderView = new View('/substorage');
272
-		$this->assertEquals('/foo.txt', $folderView->getPath($id2));
273
-	}
274
-
275
-
276
-	public function testGetPathNotExisting(): void {
277
-		$this->expectException(\OCP\Files\NotFoundException::class);
278
-
279
-		$storage1 = $this->getTestStorage();
280
-		Filesystem::mount($storage1, [], '/');
281
-
282
-		$rootView = new View('');
283
-		$cachedData = $rootView->getFileInfo('/foo.txt');
284
-		/** @var int $id1 */
285
-		$id1 = $cachedData['fileid'];
286
-		$folderView = new View('/substorage');
287
-		$this->assertNull($folderView->getPath($id1));
288
-	}
289
-
290
-	/**
291
-	 * @medium
292
-	 */
293
-	public function testMountPointOverwrite(): void {
294
-		$storage1 = $this->getTestStorage(false);
295
-		$storage2 = $this->getTestStorage();
296
-		$storage1->mkdir('substorage');
297
-		Filesystem::mount($storage1, [], '/');
298
-		Filesystem::mount($storage2, [], '/substorage');
299
-
300
-		$rootView = new View('');
301
-		$folderContent = $rootView->getDirectoryContent('/');
302
-		$this->assertCount(4, $folderContent);
303
-	}
304
-
305
-	public static function sharingDisabledPermissionProvider(): array {
306
-		return [
307
-			['no', '', true],
308
-			['yes', 'group1', false],
309
-		];
310
-	}
311
-
312
-	/**
313
-	 * @dataProvider sharingDisabledPermissionProvider
314
-	 */
315
-	public function testRemoveSharePermissionWhenSharingDisabledForUser($excludeGroups, $excludeGroupsList, $expectedShareable): void {
316
-		// Reset sharing disabled for users cache
317
-		self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
318
-
319
-		$config = \OC::$server->getConfig();
320
-		$oldExcludeGroupsFlag = $config->getAppValue('core', 'shareapi_exclude_groups', 'no');
321
-		$oldExcludeGroupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
322
-		$config->setAppValue('core', 'shareapi_exclude_groups', $excludeGroups);
323
-		$config->setAppValue('core', 'shareapi_exclude_groups_list', $excludeGroupsList);
324
-
325
-		$storage1 = $this->getTestStorage();
326
-		$storage2 = $this->getTestStorage();
327
-		Filesystem::mount($storage1, [], '/');
328
-		Filesystem::mount($storage2, [], '/mount');
329
-
330
-		$view = new View('/');
331
-
332
-		$folderContent = $view->getDirectoryContent('');
333
-		$this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
334
-
335
-		$folderContent = $view->getDirectoryContent('mount');
336
-		$this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
337
-
338
-		$config->setAppValue('core', 'shareapi_exclude_groups', $oldExcludeGroupsFlag);
339
-		$config->setAppValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList);
340
-
341
-		// Reset sharing disabled for users cache
342
-		self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
343
-	}
344
-
345
-	public function testCacheIncompleteFolder(): void {
346
-		$storage1 = $this->getTestStorage(false);
347
-		Filesystem::mount($storage1, [], '/incomplete');
348
-		$rootView = new View('/incomplete');
349
-
350
-		$entries = $rootView->getDirectoryContent('/');
351
-		$this->assertCount(3, $entries);
352
-
353
-		// /folder will already be in the cache but not scanned
354
-		$entries = $rootView->getDirectoryContent('/folder');
355
-		$this->assertCount(1, $entries);
356
-	}
357
-
358
-	public function testAutoScan(): void {
359
-		$storage1 = $this->getTestStorage(false);
360
-		$storage2 = $this->getTestStorage(false);
361
-		Filesystem::mount($storage1, [], '/');
362
-		Filesystem::mount($storage2, [], '/substorage');
363
-		$textSize = strlen("dummy file data\n");
364
-
365
-		$rootView = new View('');
366
-
367
-		$cachedData = $rootView->getFileInfo('/');
368
-		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
369
-		$this->assertEquals(-1, $cachedData['size']);
370
-
371
-		$folderData = $rootView->getDirectoryContent('/substorage/folder');
372
-		$this->assertEquals('text/plain', $folderData[0]['mimetype']);
373
-		$this->assertEquals($textSize, $folderData[0]['size']);
374
-	}
375
-
376
-	/**
377
-	 * @medium
378
-	 */
379
-	public function testSearch(): void {
380
-		$storage1 = $this->getTestStorage();
381
-		$storage2 = $this->getTestStorage();
382
-		$storage3 = $this->getTestStorage();
383
-		Filesystem::mount($storage1, [], '/');
384
-		Filesystem::mount($storage2, [], '/substorage');
385
-		Filesystem::mount($storage3, [], '/folder/anotherstorage');
386
-
387
-		$rootView = new View('');
388
-
389
-		$results = $rootView->search('foo');
390
-		$this->assertCount(6, $results);
391
-		$paths = [];
392
-		foreach ($results as $result) {
393
-			$this->assertEquals($result['path'], Filesystem::normalizePath($result['path']));
394
-			$paths[] = $result['path'];
395
-		}
396
-		$this->assertContains('/foo.txt', $paths);
397
-		$this->assertContains('/foo.png', $paths);
398
-		$this->assertContains('/substorage/foo.txt', $paths);
399
-		$this->assertContains('/substorage/foo.png', $paths);
400
-		$this->assertContains('/folder/anotherstorage/foo.txt', $paths);
401
-		$this->assertContains('/folder/anotherstorage/foo.png', $paths);
402
-
403
-		$folderView = new View('/folder');
404
-		$results = $folderView->search('bar');
405
-		$this->assertCount(2, $results);
406
-		$paths = [];
407
-		foreach ($results as $result) {
408
-			$paths[] = $result['path'];
409
-		}
410
-		$this->assertContains('/anotherstorage/folder/bar.txt', $paths);
411
-		$this->assertContains('/bar.txt', $paths);
412
-
413
-		$results = $folderView->search('foo');
414
-		$this->assertCount(2, $results);
415
-		$paths = [];
416
-		foreach ($results as $result) {
417
-			$paths[] = $result['path'];
418
-		}
419
-		$this->assertContains('/anotherstorage/foo.txt', $paths);
420
-		$this->assertContains('/anotherstorage/foo.png', $paths);
421
-
422
-		$this->assertCount(6, $rootView->searchByMime('text'));
423
-		$this->assertCount(3, $folderView->searchByMime('text'));
424
-	}
425
-
426
-	/**
427
-	 * @medium
428
-	 */
429
-	public function testWatcher(): void {
430
-		$storage1 = $this->getTestStorage();
431
-		Filesystem::mount($storage1, [], '/');
432
-		$storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
433
-
434
-		$rootView = new View('');
435
-
436
-		$cachedData = $rootView->getFileInfo('foo.txt');
437
-		$this->assertEquals(16, $cachedData['size']);
438
-
439
-		$rootView->putFileInfo('foo.txt', ['storage_mtime' => 10]);
440
-		$storage1->file_put_contents('foo.txt', 'foo');
441
-		clearstatcache();
442
-
443
-		$cachedData = $rootView->getFileInfo('foo.txt');
444
-		$this->assertEquals(3, $cachedData['size']);
445
-	}
446
-
447
-	/**
448
-	 * @medium
449
-	 */
450
-	public function testCopyBetweenStorageNoCross(): void {
451
-		$storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
452
-		$storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
453
-		$this->copyBetweenStorages($storage1, $storage2);
454
-	}
455
-
456
-	/**
457
-	 * @medium
458
-	 */
459
-	public function testCopyBetweenStorageCross(): void {
460
-		$storage1 = $this->getTestStorage();
461
-		$storage2 = $this->getTestStorage();
462
-		$this->copyBetweenStorages($storage1, $storage2);
463
-	}
464
-
465
-	/**
466
-	 * @medium
467
-	 */
468
-	public function testCopyBetweenStorageCrossNonLocal(): void {
469
-		$storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
470
-		$storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
471
-		$this->copyBetweenStorages($storage1, $storage2);
472
-	}
473
-
474
-	public function copyBetweenStorages($storage1, $storage2) {
475
-		Filesystem::mount($storage1, [], '/');
476
-		Filesystem::mount($storage2, [], '/substorage');
477
-
478
-		$rootView = new View('');
479
-		$rootView->mkdir('substorage/emptyfolder');
480
-		$rootView->copy('substorage', 'anotherfolder');
481
-		$this->assertTrue($rootView->is_dir('/anotherfolder'));
482
-		$this->assertTrue($rootView->is_dir('/substorage'));
483
-		$this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder'));
484
-		$this->assertTrue($rootView->is_dir('/substorage/emptyfolder'));
485
-		$this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt'));
486
-		$this->assertTrue($rootView->file_exists('/anotherfolder/foo.png'));
487
-		$this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt'));
488
-		$this->assertTrue($rootView->file_exists('/substorage/foo.txt'));
489
-		$this->assertTrue($rootView->file_exists('/substorage/foo.png'));
490
-		$this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt'));
491
-	}
492
-
493
-	/**
494
-	 * @medium
495
-	 */
496
-	public function testMoveBetweenStorageNoCross(): void {
497
-		$storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
498
-		$storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
499
-		$this->moveBetweenStorages($storage1, $storage2);
500
-	}
501
-
502
-	/**
503
-	 * @medium
504
-	 */
505
-	public function testMoveBetweenStorageCross(): void {
506
-		$storage1 = $this->getTestStorage();
507
-		$storage2 = $this->getTestStorage();
508
-		$this->moveBetweenStorages($storage1, $storage2);
509
-	}
510
-
511
-	/**
512
-	 * @medium
513
-	 */
514
-	public function testMoveBetweenStorageCrossNonLocal(): void {
515
-		$storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
516
-		$storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
517
-		$this->moveBetweenStorages($storage1, $storage2);
518
-	}
519
-
520
-	public function moveBetweenStorages($storage1, $storage2) {
521
-		Filesystem::mount($storage1, [], '/');
522
-		Filesystem::mount($storage2, [], '/substorage');
523
-
524
-		$rootView = new View('');
525
-		$rootView->rename('foo.txt', 'substorage/folder/foo.txt');
526
-		$this->assertFalse($rootView->file_exists('foo.txt'));
527
-		$this->assertTrue($rootView->file_exists('substorage/folder/foo.txt'));
528
-		$rootView->rename('substorage/folder', 'anotherfolder');
529
-		$this->assertFalse($rootView->is_dir('substorage/folder'));
530
-		$this->assertTrue($rootView->file_exists('anotherfolder/foo.txt'));
531
-		$this->assertTrue($rootView->file_exists('anotherfolder/bar.txt'));
532
-	}
533
-
534
-	/**
535
-	 * @medium
536
-	 */
537
-	public function testUnlink(): void {
538
-		$storage1 = $this->getTestStorage();
539
-		$storage2 = $this->getTestStorage();
540
-		Filesystem::mount($storage1, [], '/');
541
-		Filesystem::mount($storage2, [], '/substorage');
542
-
543
-		$rootView = new View('');
544
-		$rootView->file_put_contents('/foo.txt', 'asd');
545
-		$rootView->file_put_contents('/substorage/bar.txt', 'asd');
546
-
547
-		$this->assertTrue($rootView->file_exists('foo.txt'));
548
-		$this->assertTrue($rootView->file_exists('substorage/bar.txt'));
549
-
550
-		$this->assertTrue($rootView->unlink('foo.txt'));
551
-		$this->assertTrue($rootView->unlink('substorage/bar.txt'));
552
-
553
-		$this->assertFalse($rootView->file_exists('foo.txt'));
554
-		$this->assertFalse($rootView->file_exists('substorage/bar.txt'));
555
-	}
556
-
557
-	public static function rmdirOrUnlinkDataProvider(): array {
558
-		return [['rmdir'], ['unlink']];
559
-	}
560
-
561
-	/**
562
-	 * @dataProvider rmdirOrUnlinkDataProvider
563
-	 */
564
-	public function testRmdir($method): void {
565
-		$storage1 = $this->getTestStorage();
566
-		Filesystem::mount($storage1, [], '/');
567
-
568
-		$rootView = new View('');
569
-		$rootView->mkdir('sub');
570
-		$rootView->mkdir('sub/deep');
571
-		$rootView->file_put_contents('/sub/deep/foo.txt', 'asd');
572
-
573
-		$this->assertTrue($rootView->file_exists('sub/deep/foo.txt'));
574
-
575
-		$this->assertTrue($rootView->$method('sub'));
576
-
577
-		$this->assertFalse($rootView->file_exists('sub'));
578
-	}
579
-
580
-	/**
581
-	 * @medium
582
-	 */
583
-	public function testUnlinkRootMustFail(): void {
584
-		$storage1 = $this->getTestStorage();
585
-		$storage2 = $this->getTestStorage();
586
-		Filesystem::mount($storage1, [], '/');
587
-		Filesystem::mount($storage2, [], '/substorage');
588
-
589
-		$rootView = new View('');
590
-		$rootView->file_put_contents('/foo.txt', 'asd');
591
-		$rootView->file_put_contents('/substorage/bar.txt', 'asd');
592
-
593
-		$this->assertFalse($rootView->unlink(''));
594
-		$this->assertFalse($rootView->unlink('/'));
595
-		$this->assertFalse($rootView->unlink('substorage'));
596
-		$this->assertFalse($rootView->unlink('/substorage'));
597
-	}
598
-
599
-	/**
600
-	 * @medium
601
-	 */
602
-	public function testTouch(): void {
603
-		$storage = $this->getTestStorage(true, TemporaryNoTouch::class);
604
-
605
-		Filesystem::mount($storage, [], '/');
606
-
607
-		$rootView = new View('');
608
-		$oldCachedData = $rootView->getFileInfo('foo.txt');
609
-
610
-		$rootView->touch('foo.txt', 500);
611
-
612
-		$cachedData = $rootView->getFileInfo('foo.txt');
613
-		$this->assertEquals(500, $cachedData['mtime']);
614
-		$this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']);
615
-
616
-		$rootView->putFileInfo('foo.txt', ['storage_mtime' => 1000]); //make sure the watcher detects the change
617
-		$rootView->file_put_contents('foo.txt', 'asd');
618
-		$cachedData = $rootView->getFileInfo('foo.txt');
619
-		$this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']);
620
-		$this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']);
621
-	}
622
-
623
-	/**
624
-	 * @medium
625
-	 */
626
-	public function testTouchFloat(): void {
627
-		$storage = $this->getTestStorage(true, TemporaryNoTouch::class);
628
-
629
-		Filesystem::mount($storage, [], '/');
630
-
631
-		$rootView = new View('');
632
-		$oldCachedData = $rootView->getFileInfo('foo.txt');
633
-
634
-		$rootView->touch('foo.txt', 500.5);
635
-
636
-		$cachedData = $rootView->getFileInfo('foo.txt');
637
-		$this->assertEquals(500, $cachedData['mtime']);
638
-	}
639
-
640
-	/**
641
-	 * @medium
642
-	 */
643
-	public function testViewHooks(): void {
644
-		$storage1 = $this->getTestStorage();
645
-		$storage2 = $this->getTestStorage();
646
-		$defaultRoot = Filesystem::getRoot();
647
-		Filesystem::mount($storage1, [], '/');
648
-		Filesystem::mount($storage2, [], $defaultRoot . '/substorage');
649
-		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
650
-
651
-		$rootView = new View('');
652
-		$subView = new View($defaultRoot . '/substorage');
653
-		$this->hookPath = null;
654
-
655
-		$rootView->file_put_contents('/foo.txt', 'asd');
656
-		$this->assertNull($this->hookPath);
657
-
658
-		$subView->file_put_contents('/foo.txt', 'asd');
659
-		$this->assertEquals('/substorage/foo.txt', $this->hookPath);
660
-	}
661
-
662
-	private $hookPath;
663
-
664
-	public function dummyHook($params) {
665
-		$this->hookPath = $params['path'];
666
-	}
667
-
668
-	public function testSearchNotOutsideView(): void {
669
-		$storage1 = $this->getTestStorage();
670
-		Filesystem::mount($storage1, [], '/');
671
-		$storage1->rename('folder', 'foo');
672
-		$scanner = $storage1->getScanner();
673
-		$scanner->scan('');
674
-
675
-		$view = new View('/foo');
676
-
677
-		$result = $view->search('.txt');
678
-		$this->assertCount(1, $result);
679
-	}
680
-
681
-	/**
682
-	 * @param bool $scan
683
-	 * @param string $class
684
-	 * @return \OC\Files\Storage\Storage
685
-	 */
686
-	private function getTestStorage($scan = true, $class = Temporary::class) {
687
-		/**
688
-		 * @var \OC\Files\Storage\Storage $storage
689
-		 */
690
-		$storage = new $class([]);
691
-		$textData = "dummy file data\n";
692
-		$imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo/logo.png');
693
-		$storage->mkdir('folder');
694
-		$storage->file_put_contents('foo.txt', $textData);
695
-		$storage->file_put_contents('foo.png', $imgData);
696
-		$storage->file_put_contents('folder/bar.txt', $textData);
697
-
698
-		if ($scan) {
699
-			$scanner = $storage->getScanner();
700
-			$scanner->scan('');
701
-		}
702
-		$this->storages[] = $storage;
703
-		return $storage;
704
-	}
705
-
706
-	/**
707
-	 * @medium
708
-	 */
709
-	public function testViewHooksIfRootStartsTheSame(): void {
710
-		$storage1 = $this->getTestStorage();
711
-		$storage2 = $this->getTestStorage();
712
-		$defaultRoot = Filesystem::getRoot();
713
-		Filesystem::mount($storage1, [], '/');
714
-		Filesystem::mount($storage2, [], $defaultRoot . '_substorage');
715
-		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
716
-
717
-		$subView = new View($defaultRoot . '_substorage');
718
-		$this->hookPath = null;
719
-
720
-		$subView->file_put_contents('/foo.txt', 'asd');
721
-		$this->assertNull($this->hookPath);
722
-	}
723
-
724
-	private $hookWritePath;
725
-	private $hookCreatePath;
726
-	private $hookUpdatePath;
727
-
728
-	public function dummyHookWrite($params) {
729
-		$this->hookWritePath = $params['path'];
730
-	}
731
-
732
-	public function dummyHookUpdate($params) {
733
-		$this->hookUpdatePath = $params['path'];
734
-	}
735
-
736
-	public function dummyHookCreate($params) {
737
-		$this->hookCreatePath = $params['path'];
738
-	}
739
-
740
-	public function testEditNoCreateHook(): void {
741
-		$storage1 = $this->getTestStorage();
742
-		$storage2 = $this->getTestStorage();
743
-		$defaultRoot = Filesystem::getRoot();
744
-		Filesystem::mount($storage1, [], '/');
745
-		Filesystem::mount($storage2, [], $defaultRoot);
746
-		\OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate');
747
-		\OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate');
748
-		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite');
749
-
750
-		$view = new View($defaultRoot);
751
-		$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
752
-
753
-		$view->file_put_contents('/asd.txt', 'foo');
754
-		$this->assertEquals('/asd.txt', $this->hookCreatePath);
755
-		$this->assertNull($this->hookUpdatePath);
756
-		$this->assertEquals('/asd.txt', $this->hookWritePath);
757
-
758
-		$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
759
-
760
-		$view->file_put_contents('/asd.txt', 'foo');
761
-		$this->assertNull($this->hookCreatePath);
762
-		$this->assertEquals('/asd.txt', $this->hookUpdatePath);
763
-		$this->assertEquals('/asd.txt', $this->hookWritePath);
764
-
765
-		\OC_Hook::clear('OC_Filesystem', 'post_create');
766
-		\OC_Hook::clear('OC_Filesystem', 'post_update');
767
-		\OC_Hook::clear('OC_Filesystem', 'post_write');
768
-	}
769
-
770
-	/**
771
-	 * @dataProvider resolvePathTestProvider
772
-	 */
773
-	public function testResolvePath($expected, $pathToTest): void {
774
-		$storage1 = $this->getTestStorage();
775
-		Filesystem::mount($storage1, [], '/');
776
-
777
-		$view = new View('');
778
-
779
-		$result = $view->resolvePath($pathToTest);
780
-		$this->assertEquals($expected, $result[1]);
781
-
782
-		$exists = $view->file_exists($pathToTest);
783
-		$this->assertTrue($exists);
784
-
785
-		$exists = $view->file_exists($result[1]);
786
-		$this->assertTrue($exists);
787
-	}
788
-
789
-	public static function resolvePathTestProvider(): array {
790
-		return [
791
-			['foo.txt', 'foo.txt'],
792
-			['foo.txt', '/foo.txt'],
793
-			['folder', 'folder'],
794
-			['folder', '/folder'],
795
-			['folder', 'folder/'],
796
-			['folder', '/folder/'],
797
-			['folder/bar.txt', 'folder/bar.txt'],
798
-			['folder/bar.txt', '/folder/bar.txt'],
799
-			['', ''],
800
-			['', '/'],
801
-		];
802
-	}
803
-
804
-	public function testUTF8Names(): void {
805
-		$names = ['虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا'];
806
-
807
-		$storage = new Temporary([]);
808
-		Filesystem::mount($storage, [], '/');
809
-
810
-		$rootView = new View('');
811
-		foreach ($names as $name) {
812
-			$rootView->file_put_contents('/' . $name, 'dummy content');
813
-		}
814
-
815
-		$list = $rootView->getDirectoryContent('/');
816
-
817
-		$this->assertCount(count($names), $list);
818
-		foreach ($list as $item) {
819
-			$this->assertContains($item['name'], $names);
820
-		}
821
-
822
-		$cache = $storage->getCache();
823
-		$scanner = $storage->getScanner();
824
-		$scanner->scan('');
825
-
826
-		$list = $cache->getFolderContents('');
827
-
828
-		$this->assertCount(count($names), $list);
829
-		foreach ($list as $item) {
830
-			$this->assertContains($item['name'], $names);
831
-		}
832
-	}
833
-
834
-	public function xtestLongPath() {
835
-		$storage = new Temporary([]);
836
-		Filesystem::mount($storage, [], '/');
837
-
838
-		$rootView = new View('');
839
-
840
-		$longPath = '';
841
-		$ds = DIRECTORY_SEPARATOR;
842
-		/*
86
+    use UserTrait;
87
+
88
+    /**
89
+     * @var \OC\Files\Storage\Storage[] $storages
90
+     */
91
+    private $storages = [];
92
+
93
+    /**
94
+     * @var string
95
+     */
96
+    private $user;
97
+
98
+    /**
99
+     * @var \OCP\IUser
100
+     */
101
+    private $userObject;
102
+
103
+    /**
104
+     * @var \OCP\IGroup
105
+     */
106
+    private $groupObject;
107
+
108
+    /** @var \OC\Files\Storage\Storage */
109
+    private $tempStorage;
110
+
111
+    protected function setUp(): void {
112
+        parent::setUp();
113
+        \OC_Hook::clear();
114
+
115
+        Server::get(IUserManager::class)->clearBackends();
116
+        Server::get(IUserManager::class)->registerBackend(new \Test\Util\User\Dummy());
117
+
118
+        //login
119
+        $userManager = \OC::$server->getUserManager();
120
+        $groupManager = \OC::$server->getGroupManager();
121
+        $this->user = 'test';
122
+        $this->userObject = $userManager->createUser('test', 'test');
123
+
124
+        $this->groupObject = $groupManager->createGroup('group1');
125
+        $this->groupObject->addUser($this->userObject);
126
+
127
+        self::loginAsUser($this->user);
128
+
129
+        /** @var IMountManager $manager */
130
+        $manager = \OC::$server->get(IMountManager::class);
131
+        $manager->removeMount('/test');
132
+
133
+        $this->tempStorage = null;
134
+    }
135
+
136
+    protected function tearDown(): void {
137
+        \OC_User::setUserId($this->user);
138
+        foreach ($this->storages as $storage) {
139
+            $cache = $storage->getCache();
140
+            $ids = $cache->getAll();
141
+            $cache->clear();
142
+        }
143
+
144
+        if ($this->tempStorage) {
145
+            system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
146
+        }
147
+
148
+        self::logout();
149
+
150
+        /** @var SetupManager $setupManager */
151
+        $setupManager = \OC::$server->get(SetupManager::class);
152
+        $setupManager->setupRoot();
153
+
154
+        $this->userObject->delete();
155
+        $this->groupObject->delete();
156
+
157
+        $mountProviderCollection = \OC::$server->getMountProviderCollection();
158
+        self::invokePrivate($mountProviderCollection, 'providers', [[]]);
159
+
160
+        parent::tearDown();
161
+    }
162
+
163
+    /**
164
+     * @medium
165
+     */
166
+    public function testCacheAPI(): void {
167
+        $storage1 = $this->getTestStorage();
168
+        $storage2 = $this->getTestStorage();
169
+        $storage3 = $this->getTestStorage();
170
+        $root = self::getUniqueID('/');
171
+        Filesystem::mount($storage1, [], $root . '/');
172
+        Filesystem::mount($storage2, [], $root . '/substorage');
173
+        Filesystem::mount($storage3, [], $root . '/folder/anotherstorage');
174
+        $textSize = strlen("dummy file data\n");
175
+        $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo/logo.png');
176
+        $storageSize = $textSize * 2 + $imageSize;
177
+
178
+        $storageInfo = $storage3->getCache()->get('');
179
+        $this->assertEquals($storageSize, $storageInfo['size']);
180
+
181
+        $rootView = new View($root);
182
+
183
+        $cachedData = $rootView->getFileInfo('/foo.txt');
184
+        $this->assertEquals($textSize, $cachedData['size']);
185
+        $this->assertEquals('text/plain', $cachedData['mimetype']);
186
+        $this->assertNotEquals(-1, $cachedData['permissions']);
187
+
188
+        $cachedData = $rootView->getFileInfo('/');
189
+        $this->assertEquals($storageSize * 3, $cachedData['size']);
190
+        $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
191
+
192
+        // get cached data excluding mount points
193
+        $cachedData = $rootView->getFileInfo('/', false);
194
+        $this->assertEquals($storageSize, $cachedData['size']);
195
+        $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
196
+
197
+        $cachedData = $rootView->getFileInfo('/folder');
198
+        $this->assertEquals($storageSize + $textSize, $cachedData['size']);
199
+        $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
200
+
201
+        $folderData = $rootView->getDirectoryContent('/');
202
+        /**
203
+         * expected entries:
204
+         * folder
205
+         * foo.png
206
+         * foo.txt
207
+         * substorage
208
+         */
209
+        $this->assertCount(4, $folderData);
210
+        $this->assertEquals('folder', $folderData[0]['name']);
211
+        $this->assertEquals('foo.png', $folderData[1]['name']);
212
+        $this->assertEquals('foo.txt', $folderData[2]['name']);
213
+        $this->assertEquals('substorage', $folderData[3]['name']);
214
+
215
+        $this->assertEquals($storageSize + $textSize, $folderData[0]['size']);
216
+        $this->assertEquals($imageSize, $folderData[1]['size']);
217
+        $this->assertEquals($textSize, $folderData[2]['size']);
218
+        $this->assertEquals($storageSize, $folderData[3]['size']);
219
+
220
+        $folderData = $rootView->getDirectoryContent('/substorage');
221
+        /**
222
+         * expected entries:
223
+         * folder
224
+         * foo.png
225
+         * foo.txt
226
+         */
227
+        $this->assertCount(3, $folderData);
228
+        $this->assertEquals('folder', $folderData[0]['name']);
229
+        $this->assertEquals('foo.png', $folderData[1]['name']);
230
+        $this->assertEquals('foo.txt', $folderData[2]['name']);
231
+
232
+        $folderView = new View($root . '/folder');
233
+        $this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
234
+
235
+        $cachedData = $rootView->getFileInfo('/foo.txt');
236
+        $this->assertFalse($cachedData['encrypted']);
237
+        $id = $rootView->putFileInfo('/foo.txt', ['encrypted' => true]);
238
+        $cachedData = $rootView->getFileInfo('/foo.txt');
239
+        $this->assertTrue($cachedData['encrypted']);
240
+        $this->assertEquals($cachedData['fileid'], $id);
241
+
242
+        $this->assertFalse($rootView->getFileInfo('/non/existing'));
243
+        $this->assertEquals([], $rootView->getDirectoryContent('/non/existing'));
244
+    }
245
+
246
+    /**
247
+     * @medium
248
+     */
249
+    public function testGetPath(): void {
250
+        $storage1 = $this->getTestStorage();
251
+        $storage2 = $this->getTestStorage();
252
+        $storage3 = $this->getTestStorage();
253
+
254
+        Filesystem::mount($storage1, [], '/');
255
+        Filesystem::mount($storage2, [], '/substorage');
256
+        Filesystem::mount($storage3, [], '/folder/anotherstorage');
257
+
258
+        $rootView = new View('');
259
+
260
+
261
+        $cachedData = $rootView->getFileInfo('/foo.txt');
262
+        /** @var int $id1 */
263
+        $id1 = $cachedData['fileid'];
264
+        $this->assertEquals('/foo.txt', $rootView->getPath($id1));
265
+
266
+        $cachedData = $rootView->getFileInfo('/substorage/foo.txt');
267
+        /** @var int $id2 */
268
+        $id2 = $cachedData['fileid'];
269
+        $this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2));
270
+
271
+        $folderView = new View('/substorage');
272
+        $this->assertEquals('/foo.txt', $folderView->getPath($id2));
273
+    }
274
+
275
+
276
+    public function testGetPathNotExisting(): void {
277
+        $this->expectException(\OCP\Files\NotFoundException::class);
278
+
279
+        $storage1 = $this->getTestStorage();
280
+        Filesystem::mount($storage1, [], '/');
281
+
282
+        $rootView = new View('');
283
+        $cachedData = $rootView->getFileInfo('/foo.txt');
284
+        /** @var int $id1 */
285
+        $id1 = $cachedData['fileid'];
286
+        $folderView = new View('/substorage');
287
+        $this->assertNull($folderView->getPath($id1));
288
+    }
289
+
290
+    /**
291
+     * @medium
292
+     */
293
+    public function testMountPointOverwrite(): void {
294
+        $storage1 = $this->getTestStorage(false);
295
+        $storage2 = $this->getTestStorage();
296
+        $storage1->mkdir('substorage');
297
+        Filesystem::mount($storage1, [], '/');
298
+        Filesystem::mount($storage2, [], '/substorage');
299
+
300
+        $rootView = new View('');
301
+        $folderContent = $rootView->getDirectoryContent('/');
302
+        $this->assertCount(4, $folderContent);
303
+    }
304
+
305
+    public static function sharingDisabledPermissionProvider(): array {
306
+        return [
307
+            ['no', '', true],
308
+            ['yes', 'group1', false],
309
+        ];
310
+    }
311
+
312
+    /**
313
+     * @dataProvider sharingDisabledPermissionProvider
314
+     */
315
+    public function testRemoveSharePermissionWhenSharingDisabledForUser($excludeGroups, $excludeGroupsList, $expectedShareable): void {
316
+        // Reset sharing disabled for users cache
317
+        self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
318
+
319
+        $config = \OC::$server->getConfig();
320
+        $oldExcludeGroupsFlag = $config->getAppValue('core', 'shareapi_exclude_groups', 'no');
321
+        $oldExcludeGroupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
322
+        $config->setAppValue('core', 'shareapi_exclude_groups', $excludeGroups);
323
+        $config->setAppValue('core', 'shareapi_exclude_groups_list', $excludeGroupsList);
324
+
325
+        $storage1 = $this->getTestStorage();
326
+        $storage2 = $this->getTestStorage();
327
+        Filesystem::mount($storage1, [], '/');
328
+        Filesystem::mount($storage2, [], '/mount');
329
+
330
+        $view = new View('/');
331
+
332
+        $folderContent = $view->getDirectoryContent('');
333
+        $this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
334
+
335
+        $folderContent = $view->getDirectoryContent('mount');
336
+        $this->assertEquals($expectedShareable, $folderContent[0]->isShareable());
337
+
338
+        $config->setAppValue('core', 'shareapi_exclude_groups', $oldExcludeGroupsFlag);
339
+        $config->setAppValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList);
340
+
341
+        // Reset sharing disabled for users cache
342
+        self::invokePrivate(\OC::$server->get(ShareDisableChecker::class), 'sharingDisabledForUsersCache', [new CappedMemoryCache()]);
343
+    }
344
+
345
+    public function testCacheIncompleteFolder(): void {
346
+        $storage1 = $this->getTestStorage(false);
347
+        Filesystem::mount($storage1, [], '/incomplete');
348
+        $rootView = new View('/incomplete');
349
+
350
+        $entries = $rootView->getDirectoryContent('/');
351
+        $this->assertCount(3, $entries);
352
+
353
+        // /folder will already be in the cache but not scanned
354
+        $entries = $rootView->getDirectoryContent('/folder');
355
+        $this->assertCount(1, $entries);
356
+    }
357
+
358
+    public function testAutoScan(): void {
359
+        $storage1 = $this->getTestStorage(false);
360
+        $storage2 = $this->getTestStorage(false);
361
+        Filesystem::mount($storage1, [], '/');
362
+        Filesystem::mount($storage2, [], '/substorage');
363
+        $textSize = strlen("dummy file data\n");
364
+
365
+        $rootView = new View('');
366
+
367
+        $cachedData = $rootView->getFileInfo('/');
368
+        $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
369
+        $this->assertEquals(-1, $cachedData['size']);
370
+
371
+        $folderData = $rootView->getDirectoryContent('/substorage/folder');
372
+        $this->assertEquals('text/plain', $folderData[0]['mimetype']);
373
+        $this->assertEquals($textSize, $folderData[0]['size']);
374
+    }
375
+
376
+    /**
377
+     * @medium
378
+     */
379
+    public function testSearch(): void {
380
+        $storage1 = $this->getTestStorage();
381
+        $storage2 = $this->getTestStorage();
382
+        $storage3 = $this->getTestStorage();
383
+        Filesystem::mount($storage1, [], '/');
384
+        Filesystem::mount($storage2, [], '/substorage');
385
+        Filesystem::mount($storage3, [], '/folder/anotherstorage');
386
+
387
+        $rootView = new View('');
388
+
389
+        $results = $rootView->search('foo');
390
+        $this->assertCount(6, $results);
391
+        $paths = [];
392
+        foreach ($results as $result) {
393
+            $this->assertEquals($result['path'], Filesystem::normalizePath($result['path']));
394
+            $paths[] = $result['path'];
395
+        }
396
+        $this->assertContains('/foo.txt', $paths);
397
+        $this->assertContains('/foo.png', $paths);
398
+        $this->assertContains('/substorage/foo.txt', $paths);
399
+        $this->assertContains('/substorage/foo.png', $paths);
400
+        $this->assertContains('/folder/anotherstorage/foo.txt', $paths);
401
+        $this->assertContains('/folder/anotherstorage/foo.png', $paths);
402
+
403
+        $folderView = new View('/folder');
404
+        $results = $folderView->search('bar');
405
+        $this->assertCount(2, $results);
406
+        $paths = [];
407
+        foreach ($results as $result) {
408
+            $paths[] = $result['path'];
409
+        }
410
+        $this->assertContains('/anotherstorage/folder/bar.txt', $paths);
411
+        $this->assertContains('/bar.txt', $paths);
412
+
413
+        $results = $folderView->search('foo');
414
+        $this->assertCount(2, $results);
415
+        $paths = [];
416
+        foreach ($results as $result) {
417
+            $paths[] = $result['path'];
418
+        }
419
+        $this->assertContains('/anotherstorage/foo.txt', $paths);
420
+        $this->assertContains('/anotherstorage/foo.png', $paths);
421
+
422
+        $this->assertCount(6, $rootView->searchByMime('text'));
423
+        $this->assertCount(3, $folderView->searchByMime('text'));
424
+    }
425
+
426
+    /**
427
+     * @medium
428
+     */
429
+    public function testWatcher(): void {
430
+        $storage1 = $this->getTestStorage();
431
+        Filesystem::mount($storage1, [], '/');
432
+        $storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
433
+
434
+        $rootView = new View('');
435
+
436
+        $cachedData = $rootView->getFileInfo('foo.txt');
437
+        $this->assertEquals(16, $cachedData['size']);
438
+
439
+        $rootView->putFileInfo('foo.txt', ['storage_mtime' => 10]);
440
+        $storage1->file_put_contents('foo.txt', 'foo');
441
+        clearstatcache();
442
+
443
+        $cachedData = $rootView->getFileInfo('foo.txt');
444
+        $this->assertEquals(3, $cachedData['size']);
445
+    }
446
+
447
+    /**
448
+     * @medium
449
+     */
450
+    public function testCopyBetweenStorageNoCross(): void {
451
+        $storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
452
+        $storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
453
+        $this->copyBetweenStorages($storage1, $storage2);
454
+    }
455
+
456
+    /**
457
+     * @medium
458
+     */
459
+    public function testCopyBetweenStorageCross(): void {
460
+        $storage1 = $this->getTestStorage();
461
+        $storage2 = $this->getTestStorage();
462
+        $this->copyBetweenStorages($storage1, $storage2);
463
+    }
464
+
465
+    /**
466
+     * @medium
467
+     */
468
+    public function testCopyBetweenStorageCrossNonLocal(): void {
469
+        $storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
470
+        $storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
471
+        $this->copyBetweenStorages($storage1, $storage2);
472
+    }
473
+
474
+    public function copyBetweenStorages($storage1, $storage2) {
475
+        Filesystem::mount($storage1, [], '/');
476
+        Filesystem::mount($storage2, [], '/substorage');
477
+
478
+        $rootView = new View('');
479
+        $rootView->mkdir('substorage/emptyfolder');
480
+        $rootView->copy('substorage', 'anotherfolder');
481
+        $this->assertTrue($rootView->is_dir('/anotherfolder'));
482
+        $this->assertTrue($rootView->is_dir('/substorage'));
483
+        $this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder'));
484
+        $this->assertTrue($rootView->is_dir('/substorage/emptyfolder'));
485
+        $this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt'));
486
+        $this->assertTrue($rootView->file_exists('/anotherfolder/foo.png'));
487
+        $this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt'));
488
+        $this->assertTrue($rootView->file_exists('/substorage/foo.txt'));
489
+        $this->assertTrue($rootView->file_exists('/substorage/foo.png'));
490
+        $this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt'));
491
+    }
492
+
493
+    /**
494
+     * @medium
495
+     */
496
+    public function testMoveBetweenStorageNoCross(): void {
497
+        $storage1 = $this->getTestStorage(true, TemporaryNoCross::class);
498
+        $storage2 = $this->getTestStorage(true, TemporaryNoCross::class);
499
+        $this->moveBetweenStorages($storage1, $storage2);
500
+    }
501
+
502
+    /**
503
+     * @medium
504
+     */
505
+    public function testMoveBetweenStorageCross(): void {
506
+        $storage1 = $this->getTestStorage();
507
+        $storage2 = $this->getTestStorage();
508
+        $this->moveBetweenStorages($storage1, $storage2);
509
+    }
510
+
511
+    /**
512
+     * @medium
513
+     */
514
+    public function testMoveBetweenStorageCrossNonLocal(): void {
515
+        $storage1 = $this->getTestStorage(true, TemporaryNoLocal::class);
516
+        $storage2 = $this->getTestStorage(true, TemporaryNoLocal::class);
517
+        $this->moveBetweenStorages($storage1, $storage2);
518
+    }
519
+
520
+    public function moveBetweenStorages($storage1, $storage2) {
521
+        Filesystem::mount($storage1, [], '/');
522
+        Filesystem::mount($storage2, [], '/substorage');
523
+
524
+        $rootView = new View('');
525
+        $rootView->rename('foo.txt', 'substorage/folder/foo.txt');
526
+        $this->assertFalse($rootView->file_exists('foo.txt'));
527
+        $this->assertTrue($rootView->file_exists('substorage/folder/foo.txt'));
528
+        $rootView->rename('substorage/folder', 'anotherfolder');
529
+        $this->assertFalse($rootView->is_dir('substorage/folder'));
530
+        $this->assertTrue($rootView->file_exists('anotherfolder/foo.txt'));
531
+        $this->assertTrue($rootView->file_exists('anotherfolder/bar.txt'));
532
+    }
533
+
534
+    /**
535
+     * @medium
536
+     */
537
+    public function testUnlink(): void {
538
+        $storage1 = $this->getTestStorage();
539
+        $storage2 = $this->getTestStorage();
540
+        Filesystem::mount($storage1, [], '/');
541
+        Filesystem::mount($storage2, [], '/substorage');
542
+
543
+        $rootView = new View('');
544
+        $rootView->file_put_contents('/foo.txt', 'asd');
545
+        $rootView->file_put_contents('/substorage/bar.txt', 'asd');
546
+
547
+        $this->assertTrue($rootView->file_exists('foo.txt'));
548
+        $this->assertTrue($rootView->file_exists('substorage/bar.txt'));
549
+
550
+        $this->assertTrue($rootView->unlink('foo.txt'));
551
+        $this->assertTrue($rootView->unlink('substorage/bar.txt'));
552
+
553
+        $this->assertFalse($rootView->file_exists('foo.txt'));
554
+        $this->assertFalse($rootView->file_exists('substorage/bar.txt'));
555
+    }
556
+
557
+    public static function rmdirOrUnlinkDataProvider(): array {
558
+        return [['rmdir'], ['unlink']];
559
+    }
560
+
561
+    /**
562
+     * @dataProvider rmdirOrUnlinkDataProvider
563
+     */
564
+    public function testRmdir($method): void {
565
+        $storage1 = $this->getTestStorage();
566
+        Filesystem::mount($storage1, [], '/');
567
+
568
+        $rootView = new View('');
569
+        $rootView->mkdir('sub');
570
+        $rootView->mkdir('sub/deep');
571
+        $rootView->file_put_contents('/sub/deep/foo.txt', 'asd');
572
+
573
+        $this->assertTrue($rootView->file_exists('sub/deep/foo.txt'));
574
+
575
+        $this->assertTrue($rootView->$method('sub'));
576
+
577
+        $this->assertFalse($rootView->file_exists('sub'));
578
+    }
579
+
580
+    /**
581
+     * @medium
582
+     */
583
+    public function testUnlinkRootMustFail(): void {
584
+        $storage1 = $this->getTestStorage();
585
+        $storage2 = $this->getTestStorage();
586
+        Filesystem::mount($storage1, [], '/');
587
+        Filesystem::mount($storage2, [], '/substorage');
588
+
589
+        $rootView = new View('');
590
+        $rootView->file_put_contents('/foo.txt', 'asd');
591
+        $rootView->file_put_contents('/substorage/bar.txt', 'asd');
592
+
593
+        $this->assertFalse($rootView->unlink(''));
594
+        $this->assertFalse($rootView->unlink('/'));
595
+        $this->assertFalse($rootView->unlink('substorage'));
596
+        $this->assertFalse($rootView->unlink('/substorage'));
597
+    }
598
+
599
+    /**
600
+     * @medium
601
+     */
602
+    public function testTouch(): void {
603
+        $storage = $this->getTestStorage(true, TemporaryNoTouch::class);
604
+
605
+        Filesystem::mount($storage, [], '/');
606
+
607
+        $rootView = new View('');
608
+        $oldCachedData = $rootView->getFileInfo('foo.txt');
609
+
610
+        $rootView->touch('foo.txt', 500);
611
+
612
+        $cachedData = $rootView->getFileInfo('foo.txt');
613
+        $this->assertEquals(500, $cachedData['mtime']);
614
+        $this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']);
615
+
616
+        $rootView->putFileInfo('foo.txt', ['storage_mtime' => 1000]); //make sure the watcher detects the change
617
+        $rootView->file_put_contents('foo.txt', 'asd');
618
+        $cachedData = $rootView->getFileInfo('foo.txt');
619
+        $this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']);
620
+        $this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']);
621
+    }
622
+
623
+    /**
624
+     * @medium
625
+     */
626
+    public function testTouchFloat(): void {
627
+        $storage = $this->getTestStorage(true, TemporaryNoTouch::class);
628
+
629
+        Filesystem::mount($storage, [], '/');
630
+
631
+        $rootView = new View('');
632
+        $oldCachedData = $rootView->getFileInfo('foo.txt');
633
+
634
+        $rootView->touch('foo.txt', 500.5);
635
+
636
+        $cachedData = $rootView->getFileInfo('foo.txt');
637
+        $this->assertEquals(500, $cachedData['mtime']);
638
+    }
639
+
640
+    /**
641
+     * @medium
642
+     */
643
+    public function testViewHooks(): void {
644
+        $storage1 = $this->getTestStorage();
645
+        $storage2 = $this->getTestStorage();
646
+        $defaultRoot = Filesystem::getRoot();
647
+        Filesystem::mount($storage1, [], '/');
648
+        Filesystem::mount($storage2, [], $defaultRoot . '/substorage');
649
+        \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
650
+
651
+        $rootView = new View('');
652
+        $subView = new View($defaultRoot . '/substorage');
653
+        $this->hookPath = null;
654
+
655
+        $rootView->file_put_contents('/foo.txt', 'asd');
656
+        $this->assertNull($this->hookPath);
657
+
658
+        $subView->file_put_contents('/foo.txt', 'asd');
659
+        $this->assertEquals('/substorage/foo.txt', $this->hookPath);
660
+    }
661
+
662
+    private $hookPath;
663
+
664
+    public function dummyHook($params) {
665
+        $this->hookPath = $params['path'];
666
+    }
667
+
668
+    public function testSearchNotOutsideView(): void {
669
+        $storage1 = $this->getTestStorage();
670
+        Filesystem::mount($storage1, [], '/');
671
+        $storage1->rename('folder', 'foo');
672
+        $scanner = $storage1->getScanner();
673
+        $scanner->scan('');
674
+
675
+        $view = new View('/foo');
676
+
677
+        $result = $view->search('.txt');
678
+        $this->assertCount(1, $result);
679
+    }
680
+
681
+    /**
682
+     * @param bool $scan
683
+     * @param string $class
684
+     * @return \OC\Files\Storage\Storage
685
+     */
686
+    private function getTestStorage($scan = true, $class = Temporary::class) {
687
+        /**
688
+         * @var \OC\Files\Storage\Storage $storage
689
+         */
690
+        $storage = new $class([]);
691
+        $textData = "dummy file data\n";
692
+        $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo/logo.png');
693
+        $storage->mkdir('folder');
694
+        $storage->file_put_contents('foo.txt', $textData);
695
+        $storage->file_put_contents('foo.png', $imgData);
696
+        $storage->file_put_contents('folder/bar.txt', $textData);
697
+
698
+        if ($scan) {
699
+            $scanner = $storage->getScanner();
700
+            $scanner->scan('');
701
+        }
702
+        $this->storages[] = $storage;
703
+        return $storage;
704
+    }
705
+
706
+    /**
707
+     * @medium
708
+     */
709
+    public function testViewHooksIfRootStartsTheSame(): void {
710
+        $storage1 = $this->getTestStorage();
711
+        $storage2 = $this->getTestStorage();
712
+        $defaultRoot = Filesystem::getRoot();
713
+        Filesystem::mount($storage1, [], '/');
714
+        Filesystem::mount($storage2, [], $defaultRoot . '_substorage');
715
+        \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
716
+
717
+        $subView = new View($defaultRoot . '_substorage');
718
+        $this->hookPath = null;
719
+
720
+        $subView->file_put_contents('/foo.txt', 'asd');
721
+        $this->assertNull($this->hookPath);
722
+    }
723
+
724
+    private $hookWritePath;
725
+    private $hookCreatePath;
726
+    private $hookUpdatePath;
727
+
728
+    public function dummyHookWrite($params) {
729
+        $this->hookWritePath = $params['path'];
730
+    }
731
+
732
+    public function dummyHookUpdate($params) {
733
+        $this->hookUpdatePath = $params['path'];
734
+    }
735
+
736
+    public function dummyHookCreate($params) {
737
+        $this->hookCreatePath = $params['path'];
738
+    }
739
+
740
+    public function testEditNoCreateHook(): void {
741
+        $storage1 = $this->getTestStorage();
742
+        $storage2 = $this->getTestStorage();
743
+        $defaultRoot = Filesystem::getRoot();
744
+        Filesystem::mount($storage1, [], '/');
745
+        Filesystem::mount($storage2, [], $defaultRoot);
746
+        \OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate');
747
+        \OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate');
748
+        \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite');
749
+
750
+        $view = new View($defaultRoot);
751
+        $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
752
+
753
+        $view->file_put_contents('/asd.txt', 'foo');
754
+        $this->assertEquals('/asd.txt', $this->hookCreatePath);
755
+        $this->assertNull($this->hookUpdatePath);
756
+        $this->assertEquals('/asd.txt', $this->hookWritePath);
757
+
758
+        $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
759
+
760
+        $view->file_put_contents('/asd.txt', 'foo');
761
+        $this->assertNull($this->hookCreatePath);
762
+        $this->assertEquals('/asd.txt', $this->hookUpdatePath);
763
+        $this->assertEquals('/asd.txt', $this->hookWritePath);
764
+
765
+        \OC_Hook::clear('OC_Filesystem', 'post_create');
766
+        \OC_Hook::clear('OC_Filesystem', 'post_update');
767
+        \OC_Hook::clear('OC_Filesystem', 'post_write');
768
+    }
769
+
770
+    /**
771
+     * @dataProvider resolvePathTestProvider
772
+     */
773
+    public function testResolvePath($expected, $pathToTest): void {
774
+        $storage1 = $this->getTestStorage();
775
+        Filesystem::mount($storage1, [], '/');
776
+
777
+        $view = new View('');
778
+
779
+        $result = $view->resolvePath($pathToTest);
780
+        $this->assertEquals($expected, $result[1]);
781
+
782
+        $exists = $view->file_exists($pathToTest);
783
+        $this->assertTrue($exists);
784
+
785
+        $exists = $view->file_exists($result[1]);
786
+        $this->assertTrue($exists);
787
+    }
788
+
789
+    public static function resolvePathTestProvider(): array {
790
+        return [
791
+            ['foo.txt', 'foo.txt'],
792
+            ['foo.txt', '/foo.txt'],
793
+            ['folder', 'folder'],
794
+            ['folder', '/folder'],
795
+            ['folder', 'folder/'],
796
+            ['folder', '/folder/'],
797
+            ['folder/bar.txt', 'folder/bar.txt'],
798
+            ['folder/bar.txt', '/folder/bar.txt'],
799
+            ['', ''],
800
+            ['', '/'],
801
+        ];
802
+    }
803
+
804
+    public function testUTF8Names(): void {
805
+        $names = ['虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا'];
806
+
807
+        $storage = new Temporary([]);
808
+        Filesystem::mount($storage, [], '/');
809
+
810
+        $rootView = new View('');
811
+        foreach ($names as $name) {
812
+            $rootView->file_put_contents('/' . $name, 'dummy content');
813
+        }
814
+
815
+        $list = $rootView->getDirectoryContent('/');
816
+
817
+        $this->assertCount(count($names), $list);
818
+        foreach ($list as $item) {
819
+            $this->assertContains($item['name'], $names);
820
+        }
821
+
822
+        $cache = $storage->getCache();
823
+        $scanner = $storage->getScanner();
824
+        $scanner->scan('');
825
+
826
+        $list = $cache->getFolderContents('');
827
+
828
+        $this->assertCount(count($names), $list);
829
+        foreach ($list as $item) {
830
+            $this->assertContains($item['name'], $names);
831
+        }
832
+    }
833
+
834
+    public function xtestLongPath() {
835
+        $storage = new Temporary([]);
836
+        Filesystem::mount($storage, [], '/');
837
+
838
+        $rootView = new View('');
839
+
840
+        $longPath = '';
841
+        $ds = DIRECTORY_SEPARATOR;
842
+        /*
843 843
 		 * 4096 is the maximum path length in file_cache.path in *nix
844 844
 		 * 1024 is the max path length in mac
845 845
 		 */
846
-		$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
847
-		$tmpdirLength = strlen(\OC::$server->getTempManager()->getTemporaryFolder());
848
-		if (\OC_Util::runningOnMac()) {
849
-			$depth = ((1024 - $tmpdirLength) / 57);
850
-		} else {
851
-			$depth = ((4000 - $tmpdirLength) / 57);
852
-		}
853
-		foreach (range(0, $depth - 1) as $i) {
854
-			$longPath .= $ds . $folderName;
855
-			$result = $rootView->mkdir($longPath);
856
-			$this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
857
-
858
-			$result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
859
-			$this->assertEquals(5, $result, "file_put_contents failed on $i");
860
-
861
-			$this->assertTrue($rootView->file_exists($longPath));
862
-			$this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
863
-		}
864
-
865
-		$cache = $storage->getCache();
866
-		$scanner = $storage->getScanner();
867
-		$scanner->scan('');
868
-
869
-		$longPath = $folderName;
870
-		foreach (range(0, $depth - 1) as $i) {
871
-			$cachedFolder = $cache->get($longPath);
872
-			$this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
873
-			$this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
874
-
875
-			$cachedFile = $cache->get($longPath . '/test.txt');
876
-			$this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
877
-			$this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
878
-
879
-			$longPath .= $ds . $folderName;
880
-		}
881
-	}
882
-
883
-	public function testTouchNotSupported(): void {
884
-		$storage = new TemporaryNoTouch([]);
885
-		$scanner = $storage->getScanner();
886
-		Filesystem::mount($storage, [], '/test/');
887
-		$past = time() - 100;
888
-		$storage->file_put_contents('test', 'foobar');
889
-		$scanner->scan('');
890
-		$view = new View('');
891
-		$info = $view->getFileInfo('/test/test');
892
-
893
-		$view->touch('/test/test', $past);
894
-		$scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG);
895
-
896
-		$info2 = $view->getFileInfo('/test/test');
897
-		$this->assertSame($info['etag'], $info2['etag']);
898
-	}
899
-
900
-	public function testWatcherEtagCrossStorage(): void {
901
-		$storage1 = new Temporary([]);
902
-		$storage2 = new Temporary([]);
903
-		$scanner1 = $storage1->getScanner();
904
-		$scanner2 = $storage2->getScanner();
905
-		$storage1->mkdir('sub');
906
-		Filesystem::mount($storage1, [], '/test/');
907
-		Filesystem::mount($storage2, [], '/test/sub/storage');
908
-
909
-		$past = time() - 100;
910
-		$storage2->file_put_contents('test.txt', 'foobar');
911
-		$scanner1->scan('');
912
-		$scanner2->scan('');
913
-		$view = new View('');
914
-
915
-		$storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS);
916
-
917
-		$oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt');
918
-		$oldFolderInfo = $view->getFileInfo('/test');
919
-
920
-		$storage2->getCache()->update($oldFileInfo->getId(), [
921
-			'storage_mtime' => $past,
922
-		]);
923
-
924
-		$oldEtag = $oldFolderInfo->getEtag();
925
-
926
-		$view->getFileInfo('/test/sub/storage/test.txt');
927
-		$newFolderInfo = $view->getFileInfo('/test');
928
-
929
-		$this->assertNotEquals($newFolderInfo->getEtag(), $oldEtag);
930
-	}
931
-
932
-	/**
933
-	 * @dataProvider absolutePathProvider
934
-	 */
935
-	public function testGetAbsolutePath($expectedPath, $relativePath): void {
936
-		$view = new View('/files');
937
-		$this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath));
938
-	}
939
-
940
-	public function testPartFileInfo(): void {
941
-		$storage = new Temporary([]);
942
-		$scanner = $storage->getScanner();
943
-		Filesystem::mount($storage, [], '/test/');
944
-		$storage->file_put_contents('test.part', 'foobar');
945
-		$scanner->scan('');
946
-		$view = new View('/test');
947
-		$info = $view->getFileInfo('test.part');
948
-
949
-		$this->assertInstanceOf('\OCP\Files\FileInfo', $info);
950
-		$this->assertNull($info->getId());
951
-		$this->assertEquals(6, $info->getSize());
952
-	}
953
-
954
-	public static function absolutePathProvider(): array {
955
-		return [
956
-			['/files/', ''],
957
-			['/files/0', '0'],
958
-			['/files/false', 'false'],
959
-			['/files/true', 'true'],
960
-			['/files/', '/'],
961
-			['/files/test', 'test'],
962
-			['/files/test', '/test'],
963
-		];
964
-	}
965
-
966
-	/**
967
-	 * @dataProvider chrootRelativePathProvider
968
-	 */
969
-	public function testChrootGetRelativePath($root, $absolutePath, $expectedPath): void {
970
-		$view = new View('/files');
971
-		$view->chroot($root);
972
-		$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
973
-	}
974
-
975
-	public static function chrootRelativePathProvider(): array {
976
-		return self::relativePathProvider('/');
977
-	}
978
-
979
-	/**
980
-	 * @dataProvider initRelativePathProvider
981
-	 */
982
-	public function testInitGetRelativePath($root, $absolutePath, $expectedPath): void {
983
-		$view = new View($root);
984
-		$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
985
-	}
986
-
987
-	public static function initRelativePathProvider(): array {
988
-		return self::relativePathProvider(null);
989
-	}
990
-
991
-	public static function relativePathProvider($missingRootExpectedPath): array {
992
-		return [
993
-			// No root - returns the path
994
-			['', '/files', '/files'],
995
-			['', '/files/', '/files/'],
996
-
997
-			// Root equals path - /
998
-			['/files/', '/files/', '/'],
999
-			['/files/', '/files', '/'],
1000
-			['/files', '/files/', '/'],
1001
-			['/files', '/files', '/'],
1002
-
1003
-			// False negatives: chroot fixes those by adding the leading slash.
1004
-			// But setting them up with this root (instead of chroot($root))
1005
-			// will fail them, although they should be the same.
1006
-			// TODO init should be fixed, so it also adds the leading slash
1007
-			['files/', '/files/', $missingRootExpectedPath],
1008
-			['files', '/files/', $missingRootExpectedPath],
1009
-			['files/', '/files', $missingRootExpectedPath],
1010
-			['files', '/files', $missingRootExpectedPath],
1011
-
1012
-			// False negatives: Paths provided to the method should have a leading slash
1013
-			// TODO input should be checked to have a leading slash
1014
-			['/files/', 'files/', null],
1015
-			['/files', 'files/', null],
1016
-			['/files/', 'files', null],
1017
-			['/files', 'files', null],
1018
-
1019
-			// with trailing slashes
1020
-			['/files/', '/files/0', '0'],
1021
-			['/files/', '/files/false', 'false'],
1022
-			['/files/', '/files/true', 'true'],
1023
-			['/files/', '/files/test', 'test'],
1024
-			['/files/', '/files/test/foo', 'test/foo'],
1025
-
1026
-			// without trailing slashes
1027
-			// TODO false expectation: Should match "with trailing slashes"
1028
-			['/files', '/files/0', '/0'],
1029
-			['/files', '/files/false', '/false'],
1030
-			['/files', '/files/true', '/true'],
1031
-			['/files', '/files/test', '/test'],
1032
-			['/files', '/files/test/foo', '/test/foo'],
1033
-
1034
-			// leading slashes
1035
-			['/files/', '/files_trashbin/', null],
1036
-			['/files', '/files_trashbin/', null],
1037
-			['/files/', '/files_trashbin', null],
1038
-			['/files', '/files_trashbin', null],
1039
-
1040
-			// no leading slashes
1041
-			['files/', 'files_trashbin/', null],
1042
-			['files', 'files_trashbin/', null],
1043
-			['files/', 'files_trashbin', null],
1044
-			['files', 'files_trashbin', null],
1045
-
1046
-			// mixed leading slashes
1047
-			['files/', '/files_trashbin/', null],
1048
-			['/files/', 'files_trashbin/', null],
1049
-			['files', '/files_trashbin/', null],
1050
-			['/files', 'files_trashbin/', null],
1051
-			['files/', '/files_trashbin', null],
1052
-			['/files/', 'files_trashbin', null],
1053
-			['files', '/files_trashbin', null],
1054
-			['/files', 'files_trashbin', null],
1055
-
1056
-			['files', 'files_trashbin/test', null],
1057
-			['/files', '/files_trashbin/test', null],
1058
-			['/files', 'files_trashbin/test', null],
1059
-		];
1060
-	}
1061
-
1062
-	public function testFileView(): void {
1063
-		$storage = new Temporary([]);
1064
-		$scanner = $storage->getScanner();
1065
-		$storage->file_put_contents('foo.txt', 'bar');
1066
-		Filesystem::mount($storage, [], '/test/');
1067
-		$scanner->scan('');
1068
-		$view = new View('/test/foo.txt');
1069
-
1070
-		$this->assertEquals('bar', $view->file_get_contents(''));
1071
-		$fh = tmpfile();
1072
-		fwrite($fh, 'foo');
1073
-		rewind($fh);
1074
-		$view->file_put_contents('', $fh);
1075
-		$this->assertEquals('foo', $view->file_get_contents(''));
1076
-	}
1077
-
1078
-	/**
1079
-	 * @dataProvider tooLongPathDataProvider
1080
-	 */
1081
-	public function testTooLongPath($operation, $param0 = null): void {
1082
-		$this->expectException(\OCP\Files\InvalidPathException::class);
1083
-
1084
-
1085
-		$longPath = '';
1086
-		// 4000 is the maximum path length in file_cache.path
1087
-		$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
1088
-		$depth = (4000 / 57);
1089
-		foreach (range(0, $depth + 1) as $i) {
1090
-			$longPath .= '/' . $folderName;
1091
-		}
1092
-
1093
-		$storage = new Temporary([]);
1094
-		$this->tempStorage = $storage; // for later hard cleanup
1095
-		Filesystem::mount($storage, [], '/');
1096
-
1097
-		$rootView = new View('');
1098
-
1099
-		if ($param0 === '@0') {
1100
-			$param0 = $longPath;
1101
-		}
1102
-
1103
-		if ($operation === 'hash') {
1104
-			$param0 = $longPath;
1105
-			$longPath = 'md5';
1106
-		}
1107
-
1108
-		call_user_func([$rootView, $operation], $longPath, $param0);
1109
-	}
1110
-
1111
-	public static function tooLongPathDataProvider(): array {
1112
-		return [
1113
-			['getAbsolutePath'],
1114
-			['getRelativePath'],
1115
-			['getMountPoint'],
1116
-			['resolvePath'],
1117
-			['getLocalFile'],
1118
-			['mkdir'],
1119
-			['rmdir'],
1120
-			['opendir'],
1121
-			['is_dir'],
1122
-			['is_file'],
1123
-			['stat'],
1124
-			['filetype'],
1125
-			['filesize'],
1126
-			['readfile'],
1127
-			['isCreatable'],
1128
-			['isReadable'],
1129
-			['isUpdatable'],
1130
-			['isDeletable'],
1131
-			['isSharable'],
1132
-			['file_exists'],
1133
-			['filemtime'],
1134
-			['touch'],
1135
-			['file_get_contents'],
1136
-			['unlink'],
1137
-			['deleteAll'],
1138
-			['toTmpFile'],
1139
-			['getMimeType'],
1140
-			['free_space'],
1141
-			['getFileInfo'],
1142
-			['getDirectoryContent'],
1143
-			['getOwner'],
1144
-			['getETag'],
1145
-			['file_put_contents', 'ipsum'],
1146
-			['rename', '@0'],
1147
-			['copy', '@0'],
1148
-			['fopen', 'r'],
1149
-			['fromTmpFile', '@0'],
1150
-			['hash'],
1151
-			['hasUpdated', 0],
1152
-			['putFileInfo', []],
1153
-		];
1154
-	}
1155
-
1156
-	public function testRenameCrossStoragePreserveMtime(): void {
1157
-		$storage1 = new Temporary([]);
1158
-		$storage2 = new Temporary([]);
1159
-		$storage1->mkdir('sub');
1160
-		$storage1->mkdir('foo');
1161
-		$storage1->file_put_contents('foo.txt', 'asd');
1162
-		$storage1->file_put_contents('foo/bar.txt', 'asd');
1163
-		Filesystem::mount($storage1, [], '/test/');
1164
-		Filesystem::mount($storage2, [], '/test/sub/storage');
1165
-
1166
-		$view = new View('');
1167
-		$time = time() - 200;
1168
-		$view->touch('/test/foo.txt', $time);
1169
-		$view->touch('/test/foo', $time);
1170
-		$view->touch('/test/foo/bar.txt', $time);
1171
-
1172
-		$view->rename('/test/foo.txt', '/test/sub/storage/foo.txt');
1173
-
1174
-		$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt'));
1175
-
1176
-		$view->rename('/test/foo', '/test/sub/storage/foo');
1177
-
1178
-		$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt'));
1179
-	}
1180
-
1181
-	public function testRenameFailDeleteTargetKeepSource(): void {
1182
-		$this->doTestCopyRenameFail('rename');
1183
-	}
1184
-
1185
-	public function testCopyFailDeleteTargetKeepSource(): void {
1186
-		$this->doTestCopyRenameFail('copy');
1187
-	}
1188
-
1189
-	private function doTestCopyRenameFail($operation) {
1190
-		$storage1 = new Temporary([]);
1191
-		/** @var \PHPUnit\Framework\MockObject\MockObject|Temporary $storage2 */
1192
-		$storage2 = $this->getMockBuilder(TemporaryNoCross::class)
1193
-			->setConstructorArgs([[]])
1194
-			->onlyMethods(['fopen', 'writeStream'])
1195
-			->getMock();
1196
-
1197
-		$storage2->method('writeStream')
1198
-			->willThrowException(new GenericFileException('Failed to copy stream'));
1199
-
1200
-		$storage1->mkdir('sub');
1201
-		$storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
1202
-		$storage1->mkdir('dirtomove');
1203
-		$storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
1204
-		$storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
1205
-		$storage2->file_put_contents('existing.txt', '0123');
1206
-		$storage1->getScanner()->scan('');
1207
-		$storage2->getScanner()->scan('');
1208
-		Filesystem::mount($storage1, [], '/test/');
1209
-		Filesystem::mount($storage2, [], '/test/sub/storage');
1210
-
1211
-		// move file
1212
-		$view = new View('');
1213
-		$this->assertTrue($storage1->file_exists('foo.txt'));
1214
-		$this->assertFalse($storage2->file_exists('foo.txt'));
1215
-		$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt'));
1216
-		$this->assertFalse($storage2->file_exists('foo.txt'));
1217
-		$this->assertFalse($storage2->getCache()->get('foo.txt'));
1218
-		$this->assertTrue($storage1->file_exists('foo.txt'));
1219
-
1220
-		// if target exists, it will be deleted too
1221
-		$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt'));
1222
-		$this->assertFalse($storage2->file_exists('existing.txt'));
1223
-		$this->assertFalse($storage2->getCache()->get('existing.txt'));
1224
-		$this->assertTrue($storage1->file_exists('foo.txt'));
1225
-
1226
-		// move folder
1227
-		$this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/'));
1228
-		// since the move failed, the full source tree is kept
1229
-		$this->assertTrue($storage1->file_exists('dirtomove/indir1.txt'));
1230
-		$this->assertTrue($storage1->file_exists('dirtomove/indir2.txt'));
1231
-		// second file not moved/copied
1232
-		$this->assertFalse($storage2->file_exists('dirtomove/indir2.txt'));
1233
-		$this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt'));
1234
-	}
1235
-
1236
-	public function testDeleteFailKeepCache(): void {
1237
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
1238
-		$storage = $this->getMockBuilder(Temporary::class)
1239
-			->setConstructorArgs([[]])
1240
-			->onlyMethods(['unlink'])
1241
-			->getMock();
1242
-		$storage->expects($this->once())
1243
-			->method('unlink')
1244
-			->willReturn(false);
1245
-		$scanner = $storage->getScanner();
1246
-		$cache = $storage->getCache();
1247
-		$storage->file_put_contents('foo.txt', 'asd');
1248
-		$scanner->scan('');
1249
-		Filesystem::mount($storage, [], '/test/');
1250
-
1251
-		$view = new View('/test');
1252
-
1253
-		$this->assertFalse($view->unlink('foo.txt'));
1254
-		$this->assertTrue($cache->inCache('foo.txt'));
1255
-	}
1256
-
1257
-	public static function directoryTraversalProvider(): array {
1258
-		return [
1259
-			['../test/'],
1260
-			['..\\test\\my/../folder'],
1261
-			['/test/my/../foo\\'],
1262
-		];
1263
-	}
1264
-
1265
-	/**
1266
-	 * @dataProvider directoryTraversalProvider
1267
-	 * @param string $root
1268
-	 */
1269
-	public function testConstructDirectoryTraversalException($root): void {
1270
-		$this->expectException(\Exception::class);
1271
-
1272
-		new View($root);
1273
-	}
1274
-
1275
-	public function testRenameOverWrite(): void {
1276
-		$storage = new Temporary([]);
1277
-		$scanner = $storage->getScanner();
1278
-		$storage->mkdir('sub');
1279
-		$storage->mkdir('foo');
1280
-		$storage->file_put_contents('foo.txt', 'asd');
1281
-		$storage->file_put_contents('foo/bar.txt', 'asd');
1282
-		$scanner->scan('');
1283
-		Filesystem::mount($storage, [], '/test/');
1284
-		$view = new View('');
1285
-		$this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt'));
1286
-	}
1287
-
1288
-	public function testSetMountOptionsInStorage(): void {
1289
-		$mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['foo' => 'bar']);
1290
-		Filesystem::getMountManager()->addMount($mount);
1291
-		/** @var \OC\Files\Storage\Common $storage */
1292
-		$storage = $mount->getStorage();
1293
-		$this->assertEquals($storage->getMountOption('foo'), 'bar');
1294
-	}
1295
-
1296
-	public function testSetMountOptionsWatcherPolicy(): void {
1297
-		$mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]);
1298
-		Filesystem::getMountManager()->addMount($mount);
1299
-		/** @var \OC\Files\Storage\Common $storage */
1300
-		$storage = $mount->getStorage();
1301
-		$watcher = $storage->getWatcher();
1302
-		$this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy());
1303
-	}
1304
-
1305
-	public function testGetAbsolutePathOnNull(): void {
1306
-		$view = new View();
1307
-		$this->assertNull($view->getAbsolutePath(null));
1308
-	}
1309
-
1310
-	public function testGetRelativePathOnNull(): void {
1311
-		$view = new View();
1312
-		$this->assertNull($view->getRelativePath(null));
1313
-	}
1314
-
1315
-
1316
-	public function testNullAsRoot(): void {
1317
-		$this->expectException(\TypeError::class);
1318
-
1319
-		new View(null);
1320
-	}
1321
-
1322
-	/**
1323
-	 * e.g. reading from a folder that's being renamed
1324
-	 *
1325
-	 *
1326
-	 * @dataProvider dataLockPaths
1327
-	 *
1328
-	 * @param string $rootPath
1329
-	 * @param string $pathPrefix
1330
-	 */
1331
-	public function testReadFromWriteLockedPath($rootPath, $pathPrefix): void {
1332
-		$this->expectException(\OCP\Lock\LockedException::class);
1333
-
1334
-		$rootPath = str_replace('{folder}', 'files', $rootPath);
1335
-		$pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
1336
-
1337
-		$view = new View($rootPath);
1338
-		$storage = new Temporary([]);
1339
-		Filesystem::mount($storage, [], '/');
1340
-		$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1341
-		$view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED);
1342
-	}
1343
-
1344
-	/**
1345
-	 * Reading from a files_encryption folder that's being renamed
1346
-	 *
1347
-	 * @dataProvider dataLockPaths
1348
-	 *
1349
-	 * @param string $rootPath
1350
-	 * @param string $pathPrefix
1351
-	 */
1352
-	public function testReadFromWriteUnlockablePath($rootPath, $pathPrefix): void {
1353
-		$rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
1354
-		$pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
1355
-
1356
-		$view = new View($rootPath);
1357
-		$storage = new Temporary([]);
1358
-		Filesystem::mount($storage, [], '/');
1359
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1360
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED));
1361
-	}
1362
-
1363
-	/**
1364
-	 * e.g. writing a file that's being downloaded
1365
-	 *
1366
-	 *
1367
-	 * @dataProvider dataLockPaths
1368
-	 *
1369
-	 * @param string $rootPath
1370
-	 * @param string $pathPrefix
1371
-	 */
1372
-	public function testWriteToReadLockedFile($rootPath, $pathPrefix): void {
1373
-		$this->expectException(\OCP\Lock\LockedException::class);
1374
-
1375
-		$rootPath = str_replace('{folder}', 'files', $rootPath);
1376
-		$pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
1377
-
1378
-		$view = new View($rootPath);
1379
-		$storage = new Temporary([]);
1380
-		Filesystem::mount($storage, [], '/');
1381
-		$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1382
-		$view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE);
1383
-	}
1384
-
1385
-	/**
1386
-	 * Writing a file that's being downloaded
1387
-	 *
1388
-	 * @dataProvider dataLockPaths
1389
-	 *
1390
-	 * @param string $rootPath
1391
-	 * @param string $pathPrefix
1392
-	 */
1393
-	public function testWriteToReadUnlockableFile($rootPath, $pathPrefix): void {
1394
-		$rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
1395
-		$pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
1396
-
1397
-		$view = new View($rootPath);
1398
-		$storage = new Temporary([]);
1399
-		Filesystem::mount($storage, [], '/');
1400
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1401
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1402
-	}
1403
-
1404
-	/**
1405
-	 * Test that locks are on mount point paths instead of mount root
1406
-	 */
1407
-	public function testLockLocalMountPointPathInsteadOfStorageRoot(): void {
1408
-		$lockingProvider = \OC::$server->get(ILockingProvider::class);
1409
-		$view = new View('/testuser/files/');
1410
-		$storage = new Temporary([]);
1411
-		Filesystem::mount($storage, [], '/');
1412
-		$mountedStorage = new Temporary([]);
1413
-		Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
1414
-
1415
-		$this->assertTrue(
1416
-			$view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, true),
1417
-			'Can lock mount point'
1418
-		);
1419
-
1420
-		// no exception here because storage root was not locked
1421
-		$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1422
-
1423
-		$thrown = false;
1424
-		try {
1425
-			$storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1426
-		} catch (LockedException $e) {
1427
-			$thrown = true;
1428
-		}
1429
-		$this->assertTrue($thrown, 'Mount point path was locked on root storage');
1430
-
1431
-		$lockingProvider->releaseAll();
1432
-	}
1433
-
1434
-	/**
1435
-	 * Test that locks are on mount point paths and also mount root when requested
1436
-	 */
1437
-	public function testLockStorageRootButNotLocalMountPoint(): void {
1438
-		$lockingProvider = \OC::$server->get(ILockingProvider::class);
1439
-		$view = new View('/testuser/files/');
1440
-		$storage = new Temporary([]);
1441
-		Filesystem::mount($storage, [], '/');
1442
-		$mountedStorage = new Temporary([]);
1443
-		Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
1444
-
1445
-		$this->assertTrue(
1446
-			$view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, false),
1447
-			'Can lock mount point'
1448
-		);
1449
-
1450
-		$thrown = false;
1451
-		try {
1452
-			$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1453
-		} catch (LockedException $e) {
1454
-			$thrown = true;
1455
-		}
1456
-		$this->assertTrue($thrown, 'Mount point storage root was locked on original storage');
1457
-
1458
-		// local mount point was not locked
1459
-		$storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1460
-
1461
-		$lockingProvider->releaseAll();
1462
-	}
1463
-
1464
-	/**
1465
-	 * Test that locks are on mount point paths and also mount root when requested
1466
-	 */
1467
-	public function testLockMountPointPathFailReleasesBoth(): void {
1468
-		$lockingProvider = \OC::$server->get(ILockingProvider::class);
1469
-		$view = new View('/testuser/files/');
1470
-		$storage = new Temporary([]);
1471
-		Filesystem::mount($storage, [], '/');
1472
-		$mountedStorage = new Temporary([]);
1473
-		Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint.txt');
1474
-
1475
-		// this would happen if someone is writing on the mount point
1476
-		$mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1477
-
1478
-		$thrown = false;
1479
-		try {
1480
-			// this actually acquires two locks, one on the mount point and one on the storage root,
1481
-			// but the one on the storage root will fail
1482
-			$view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED);
1483
-		} catch (LockedException $e) {
1484
-			$thrown = true;
1485
-		}
1486
-		$this->assertTrue($thrown, 'Cannot acquire shared lock because storage root is already locked');
1487
-
1488
-		// from here we expect that the lock on the local mount point was released properly
1489
-		// so acquiring an exclusive lock will succeed
1490
-		$storage->acquireLock('/testuser/files/mountpoint.txt', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1491
-
1492
-		$lockingProvider->releaseAll();
1493
-	}
1494
-
1495
-	public static function dataLockPaths(): array {
1496
-		return [
1497
-			['/testuser/{folder}', ''],
1498
-			['/testuser', '/{folder}'],
1499
-			['', '/testuser/{folder}'],
1500
-		];
1501
-	}
1502
-
1503
-	public static function pathRelativeToFilesProvider(): array {
1504
-		return [
1505
-			['admin/files', ''],
1506
-			['admin/files/x', 'x'],
1507
-			['/admin/files', ''],
1508
-			['/admin/files/sub', 'sub'],
1509
-			['/admin/files/sub/', 'sub'],
1510
-			['/admin/files/sub/sub2', 'sub/sub2'],
1511
-			['//admin//files/sub//sub2', 'sub/sub2'],
1512
-		];
1513
-	}
1514
-
1515
-	/**
1516
-	 * @dataProvider pathRelativeToFilesProvider
1517
-	 */
1518
-	public function testGetPathRelativeToFiles($path, $expectedPath): void {
1519
-		$view = new View();
1520
-		$this->assertEquals($expectedPath, $view->getPathRelativeToFiles($path));
1521
-	}
1522
-
1523
-	public static function pathRelativeToFilesProviderExceptionCases(): array {
1524
-		return [
1525
-			[''],
1526
-			['x'],
1527
-			['files'],
1528
-			['/files'],
1529
-			['/admin/files_versions/abc'],
1530
-		];
1531
-	}
1532
-
1533
-	/**
1534
-	 * @dataProvider pathRelativeToFilesProviderExceptionCases
1535
-	 * @param string $path
1536
-	 */
1537
-	public function testGetPathRelativeToFilesWithInvalidArgument($path): void {
1538
-		$this->expectException(\InvalidArgumentException::class);
1539
-		$this->expectExceptionMessage('$absolutePath must be relative to "files"');
1540
-
1541
-		$view = new View();
1542
-		$view->getPathRelativeToFiles($path);
1543
-	}
1544
-
1545
-	public function testChangeLock(): void {
1546
-		$view = new View('/testuser/files/');
1547
-		$storage = new Temporary([]);
1548
-		Filesystem::mount($storage, [], '/');
1549
-
1550
-		$view->lockFile('/test/sub', ILockingProvider::LOCK_SHARED);
1551
-		$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1552
-		$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1553
-
1554
-		$view->changeLock('//test/sub', ILockingProvider::LOCK_EXCLUSIVE);
1555
-		$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1556
-
1557
-		$view->changeLock('test/sub', ILockingProvider::LOCK_SHARED);
1558
-		$this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1559
-
1560
-		$view->unlockFile('/test/sub/', ILockingProvider::LOCK_SHARED);
1561
-
1562
-		$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1563
-		$this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1564
-	}
1565
-
1566
-	public static function hookPathProvider(): array {
1567
-		return [
1568
-			['/foo/files', '/foo', true],
1569
-			['/foo/files/bar', '/foo', true],
1570
-			['/foo', '/foo', false],
1571
-			['/foo', '/files/foo', true],
1572
-			['/foo', 'filesfoo', false],
1573
-			['', '/foo/files', true],
1574
-			['', '/foo/files/bar.txt', true],
1575
-		];
1576
-	}
1577
-
1578
-	/**
1579
-	 * @dataProvider hookPathProvider
1580
-	 * @param $root
1581
-	 * @param $path
1582
-	 * @param $shouldEmit
1583
-	 */
1584
-	public function testHookPaths($root, $path, $shouldEmit): void {
1585
-		$filesystemReflection = new \ReflectionClass(Filesystem::class);
1586
-		$defaultRootValue = $filesystemReflection->getProperty('defaultInstance');
1587
-		$defaultRootValue->setAccessible(true);
1588
-		$oldRoot = $defaultRootValue->getValue();
1589
-		$defaultView = new View('/foo/files');
1590
-		$defaultRootValue->setValue(null, $defaultView);
1591
-		$view = new View($root);
1592
-		$result = self::invokePrivate($view, 'shouldEmitHooks', [$path]);
1593
-		$defaultRootValue->setValue(null, $oldRoot);
1594
-		$this->assertEquals($shouldEmit, $result);
1595
-	}
1596
-
1597
-	/**
1598
-	 * Create test movable mount points
1599
-	 *
1600
-	 * @param array $mountPoints array of mount point locations
1601
-	 * @return array array of MountPoint objects
1602
-	 */
1603
-	private function createTestMovableMountPoints($mountPoints) {
1604
-		$mounts = [];
1605
-		foreach ($mountPoints as $mountPoint) {
1606
-			$storage = $this->getMockBuilder(Storage::class)
1607
-				->onlyMethods([])
1608
-				->getMock();
1609
-			$storage->method('getId')->willReturn('non-null-id');
1610
-			$storage->method('getStorageCache')->willReturnCallback(function () use ($storage) {
1611
-				return new \OC\Files\Cache\Storage($storage, true, \OC::$server->get(IDBConnection::class));
1612
-			});
1613
-
1614
-			$mounts[] = $this->getMockBuilder(TestMoveableMountPoint::class)
1615
-				->onlyMethods(['moveMount'])
1616
-				->setConstructorArgs([$storage, $mountPoint])
1617
-				->getMock();
1618
-		}
1619
-
1620
-		/** @var IMountProvider|\PHPUnit\Framework\MockObject\MockObject $mountProvider */
1621
-		$mountProvider = $this->createMock(IMountProvider::class);
1622
-		$mountProvider->expects($this->any())
1623
-			->method('getMountsForUser')
1624
-			->willReturn($mounts);
1625
-
1626
-		$mountProviderCollection = \OC::$server->getMountProviderCollection();
1627
-		$mountProviderCollection->registerProvider($mountProvider);
1628
-
1629
-		return $mounts;
1630
-	}
1631
-
1632
-	/**
1633
-	 * Test mount point move
1634
-	 */
1635
-	public function testMountPointMove(): void {
1636
-		self::loginAsUser($this->user);
1637
-
1638
-		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1639
-			$this->user . '/files/mount1',
1640
-			$this->user . '/files/mount2',
1641
-		]);
1642
-		$mount1->expects($this->once())
1643
-			->method('moveMount')
1644
-			->willReturn(true);
1645
-
1646
-		$mount2->expects($this->once())
1647
-			->method('moveMount')
1648
-			->willReturn(true);
1649
-
1650
-		$view = new View('/' . $this->user . '/files/');
1651
-		$view->mkdir('sub');
1652
-
1653
-		$this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point');
1654
-		$this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory');
1655
-	}
1656
-
1657
-	public function testMoveMountPointOverwrite(): void {
1658
-		self::loginAsUser($this->user);
1659
-
1660
-		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1661
-			$this->user . '/files/mount1',
1662
-			$this->user . '/files/mount2',
1663
-		]);
1664
-
1665
-		$mount1->expects($this->never())
1666
-			->method('moveMount');
1667
-
1668
-		$mount2->expects($this->never())
1669
-			->method('moveMount');
1670
-
1671
-		$view = new View('/' . $this->user . '/files/');
1672
-
1673
-		$this->expectException(ForbiddenException::class);
1674
-		$view->rename('mount1', 'mount2');
1675
-	}
1676
-
1677
-	public function testMoveMountPointIntoMount(): void {
1678
-		self::loginAsUser($this->user);
1679
-
1680
-		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1681
-			$this->user . '/files/mount1',
1682
-			$this->user . '/files/mount2',
1683
-		]);
1684
-
1685
-		$mount1->expects($this->never())
1686
-			->method('moveMount');
1687
-
1688
-		$mount2->expects($this->never())
1689
-			->method('moveMount');
1690
-
1691
-		$view = new View('/' . $this->user . '/files/');
1692
-
1693
-		$this->expectException(ForbiddenException::class);
1694
-		$view->rename('mount1', 'mount2/sub');
1695
-	}
1696
-
1697
-	/**
1698
-	 * Test that moving a mount point into a shared folder is forbidden
1699
-	 */
1700
-	public function testMoveMountPointIntoSharedFolder(): void {
1701
-		self::loginAsUser($this->user);
1702
-
1703
-		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1704
-			$this->user . '/files/mount1',
1705
-			$this->user . '/files/mount2',
1706
-		]);
1707
-
1708
-		$mount1->expects($this->never())
1709
-			->method('moveMount');
1710
-
1711
-		$mount2->expects($this->once())
1712
-			->method('moveMount')
1713
-			->willReturn(true);
1714
-
1715
-		$view = new View('/' . $this->user . '/files/');
1716
-		$view->mkdir('shareddir');
1717
-		$view->mkdir('shareddir/sub');
1718
-		$view->mkdir('shareddir/sub2');
1719
-		// Create a similar named but non-shared folder
1720
-		$view->mkdir('shareddir notshared');
1721
-
1722
-		$fileId = $view->getFileInfo('shareddir')->getId();
1723
-		$userObject = \OC::$server->getUserManager()->createUser('test2', 'IHateNonMockableStaticClasses');
1724
-
1725
-		$userFolder = \OC::$server->getUserFolder($this->user);
1726
-		$shareDir = $userFolder->get('shareddir');
1727
-		$shareManager = \OC::$server->get(IShareManager::class);
1728
-		$share = $shareManager->newShare();
1729
-		$share->setSharedWith('test2')
1730
-			->setSharedBy($this->user)
1731
-			->setShareType(IShare::TYPE_USER)
1732
-			->setPermissions(\OCP\Constants::PERMISSION_READ)
1733
-			->setNode($shareDir);
1734
-		$shareManager->createShare($share);
1735
-
1736
-		try {
1737
-			$view->rename('mount1', 'shareddir');
1738
-			$this->fail('Cannot overwrite shared folder');
1739
-		} catch (ForbiddenException $e) {
1740
-
1741
-		}
1742
-		try {
1743
-			$view->rename('mount1', 'shareddir/sub');
1744
-			$this->fail('Cannot move mount point into shared folder');
1745
-		} catch (ForbiddenException $e) {
1746
-
1747
-		}
1748
-		try {
1749
-			$view->rename('mount1', 'shareddir/sub/sub2');
1750
-			$this->fail('Cannot move mount point into shared subfolder');
1751
-		} catch (ForbiddenException $e) {
1752
-
1753
-		}
1754
-		$this->assertTrue($view->rename('mount2', 'shareddir notshared/sub'), 'Can move mount point into a similarly named but non-shared folder');
1755
-
1756
-		$shareManager->deleteShare($share);
1757
-		$userObject->delete();
1758
-	}
1759
-
1760
-	public static function basicOperationProviderForLocks(): array {
1761
-		return [
1762
-			// --- write hook ----
1763
-			[
1764
-				'touch',
1765
-				['touch-create.txt'],
1766
-				'touch-create.txt',
1767
-				'create',
1768
-				ILockingProvider::LOCK_SHARED,
1769
-				ILockingProvider::LOCK_EXCLUSIVE,
1770
-				ILockingProvider::LOCK_SHARED,
1771
-			],
1772
-			[
1773
-				'fopen',
1774
-				['test-write.txt', 'w'],
1775
-				'test-write.txt',
1776
-				'write',
1777
-				ILockingProvider::LOCK_SHARED,
1778
-				ILockingProvider::LOCK_EXCLUSIVE,
1779
-				null,
1780
-				// exclusive lock stays until fclose
1781
-				ILockingProvider::LOCK_EXCLUSIVE,
1782
-			],
1783
-			[
1784
-				'mkdir',
1785
-				['newdir'],
1786
-				'newdir',
1787
-				'write',
1788
-				ILockingProvider::LOCK_SHARED,
1789
-				ILockingProvider::LOCK_EXCLUSIVE,
1790
-				ILockingProvider::LOCK_SHARED,
1791
-			],
1792
-			[
1793
-				'file_put_contents',
1794
-				['file_put_contents.txt', 'blah'],
1795
-				'file_put_contents.txt',
1796
-				'write',
1797
-				ILockingProvider::LOCK_SHARED,
1798
-				ILockingProvider::LOCK_EXCLUSIVE,
1799
-				ILockingProvider::LOCK_SHARED,
1800
-				null,
1801
-				0,
1802
-			],
1803
-
1804
-			// ---- delete hook ----
1805
-			[
1806
-				'rmdir',
1807
-				['dir'],
1808
-				'dir',
1809
-				'delete',
1810
-				ILockingProvider::LOCK_SHARED,
1811
-				ILockingProvider::LOCK_EXCLUSIVE,
1812
-				ILockingProvider::LOCK_SHARED,
1813
-			],
1814
-			[
1815
-				'unlink',
1816
-				['test.txt'],
1817
-				'test.txt',
1818
-				'delete',
1819
-				ILockingProvider::LOCK_SHARED,
1820
-				ILockingProvider::LOCK_EXCLUSIVE,
1821
-				ILockingProvider::LOCK_SHARED,
1822
-			],
1823
-
1824
-			// ---- read hook (no post hooks) ----
1825
-			[
1826
-				'file_get_contents',
1827
-				['test.txt'],
1828
-				'test.txt',
1829
-				'read',
1830
-				ILockingProvider::LOCK_SHARED,
1831
-				ILockingProvider::LOCK_SHARED,
1832
-				null,
1833
-				null,
1834
-				false,
1835
-			],
1836
-			[
1837
-				'fopen',
1838
-				['test.txt', 'r'],
1839
-				'test.txt',
1840
-				'read',
1841
-				ILockingProvider::LOCK_SHARED,
1842
-				ILockingProvider::LOCK_SHARED,
1843
-				null,
1844
-			],
1845
-			[
1846
-				'opendir',
1847
-				['dir'],
1848
-				'dir',
1849
-				'read',
1850
-				ILockingProvider::LOCK_SHARED,
1851
-				ILockingProvider::LOCK_SHARED,
1852
-				null,
1853
-			],
1854
-
1855
-			// ---- no lock, touch hook ---
1856
-			['touch', ['test.txt'], 'test.txt', 'touch', null, null, null],
1857
-
1858
-			// ---- no hooks, no locks ---
1859
-			['is_dir', ['dir'], 'dir', null],
1860
-			['is_file', ['dir'], 'dir', null],
1861
-			[
1862
-				'stat',
1863
-				['dir'],
1864
-				'dir',
1865
-				null,
1866
-				ILockingProvider::LOCK_SHARED,
1867
-				ILockingProvider::LOCK_SHARED,
1868
-				ILockingProvider::LOCK_SHARED,
1869
-				null,
1870
-				false,
1871
-			],
1872
-			[
1873
-				'filetype',
1874
-				['dir'],
1875
-				'dir',
1876
-				null,
1877
-				ILockingProvider::LOCK_SHARED,
1878
-				ILockingProvider::LOCK_SHARED,
1879
-				ILockingProvider::LOCK_SHARED,
1880
-				null,
1881
-				false,
1882
-			],
1883
-			[
1884
-				'filesize',
1885
-				['dir'],
1886
-				'dir',
1887
-				null,
1888
-				ILockingProvider::LOCK_SHARED,
1889
-				ILockingProvider::LOCK_SHARED,
1890
-				ILockingProvider::LOCK_SHARED,
1891
-				null,
1892
-				/* Return an int */
1893
-				100
1894
-			],
1895
-			['isCreatable', ['dir'], 'dir', null],
1896
-			['isReadable', ['dir'], 'dir', null],
1897
-			['isUpdatable', ['dir'], 'dir', null],
1898
-			['isDeletable', ['dir'], 'dir', null],
1899
-			['isSharable', ['dir'], 'dir', null],
1900
-			['file_exists', ['dir'], 'dir', null],
1901
-			[
1902
-				'filemtime',
1903
-				['dir'],
1904
-				'dir',
1905
-				null,
1906
-				ILockingProvider::LOCK_SHARED,
1907
-				ILockingProvider::LOCK_SHARED,
1908
-				ILockingProvider::LOCK_SHARED,
1909
-				null,
1910
-				false,
1911
-			],
1912
-		];
1913
-	}
1914
-
1915
-	/**
1916
-	 * Test whether locks are set before and after the operation
1917
-	 *
1918
-	 * @dataProvider basicOperationProviderForLocks
1919
-	 *
1920
-	 * @param string $operation operation name on the view
1921
-	 * @param array $operationArgs arguments for the operation
1922
-	 * @param string $lockedPath path of the locked item to check
1923
-	 * @param string $hookType hook type
1924
-	 * @param int $expectedLockBefore expected lock during pre hooks
1925
-	 * @param int $expectedLockDuring expected lock during operation
1926
-	 * @param int $expectedLockAfter expected lock during post hooks
1927
-	 * @param int $expectedStrayLock expected lock after returning, should
1928
-	 *                               be null (unlock) for most operations
1929
-	 */
1930
-	public function testLockBasicOperation(
1931
-		$operation,
1932
-		$operationArgs,
1933
-		$lockedPath,
1934
-		$hookType,
1935
-		$expectedLockBefore = ILockingProvider::LOCK_SHARED,
1936
-		$expectedLockDuring = ILockingProvider::LOCK_SHARED,
1937
-		$expectedLockAfter = ILockingProvider::LOCK_SHARED,
1938
-		$expectedStrayLock = null,
1939
-		$returnValue = true,
1940
-	): void {
1941
-		$view = new View('/' . $this->user . '/files/');
1942
-
1943
-		/** @var Temporary&MockObject $storage */
1944
-		$storage = $this->getMockBuilder(Temporary::class)
1945
-			->onlyMethods([$operation])
1946
-			->getMock();
1947
-
1948
-		/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
1949
-		Server::get(ITrashManager::class)->pauseTrash();
1950
-
1951
-		Filesystem::mount($storage, [], $this->user . '/');
1952
-
1953
-		// work directly on disk because mkdir might be mocked
1954
-		$realPath = $storage->getSourcePath('');
1955
-		mkdir($realPath . '/files');
1956
-		mkdir($realPath . '/files/dir');
1957
-		file_put_contents($realPath . '/files/test.txt', 'blah');
1958
-		$storage->getScanner()->scan('files');
1959
-
1960
-		$storage->expects($this->once())
1961
-			->method($operation)
1962
-			->willReturnCallback(
1963
-				function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
1964
-					$lockTypeDuring = $this->getFileLockType($view, $lockedPath);
1965
-
1966
-					return $returnValue;
1967
-				}
1968
-			);
1969
-
1970
-		$this->assertNull($this->getFileLockType($view, $lockedPath), 'File not locked before operation');
1971
-
1972
-		$this->connectMockHooks($hookType, $view, $lockedPath, $lockTypePre, $lockTypePost);
1973
-
1974
-		// do operation
1975
-		call_user_func_array([$view, $operation], $operationArgs);
1976
-
1977
-		if ($hookType !== null) {
1978
-			$this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook');
1979
-			$this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook');
1980
-			$this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation');
1981
-		} else {
1982
-			$this->assertNull($lockTypeDuring, 'File not locked during operation');
1983
-		}
1984
-
1985
-		$this->assertEquals($expectedStrayLock, $this->getFileLockType($view, $lockedPath));
1986
-
1987
-		/* Resume trash to avoid side effects */
1988
-		Server::get(ITrashManager::class)->resumeTrash();
1989
-	}
1990
-
1991
-	/**
1992
-	 * Test locks for file_put_content with stream.
1993
-	 * This code path uses $storage->fopen instead
1994
-	 */
1995
-	public function testLockFilePutContentWithStream(): void {
1996
-		$view = new View('/' . $this->user . '/files/');
1997
-
1998
-		$path = 'test_file_put_contents.txt';
1999
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2000
-		$storage = $this->getMockBuilder(Temporary::class)
2001
-			->onlyMethods(['fopen'])
2002
-			->getMock();
2003
-
2004
-		Filesystem::mount($storage, [], $this->user . '/');
2005
-		$storage->mkdir('files');
2006
-
2007
-		$storage->expects($this->once())
2008
-			->method('fopen')
2009
-			->willReturnCallback(
2010
-				function () use ($view, $path, &$lockTypeDuring) {
2011
-					$lockTypeDuring = $this->getFileLockType($view, $path);
2012
-
2013
-					return fopen('php://temp', 'r+');
2014
-				}
2015
-			);
2016
-
2017
-		$this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
2018
-
2019
-		$this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
2020
-
2021
-		// do operation
2022
-		$view->file_put_contents($path, fopen('php://temp', 'r+'));
2023
-
2024
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
2025
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePost, 'File locked properly during post-hook');
2026
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
2027
-
2028
-		$this->assertNull($this->getFileLockType($view, $path));
2029
-	}
2030
-
2031
-	/**
2032
-	 * Test locks for fopen with fclose at the end
2033
-	 */
2034
-	public function testLockFopen(): void {
2035
-		$view = new View('/' . $this->user . '/files/');
2036
-
2037
-		$path = 'test_file_put_contents.txt';
2038
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2039
-		$storage = $this->getMockBuilder(Temporary::class)
2040
-			->onlyMethods(['fopen'])
2041
-			->getMock();
2042
-
2043
-		Filesystem::mount($storage, [], $this->user . '/');
2044
-		$storage->mkdir('files');
2045
-
2046
-		$storage->expects($this->once())
2047
-			->method('fopen')
2048
-			->willReturnCallback(
2049
-				function () use ($view, $path, &$lockTypeDuring) {
2050
-					$lockTypeDuring = $this->getFileLockType($view, $path);
2051
-
2052
-					return fopen('php://temp', 'r+');
2053
-				}
2054
-			);
2055
-
2056
-		$this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
2057
-
2058
-		$this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
2059
-
2060
-		// do operation
2061
-		$res = $view->fopen($path, 'w');
2062
-
2063
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
2064
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
2065
-		$this->assertNull($lockTypePost, 'No post hook, no lock check possible');
2066
-
2067
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File still locked after fopen');
2068
-
2069
-		fclose($res);
2070
-
2071
-		$this->assertNull($this->getFileLockType($view, $path), 'File unlocked after fclose');
2072
-	}
2073
-
2074
-	/**
2075
-	 * Test locks for fopen with fclose at the end
2076
-	 *
2077
-	 * @dataProvider basicOperationProviderForLocks
2078
-	 *
2079
-	 * @param string $operation operation name on the view
2080
-	 * @param array $operationArgs arguments for the operation
2081
-	 * @param string $path path of the locked item to check
2082
-	 */
2083
-	public function testLockBasicOperationUnlocksAfterException(
2084
-		$operation,
2085
-		$operationArgs,
2086
-		$path,
2087
-	): void {
2088
-		if ($operation === 'touch') {
2089
-			$this->markTestSkipped('touch handles storage exceptions internally');
2090
-		}
2091
-		$view = new View('/' . $this->user . '/files/');
2092
-
2093
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2094
-		$storage = $this->getMockBuilder(Temporary::class)
2095
-			->onlyMethods([$operation])
2096
-			->getMock();
2097
-
2098
-		/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
2099
-		Server::get(ITrashManager::class)->pauseTrash();
2100
-
2101
-		Filesystem::mount($storage, [], $this->user . '/');
2102
-
2103
-		// work directly on disk because mkdir might be mocked
2104
-		$realPath = $storage->getSourcePath('');
2105
-		mkdir($realPath . '/files');
2106
-		mkdir($realPath . '/files/dir');
2107
-		file_put_contents($realPath . '/files/test.txt', 'blah');
2108
-		$storage->getScanner()->scan('files');
2109
-
2110
-		$storage->expects($this->once())
2111
-			->method($operation)
2112
-			->willReturnCallback(
2113
-				function () {
2114
-					throw new \Exception('Simulated exception');
2115
-				}
2116
-			);
2117
-
2118
-		$thrown = false;
2119
-		try {
2120
-			call_user_func_array([$view, $operation], $operationArgs);
2121
-		} catch (\Exception $e) {
2122
-			$thrown = true;
2123
-			$this->assertEquals('Simulated exception', $e->getMessage());
2124
-		}
2125
-		$this->assertTrue($thrown, 'Exception was rethrown');
2126
-		$this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
2127
-
2128
-		/* Resume trash to avoid side effects */
2129
-		Server::get(ITrashManager::class)->resumeTrash();
2130
-	}
2131
-
2132
-	public function testLockBasicOperationUnlocksAfterLockException(): void {
2133
-		$view = new View('/' . $this->user . '/files/');
2134
-
2135
-		$storage = new Temporary([]);
2136
-
2137
-		Filesystem::mount($storage, [], $this->user . '/');
2138
-
2139
-		$storage->mkdir('files');
2140
-		$storage->mkdir('files/dir');
2141
-		$storage->file_put_contents('files/test.txt', 'blah');
2142
-		$storage->getScanner()->scan('files');
2143
-
2144
-		// get a shared lock
2145
-		$handle = $view->fopen('test.txt', 'r');
2146
-
2147
-		$thrown = false;
2148
-		try {
2149
-			// try (and fail) to get a write lock
2150
-			$view->unlink('test.txt');
2151
-		} catch (\Exception $e) {
2152
-			$thrown = true;
2153
-			$this->assertInstanceOf(LockedException::class, $e);
2154
-		}
2155
-		$this->assertTrue($thrown, 'Exception was rethrown');
2156
-
2157
-		// clean shared lock
2158
-		fclose($handle);
2159
-
2160
-		$this->assertNull($this->getFileLockType($view, 'test.txt'), 'File got unlocked');
2161
-	}
2162
-
2163
-	/**
2164
-	 * Test locks for fopen with fclose at the end
2165
-	 *
2166
-	 * @dataProvider basicOperationProviderForLocks
2167
-	 *
2168
-	 * @param string $operation operation name on the view
2169
-	 * @param array $operationArgs arguments for the operation
2170
-	 * @param string $path path of the locked item to check
2171
-	 * @param string $hookType hook type
2172
-	 */
2173
-	public function testLockBasicOperationUnlocksAfterCancelledHook(
2174
-		$operation,
2175
-		$operationArgs,
2176
-		$path,
2177
-		$hookType,
2178
-	): void {
2179
-		$view = new View('/' . $this->user . '/files/');
2180
-
2181
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2182
-		$storage = $this->getMockBuilder(Temporary::class)
2183
-			->onlyMethods([$operation])
2184
-			->getMock();
2185
-
2186
-		Filesystem::mount($storage, [], $this->user . '/');
2187
-		$storage->mkdir('files');
2188
-
2189
-		Util::connectHook(
2190
-			Filesystem::CLASSNAME,
2191
-			$hookType,
2192
-			HookHelper::class,
2193
-			'cancellingCallback'
2194
-		);
2195
-
2196
-		call_user_func_array([$view, $operation], $operationArgs);
2197
-
2198
-		$this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
2199
-	}
2200
-
2201
-	public static function lockFileRenameOrCopyDataProvider(): array {
2202
-		return [
2203
-			['rename', ILockingProvider::LOCK_EXCLUSIVE],
2204
-			['copy', ILockingProvider::LOCK_SHARED],
2205
-		];
2206
-	}
2207
-
2208
-	/**
2209
-	 * Test locks for rename or copy operation
2210
-	 *
2211
-	 * @dataProvider lockFileRenameOrCopyDataProvider
2212
-	 *
2213
-	 * @param string $operation operation to be done on the view
2214
-	 * @param int $expectedLockTypeSourceDuring expected lock type on source file during
2215
-	 *                                          the operation
2216
-	 */
2217
-	public function testLockFileRename($operation, $expectedLockTypeSourceDuring): void {
2218
-		$view = new View('/' . $this->user . '/files/');
2219
-
2220
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2221
-		$storage = $this->getMockBuilder(Temporary::class)
2222
-			->onlyMethods([$operation, 'getMetaData', 'filemtime'])
2223
-			->getMock();
2224
-
2225
-		$storage->expects($this->any())
2226
-			->method('getMetaData')
2227
-			->will($this->returnValue([
2228
-				'mtime' => 1885434487,
2229
-				'etag' => '',
2230
-				'mimetype' => 'text/plain',
2231
-				'permissions' => Constants::PERMISSION_ALL,
2232
-				'size' => 3
2233
-			]));
2234
-		$storage->expects($this->any())
2235
-			->method('filemtime')
2236
-			->willReturn(123456789);
2237
-
2238
-		$sourcePath = 'original.txt';
2239
-		$targetPath = 'target.txt';
2240
-
2241
-		Filesystem::mount($storage, [], $this->user . '/');
2242
-		$storage->mkdir('files');
2243
-		$view->file_put_contents($sourcePath, 'meh');
2244
-
2245
-		$storage->expects($this->once())
2246
-			->method($operation)
2247
-			->willReturnCallback(
2248
-				function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2249
-					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2250
-					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2251
-
2252
-					return true;
2253
-				}
2254
-			);
2255
-
2256
-		$this->connectMockHooks($operation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2257
-		$this->connectMockHooks($operation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2258
-
2259
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2260
-		$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2261
-
2262
-		$view->$operation($sourcePath, $targetPath);
2263
-
2264
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
2265
-		$this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
2266
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
2267
-
2268
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
2269
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
2270
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
2271
-
2272
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2273
-		$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2274
-	}
2275
-
2276
-	/**
2277
-	 * simulate a failed copy operation.
2278
-	 * We expect that we catch the exception, free the lock and re-throw it.
2279
-	 *
2280
-	 */
2281
-	public function testLockFileCopyException(): void {
2282
-		$this->expectException(\Exception::class);
2283
-
2284
-		$view = new View('/' . $this->user . '/files/');
2285
-
2286
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2287
-		$storage = $this->getMockBuilder(Temporary::class)
2288
-			->onlyMethods(['copy'])
2289
-			->getMock();
2290
-
2291
-		$sourcePath = 'original.txt';
2292
-		$targetPath = 'target.txt';
2293
-
2294
-		Filesystem::mount($storage, [], $this->user . '/');
2295
-		$storage->mkdir('files');
2296
-		$view->file_put_contents($sourcePath, 'meh');
2297
-
2298
-		$storage->expects($this->once())
2299
-			->method('copy')
2300
-			->willReturnCallback(
2301
-				function () {
2302
-					throw new \Exception();
2303
-				}
2304
-			);
2305
-
2306
-		$this->connectMockHooks('copy', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2307
-		$this->connectMockHooks('copy', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2308
-
2309
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2310
-		$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2311
-
2312
-		try {
2313
-			$view->copy($sourcePath, $targetPath);
2314
-		} catch (\Exception $e) {
2315
-			$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2316
-			$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2317
-			throw $e;
2318
-		}
2319
-	}
2320
-
2321
-	/**
2322
-	 * Test rename operation: unlock first path when second path was locked
2323
-	 */
2324
-	public function testLockFileRenameUnlockOnException(): void {
2325
-		self::loginAsUser('test');
2326
-
2327
-		$view = new View('/' . $this->user . '/files/');
2328
-
2329
-		$sourcePath = 'original.txt';
2330
-		$targetPath = 'target.txt';
2331
-		$view->file_put_contents($sourcePath, 'meh');
2332
-
2333
-		// simulate that the target path is already locked
2334
-		$view->lockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
2335
-
2336
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2337
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file is locked before operation');
2338
-
2339
-		$thrown = false;
2340
-		try {
2341
-			$view->rename($sourcePath, $targetPath);
2342
-		} catch (LockedException $e) {
2343
-			$thrown = true;
2344
-		}
2345
-
2346
-		$this->assertTrue($thrown, 'LockedException thrown');
2347
-
2348
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2349
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file still locked after operation');
2350
-
2351
-		$view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
2352
-	}
2353
-
2354
-	/**
2355
-	 * Test rename operation: unlock first path when second path was locked
2356
-	 */
2357
-	public function testGetOwner(): void {
2358
-		self::loginAsUser('test');
2359
-
2360
-		$view = new View('/test/files/');
2361
-
2362
-		$path = 'foo.txt';
2363
-		$view->file_put_contents($path, 'meh');
2364
-
2365
-		$this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID());
2366
-
2367
-		$folderInfo = $view->getDirectoryContent('');
2368
-		$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2369
-			return $info->getName() === 'foo.txt';
2370
-		}));
2371
-
2372
-		$this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
2373
-
2374
-		$subStorage = new Temporary();
2375
-		Filesystem::mount($subStorage, [], '/test/files/asd');
2376
-
2377
-		$folderInfo = $view->getDirectoryContent('');
2378
-		$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2379
-			return $info->getName() === 'asd';
2380
-		}));
2381
-
2382
-		$this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
2383
-	}
2384
-
2385
-	public static function lockFileRenameOrCopyCrossStorageDataProvider(): array {
2386
-		return [
2387
-			['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE],
2388
-			['copy', 'copyFromStorage', ILockingProvider::LOCK_SHARED],
2389
-		];
2390
-	}
2391
-
2392
-	/**
2393
-	 * Test locks for rename or copy operation cross-storage
2394
-	 *
2395
-	 * @dataProvider lockFileRenameOrCopyCrossStorageDataProvider
2396
-	 *
2397
-	 * @param string $viewOperation operation to be done on the view
2398
-	 * @param string $storageOperation operation to be mocked on the storage
2399
-	 * @param int $expectedLockTypeSourceDuring expected lock type on source file during
2400
-	 *                                          the operation
2401
-	 */
2402
-	public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring): void {
2403
-		$view = new View('/' . $this->user . '/files/');
2404
-
2405
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2406
-		$storage = $this->getMockBuilder(Temporary::class)
2407
-			->onlyMethods([$storageOperation])
2408
-			->getMock();
2409
-		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage2 */
2410
-		$storage2 = $this->getMockBuilder(Temporary::class)
2411
-			->onlyMethods([$storageOperation, 'getMetaData', 'filemtime'])
2412
-			->getMock();
2413
-
2414
-		$storage2->expects($this->any())
2415
-			->method('getMetaData')
2416
-			->will($this->returnValue([
2417
-				'mtime' => 1885434487,
2418
-				'etag' => '',
2419
-				'mimetype' => 'text/plain',
2420
-				'permissions' => Constants::PERMISSION_ALL,
2421
-				'size' => 3
2422
-			]));
2423
-		$storage2->expects($this->any())
2424
-			->method('filemtime')
2425
-			->willReturn(123456789);
2426
-
2427
-		$sourcePath = 'original.txt';
2428
-		$targetPath = 'substorage/target.txt';
2429
-
2430
-		Filesystem::mount($storage, [], $this->user . '/');
2431
-		Filesystem::mount($storage2, [], $this->user . '/files/substorage');
2432
-		$storage->mkdir('files');
2433
-		$view->file_put_contents($sourcePath, 'meh');
2434
-		$storage2->getUpdater()->update('');
2435
-
2436
-		$storage->expects($this->never())
2437
-			->method($storageOperation);
2438
-		$storage2->expects($this->once())
2439
-			->method($storageOperation)
2440
-			->willReturnCallback(
2441
-				function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2442
-					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2443
-					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2444
-
2445
-					return true;
2446
-				}
2447
-			);
2448
-
2449
-		$this->connectMockHooks($viewOperation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2450
-		$this->connectMockHooks($viewOperation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2451
-
2452
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2453
-		$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2454
-
2455
-		$view->$viewOperation($sourcePath, $targetPath);
2456
-
2457
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
2458
-		$this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
2459
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
2460
-
2461
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
2462
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
2463
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
2464
-
2465
-		$this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2466
-		$this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2467
-	}
2468
-
2469
-	/**
2470
-	 * Test locks when moving a mount point
2471
-	 */
2472
-	public function testLockMoveMountPoint(): void {
2473
-		self::loginAsUser('test');
2474
-
2475
-		[$mount] = $this->createTestMovableMountPoints([
2476
-			$this->user . '/files/substorage',
2477
-		]);
2478
-
2479
-		$view = new View('/' . $this->user . '/files/');
2480
-		$view->mkdir('subdir');
2481
-
2482
-		$sourcePath = 'substorage';
2483
-		$targetPath = 'subdir/substorage_moved';
2484
-
2485
-		$mount->expects($this->once())
2486
-			->method('moveMount')
2487
-			->willReturnCallback(
2488
-				function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) {
2489
-					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true);
2490
-					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true);
2491
-
2492
-					$lockTypeSharedRootDuring = $this->getFileLockType($view, $sourcePath, false);
2493
-
2494
-					$mount->setMountPoint($target);
2495
-
2496
-					return true;
2497
-				}
2498
-			);
2499
-
2500
-		$this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost, true);
2501
-		$this->connectMockHooks('rename', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost, true);
2502
-		// in pre-hook, mount point is still on $sourcePath
2503
-		$this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSharedRootPre, $dummy, false);
2504
-		// in post-hook, mount point is now on $targetPath
2505
-		$this->connectMockHooks('rename', $view, $targetPath, $dummy, $lockTypeSharedRootPost, false);
2506
-
2507
-		$this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked before operation');
2508
-		$this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked before operation');
2509
-		$this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked before operation');
2510
-
2511
-		$view->rename($sourcePath, $targetPath);
2512
-
2513
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source path locked properly during pre-hook');
2514
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeSourceDuring, 'Source path locked properly during operation');
2515
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source path locked properly during post-hook');
2516
-
2517
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target path locked properly during pre-hook');
2518
-		$this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target path locked properly during operation');
2519
-		$this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target path locked properly during post-hook');
2520
-
2521
-		$this->assertNull($lockTypeSharedRootPre, 'Shared storage root not locked during pre-hook');
2522
-		$this->assertNull($lockTypeSharedRootDuring, 'Shared storage root not locked during move');
2523
-		$this->assertNull($lockTypeSharedRootPost, 'Shared storage root not locked during post-hook');
2524
-
2525
-		$this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked after operation');
2526
-		$this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked after operation');
2527
-		$this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked after operation');
2528
-	}
2529
-
2530
-	/**
2531
-	 * Connect hook callbacks for hook type
2532
-	 *
2533
-	 * @param string $hookType hook type or null for none
2534
-	 * @param View $view view to check the lock on
2535
-	 * @param string $path path for which to check the lock
2536
-	 * @param int $lockTypePre variable to receive lock type that was active in the pre-hook
2537
-	 * @param int $lockTypePost variable to receive lock type that was active in the post-hook
2538
-	 * @param bool $onMountPoint true to check the mount point instead of the
2539
-	 *                           mounted storage
2540
-	 */
2541
-	private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) {
2542
-		if ($hookType === null) {
2543
-			return;
2544
-		}
2545
-
2546
-		$eventHandler = $this->getMockBuilder(TestEventHandler::class)
2547
-			->onlyMethods(['preCallback', 'postCallback'])
2548
-			->getMock();
2549
-
2550
-		$eventHandler->expects($this->any())
2551
-			->method('preCallback')
2552
-			->willReturnCallback(
2553
-				function () use ($view, $path, $onMountPoint, &$lockTypePre) {
2554
-					$lockTypePre = $this->getFileLockType($view, $path, $onMountPoint);
2555
-				}
2556
-			);
2557
-		$eventHandler->expects($this->any())
2558
-			->method('postCallback')
2559
-			->willReturnCallback(
2560
-				function () use ($view, $path, $onMountPoint, &$lockTypePost) {
2561
-					$lockTypePost = $this->getFileLockType($view, $path, $onMountPoint);
2562
-				}
2563
-			);
2564
-
2565
-		if ($hookType !== null) {
2566
-			Util::connectHook(
2567
-				Filesystem::CLASSNAME,
2568
-				$hookType,
2569
-				$eventHandler,
2570
-				'preCallback'
2571
-			);
2572
-			Util::connectHook(
2573
-				Filesystem::CLASSNAME,
2574
-				'post_' . $hookType,
2575
-				$eventHandler,
2576
-				'postCallback'
2577
-			);
2578
-		}
2579
-	}
2580
-
2581
-	/**
2582
-	 * Returns the file lock type
2583
-	 *
2584
-	 * @param View $view view
2585
-	 * @param string $path path
2586
-	 * @param bool $onMountPoint true to check the mount point instead of the
2587
-	 *                           mounted storage
2588
-	 *
2589
-	 * @return int lock type or null if file was not locked
2590
-	 */
2591
-	private function getFileLockType(View $view, $path, $onMountPoint = false) {
2592
-		if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE, $onMountPoint)) {
2593
-			return ILockingProvider::LOCK_EXCLUSIVE;
2594
-		} elseif ($this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED, $onMountPoint)) {
2595
-			return ILockingProvider::LOCK_SHARED;
2596
-		}
2597
-		return null;
2598
-	}
2599
-
2600
-
2601
-	public function testRemoveMoveableMountPoint(): void {
2602
-		$mountPoint = '/' . $this->user . '/files/mount/';
2603
-
2604
-		// Mock the mount point
2605
-		/** @var TestMoveableMountPoint|\PHPUnit\Framework\MockObject\MockObject $mount */
2606
-		$mount = $this->createMock(TestMoveableMountPoint::class);
2607
-		$mount->expects($this->once())
2608
-			->method('getMountPoint')
2609
-			->willReturn($mountPoint);
2610
-		$mount->expects($this->once())
2611
-			->method('removeMount')
2612
-			->willReturn('foo');
2613
-		$mount->expects($this->any())
2614
-			->method('getInternalPath')
2615
-			->willReturn('');
2616
-
2617
-		// Register mount
2618
-		Filesystem::getMountManager()->addMount($mount);
2619
-
2620
-		// Listen for events
2621
-		$eventHandler = $this->getMockBuilder(TestEventHandler::class)
2622
-			->onlyMethods(['umount', 'post_umount'])
2623
-			->getMock();
2624
-		$eventHandler->expects($this->once())
2625
-			->method('umount')
2626
-			->with([Filesystem::signal_param_path => '/mount']);
2627
-		$eventHandler->expects($this->once())
2628
-			->method('post_umount')
2629
-			->with([Filesystem::signal_param_path => '/mount']);
2630
-		Util::connectHook(
2631
-			Filesystem::CLASSNAME,
2632
-			'umount',
2633
-			$eventHandler,
2634
-			'umount'
2635
-		);
2636
-		Util::connectHook(
2637
-			Filesystem::CLASSNAME,
2638
-			'post_umount',
2639
-			$eventHandler,
2640
-			'post_umount'
2641
-		);
2642
-
2643
-		//Delete the mountpoint
2644
-		$view = new View('/' . $this->user . '/files');
2645
-		$this->assertEquals('foo', $view->rmdir('mount'));
2646
-	}
2647
-
2648
-	public static function mimeFilterProvider(): array {
2649
-		return [
2650
-			[null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']],
2651
-			['text/plain', ['test1.txt', 'test2.txt']],
2652
-			['text/markdown', ['test3.md']],
2653
-			['text', ['test1.txt', 'test2.txt', 'test3.md']],
2654
-		];
2655
-	}
2656
-
2657
-	/**
2658
-	 * @param string $filter
2659
-	 * @param string[] $expected
2660
-	 * @dataProvider mimeFilterProvider
2661
-	 */
2662
-	public function testGetDirectoryContentMimeFilter($filter, $expected): void {
2663
-		$storage1 = new Temporary();
2664
-		$root = self::getUniqueID('/');
2665
-		Filesystem::mount($storage1, [], $root . '/');
2666
-		$view = new View($root);
2667
-
2668
-		$view->file_put_contents('test1.txt', 'asd');
2669
-		$view->file_put_contents('test2.txt', 'asd');
2670
-		$view->file_put_contents('test3.md', 'asd');
2671
-		$view->file_put_contents('test4.png', '');
2672
-
2673
-		$content = $view->getDirectoryContent('', $filter);
2674
-
2675
-		$files = array_map(function (FileInfo $info) {
2676
-			return $info->getName();
2677
-		}, $content);
2678
-		sort($files);
2679
-
2680
-		$this->assertEquals($expected, $files);
2681
-	}
2682
-
2683
-	public function testFilePutContentsClearsChecksum(): void {
2684
-		$storage = new Temporary([]);
2685
-		$scanner = $storage->getScanner();
2686
-		$storage->file_put_contents('foo.txt', 'bar');
2687
-		Filesystem::mount($storage, [], '/test/');
2688
-		$scanner->scan('');
2689
-
2690
-		$view = new View('/test/foo.txt');
2691
-		$view->putFileInfo('.', ['checksum' => '42']);
2692
-
2693
-		$this->assertEquals('bar', $view->file_get_contents(''));
2694
-		$fh = tmpfile();
2695
-		fwrite($fh, 'fooo');
2696
-		rewind($fh);
2697
-		clearstatcache();
2698
-		$view->file_put_contents('', $fh);
2699
-		$this->assertEquals('fooo', $view->file_get_contents(''));
2700
-		$data = $view->getFileInfo('.');
2701
-		$this->assertEquals('', $data->getChecksum());
2702
-	}
2703
-
2704
-	public function testDeleteGhostFile(): void {
2705
-		$storage = new Temporary([]);
2706
-		$scanner = $storage->getScanner();
2707
-		$cache = $storage->getCache();
2708
-		$storage->file_put_contents('foo.txt', 'bar');
2709
-		Filesystem::mount($storage, [], '/test/');
2710
-		$scanner->scan('');
2711
-
2712
-		$storage->unlink('foo.txt');
2713
-
2714
-		$this->assertTrue($cache->inCache('foo.txt'));
2715
-
2716
-		$view = new View('/test');
2717
-		$rootInfo = $view->getFileInfo('');
2718
-		$this->assertEquals(3, $rootInfo->getSize());
2719
-		$view->unlink('foo.txt');
2720
-		$newInfo = $view->getFileInfo('');
2721
-
2722
-		$this->assertFalse($cache->inCache('foo.txt'));
2723
-		$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
2724
-		$this->assertEquals(0, $newInfo->getSize());
2725
-	}
2726
-
2727
-	public function testDeleteGhostFolder(): void {
2728
-		$storage = new Temporary([]);
2729
-		$scanner = $storage->getScanner();
2730
-		$cache = $storage->getCache();
2731
-		$storage->mkdir('foo');
2732
-		$storage->file_put_contents('foo/foo.txt', 'bar');
2733
-		Filesystem::mount($storage, [], '/test/');
2734
-		$scanner->scan('');
2735
-
2736
-		$storage->rmdir('foo');
2737
-
2738
-		$this->assertTrue($cache->inCache('foo'));
2739
-		$this->assertTrue($cache->inCache('foo/foo.txt'));
2740
-
2741
-		$view = new View('/test');
2742
-		$rootInfo = $view->getFileInfo('');
2743
-		$this->assertEquals(3, $rootInfo->getSize());
2744
-		$view->rmdir('foo');
2745
-		$newInfo = $view->getFileInfo('');
2746
-
2747
-		$this->assertFalse($cache->inCache('foo'));
2748
-		$this->assertFalse($cache->inCache('foo/foo.txt'));
2749
-		$this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
2750
-		$this->assertEquals(0, $newInfo->getSize());
2751
-	}
2752
-
2753
-	public function testCreateParentDirectories(): void {
2754
-		$view = $this->getMockBuilder(View::class)
2755
-			->disableOriginalConstructor()
2756
-			->onlyMethods([
2757
-				'is_file',
2758
-				'file_exists',
2759
-				'mkdir',
2760
-			])
2761
-			->getMock();
2762
-
2763
-		$view->expects($this->exactly(3))
2764
-			->method('is_file')
2765
-			->willReturnMap([
2766
-				['/new', false],
2767
-				['/new/folder', false],
2768
-				['/new/folder/structure', false],
2769
-			]);
2770
-		$view->expects($this->exactly(3))
2771
-			->method('file_exists')
2772
-			->willReturnMap([
2773
-				['/new', true],
2774
-				['/new/folder', false],
2775
-				['/new/folder/structure', false],
2776
-			]);
2777
-
2778
-		$calls = ['/new/folder', '/new/folder/structure'];
2779
-		$view->expects($this->exactly(2))
2780
-			->method('mkdir')
2781
-			->willReturnCallback(function ($dir) use (&$calls) {
2782
-				$expected = array_shift($calls);
2783
-				$this->assertEquals($expected, $dir);
2784
-			});
2785
-
2786
-		$this->assertTrue(self::invokePrivate($view, 'createParentDirectories', ['/new/folder/structure']));
2787
-	}
2788
-
2789
-	public function testCreateParentDirectoriesWithExistingFile(): void {
2790
-		$view = $this->getMockBuilder(View::class)
2791
-			->disableOriginalConstructor()
2792
-			->onlyMethods([
2793
-				'is_file',
2794
-				'file_exists',
2795
-				'mkdir',
2796
-			])
2797
-			->getMock();
2798
-
2799
-		$view
2800
-			->expects($this->once())
2801
-			->method('is_file')
2802
-			->with('/file.txt')
2803
-			->willReturn(true);
2804
-		$this->assertFalse(self::invokePrivate($view, 'createParentDirectories', ['/file.txt/folder/structure']));
2805
-	}
2806
-
2807
-	public function testCacheExtension(): void {
2808
-		$storage = new Temporary([]);
2809
-		$scanner = $storage->getScanner();
2810
-		$storage->file_put_contents('foo.txt', 'bar');
2811
-		$scanner->scan('');
2812
-
2813
-		Filesystem::mount($storage, [], '/test/');
2814
-		$view = new View('/test');
2815
-
2816
-		$info = $view->getFileInfo('/foo.txt');
2817
-		$this->assertEquals(0, $info->getUploadTime());
2818
-		$this->assertEquals(0, $info->getCreationTime());
2819
-
2820
-		$view->putFileInfo('/foo.txt', ['upload_time' => 25]);
2821
-
2822
-		$info = $view->getFileInfo('/foo.txt');
2823
-		$this->assertEquals(25, $info->getUploadTime());
2824
-		$this->assertEquals(0, $info->getCreationTime());
2825
-	}
2826
-
2827
-	public function testFopenGone(): void {
2828
-		$storage = new Temporary([]);
2829
-		$scanner = $storage->getScanner();
2830
-		$storage->file_put_contents('foo.txt', 'bar');
2831
-		$scanner->scan('');
2832
-		$cache = $storage->getCache();
2833
-
2834
-		Filesystem::mount($storage, [], '/test/');
2835
-		$view = new View('/test');
2836
-
2837
-		$storage->unlink('foo.txt');
2838
-
2839
-		$this->assertTrue($cache->inCache('foo.txt'));
2840
-
2841
-		$this->assertFalse($view->fopen('foo.txt', 'r'));
2842
-
2843
-		$this->assertFalse($cache->inCache('foo.txt'));
2844
-	}
2845
-
2846
-	public function testMountpointParentsCreated(): void {
2847
-		$storage1 = $this->getTestStorage();
2848
-		Filesystem::mount($storage1, [], '/');
2849
-
2850
-		$storage2 = $this->getTestStorage();
2851
-		Filesystem::mount($storage2, [], '/A/B/C');
2852
-
2853
-		$rootView = new View('');
2854
-
2855
-		$folderData = $rootView->getDirectoryContent('/');
2856
-		$this->assertCount(4, $folderData);
2857
-		$this->assertEquals('folder', $folderData[0]['name']);
2858
-		$this->assertEquals('foo.png', $folderData[1]['name']);
2859
-		$this->assertEquals('foo.txt', $folderData[2]['name']);
2860
-		$this->assertEquals('A', $folderData[3]['name']);
2861
-
2862
-		$folderData = $rootView->getDirectoryContent('/A');
2863
-		$this->assertCount(1, $folderData);
2864
-		$this->assertEquals('B', $folderData[0]['name']);
2865
-
2866
-		$folderData = $rootView->getDirectoryContent('/A/B');
2867
-		$this->assertCount(1, $folderData);
2868
-		$this->assertEquals('C', $folderData[0]['name']);
2869
-
2870
-		$folderData = $rootView->getDirectoryContent('/A/B/C');
2871
-		$this->assertCount(3, $folderData);
2872
-		$this->assertEquals('folder', $folderData[0]['name']);
2873
-		$this->assertEquals('foo.png', $folderData[1]['name']);
2874
-		$this->assertEquals('foo.txt', $folderData[2]['name']);
2875
-	}
2876
-
2877
-	public function testCopyPreservesContent() {
2878
-		$viewUser1 = new View('/' . 'userId' . '/files');
2879
-		$viewUser1->mkdir('');
2880
-		$viewUser1->file_put_contents('foo.txt', 'foo');
2881
-		$viewUser1->copy('foo.txt', 'bar.txt');
2882
-		$this->assertEquals('foo', $viewUser1->file_get_contents('bar.txt'));
2883
-	}
846
+        $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
847
+        $tmpdirLength = strlen(\OC::$server->getTempManager()->getTemporaryFolder());
848
+        if (\OC_Util::runningOnMac()) {
849
+            $depth = ((1024 - $tmpdirLength) / 57);
850
+        } else {
851
+            $depth = ((4000 - $tmpdirLength) / 57);
852
+        }
853
+        foreach (range(0, $depth - 1) as $i) {
854
+            $longPath .= $ds . $folderName;
855
+            $result = $rootView->mkdir($longPath);
856
+            $this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
857
+
858
+            $result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
859
+            $this->assertEquals(5, $result, "file_put_contents failed on $i");
860
+
861
+            $this->assertTrue($rootView->file_exists($longPath));
862
+            $this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
863
+        }
864
+
865
+        $cache = $storage->getCache();
866
+        $scanner = $storage->getScanner();
867
+        $scanner->scan('');
868
+
869
+        $longPath = $folderName;
870
+        foreach (range(0, $depth - 1) as $i) {
871
+            $cachedFolder = $cache->get($longPath);
872
+            $this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
873
+            $this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
874
+
875
+            $cachedFile = $cache->get($longPath . '/test.txt');
876
+            $this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
877
+            $this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
878
+
879
+            $longPath .= $ds . $folderName;
880
+        }
881
+    }
882
+
883
+    public function testTouchNotSupported(): void {
884
+        $storage = new TemporaryNoTouch([]);
885
+        $scanner = $storage->getScanner();
886
+        Filesystem::mount($storage, [], '/test/');
887
+        $past = time() - 100;
888
+        $storage->file_put_contents('test', 'foobar');
889
+        $scanner->scan('');
890
+        $view = new View('');
891
+        $info = $view->getFileInfo('/test/test');
892
+
893
+        $view->touch('/test/test', $past);
894
+        $scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG);
895
+
896
+        $info2 = $view->getFileInfo('/test/test');
897
+        $this->assertSame($info['etag'], $info2['etag']);
898
+    }
899
+
900
+    public function testWatcherEtagCrossStorage(): void {
901
+        $storage1 = new Temporary([]);
902
+        $storage2 = new Temporary([]);
903
+        $scanner1 = $storage1->getScanner();
904
+        $scanner2 = $storage2->getScanner();
905
+        $storage1->mkdir('sub');
906
+        Filesystem::mount($storage1, [], '/test/');
907
+        Filesystem::mount($storage2, [], '/test/sub/storage');
908
+
909
+        $past = time() - 100;
910
+        $storage2->file_put_contents('test.txt', 'foobar');
911
+        $scanner1->scan('');
912
+        $scanner2->scan('');
913
+        $view = new View('');
914
+
915
+        $storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS);
916
+
917
+        $oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt');
918
+        $oldFolderInfo = $view->getFileInfo('/test');
919
+
920
+        $storage2->getCache()->update($oldFileInfo->getId(), [
921
+            'storage_mtime' => $past,
922
+        ]);
923
+
924
+        $oldEtag = $oldFolderInfo->getEtag();
925
+
926
+        $view->getFileInfo('/test/sub/storage/test.txt');
927
+        $newFolderInfo = $view->getFileInfo('/test');
928
+
929
+        $this->assertNotEquals($newFolderInfo->getEtag(), $oldEtag);
930
+    }
931
+
932
+    /**
933
+     * @dataProvider absolutePathProvider
934
+     */
935
+    public function testGetAbsolutePath($expectedPath, $relativePath): void {
936
+        $view = new View('/files');
937
+        $this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath));
938
+    }
939
+
940
+    public function testPartFileInfo(): void {
941
+        $storage = new Temporary([]);
942
+        $scanner = $storage->getScanner();
943
+        Filesystem::mount($storage, [], '/test/');
944
+        $storage->file_put_contents('test.part', 'foobar');
945
+        $scanner->scan('');
946
+        $view = new View('/test');
947
+        $info = $view->getFileInfo('test.part');
948
+
949
+        $this->assertInstanceOf('\OCP\Files\FileInfo', $info);
950
+        $this->assertNull($info->getId());
951
+        $this->assertEquals(6, $info->getSize());
952
+    }
953
+
954
+    public static function absolutePathProvider(): array {
955
+        return [
956
+            ['/files/', ''],
957
+            ['/files/0', '0'],
958
+            ['/files/false', 'false'],
959
+            ['/files/true', 'true'],
960
+            ['/files/', '/'],
961
+            ['/files/test', 'test'],
962
+            ['/files/test', '/test'],
963
+        ];
964
+    }
965
+
966
+    /**
967
+     * @dataProvider chrootRelativePathProvider
968
+     */
969
+    public function testChrootGetRelativePath($root, $absolutePath, $expectedPath): void {
970
+        $view = new View('/files');
971
+        $view->chroot($root);
972
+        $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
973
+    }
974
+
975
+    public static function chrootRelativePathProvider(): array {
976
+        return self::relativePathProvider('/');
977
+    }
978
+
979
+    /**
980
+     * @dataProvider initRelativePathProvider
981
+     */
982
+    public function testInitGetRelativePath($root, $absolutePath, $expectedPath): void {
983
+        $view = new View($root);
984
+        $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
985
+    }
986
+
987
+    public static function initRelativePathProvider(): array {
988
+        return self::relativePathProvider(null);
989
+    }
990
+
991
+    public static function relativePathProvider($missingRootExpectedPath): array {
992
+        return [
993
+            // No root - returns the path
994
+            ['', '/files', '/files'],
995
+            ['', '/files/', '/files/'],
996
+
997
+            // Root equals path - /
998
+            ['/files/', '/files/', '/'],
999
+            ['/files/', '/files', '/'],
1000
+            ['/files', '/files/', '/'],
1001
+            ['/files', '/files', '/'],
1002
+
1003
+            // False negatives: chroot fixes those by adding the leading slash.
1004
+            // But setting them up with this root (instead of chroot($root))
1005
+            // will fail them, although they should be the same.
1006
+            // TODO init should be fixed, so it also adds the leading slash
1007
+            ['files/', '/files/', $missingRootExpectedPath],
1008
+            ['files', '/files/', $missingRootExpectedPath],
1009
+            ['files/', '/files', $missingRootExpectedPath],
1010
+            ['files', '/files', $missingRootExpectedPath],
1011
+
1012
+            // False negatives: Paths provided to the method should have a leading slash
1013
+            // TODO input should be checked to have a leading slash
1014
+            ['/files/', 'files/', null],
1015
+            ['/files', 'files/', null],
1016
+            ['/files/', 'files', null],
1017
+            ['/files', 'files', null],
1018
+
1019
+            // with trailing slashes
1020
+            ['/files/', '/files/0', '0'],
1021
+            ['/files/', '/files/false', 'false'],
1022
+            ['/files/', '/files/true', 'true'],
1023
+            ['/files/', '/files/test', 'test'],
1024
+            ['/files/', '/files/test/foo', 'test/foo'],
1025
+
1026
+            // without trailing slashes
1027
+            // TODO false expectation: Should match "with trailing slashes"
1028
+            ['/files', '/files/0', '/0'],
1029
+            ['/files', '/files/false', '/false'],
1030
+            ['/files', '/files/true', '/true'],
1031
+            ['/files', '/files/test', '/test'],
1032
+            ['/files', '/files/test/foo', '/test/foo'],
1033
+
1034
+            // leading slashes
1035
+            ['/files/', '/files_trashbin/', null],
1036
+            ['/files', '/files_trashbin/', null],
1037
+            ['/files/', '/files_trashbin', null],
1038
+            ['/files', '/files_trashbin', null],
1039
+
1040
+            // no leading slashes
1041
+            ['files/', 'files_trashbin/', null],
1042
+            ['files', 'files_trashbin/', null],
1043
+            ['files/', 'files_trashbin', null],
1044
+            ['files', 'files_trashbin', null],
1045
+
1046
+            // mixed leading slashes
1047
+            ['files/', '/files_trashbin/', null],
1048
+            ['/files/', 'files_trashbin/', null],
1049
+            ['files', '/files_trashbin/', null],
1050
+            ['/files', 'files_trashbin/', null],
1051
+            ['files/', '/files_trashbin', null],
1052
+            ['/files/', 'files_trashbin', null],
1053
+            ['files', '/files_trashbin', null],
1054
+            ['/files', 'files_trashbin', null],
1055
+
1056
+            ['files', 'files_trashbin/test', null],
1057
+            ['/files', '/files_trashbin/test', null],
1058
+            ['/files', 'files_trashbin/test', null],
1059
+        ];
1060
+    }
1061
+
1062
+    public function testFileView(): void {
1063
+        $storage = new Temporary([]);
1064
+        $scanner = $storage->getScanner();
1065
+        $storage->file_put_contents('foo.txt', 'bar');
1066
+        Filesystem::mount($storage, [], '/test/');
1067
+        $scanner->scan('');
1068
+        $view = new View('/test/foo.txt');
1069
+
1070
+        $this->assertEquals('bar', $view->file_get_contents(''));
1071
+        $fh = tmpfile();
1072
+        fwrite($fh, 'foo');
1073
+        rewind($fh);
1074
+        $view->file_put_contents('', $fh);
1075
+        $this->assertEquals('foo', $view->file_get_contents(''));
1076
+    }
1077
+
1078
+    /**
1079
+     * @dataProvider tooLongPathDataProvider
1080
+     */
1081
+    public function testTooLongPath($operation, $param0 = null): void {
1082
+        $this->expectException(\OCP\Files\InvalidPathException::class);
1083
+
1084
+
1085
+        $longPath = '';
1086
+        // 4000 is the maximum path length in file_cache.path
1087
+        $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
1088
+        $depth = (4000 / 57);
1089
+        foreach (range(0, $depth + 1) as $i) {
1090
+            $longPath .= '/' . $folderName;
1091
+        }
1092
+
1093
+        $storage = new Temporary([]);
1094
+        $this->tempStorage = $storage; // for later hard cleanup
1095
+        Filesystem::mount($storage, [], '/');
1096
+
1097
+        $rootView = new View('');
1098
+
1099
+        if ($param0 === '@0') {
1100
+            $param0 = $longPath;
1101
+        }
1102
+
1103
+        if ($operation === 'hash') {
1104
+            $param0 = $longPath;
1105
+            $longPath = 'md5';
1106
+        }
1107
+
1108
+        call_user_func([$rootView, $operation], $longPath, $param0);
1109
+    }
1110
+
1111
+    public static function tooLongPathDataProvider(): array {
1112
+        return [
1113
+            ['getAbsolutePath'],
1114
+            ['getRelativePath'],
1115
+            ['getMountPoint'],
1116
+            ['resolvePath'],
1117
+            ['getLocalFile'],
1118
+            ['mkdir'],
1119
+            ['rmdir'],
1120
+            ['opendir'],
1121
+            ['is_dir'],
1122
+            ['is_file'],
1123
+            ['stat'],
1124
+            ['filetype'],
1125
+            ['filesize'],
1126
+            ['readfile'],
1127
+            ['isCreatable'],
1128
+            ['isReadable'],
1129
+            ['isUpdatable'],
1130
+            ['isDeletable'],
1131
+            ['isSharable'],
1132
+            ['file_exists'],
1133
+            ['filemtime'],
1134
+            ['touch'],
1135
+            ['file_get_contents'],
1136
+            ['unlink'],
1137
+            ['deleteAll'],
1138
+            ['toTmpFile'],
1139
+            ['getMimeType'],
1140
+            ['free_space'],
1141
+            ['getFileInfo'],
1142
+            ['getDirectoryContent'],
1143
+            ['getOwner'],
1144
+            ['getETag'],
1145
+            ['file_put_contents', 'ipsum'],
1146
+            ['rename', '@0'],
1147
+            ['copy', '@0'],
1148
+            ['fopen', 'r'],
1149
+            ['fromTmpFile', '@0'],
1150
+            ['hash'],
1151
+            ['hasUpdated', 0],
1152
+            ['putFileInfo', []],
1153
+        ];
1154
+    }
1155
+
1156
+    public function testRenameCrossStoragePreserveMtime(): void {
1157
+        $storage1 = new Temporary([]);
1158
+        $storage2 = new Temporary([]);
1159
+        $storage1->mkdir('sub');
1160
+        $storage1->mkdir('foo');
1161
+        $storage1->file_put_contents('foo.txt', 'asd');
1162
+        $storage1->file_put_contents('foo/bar.txt', 'asd');
1163
+        Filesystem::mount($storage1, [], '/test/');
1164
+        Filesystem::mount($storage2, [], '/test/sub/storage');
1165
+
1166
+        $view = new View('');
1167
+        $time = time() - 200;
1168
+        $view->touch('/test/foo.txt', $time);
1169
+        $view->touch('/test/foo', $time);
1170
+        $view->touch('/test/foo/bar.txt', $time);
1171
+
1172
+        $view->rename('/test/foo.txt', '/test/sub/storage/foo.txt');
1173
+
1174
+        $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt'));
1175
+
1176
+        $view->rename('/test/foo', '/test/sub/storage/foo');
1177
+
1178
+        $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt'));
1179
+    }
1180
+
1181
+    public function testRenameFailDeleteTargetKeepSource(): void {
1182
+        $this->doTestCopyRenameFail('rename');
1183
+    }
1184
+
1185
+    public function testCopyFailDeleteTargetKeepSource(): void {
1186
+        $this->doTestCopyRenameFail('copy');
1187
+    }
1188
+
1189
+    private function doTestCopyRenameFail($operation) {
1190
+        $storage1 = new Temporary([]);
1191
+        /** @var \PHPUnit\Framework\MockObject\MockObject|Temporary $storage2 */
1192
+        $storage2 = $this->getMockBuilder(TemporaryNoCross::class)
1193
+            ->setConstructorArgs([[]])
1194
+            ->onlyMethods(['fopen', 'writeStream'])
1195
+            ->getMock();
1196
+
1197
+        $storage2->method('writeStream')
1198
+            ->willThrowException(new GenericFileException('Failed to copy stream'));
1199
+
1200
+        $storage1->mkdir('sub');
1201
+        $storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
1202
+        $storage1->mkdir('dirtomove');
1203
+        $storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
1204
+        $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
1205
+        $storage2->file_put_contents('existing.txt', '0123');
1206
+        $storage1->getScanner()->scan('');
1207
+        $storage2->getScanner()->scan('');
1208
+        Filesystem::mount($storage1, [], '/test/');
1209
+        Filesystem::mount($storage2, [], '/test/sub/storage');
1210
+
1211
+        // move file
1212
+        $view = new View('');
1213
+        $this->assertTrue($storage1->file_exists('foo.txt'));
1214
+        $this->assertFalse($storage2->file_exists('foo.txt'));
1215
+        $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt'));
1216
+        $this->assertFalse($storage2->file_exists('foo.txt'));
1217
+        $this->assertFalse($storage2->getCache()->get('foo.txt'));
1218
+        $this->assertTrue($storage1->file_exists('foo.txt'));
1219
+
1220
+        // if target exists, it will be deleted too
1221
+        $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt'));
1222
+        $this->assertFalse($storage2->file_exists('existing.txt'));
1223
+        $this->assertFalse($storage2->getCache()->get('existing.txt'));
1224
+        $this->assertTrue($storage1->file_exists('foo.txt'));
1225
+
1226
+        // move folder
1227
+        $this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/'));
1228
+        // since the move failed, the full source tree is kept
1229
+        $this->assertTrue($storage1->file_exists('dirtomove/indir1.txt'));
1230
+        $this->assertTrue($storage1->file_exists('dirtomove/indir2.txt'));
1231
+        // second file not moved/copied
1232
+        $this->assertFalse($storage2->file_exists('dirtomove/indir2.txt'));
1233
+        $this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt'));
1234
+    }
1235
+
1236
+    public function testDeleteFailKeepCache(): void {
1237
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
1238
+        $storage = $this->getMockBuilder(Temporary::class)
1239
+            ->setConstructorArgs([[]])
1240
+            ->onlyMethods(['unlink'])
1241
+            ->getMock();
1242
+        $storage->expects($this->once())
1243
+            ->method('unlink')
1244
+            ->willReturn(false);
1245
+        $scanner = $storage->getScanner();
1246
+        $cache = $storage->getCache();
1247
+        $storage->file_put_contents('foo.txt', 'asd');
1248
+        $scanner->scan('');
1249
+        Filesystem::mount($storage, [], '/test/');
1250
+
1251
+        $view = new View('/test');
1252
+
1253
+        $this->assertFalse($view->unlink('foo.txt'));
1254
+        $this->assertTrue($cache->inCache('foo.txt'));
1255
+    }
1256
+
1257
+    public static function directoryTraversalProvider(): array {
1258
+        return [
1259
+            ['../test/'],
1260
+            ['..\\test\\my/../folder'],
1261
+            ['/test/my/../foo\\'],
1262
+        ];
1263
+    }
1264
+
1265
+    /**
1266
+     * @dataProvider directoryTraversalProvider
1267
+     * @param string $root
1268
+     */
1269
+    public function testConstructDirectoryTraversalException($root): void {
1270
+        $this->expectException(\Exception::class);
1271
+
1272
+        new View($root);
1273
+    }
1274
+
1275
+    public function testRenameOverWrite(): void {
1276
+        $storage = new Temporary([]);
1277
+        $scanner = $storage->getScanner();
1278
+        $storage->mkdir('sub');
1279
+        $storage->mkdir('foo');
1280
+        $storage->file_put_contents('foo.txt', 'asd');
1281
+        $storage->file_put_contents('foo/bar.txt', 'asd');
1282
+        $scanner->scan('');
1283
+        Filesystem::mount($storage, [], '/test/');
1284
+        $view = new View('');
1285
+        $this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt'));
1286
+    }
1287
+
1288
+    public function testSetMountOptionsInStorage(): void {
1289
+        $mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['foo' => 'bar']);
1290
+        Filesystem::getMountManager()->addMount($mount);
1291
+        /** @var \OC\Files\Storage\Common $storage */
1292
+        $storage = $mount->getStorage();
1293
+        $this->assertEquals($storage->getMountOption('foo'), 'bar');
1294
+    }
1295
+
1296
+    public function testSetMountOptionsWatcherPolicy(): void {
1297
+        $mount = new MountPoint(Temporary::class, '/asd/', [[]], Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]);
1298
+        Filesystem::getMountManager()->addMount($mount);
1299
+        /** @var \OC\Files\Storage\Common $storage */
1300
+        $storage = $mount->getStorage();
1301
+        $watcher = $storage->getWatcher();
1302
+        $this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy());
1303
+    }
1304
+
1305
+    public function testGetAbsolutePathOnNull(): void {
1306
+        $view = new View();
1307
+        $this->assertNull($view->getAbsolutePath(null));
1308
+    }
1309
+
1310
+    public function testGetRelativePathOnNull(): void {
1311
+        $view = new View();
1312
+        $this->assertNull($view->getRelativePath(null));
1313
+    }
1314
+
1315
+
1316
+    public function testNullAsRoot(): void {
1317
+        $this->expectException(\TypeError::class);
1318
+
1319
+        new View(null);
1320
+    }
1321
+
1322
+    /**
1323
+     * e.g. reading from a folder that's being renamed
1324
+     *
1325
+     *
1326
+     * @dataProvider dataLockPaths
1327
+     *
1328
+     * @param string $rootPath
1329
+     * @param string $pathPrefix
1330
+     */
1331
+    public function testReadFromWriteLockedPath($rootPath, $pathPrefix): void {
1332
+        $this->expectException(\OCP\Lock\LockedException::class);
1333
+
1334
+        $rootPath = str_replace('{folder}', 'files', $rootPath);
1335
+        $pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
1336
+
1337
+        $view = new View($rootPath);
1338
+        $storage = new Temporary([]);
1339
+        Filesystem::mount($storage, [], '/');
1340
+        $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1341
+        $view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED);
1342
+    }
1343
+
1344
+    /**
1345
+     * Reading from a files_encryption folder that's being renamed
1346
+     *
1347
+     * @dataProvider dataLockPaths
1348
+     *
1349
+     * @param string $rootPath
1350
+     * @param string $pathPrefix
1351
+     */
1352
+    public function testReadFromWriteUnlockablePath($rootPath, $pathPrefix): void {
1353
+        $rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
1354
+        $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
1355
+
1356
+        $view = new View($rootPath);
1357
+        $storage = new Temporary([]);
1358
+        Filesystem::mount($storage, [], '/');
1359
+        $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1360
+        $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED));
1361
+    }
1362
+
1363
+    /**
1364
+     * e.g. writing a file that's being downloaded
1365
+     *
1366
+     *
1367
+     * @dataProvider dataLockPaths
1368
+     *
1369
+     * @param string $rootPath
1370
+     * @param string $pathPrefix
1371
+     */
1372
+    public function testWriteToReadLockedFile($rootPath, $pathPrefix): void {
1373
+        $this->expectException(\OCP\Lock\LockedException::class);
1374
+
1375
+        $rootPath = str_replace('{folder}', 'files', $rootPath);
1376
+        $pathPrefix = str_replace('{folder}', 'files', $pathPrefix);
1377
+
1378
+        $view = new View($rootPath);
1379
+        $storage = new Temporary([]);
1380
+        Filesystem::mount($storage, [], '/');
1381
+        $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1382
+        $view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE);
1383
+    }
1384
+
1385
+    /**
1386
+     * Writing a file that's being downloaded
1387
+     *
1388
+     * @dataProvider dataLockPaths
1389
+     *
1390
+     * @param string $rootPath
1391
+     * @param string $pathPrefix
1392
+     */
1393
+    public function testWriteToReadUnlockableFile($rootPath, $pathPrefix): void {
1394
+        $rootPath = str_replace('{folder}', 'files_encryption', $rootPath);
1395
+        $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix);
1396
+
1397
+        $view = new View($rootPath);
1398
+        $storage = new Temporary([]);
1399
+        Filesystem::mount($storage, [], '/');
1400
+        $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1401
+        $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1402
+    }
1403
+
1404
+    /**
1405
+     * Test that locks are on mount point paths instead of mount root
1406
+     */
1407
+    public function testLockLocalMountPointPathInsteadOfStorageRoot(): void {
1408
+        $lockingProvider = \OC::$server->get(ILockingProvider::class);
1409
+        $view = new View('/testuser/files/');
1410
+        $storage = new Temporary([]);
1411
+        Filesystem::mount($storage, [], '/');
1412
+        $mountedStorage = new Temporary([]);
1413
+        Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
1414
+
1415
+        $this->assertTrue(
1416
+            $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, true),
1417
+            'Can lock mount point'
1418
+        );
1419
+
1420
+        // no exception here because storage root was not locked
1421
+        $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1422
+
1423
+        $thrown = false;
1424
+        try {
1425
+            $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1426
+        } catch (LockedException $e) {
1427
+            $thrown = true;
1428
+        }
1429
+        $this->assertTrue($thrown, 'Mount point path was locked on root storage');
1430
+
1431
+        $lockingProvider->releaseAll();
1432
+    }
1433
+
1434
+    /**
1435
+     * Test that locks are on mount point paths and also mount root when requested
1436
+     */
1437
+    public function testLockStorageRootButNotLocalMountPoint(): void {
1438
+        $lockingProvider = \OC::$server->get(ILockingProvider::class);
1439
+        $view = new View('/testuser/files/');
1440
+        $storage = new Temporary([]);
1441
+        Filesystem::mount($storage, [], '/');
1442
+        $mountedStorage = new Temporary([]);
1443
+        Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint');
1444
+
1445
+        $this->assertTrue(
1446
+            $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, false),
1447
+            'Can lock mount point'
1448
+        );
1449
+
1450
+        $thrown = false;
1451
+        try {
1452
+            $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1453
+        } catch (LockedException $e) {
1454
+            $thrown = true;
1455
+        }
1456
+        $this->assertTrue($thrown, 'Mount point storage root was locked on original storage');
1457
+
1458
+        // local mount point was not locked
1459
+        $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1460
+
1461
+        $lockingProvider->releaseAll();
1462
+    }
1463
+
1464
+    /**
1465
+     * Test that locks are on mount point paths and also mount root when requested
1466
+     */
1467
+    public function testLockMountPointPathFailReleasesBoth(): void {
1468
+        $lockingProvider = \OC::$server->get(ILockingProvider::class);
1469
+        $view = new View('/testuser/files/');
1470
+        $storage = new Temporary([]);
1471
+        Filesystem::mount($storage, [], '/');
1472
+        $mountedStorage = new Temporary([]);
1473
+        Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint.txt');
1474
+
1475
+        // this would happen if someone is writing on the mount point
1476
+        $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1477
+
1478
+        $thrown = false;
1479
+        try {
1480
+            // this actually acquires two locks, one on the mount point and one on the storage root,
1481
+            // but the one on the storage root will fail
1482
+            $view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED);
1483
+        } catch (LockedException $e) {
1484
+            $thrown = true;
1485
+        }
1486
+        $this->assertTrue($thrown, 'Cannot acquire shared lock because storage root is already locked');
1487
+
1488
+        // from here we expect that the lock on the local mount point was released properly
1489
+        // so acquiring an exclusive lock will succeed
1490
+        $storage->acquireLock('/testuser/files/mountpoint.txt', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider);
1491
+
1492
+        $lockingProvider->releaseAll();
1493
+    }
1494
+
1495
+    public static function dataLockPaths(): array {
1496
+        return [
1497
+            ['/testuser/{folder}', ''],
1498
+            ['/testuser', '/{folder}'],
1499
+            ['', '/testuser/{folder}'],
1500
+        ];
1501
+    }
1502
+
1503
+    public static function pathRelativeToFilesProvider(): array {
1504
+        return [
1505
+            ['admin/files', ''],
1506
+            ['admin/files/x', 'x'],
1507
+            ['/admin/files', ''],
1508
+            ['/admin/files/sub', 'sub'],
1509
+            ['/admin/files/sub/', 'sub'],
1510
+            ['/admin/files/sub/sub2', 'sub/sub2'],
1511
+            ['//admin//files/sub//sub2', 'sub/sub2'],
1512
+        ];
1513
+    }
1514
+
1515
+    /**
1516
+     * @dataProvider pathRelativeToFilesProvider
1517
+     */
1518
+    public function testGetPathRelativeToFiles($path, $expectedPath): void {
1519
+        $view = new View();
1520
+        $this->assertEquals($expectedPath, $view->getPathRelativeToFiles($path));
1521
+    }
1522
+
1523
+    public static function pathRelativeToFilesProviderExceptionCases(): array {
1524
+        return [
1525
+            [''],
1526
+            ['x'],
1527
+            ['files'],
1528
+            ['/files'],
1529
+            ['/admin/files_versions/abc'],
1530
+        ];
1531
+    }
1532
+
1533
+    /**
1534
+     * @dataProvider pathRelativeToFilesProviderExceptionCases
1535
+     * @param string $path
1536
+     */
1537
+    public function testGetPathRelativeToFilesWithInvalidArgument($path): void {
1538
+        $this->expectException(\InvalidArgumentException::class);
1539
+        $this->expectExceptionMessage('$absolutePath must be relative to "files"');
1540
+
1541
+        $view = new View();
1542
+        $view->getPathRelativeToFiles($path);
1543
+    }
1544
+
1545
+    public function testChangeLock(): void {
1546
+        $view = new View('/testuser/files/');
1547
+        $storage = new Temporary([]);
1548
+        Filesystem::mount($storage, [], '/');
1549
+
1550
+        $view->lockFile('/test/sub', ILockingProvider::LOCK_SHARED);
1551
+        $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1552
+        $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1553
+
1554
+        $view->changeLock('//test/sub', ILockingProvider::LOCK_EXCLUSIVE);
1555
+        $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1556
+
1557
+        $view->changeLock('test/sub', ILockingProvider::LOCK_SHARED);
1558
+        $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1559
+
1560
+        $view->unlockFile('/test/sub/', ILockingProvider::LOCK_SHARED);
1561
+
1562
+        $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED));
1563
+        $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE));
1564
+    }
1565
+
1566
+    public static function hookPathProvider(): array {
1567
+        return [
1568
+            ['/foo/files', '/foo', true],
1569
+            ['/foo/files/bar', '/foo', true],
1570
+            ['/foo', '/foo', false],
1571
+            ['/foo', '/files/foo', true],
1572
+            ['/foo', 'filesfoo', false],
1573
+            ['', '/foo/files', true],
1574
+            ['', '/foo/files/bar.txt', true],
1575
+        ];
1576
+    }
1577
+
1578
+    /**
1579
+     * @dataProvider hookPathProvider
1580
+     * @param $root
1581
+     * @param $path
1582
+     * @param $shouldEmit
1583
+     */
1584
+    public function testHookPaths($root, $path, $shouldEmit): void {
1585
+        $filesystemReflection = new \ReflectionClass(Filesystem::class);
1586
+        $defaultRootValue = $filesystemReflection->getProperty('defaultInstance');
1587
+        $defaultRootValue->setAccessible(true);
1588
+        $oldRoot = $defaultRootValue->getValue();
1589
+        $defaultView = new View('/foo/files');
1590
+        $defaultRootValue->setValue(null, $defaultView);
1591
+        $view = new View($root);
1592
+        $result = self::invokePrivate($view, 'shouldEmitHooks', [$path]);
1593
+        $defaultRootValue->setValue(null, $oldRoot);
1594
+        $this->assertEquals($shouldEmit, $result);
1595
+    }
1596
+
1597
+    /**
1598
+     * Create test movable mount points
1599
+     *
1600
+     * @param array $mountPoints array of mount point locations
1601
+     * @return array array of MountPoint objects
1602
+     */
1603
+    private function createTestMovableMountPoints($mountPoints) {
1604
+        $mounts = [];
1605
+        foreach ($mountPoints as $mountPoint) {
1606
+            $storage = $this->getMockBuilder(Storage::class)
1607
+                ->onlyMethods([])
1608
+                ->getMock();
1609
+            $storage->method('getId')->willReturn('non-null-id');
1610
+            $storage->method('getStorageCache')->willReturnCallback(function () use ($storage) {
1611
+                return new \OC\Files\Cache\Storage($storage, true, \OC::$server->get(IDBConnection::class));
1612
+            });
1613
+
1614
+            $mounts[] = $this->getMockBuilder(TestMoveableMountPoint::class)
1615
+                ->onlyMethods(['moveMount'])
1616
+                ->setConstructorArgs([$storage, $mountPoint])
1617
+                ->getMock();
1618
+        }
1619
+
1620
+        /** @var IMountProvider|\PHPUnit\Framework\MockObject\MockObject $mountProvider */
1621
+        $mountProvider = $this->createMock(IMountProvider::class);
1622
+        $mountProvider->expects($this->any())
1623
+            ->method('getMountsForUser')
1624
+            ->willReturn($mounts);
1625
+
1626
+        $mountProviderCollection = \OC::$server->getMountProviderCollection();
1627
+        $mountProviderCollection->registerProvider($mountProvider);
1628
+
1629
+        return $mounts;
1630
+    }
1631
+
1632
+    /**
1633
+     * Test mount point move
1634
+     */
1635
+    public function testMountPointMove(): void {
1636
+        self::loginAsUser($this->user);
1637
+
1638
+        [$mount1, $mount2] = $this->createTestMovableMountPoints([
1639
+            $this->user . '/files/mount1',
1640
+            $this->user . '/files/mount2',
1641
+        ]);
1642
+        $mount1->expects($this->once())
1643
+            ->method('moveMount')
1644
+            ->willReturn(true);
1645
+
1646
+        $mount2->expects($this->once())
1647
+            ->method('moveMount')
1648
+            ->willReturn(true);
1649
+
1650
+        $view = new View('/' . $this->user . '/files/');
1651
+        $view->mkdir('sub');
1652
+
1653
+        $this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point');
1654
+        $this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory');
1655
+    }
1656
+
1657
+    public function testMoveMountPointOverwrite(): void {
1658
+        self::loginAsUser($this->user);
1659
+
1660
+        [$mount1, $mount2] = $this->createTestMovableMountPoints([
1661
+            $this->user . '/files/mount1',
1662
+            $this->user . '/files/mount2',
1663
+        ]);
1664
+
1665
+        $mount1->expects($this->never())
1666
+            ->method('moveMount');
1667
+
1668
+        $mount2->expects($this->never())
1669
+            ->method('moveMount');
1670
+
1671
+        $view = new View('/' . $this->user . '/files/');
1672
+
1673
+        $this->expectException(ForbiddenException::class);
1674
+        $view->rename('mount1', 'mount2');
1675
+    }
1676
+
1677
+    public function testMoveMountPointIntoMount(): void {
1678
+        self::loginAsUser($this->user);
1679
+
1680
+        [$mount1, $mount2] = $this->createTestMovableMountPoints([
1681
+            $this->user . '/files/mount1',
1682
+            $this->user . '/files/mount2',
1683
+        ]);
1684
+
1685
+        $mount1->expects($this->never())
1686
+            ->method('moveMount');
1687
+
1688
+        $mount2->expects($this->never())
1689
+            ->method('moveMount');
1690
+
1691
+        $view = new View('/' . $this->user . '/files/');
1692
+
1693
+        $this->expectException(ForbiddenException::class);
1694
+        $view->rename('mount1', 'mount2/sub');
1695
+    }
1696
+
1697
+    /**
1698
+     * Test that moving a mount point into a shared folder is forbidden
1699
+     */
1700
+    public function testMoveMountPointIntoSharedFolder(): void {
1701
+        self::loginAsUser($this->user);
1702
+
1703
+        [$mount1, $mount2] = $this->createTestMovableMountPoints([
1704
+            $this->user . '/files/mount1',
1705
+            $this->user . '/files/mount2',
1706
+        ]);
1707
+
1708
+        $mount1->expects($this->never())
1709
+            ->method('moveMount');
1710
+
1711
+        $mount2->expects($this->once())
1712
+            ->method('moveMount')
1713
+            ->willReturn(true);
1714
+
1715
+        $view = new View('/' . $this->user . '/files/');
1716
+        $view->mkdir('shareddir');
1717
+        $view->mkdir('shareddir/sub');
1718
+        $view->mkdir('shareddir/sub2');
1719
+        // Create a similar named but non-shared folder
1720
+        $view->mkdir('shareddir notshared');
1721
+
1722
+        $fileId = $view->getFileInfo('shareddir')->getId();
1723
+        $userObject = \OC::$server->getUserManager()->createUser('test2', 'IHateNonMockableStaticClasses');
1724
+
1725
+        $userFolder = \OC::$server->getUserFolder($this->user);
1726
+        $shareDir = $userFolder->get('shareddir');
1727
+        $shareManager = \OC::$server->get(IShareManager::class);
1728
+        $share = $shareManager->newShare();
1729
+        $share->setSharedWith('test2')
1730
+            ->setSharedBy($this->user)
1731
+            ->setShareType(IShare::TYPE_USER)
1732
+            ->setPermissions(\OCP\Constants::PERMISSION_READ)
1733
+            ->setNode($shareDir);
1734
+        $shareManager->createShare($share);
1735
+
1736
+        try {
1737
+            $view->rename('mount1', 'shareddir');
1738
+            $this->fail('Cannot overwrite shared folder');
1739
+        } catch (ForbiddenException $e) {
1740
+
1741
+        }
1742
+        try {
1743
+            $view->rename('mount1', 'shareddir/sub');
1744
+            $this->fail('Cannot move mount point into shared folder');
1745
+        } catch (ForbiddenException $e) {
1746
+
1747
+        }
1748
+        try {
1749
+            $view->rename('mount1', 'shareddir/sub/sub2');
1750
+            $this->fail('Cannot move mount point into shared subfolder');
1751
+        } catch (ForbiddenException $e) {
1752
+
1753
+        }
1754
+        $this->assertTrue($view->rename('mount2', 'shareddir notshared/sub'), 'Can move mount point into a similarly named but non-shared folder');
1755
+
1756
+        $shareManager->deleteShare($share);
1757
+        $userObject->delete();
1758
+    }
1759
+
1760
+    public static function basicOperationProviderForLocks(): array {
1761
+        return [
1762
+            // --- write hook ----
1763
+            [
1764
+                'touch',
1765
+                ['touch-create.txt'],
1766
+                'touch-create.txt',
1767
+                'create',
1768
+                ILockingProvider::LOCK_SHARED,
1769
+                ILockingProvider::LOCK_EXCLUSIVE,
1770
+                ILockingProvider::LOCK_SHARED,
1771
+            ],
1772
+            [
1773
+                'fopen',
1774
+                ['test-write.txt', 'w'],
1775
+                'test-write.txt',
1776
+                'write',
1777
+                ILockingProvider::LOCK_SHARED,
1778
+                ILockingProvider::LOCK_EXCLUSIVE,
1779
+                null,
1780
+                // exclusive lock stays until fclose
1781
+                ILockingProvider::LOCK_EXCLUSIVE,
1782
+            ],
1783
+            [
1784
+                'mkdir',
1785
+                ['newdir'],
1786
+                'newdir',
1787
+                'write',
1788
+                ILockingProvider::LOCK_SHARED,
1789
+                ILockingProvider::LOCK_EXCLUSIVE,
1790
+                ILockingProvider::LOCK_SHARED,
1791
+            ],
1792
+            [
1793
+                'file_put_contents',
1794
+                ['file_put_contents.txt', 'blah'],
1795
+                'file_put_contents.txt',
1796
+                'write',
1797
+                ILockingProvider::LOCK_SHARED,
1798
+                ILockingProvider::LOCK_EXCLUSIVE,
1799
+                ILockingProvider::LOCK_SHARED,
1800
+                null,
1801
+                0,
1802
+            ],
1803
+
1804
+            // ---- delete hook ----
1805
+            [
1806
+                'rmdir',
1807
+                ['dir'],
1808
+                'dir',
1809
+                'delete',
1810
+                ILockingProvider::LOCK_SHARED,
1811
+                ILockingProvider::LOCK_EXCLUSIVE,
1812
+                ILockingProvider::LOCK_SHARED,
1813
+            ],
1814
+            [
1815
+                'unlink',
1816
+                ['test.txt'],
1817
+                'test.txt',
1818
+                'delete',
1819
+                ILockingProvider::LOCK_SHARED,
1820
+                ILockingProvider::LOCK_EXCLUSIVE,
1821
+                ILockingProvider::LOCK_SHARED,
1822
+            ],
1823
+
1824
+            // ---- read hook (no post hooks) ----
1825
+            [
1826
+                'file_get_contents',
1827
+                ['test.txt'],
1828
+                'test.txt',
1829
+                'read',
1830
+                ILockingProvider::LOCK_SHARED,
1831
+                ILockingProvider::LOCK_SHARED,
1832
+                null,
1833
+                null,
1834
+                false,
1835
+            ],
1836
+            [
1837
+                'fopen',
1838
+                ['test.txt', 'r'],
1839
+                'test.txt',
1840
+                'read',
1841
+                ILockingProvider::LOCK_SHARED,
1842
+                ILockingProvider::LOCK_SHARED,
1843
+                null,
1844
+            ],
1845
+            [
1846
+                'opendir',
1847
+                ['dir'],
1848
+                'dir',
1849
+                'read',
1850
+                ILockingProvider::LOCK_SHARED,
1851
+                ILockingProvider::LOCK_SHARED,
1852
+                null,
1853
+            ],
1854
+
1855
+            // ---- no lock, touch hook ---
1856
+            ['touch', ['test.txt'], 'test.txt', 'touch', null, null, null],
1857
+
1858
+            // ---- no hooks, no locks ---
1859
+            ['is_dir', ['dir'], 'dir', null],
1860
+            ['is_file', ['dir'], 'dir', null],
1861
+            [
1862
+                'stat',
1863
+                ['dir'],
1864
+                'dir',
1865
+                null,
1866
+                ILockingProvider::LOCK_SHARED,
1867
+                ILockingProvider::LOCK_SHARED,
1868
+                ILockingProvider::LOCK_SHARED,
1869
+                null,
1870
+                false,
1871
+            ],
1872
+            [
1873
+                'filetype',
1874
+                ['dir'],
1875
+                'dir',
1876
+                null,
1877
+                ILockingProvider::LOCK_SHARED,
1878
+                ILockingProvider::LOCK_SHARED,
1879
+                ILockingProvider::LOCK_SHARED,
1880
+                null,
1881
+                false,
1882
+            ],
1883
+            [
1884
+                'filesize',
1885
+                ['dir'],
1886
+                'dir',
1887
+                null,
1888
+                ILockingProvider::LOCK_SHARED,
1889
+                ILockingProvider::LOCK_SHARED,
1890
+                ILockingProvider::LOCK_SHARED,
1891
+                null,
1892
+                /* Return an int */
1893
+                100
1894
+            ],
1895
+            ['isCreatable', ['dir'], 'dir', null],
1896
+            ['isReadable', ['dir'], 'dir', null],
1897
+            ['isUpdatable', ['dir'], 'dir', null],
1898
+            ['isDeletable', ['dir'], 'dir', null],
1899
+            ['isSharable', ['dir'], 'dir', null],
1900
+            ['file_exists', ['dir'], 'dir', null],
1901
+            [
1902
+                'filemtime',
1903
+                ['dir'],
1904
+                'dir',
1905
+                null,
1906
+                ILockingProvider::LOCK_SHARED,
1907
+                ILockingProvider::LOCK_SHARED,
1908
+                ILockingProvider::LOCK_SHARED,
1909
+                null,
1910
+                false,
1911
+            ],
1912
+        ];
1913
+    }
1914
+
1915
+    /**
1916
+     * Test whether locks are set before and after the operation
1917
+     *
1918
+     * @dataProvider basicOperationProviderForLocks
1919
+     *
1920
+     * @param string $operation operation name on the view
1921
+     * @param array $operationArgs arguments for the operation
1922
+     * @param string $lockedPath path of the locked item to check
1923
+     * @param string $hookType hook type
1924
+     * @param int $expectedLockBefore expected lock during pre hooks
1925
+     * @param int $expectedLockDuring expected lock during operation
1926
+     * @param int $expectedLockAfter expected lock during post hooks
1927
+     * @param int $expectedStrayLock expected lock after returning, should
1928
+     *                               be null (unlock) for most operations
1929
+     */
1930
+    public function testLockBasicOperation(
1931
+        $operation,
1932
+        $operationArgs,
1933
+        $lockedPath,
1934
+        $hookType,
1935
+        $expectedLockBefore = ILockingProvider::LOCK_SHARED,
1936
+        $expectedLockDuring = ILockingProvider::LOCK_SHARED,
1937
+        $expectedLockAfter = ILockingProvider::LOCK_SHARED,
1938
+        $expectedStrayLock = null,
1939
+        $returnValue = true,
1940
+    ): void {
1941
+        $view = new View('/' . $this->user . '/files/');
1942
+
1943
+        /** @var Temporary&MockObject $storage */
1944
+        $storage = $this->getMockBuilder(Temporary::class)
1945
+            ->onlyMethods([$operation])
1946
+            ->getMock();
1947
+
1948
+        /* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
1949
+        Server::get(ITrashManager::class)->pauseTrash();
1950
+
1951
+        Filesystem::mount($storage, [], $this->user . '/');
1952
+
1953
+        // work directly on disk because mkdir might be mocked
1954
+        $realPath = $storage->getSourcePath('');
1955
+        mkdir($realPath . '/files');
1956
+        mkdir($realPath . '/files/dir');
1957
+        file_put_contents($realPath . '/files/test.txt', 'blah');
1958
+        $storage->getScanner()->scan('files');
1959
+
1960
+        $storage->expects($this->once())
1961
+            ->method($operation)
1962
+            ->willReturnCallback(
1963
+                function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
1964
+                    $lockTypeDuring = $this->getFileLockType($view, $lockedPath);
1965
+
1966
+                    return $returnValue;
1967
+                }
1968
+            );
1969
+
1970
+        $this->assertNull($this->getFileLockType($view, $lockedPath), 'File not locked before operation');
1971
+
1972
+        $this->connectMockHooks($hookType, $view, $lockedPath, $lockTypePre, $lockTypePost);
1973
+
1974
+        // do operation
1975
+        call_user_func_array([$view, $operation], $operationArgs);
1976
+
1977
+        if ($hookType !== null) {
1978
+            $this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook');
1979
+            $this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook');
1980
+            $this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation');
1981
+        } else {
1982
+            $this->assertNull($lockTypeDuring, 'File not locked during operation');
1983
+        }
1984
+
1985
+        $this->assertEquals($expectedStrayLock, $this->getFileLockType($view, $lockedPath));
1986
+
1987
+        /* Resume trash to avoid side effects */
1988
+        Server::get(ITrashManager::class)->resumeTrash();
1989
+    }
1990
+
1991
+    /**
1992
+     * Test locks for file_put_content with stream.
1993
+     * This code path uses $storage->fopen instead
1994
+     */
1995
+    public function testLockFilePutContentWithStream(): void {
1996
+        $view = new View('/' . $this->user . '/files/');
1997
+
1998
+        $path = 'test_file_put_contents.txt';
1999
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2000
+        $storage = $this->getMockBuilder(Temporary::class)
2001
+            ->onlyMethods(['fopen'])
2002
+            ->getMock();
2003
+
2004
+        Filesystem::mount($storage, [], $this->user . '/');
2005
+        $storage->mkdir('files');
2006
+
2007
+        $storage->expects($this->once())
2008
+            ->method('fopen')
2009
+            ->willReturnCallback(
2010
+                function () use ($view, $path, &$lockTypeDuring) {
2011
+                    $lockTypeDuring = $this->getFileLockType($view, $path);
2012
+
2013
+                    return fopen('php://temp', 'r+');
2014
+                }
2015
+            );
2016
+
2017
+        $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
2018
+
2019
+        $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
2020
+
2021
+        // do operation
2022
+        $view->file_put_contents($path, fopen('php://temp', 'r+'));
2023
+
2024
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
2025
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePost, 'File locked properly during post-hook');
2026
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
2027
+
2028
+        $this->assertNull($this->getFileLockType($view, $path));
2029
+    }
2030
+
2031
+    /**
2032
+     * Test locks for fopen with fclose at the end
2033
+     */
2034
+    public function testLockFopen(): void {
2035
+        $view = new View('/' . $this->user . '/files/');
2036
+
2037
+        $path = 'test_file_put_contents.txt';
2038
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2039
+        $storage = $this->getMockBuilder(Temporary::class)
2040
+            ->onlyMethods(['fopen'])
2041
+            ->getMock();
2042
+
2043
+        Filesystem::mount($storage, [], $this->user . '/');
2044
+        $storage->mkdir('files');
2045
+
2046
+        $storage->expects($this->once())
2047
+            ->method('fopen')
2048
+            ->willReturnCallback(
2049
+                function () use ($view, $path, &$lockTypeDuring) {
2050
+                    $lockTypeDuring = $this->getFileLockType($view, $path);
2051
+
2052
+                    return fopen('php://temp', 'r+');
2053
+                }
2054
+            );
2055
+
2056
+        $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
2057
+
2058
+        $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
2059
+
2060
+        // do operation
2061
+        $res = $view->fopen($path, 'w');
2062
+
2063
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
2064
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
2065
+        $this->assertNull($lockTypePost, 'No post hook, no lock check possible');
2066
+
2067
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File still locked after fopen');
2068
+
2069
+        fclose($res);
2070
+
2071
+        $this->assertNull($this->getFileLockType($view, $path), 'File unlocked after fclose');
2072
+    }
2073
+
2074
+    /**
2075
+     * Test locks for fopen with fclose at the end
2076
+     *
2077
+     * @dataProvider basicOperationProviderForLocks
2078
+     *
2079
+     * @param string $operation operation name on the view
2080
+     * @param array $operationArgs arguments for the operation
2081
+     * @param string $path path of the locked item to check
2082
+     */
2083
+    public function testLockBasicOperationUnlocksAfterException(
2084
+        $operation,
2085
+        $operationArgs,
2086
+        $path,
2087
+    ): void {
2088
+        if ($operation === 'touch') {
2089
+            $this->markTestSkipped('touch handles storage exceptions internally');
2090
+        }
2091
+        $view = new View('/' . $this->user . '/files/');
2092
+
2093
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2094
+        $storage = $this->getMockBuilder(Temporary::class)
2095
+            ->onlyMethods([$operation])
2096
+            ->getMock();
2097
+
2098
+        /* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
2099
+        Server::get(ITrashManager::class)->pauseTrash();
2100
+
2101
+        Filesystem::mount($storage, [], $this->user . '/');
2102
+
2103
+        // work directly on disk because mkdir might be mocked
2104
+        $realPath = $storage->getSourcePath('');
2105
+        mkdir($realPath . '/files');
2106
+        mkdir($realPath . '/files/dir');
2107
+        file_put_contents($realPath . '/files/test.txt', 'blah');
2108
+        $storage->getScanner()->scan('files');
2109
+
2110
+        $storage->expects($this->once())
2111
+            ->method($operation)
2112
+            ->willReturnCallback(
2113
+                function () {
2114
+                    throw new \Exception('Simulated exception');
2115
+                }
2116
+            );
2117
+
2118
+        $thrown = false;
2119
+        try {
2120
+            call_user_func_array([$view, $operation], $operationArgs);
2121
+        } catch (\Exception $e) {
2122
+            $thrown = true;
2123
+            $this->assertEquals('Simulated exception', $e->getMessage());
2124
+        }
2125
+        $this->assertTrue($thrown, 'Exception was rethrown');
2126
+        $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
2127
+
2128
+        /* Resume trash to avoid side effects */
2129
+        Server::get(ITrashManager::class)->resumeTrash();
2130
+    }
2131
+
2132
+    public function testLockBasicOperationUnlocksAfterLockException(): void {
2133
+        $view = new View('/' . $this->user . '/files/');
2134
+
2135
+        $storage = new Temporary([]);
2136
+
2137
+        Filesystem::mount($storage, [], $this->user . '/');
2138
+
2139
+        $storage->mkdir('files');
2140
+        $storage->mkdir('files/dir');
2141
+        $storage->file_put_contents('files/test.txt', 'blah');
2142
+        $storage->getScanner()->scan('files');
2143
+
2144
+        // get a shared lock
2145
+        $handle = $view->fopen('test.txt', 'r');
2146
+
2147
+        $thrown = false;
2148
+        try {
2149
+            // try (and fail) to get a write lock
2150
+            $view->unlink('test.txt');
2151
+        } catch (\Exception $e) {
2152
+            $thrown = true;
2153
+            $this->assertInstanceOf(LockedException::class, $e);
2154
+        }
2155
+        $this->assertTrue($thrown, 'Exception was rethrown');
2156
+
2157
+        // clean shared lock
2158
+        fclose($handle);
2159
+
2160
+        $this->assertNull($this->getFileLockType($view, 'test.txt'), 'File got unlocked');
2161
+    }
2162
+
2163
+    /**
2164
+     * Test locks for fopen with fclose at the end
2165
+     *
2166
+     * @dataProvider basicOperationProviderForLocks
2167
+     *
2168
+     * @param string $operation operation name on the view
2169
+     * @param array $operationArgs arguments for the operation
2170
+     * @param string $path path of the locked item to check
2171
+     * @param string $hookType hook type
2172
+     */
2173
+    public function testLockBasicOperationUnlocksAfterCancelledHook(
2174
+        $operation,
2175
+        $operationArgs,
2176
+        $path,
2177
+        $hookType,
2178
+    ): void {
2179
+        $view = new View('/' . $this->user . '/files/');
2180
+
2181
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2182
+        $storage = $this->getMockBuilder(Temporary::class)
2183
+            ->onlyMethods([$operation])
2184
+            ->getMock();
2185
+
2186
+        Filesystem::mount($storage, [], $this->user . '/');
2187
+        $storage->mkdir('files');
2188
+
2189
+        Util::connectHook(
2190
+            Filesystem::CLASSNAME,
2191
+            $hookType,
2192
+            HookHelper::class,
2193
+            'cancellingCallback'
2194
+        );
2195
+
2196
+        call_user_func_array([$view, $operation], $operationArgs);
2197
+
2198
+        $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
2199
+    }
2200
+
2201
+    public static function lockFileRenameOrCopyDataProvider(): array {
2202
+        return [
2203
+            ['rename', ILockingProvider::LOCK_EXCLUSIVE],
2204
+            ['copy', ILockingProvider::LOCK_SHARED],
2205
+        ];
2206
+    }
2207
+
2208
+    /**
2209
+     * Test locks for rename or copy operation
2210
+     *
2211
+     * @dataProvider lockFileRenameOrCopyDataProvider
2212
+     *
2213
+     * @param string $operation operation to be done on the view
2214
+     * @param int $expectedLockTypeSourceDuring expected lock type on source file during
2215
+     *                                          the operation
2216
+     */
2217
+    public function testLockFileRename($operation, $expectedLockTypeSourceDuring): void {
2218
+        $view = new View('/' . $this->user . '/files/');
2219
+
2220
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2221
+        $storage = $this->getMockBuilder(Temporary::class)
2222
+            ->onlyMethods([$operation, 'getMetaData', 'filemtime'])
2223
+            ->getMock();
2224
+
2225
+        $storage->expects($this->any())
2226
+            ->method('getMetaData')
2227
+            ->will($this->returnValue([
2228
+                'mtime' => 1885434487,
2229
+                'etag' => '',
2230
+                'mimetype' => 'text/plain',
2231
+                'permissions' => Constants::PERMISSION_ALL,
2232
+                'size' => 3
2233
+            ]));
2234
+        $storage->expects($this->any())
2235
+            ->method('filemtime')
2236
+            ->willReturn(123456789);
2237
+
2238
+        $sourcePath = 'original.txt';
2239
+        $targetPath = 'target.txt';
2240
+
2241
+        Filesystem::mount($storage, [], $this->user . '/');
2242
+        $storage->mkdir('files');
2243
+        $view->file_put_contents($sourcePath, 'meh');
2244
+
2245
+        $storage->expects($this->once())
2246
+            ->method($operation)
2247
+            ->willReturnCallback(
2248
+                function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2249
+                    $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2250
+                    $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2251
+
2252
+                    return true;
2253
+                }
2254
+            );
2255
+
2256
+        $this->connectMockHooks($operation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2257
+        $this->connectMockHooks($operation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2258
+
2259
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2260
+        $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2261
+
2262
+        $view->$operation($sourcePath, $targetPath);
2263
+
2264
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
2265
+        $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
2266
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
2267
+
2268
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
2269
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
2270
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
2271
+
2272
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2273
+        $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2274
+    }
2275
+
2276
+    /**
2277
+     * simulate a failed copy operation.
2278
+     * We expect that we catch the exception, free the lock and re-throw it.
2279
+     *
2280
+     */
2281
+    public function testLockFileCopyException(): void {
2282
+        $this->expectException(\Exception::class);
2283
+
2284
+        $view = new View('/' . $this->user . '/files/');
2285
+
2286
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2287
+        $storage = $this->getMockBuilder(Temporary::class)
2288
+            ->onlyMethods(['copy'])
2289
+            ->getMock();
2290
+
2291
+        $sourcePath = 'original.txt';
2292
+        $targetPath = 'target.txt';
2293
+
2294
+        Filesystem::mount($storage, [], $this->user . '/');
2295
+        $storage->mkdir('files');
2296
+        $view->file_put_contents($sourcePath, 'meh');
2297
+
2298
+        $storage->expects($this->once())
2299
+            ->method('copy')
2300
+            ->willReturnCallback(
2301
+                function () {
2302
+                    throw new \Exception();
2303
+                }
2304
+            );
2305
+
2306
+        $this->connectMockHooks('copy', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2307
+        $this->connectMockHooks('copy', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2308
+
2309
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2310
+        $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2311
+
2312
+        try {
2313
+            $view->copy($sourcePath, $targetPath);
2314
+        } catch (\Exception $e) {
2315
+            $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2316
+            $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2317
+            throw $e;
2318
+        }
2319
+    }
2320
+
2321
+    /**
2322
+     * Test rename operation: unlock first path when second path was locked
2323
+     */
2324
+    public function testLockFileRenameUnlockOnException(): void {
2325
+        self::loginAsUser('test');
2326
+
2327
+        $view = new View('/' . $this->user . '/files/');
2328
+
2329
+        $sourcePath = 'original.txt';
2330
+        $targetPath = 'target.txt';
2331
+        $view->file_put_contents($sourcePath, 'meh');
2332
+
2333
+        // simulate that the target path is already locked
2334
+        $view->lockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
2335
+
2336
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2337
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file is locked before operation');
2338
+
2339
+        $thrown = false;
2340
+        try {
2341
+            $view->rename($sourcePath, $targetPath);
2342
+        } catch (LockedException $e) {
2343
+            $thrown = true;
2344
+        }
2345
+
2346
+        $this->assertTrue($thrown, 'LockedException thrown');
2347
+
2348
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2349
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file still locked after operation');
2350
+
2351
+        $view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
2352
+    }
2353
+
2354
+    /**
2355
+     * Test rename operation: unlock first path when second path was locked
2356
+     */
2357
+    public function testGetOwner(): void {
2358
+        self::loginAsUser('test');
2359
+
2360
+        $view = new View('/test/files/');
2361
+
2362
+        $path = 'foo.txt';
2363
+        $view->file_put_contents($path, 'meh');
2364
+
2365
+        $this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID());
2366
+
2367
+        $folderInfo = $view->getDirectoryContent('');
2368
+        $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2369
+            return $info->getName() === 'foo.txt';
2370
+        }));
2371
+
2372
+        $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
2373
+
2374
+        $subStorage = new Temporary();
2375
+        Filesystem::mount($subStorage, [], '/test/files/asd');
2376
+
2377
+        $folderInfo = $view->getDirectoryContent('');
2378
+        $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2379
+            return $info->getName() === 'asd';
2380
+        }));
2381
+
2382
+        $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID());
2383
+    }
2384
+
2385
+    public static function lockFileRenameOrCopyCrossStorageDataProvider(): array {
2386
+        return [
2387
+            ['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE],
2388
+            ['copy', 'copyFromStorage', ILockingProvider::LOCK_SHARED],
2389
+        ];
2390
+    }
2391
+
2392
+    /**
2393
+     * Test locks for rename or copy operation cross-storage
2394
+     *
2395
+     * @dataProvider lockFileRenameOrCopyCrossStorageDataProvider
2396
+     *
2397
+     * @param string $viewOperation operation to be done on the view
2398
+     * @param string $storageOperation operation to be mocked on the storage
2399
+     * @param int $expectedLockTypeSourceDuring expected lock type on source file during
2400
+     *                                          the operation
2401
+     */
2402
+    public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring): void {
2403
+        $view = new View('/' . $this->user . '/files/');
2404
+
2405
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2406
+        $storage = $this->getMockBuilder(Temporary::class)
2407
+            ->onlyMethods([$storageOperation])
2408
+            ->getMock();
2409
+        /** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage2 */
2410
+        $storage2 = $this->getMockBuilder(Temporary::class)
2411
+            ->onlyMethods([$storageOperation, 'getMetaData', 'filemtime'])
2412
+            ->getMock();
2413
+
2414
+        $storage2->expects($this->any())
2415
+            ->method('getMetaData')
2416
+            ->will($this->returnValue([
2417
+                'mtime' => 1885434487,
2418
+                'etag' => '',
2419
+                'mimetype' => 'text/plain',
2420
+                'permissions' => Constants::PERMISSION_ALL,
2421
+                'size' => 3
2422
+            ]));
2423
+        $storage2->expects($this->any())
2424
+            ->method('filemtime')
2425
+            ->willReturn(123456789);
2426
+
2427
+        $sourcePath = 'original.txt';
2428
+        $targetPath = 'substorage/target.txt';
2429
+
2430
+        Filesystem::mount($storage, [], $this->user . '/');
2431
+        Filesystem::mount($storage2, [], $this->user . '/files/substorage');
2432
+        $storage->mkdir('files');
2433
+        $view->file_put_contents($sourcePath, 'meh');
2434
+        $storage2->getUpdater()->update('');
2435
+
2436
+        $storage->expects($this->never())
2437
+            ->method($storageOperation);
2438
+        $storage2->expects($this->once())
2439
+            ->method($storageOperation)
2440
+            ->willReturnCallback(
2441
+                function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2442
+                    $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2443
+                    $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2444
+
2445
+                    return true;
2446
+                }
2447
+            );
2448
+
2449
+        $this->connectMockHooks($viewOperation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
2450
+        $this->connectMockHooks($viewOperation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
2451
+
2452
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
2453
+        $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
2454
+
2455
+        $view->$viewOperation($sourcePath, $targetPath);
2456
+
2457
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
2458
+        $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
2459
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
2460
+
2461
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
2462
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
2463
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
2464
+
2465
+        $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
2466
+        $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
2467
+    }
2468
+
2469
+    /**
2470
+     * Test locks when moving a mount point
2471
+     */
2472
+    public function testLockMoveMountPoint(): void {
2473
+        self::loginAsUser('test');
2474
+
2475
+        [$mount] = $this->createTestMovableMountPoints([
2476
+            $this->user . '/files/substorage',
2477
+        ]);
2478
+
2479
+        $view = new View('/' . $this->user . '/files/');
2480
+        $view->mkdir('subdir');
2481
+
2482
+        $sourcePath = 'substorage';
2483
+        $targetPath = 'subdir/substorage_moved';
2484
+
2485
+        $mount->expects($this->once())
2486
+            ->method('moveMount')
2487
+            ->willReturnCallback(
2488
+                function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) {
2489
+                    $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true);
2490
+                    $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true);
2491
+
2492
+                    $lockTypeSharedRootDuring = $this->getFileLockType($view, $sourcePath, false);
2493
+
2494
+                    $mount->setMountPoint($target);
2495
+
2496
+                    return true;
2497
+                }
2498
+            );
2499
+
2500
+        $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost, true);
2501
+        $this->connectMockHooks('rename', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost, true);
2502
+        // in pre-hook, mount point is still on $sourcePath
2503
+        $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSharedRootPre, $dummy, false);
2504
+        // in post-hook, mount point is now on $targetPath
2505
+        $this->connectMockHooks('rename', $view, $targetPath, $dummy, $lockTypeSharedRootPost, false);
2506
+
2507
+        $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked before operation');
2508
+        $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked before operation');
2509
+        $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked before operation');
2510
+
2511
+        $view->rename($sourcePath, $targetPath);
2512
+
2513
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source path locked properly during pre-hook');
2514
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeSourceDuring, 'Source path locked properly during operation');
2515
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source path locked properly during post-hook');
2516
+
2517
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target path locked properly during pre-hook');
2518
+        $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target path locked properly during operation');
2519
+        $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target path locked properly during post-hook');
2520
+
2521
+        $this->assertNull($lockTypeSharedRootPre, 'Shared storage root not locked during pre-hook');
2522
+        $this->assertNull($lockTypeSharedRootDuring, 'Shared storage root not locked during move');
2523
+        $this->assertNull($lockTypeSharedRootPost, 'Shared storage root not locked during post-hook');
2524
+
2525
+        $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked after operation');
2526
+        $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked after operation');
2527
+        $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked after operation');
2528
+    }
2529
+
2530
+    /**
2531
+     * Connect hook callbacks for hook type
2532
+     *
2533
+     * @param string $hookType hook type or null for none
2534
+     * @param View $view view to check the lock on
2535
+     * @param string $path path for which to check the lock
2536
+     * @param int $lockTypePre variable to receive lock type that was active in the pre-hook
2537
+     * @param int $lockTypePost variable to receive lock type that was active in the post-hook
2538
+     * @param bool $onMountPoint true to check the mount point instead of the
2539
+     *                           mounted storage
2540
+     */
2541
+    private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) {
2542
+        if ($hookType === null) {
2543
+            return;
2544
+        }
2545
+
2546
+        $eventHandler = $this->getMockBuilder(TestEventHandler::class)
2547
+            ->onlyMethods(['preCallback', 'postCallback'])
2548
+            ->getMock();
2549
+
2550
+        $eventHandler->expects($this->any())
2551
+            ->method('preCallback')
2552
+            ->willReturnCallback(
2553
+                function () use ($view, $path, $onMountPoint, &$lockTypePre) {
2554
+                    $lockTypePre = $this->getFileLockType($view, $path, $onMountPoint);
2555
+                }
2556
+            );
2557
+        $eventHandler->expects($this->any())
2558
+            ->method('postCallback')
2559
+            ->willReturnCallback(
2560
+                function () use ($view, $path, $onMountPoint, &$lockTypePost) {
2561
+                    $lockTypePost = $this->getFileLockType($view, $path, $onMountPoint);
2562
+                }
2563
+            );
2564
+
2565
+        if ($hookType !== null) {
2566
+            Util::connectHook(
2567
+                Filesystem::CLASSNAME,
2568
+                $hookType,
2569
+                $eventHandler,
2570
+                'preCallback'
2571
+            );
2572
+            Util::connectHook(
2573
+                Filesystem::CLASSNAME,
2574
+                'post_' . $hookType,
2575
+                $eventHandler,
2576
+                'postCallback'
2577
+            );
2578
+        }
2579
+    }
2580
+
2581
+    /**
2582
+     * Returns the file lock type
2583
+     *
2584
+     * @param View $view view
2585
+     * @param string $path path
2586
+     * @param bool $onMountPoint true to check the mount point instead of the
2587
+     *                           mounted storage
2588
+     *
2589
+     * @return int lock type or null if file was not locked
2590
+     */
2591
+    private function getFileLockType(View $view, $path, $onMountPoint = false) {
2592
+        if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE, $onMountPoint)) {
2593
+            return ILockingProvider::LOCK_EXCLUSIVE;
2594
+        } elseif ($this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED, $onMountPoint)) {
2595
+            return ILockingProvider::LOCK_SHARED;
2596
+        }
2597
+        return null;
2598
+    }
2599
+
2600
+
2601
+    public function testRemoveMoveableMountPoint(): void {
2602
+        $mountPoint = '/' . $this->user . '/files/mount/';
2603
+
2604
+        // Mock the mount point
2605
+        /** @var TestMoveableMountPoint|\PHPUnit\Framework\MockObject\MockObject $mount */
2606
+        $mount = $this->createMock(TestMoveableMountPoint::class);
2607
+        $mount->expects($this->once())
2608
+            ->method('getMountPoint')
2609
+            ->willReturn($mountPoint);
2610
+        $mount->expects($this->once())
2611
+            ->method('removeMount')
2612
+            ->willReturn('foo');
2613
+        $mount->expects($this->any())
2614
+            ->method('getInternalPath')
2615
+            ->willReturn('');
2616
+
2617
+        // Register mount
2618
+        Filesystem::getMountManager()->addMount($mount);
2619
+
2620
+        // Listen for events
2621
+        $eventHandler = $this->getMockBuilder(TestEventHandler::class)
2622
+            ->onlyMethods(['umount', 'post_umount'])
2623
+            ->getMock();
2624
+        $eventHandler->expects($this->once())
2625
+            ->method('umount')
2626
+            ->with([Filesystem::signal_param_path => '/mount']);
2627
+        $eventHandler->expects($this->once())
2628
+            ->method('post_umount')
2629
+            ->with([Filesystem::signal_param_path => '/mount']);
2630
+        Util::connectHook(
2631
+            Filesystem::CLASSNAME,
2632
+            'umount',
2633
+            $eventHandler,
2634
+            'umount'
2635
+        );
2636
+        Util::connectHook(
2637
+            Filesystem::CLASSNAME,
2638
+            'post_umount',
2639
+            $eventHandler,
2640
+            'post_umount'
2641
+        );
2642
+
2643
+        //Delete the mountpoint
2644
+        $view = new View('/' . $this->user . '/files');
2645
+        $this->assertEquals('foo', $view->rmdir('mount'));
2646
+    }
2647
+
2648
+    public static function mimeFilterProvider(): array {
2649
+        return [
2650
+            [null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']],
2651
+            ['text/plain', ['test1.txt', 'test2.txt']],
2652
+            ['text/markdown', ['test3.md']],
2653
+            ['text', ['test1.txt', 'test2.txt', 'test3.md']],
2654
+        ];
2655
+    }
2656
+
2657
+    /**
2658
+     * @param string $filter
2659
+     * @param string[] $expected
2660
+     * @dataProvider mimeFilterProvider
2661
+     */
2662
+    public function testGetDirectoryContentMimeFilter($filter, $expected): void {
2663
+        $storage1 = new Temporary();
2664
+        $root = self::getUniqueID('/');
2665
+        Filesystem::mount($storage1, [], $root . '/');
2666
+        $view = new View($root);
2667
+
2668
+        $view->file_put_contents('test1.txt', 'asd');
2669
+        $view->file_put_contents('test2.txt', 'asd');
2670
+        $view->file_put_contents('test3.md', 'asd');
2671
+        $view->file_put_contents('test4.png', '');
2672
+
2673
+        $content = $view->getDirectoryContent('', $filter);
2674
+
2675
+        $files = array_map(function (FileInfo $info) {
2676
+            return $info->getName();
2677
+        }, $content);
2678
+        sort($files);
2679
+
2680
+        $this->assertEquals($expected, $files);
2681
+    }
2682
+
2683
+    public function testFilePutContentsClearsChecksum(): void {
2684
+        $storage = new Temporary([]);
2685
+        $scanner = $storage->getScanner();
2686
+        $storage->file_put_contents('foo.txt', 'bar');
2687
+        Filesystem::mount($storage, [], '/test/');
2688
+        $scanner->scan('');
2689
+
2690
+        $view = new View('/test/foo.txt');
2691
+        $view->putFileInfo('.', ['checksum' => '42']);
2692
+
2693
+        $this->assertEquals('bar', $view->file_get_contents(''));
2694
+        $fh = tmpfile();
2695
+        fwrite($fh, 'fooo');
2696
+        rewind($fh);
2697
+        clearstatcache();
2698
+        $view->file_put_contents('', $fh);
2699
+        $this->assertEquals('fooo', $view->file_get_contents(''));
2700
+        $data = $view->getFileInfo('.');
2701
+        $this->assertEquals('', $data->getChecksum());
2702
+    }
2703
+
2704
+    public function testDeleteGhostFile(): void {
2705
+        $storage = new Temporary([]);
2706
+        $scanner = $storage->getScanner();
2707
+        $cache = $storage->getCache();
2708
+        $storage->file_put_contents('foo.txt', 'bar');
2709
+        Filesystem::mount($storage, [], '/test/');
2710
+        $scanner->scan('');
2711
+
2712
+        $storage->unlink('foo.txt');
2713
+
2714
+        $this->assertTrue($cache->inCache('foo.txt'));
2715
+
2716
+        $view = new View('/test');
2717
+        $rootInfo = $view->getFileInfo('');
2718
+        $this->assertEquals(3, $rootInfo->getSize());
2719
+        $view->unlink('foo.txt');
2720
+        $newInfo = $view->getFileInfo('');
2721
+
2722
+        $this->assertFalse($cache->inCache('foo.txt'));
2723
+        $this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
2724
+        $this->assertEquals(0, $newInfo->getSize());
2725
+    }
2726
+
2727
+    public function testDeleteGhostFolder(): void {
2728
+        $storage = new Temporary([]);
2729
+        $scanner = $storage->getScanner();
2730
+        $cache = $storage->getCache();
2731
+        $storage->mkdir('foo');
2732
+        $storage->file_put_contents('foo/foo.txt', 'bar');
2733
+        Filesystem::mount($storage, [], '/test/');
2734
+        $scanner->scan('');
2735
+
2736
+        $storage->rmdir('foo');
2737
+
2738
+        $this->assertTrue($cache->inCache('foo'));
2739
+        $this->assertTrue($cache->inCache('foo/foo.txt'));
2740
+
2741
+        $view = new View('/test');
2742
+        $rootInfo = $view->getFileInfo('');
2743
+        $this->assertEquals(3, $rootInfo->getSize());
2744
+        $view->rmdir('foo');
2745
+        $newInfo = $view->getFileInfo('');
2746
+
2747
+        $this->assertFalse($cache->inCache('foo'));
2748
+        $this->assertFalse($cache->inCache('foo/foo.txt'));
2749
+        $this->assertNotEquals($rootInfo->getEtag(), $newInfo->getEtag());
2750
+        $this->assertEquals(0, $newInfo->getSize());
2751
+    }
2752
+
2753
+    public function testCreateParentDirectories(): void {
2754
+        $view = $this->getMockBuilder(View::class)
2755
+            ->disableOriginalConstructor()
2756
+            ->onlyMethods([
2757
+                'is_file',
2758
+                'file_exists',
2759
+                'mkdir',
2760
+            ])
2761
+            ->getMock();
2762
+
2763
+        $view->expects($this->exactly(3))
2764
+            ->method('is_file')
2765
+            ->willReturnMap([
2766
+                ['/new', false],
2767
+                ['/new/folder', false],
2768
+                ['/new/folder/structure', false],
2769
+            ]);
2770
+        $view->expects($this->exactly(3))
2771
+            ->method('file_exists')
2772
+            ->willReturnMap([
2773
+                ['/new', true],
2774
+                ['/new/folder', false],
2775
+                ['/new/folder/structure', false],
2776
+            ]);
2777
+
2778
+        $calls = ['/new/folder', '/new/folder/structure'];
2779
+        $view->expects($this->exactly(2))
2780
+            ->method('mkdir')
2781
+            ->willReturnCallback(function ($dir) use (&$calls) {
2782
+                $expected = array_shift($calls);
2783
+                $this->assertEquals($expected, $dir);
2784
+            });
2785
+
2786
+        $this->assertTrue(self::invokePrivate($view, 'createParentDirectories', ['/new/folder/structure']));
2787
+    }
2788
+
2789
+    public function testCreateParentDirectoriesWithExistingFile(): void {
2790
+        $view = $this->getMockBuilder(View::class)
2791
+            ->disableOriginalConstructor()
2792
+            ->onlyMethods([
2793
+                'is_file',
2794
+                'file_exists',
2795
+                'mkdir',
2796
+            ])
2797
+            ->getMock();
2798
+
2799
+        $view
2800
+            ->expects($this->once())
2801
+            ->method('is_file')
2802
+            ->with('/file.txt')
2803
+            ->willReturn(true);
2804
+        $this->assertFalse(self::invokePrivate($view, 'createParentDirectories', ['/file.txt/folder/structure']));
2805
+    }
2806
+
2807
+    public function testCacheExtension(): void {
2808
+        $storage = new Temporary([]);
2809
+        $scanner = $storage->getScanner();
2810
+        $storage->file_put_contents('foo.txt', 'bar');
2811
+        $scanner->scan('');
2812
+
2813
+        Filesystem::mount($storage, [], '/test/');
2814
+        $view = new View('/test');
2815
+
2816
+        $info = $view->getFileInfo('/foo.txt');
2817
+        $this->assertEquals(0, $info->getUploadTime());
2818
+        $this->assertEquals(0, $info->getCreationTime());
2819
+
2820
+        $view->putFileInfo('/foo.txt', ['upload_time' => 25]);
2821
+
2822
+        $info = $view->getFileInfo('/foo.txt');
2823
+        $this->assertEquals(25, $info->getUploadTime());
2824
+        $this->assertEquals(0, $info->getCreationTime());
2825
+    }
2826
+
2827
+    public function testFopenGone(): void {
2828
+        $storage = new Temporary([]);
2829
+        $scanner = $storage->getScanner();
2830
+        $storage->file_put_contents('foo.txt', 'bar');
2831
+        $scanner->scan('');
2832
+        $cache = $storage->getCache();
2833
+
2834
+        Filesystem::mount($storage, [], '/test/');
2835
+        $view = new View('/test');
2836
+
2837
+        $storage->unlink('foo.txt');
2838
+
2839
+        $this->assertTrue($cache->inCache('foo.txt'));
2840
+
2841
+        $this->assertFalse($view->fopen('foo.txt', 'r'));
2842
+
2843
+        $this->assertFalse($cache->inCache('foo.txt'));
2844
+    }
2845
+
2846
+    public function testMountpointParentsCreated(): void {
2847
+        $storage1 = $this->getTestStorage();
2848
+        Filesystem::mount($storage1, [], '/');
2849
+
2850
+        $storage2 = $this->getTestStorage();
2851
+        Filesystem::mount($storage2, [], '/A/B/C');
2852
+
2853
+        $rootView = new View('');
2854
+
2855
+        $folderData = $rootView->getDirectoryContent('/');
2856
+        $this->assertCount(4, $folderData);
2857
+        $this->assertEquals('folder', $folderData[0]['name']);
2858
+        $this->assertEquals('foo.png', $folderData[1]['name']);
2859
+        $this->assertEquals('foo.txt', $folderData[2]['name']);
2860
+        $this->assertEquals('A', $folderData[3]['name']);
2861
+
2862
+        $folderData = $rootView->getDirectoryContent('/A');
2863
+        $this->assertCount(1, $folderData);
2864
+        $this->assertEquals('B', $folderData[0]['name']);
2865
+
2866
+        $folderData = $rootView->getDirectoryContent('/A/B');
2867
+        $this->assertCount(1, $folderData);
2868
+        $this->assertEquals('C', $folderData[0]['name']);
2869
+
2870
+        $folderData = $rootView->getDirectoryContent('/A/B/C');
2871
+        $this->assertCount(3, $folderData);
2872
+        $this->assertEquals('folder', $folderData[0]['name']);
2873
+        $this->assertEquals('foo.png', $folderData[1]['name']);
2874
+        $this->assertEquals('foo.txt', $folderData[2]['name']);
2875
+    }
2876
+
2877
+    public function testCopyPreservesContent() {
2878
+        $viewUser1 = new View('/' . 'userId' . '/files');
2879
+        $viewUser1->mkdir('');
2880
+        $viewUser1->file_put_contents('foo.txt', 'foo');
2881
+        $viewUser1->copy('foo.txt', 'bar.txt');
2882
+        $this->assertEquals('foo', $viewUser1->file_get_contents('bar.txt'));
2883
+    }
2884 2884
 }
Please login to merge, or discard this patch.
Spacing   +87 added lines, -87 removed lines patch added patch discarded remove patch
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 		}
143 143
 
144 144
 		if ($this->tempStorage) {
145
-			system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
145
+			system('rm -rf '.escapeshellarg($this->tempStorage->getDataDir()));
146 146
 		}
147 147
 
148 148
 		self::logout();
@@ -168,11 +168,11 @@  discard block
 block discarded – undo
168 168
 		$storage2 = $this->getTestStorage();
169 169
 		$storage3 = $this->getTestStorage();
170 170
 		$root = self::getUniqueID('/');
171
-		Filesystem::mount($storage1, [], $root . '/');
172
-		Filesystem::mount($storage2, [], $root . '/substorage');
173
-		Filesystem::mount($storage3, [], $root . '/folder/anotherstorage');
171
+		Filesystem::mount($storage1, [], $root.'/');
172
+		Filesystem::mount($storage2, [], $root.'/substorage');
173
+		Filesystem::mount($storage3, [], $root.'/folder/anotherstorage');
174 174
 		$textSize = strlen("dummy file data\n");
175
-		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo/logo.png');
175
+		$imageSize = filesize(\OC::$SERVERROOT.'/core/img/logo/logo.png');
176 176
 		$storageSize = $textSize * 2 + $imageSize;
177 177
 
178 178
 		$storageInfo = $storage3->getCache()->get('');
@@ -229,7 +229,7 @@  discard block
 block discarded – undo
229 229
 		$this->assertEquals('foo.png', $folderData[1]['name']);
230 230
 		$this->assertEquals('foo.txt', $folderData[2]['name']);
231 231
 
232
-		$folderView = new View($root . '/folder');
232
+		$folderView = new View($root.'/folder');
233 233
 		$this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
234 234
 
235 235
 		$cachedData = $rootView->getFileInfo('/foo.txt');
@@ -645,11 +645,11 @@  discard block
 block discarded – undo
645 645
 		$storage2 = $this->getTestStorage();
646 646
 		$defaultRoot = Filesystem::getRoot();
647 647
 		Filesystem::mount($storage1, [], '/');
648
-		Filesystem::mount($storage2, [], $defaultRoot . '/substorage');
648
+		Filesystem::mount($storage2, [], $defaultRoot.'/substorage');
649 649
 		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
650 650
 
651 651
 		$rootView = new View('');
652
-		$subView = new View($defaultRoot . '/substorage');
652
+		$subView = new View($defaultRoot.'/substorage');
653 653
 		$this->hookPath = null;
654 654
 
655 655
 		$rootView->file_put_contents('/foo.txt', 'asd');
@@ -689,7 +689,7 @@  discard block
 block discarded – undo
689 689
 		 */
690 690
 		$storage = new $class([]);
691 691
 		$textData = "dummy file data\n";
692
-		$imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo/logo.png');
692
+		$imgData = file_get_contents(\OC::$SERVERROOT.'/core/img/logo/logo.png');
693 693
 		$storage->mkdir('folder');
694 694
 		$storage->file_put_contents('foo.txt', $textData);
695 695
 		$storage->file_put_contents('foo.png', $imgData);
@@ -711,10 +711,10 @@  discard block
 block discarded – undo
711 711
 		$storage2 = $this->getTestStorage();
712 712
 		$defaultRoot = Filesystem::getRoot();
713 713
 		Filesystem::mount($storage1, [], '/');
714
-		Filesystem::mount($storage2, [], $defaultRoot . '_substorage');
714
+		Filesystem::mount($storage2, [], $defaultRoot.'_substorage');
715 715
 		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
716 716
 
717
-		$subView = new View($defaultRoot . '_substorage');
717
+		$subView = new View($defaultRoot.'_substorage');
718 718
 		$this->hookPath = null;
719 719
 
720 720
 		$subView->file_put_contents('/foo.txt', 'asd');
@@ -809,7 +809,7 @@  discard block
 block discarded – undo
809 809
 
810 810
 		$rootView = new View('');
811 811
 		foreach ($names as $name) {
812
-			$rootView->file_put_contents('/' . $name, 'dummy content');
812
+			$rootView->file_put_contents('/'.$name, 'dummy content');
813 813
 		}
814 814
 
815 815
 		$list = $rootView->getDirectoryContent('/');
@@ -851,15 +851,15 @@  discard block
 block discarded – undo
851 851
 			$depth = ((4000 - $tmpdirLength) / 57);
852 852
 		}
853 853
 		foreach (range(0, $depth - 1) as $i) {
854
-			$longPath .= $ds . $folderName;
854
+			$longPath .= $ds.$folderName;
855 855
 			$result = $rootView->mkdir($longPath);
856
-			$this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
856
+			$this->assertTrue($result, "mkdir failed on $i - path length: ".strlen($longPath));
857 857
 
858
-			$result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
858
+			$result = $rootView->file_put_contents($longPath."{$ds}test.txt", 'lorem');
859 859
 			$this->assertEquals(5, $result, "file_put_contents failed on $i");
860 860
 
861 861
 			$this->assertTrue($rootView->file_exists($longPath));
862
-			$this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
862
+			$this->assertTrue($rootView->file_exists($longPath."{$ds}test.txt"));
863 863
 		}
864 864
 
865 865
 		$cache = $storage->getCache();
@@ -872,11 +872,11 @@  discard block
 block discarded – undo
872 872
 			$this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
873 873
 			$this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
874 874
 
875
-			$cachedFile = $cache->get($longPath . '/test.txt');
875
+			$cachedFile = $cache->get($longPath.'/test.txt');
876 876
 			$this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
877 877
 			$this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
878 878
 
879
-			$longPath .= $ds . $folderName;
879
+			$longPath .= $ds.$folderName;
880 880
 		}
881 881
 	}
882 882
 
@@ -1087,7 +1087,7 @@  discard block
 block discarded – undo
1087 1087
 		$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
1088 1088
 		$depth = (4000 / 57);
1089 1089
 		foreach (range(0, $depth + 1) as $i) {
1090
-			$longPath .= '/' . $folderName;
1090
+			$longPath .= '/'.$folderName;
1091 1091
 		}
1092 1092
 
1093 1093
 		$storage = new Temporary([]);
@@ -1337,8 +1337,8 @@  discard block
 block discarded – undo
1337 1337
 		$view = new View($rootPath);
1338 1338
 		$storage = new Temporary([]);
1339 1339
 		Filesystem::mount($storage, [], '/');
1340
-		$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1341
-		$view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED);
1340
+		$this->assertTrue($view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1341
+		$view->lockFile($pathPrefix.'/foo/bar/asd', ILockingProvider::LOCK_SHARED);
1342 1342
 	}
1343 1343
 
1344 1344
 	/**
@@ -1356,8 +1356,8 @@  discard block
 block discarded – undo
1356 1356
 		$view = new View($rootPath);
1357 1357
 		$storage = new Temporary([]);
1358 1358
 		Filesystem::mount($storage, [], '/');
1359
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1360
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED));
1359
+		$this->assertFalse($view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1360
+		$this->assertFalse($view->lockFile($pathPrefix.'/foo/bar/asd', ILockingProvider::LOCK_SHARED));
1361 1361
 	}
1362 1362
 
1363 1363
 	/**
@@ -1378,8 +1378,8 @@  discard block
 block discarded – undo
1378 1378
 		$view = new View($rootPath);
1379 1379
 		$storage = new Temporary([]);
1380 1380
 		Filesystem::mount($storage, [], '/');
1381
-		$this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1382
-		$view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE);
1381
+		$this->assertTrue($view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_SHARED));
1382
+		$view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_EXCLUSIVE);
1383 1383
 	}
1384 1384
 
1385 1385
 	/**
@@ -1397,8 +1397,8 @@  discard block
 block discarded – undo
1397 1397
 		$view = new View($rootPath);
1398 1398
 		$storage = new Temporary([]);
1399 1399
 		Filesystem::mount($storage, [], '/');
1400
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED));
1401
-		$this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1400
+		$this->assertFalse($view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_SHARED));
1401
+		$this->assertFalse($view->lockFile($pathPrefix.'/foo/bar', ILockingProvider::LOCK_EXCLUSIVE));
1402 1402
 	}
1403 1403
 
1404 1404
 	/**
@@ -1607,7 +1607,7 @@  discard block
 block discarded – undo
1607 1607
 				->onlyMethods([])
1608 1608
 				->getMock();
1609 1609
 			$storage->method('getId')->willReturn('non-null-id');
1610
-			$storage->method('getStorageCache')->willReturnCallback(function () use ($storage) {
1610
+			$storage->method('getStorageCache')->willReturnCallback(function() use ($storage) {
1611 1611
 				return new \OC\Files\Cache\Storage($storage, true, \OC::$server->get(IDBConnection::class));
1612 1612
 			});
1613 1613
 
@@ -1636,8 +1636,8 @@  discard block
 block discarded – undo
1636 1636
 		self::loginAsUser($this->user);
1637 1637
 
1638 1638
 		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1639
-			$this->user . '/files/mount1',
1640
-			$this->user . '/files/mount2',
1639
+			$this->user.'/files/mount1',
1640
+			$this->user.'/files/mount2',
1641 1641
 		]);
1642 1642
 		$mount1->expects($this->once())
1643 1643
 			->method('moveMount')
@@ -1647,7 +1647,7 @@  discard block
 block discarded – undo
1647 1647
 			->method('moveMount')
1648 1648
 			->willReturn(true);
1649 1649
 
1650
-		$view = new View('/' . $this->user . '/files/');
1650
+		$view = new View('/'.$this->user.'/files/');
1651 1651
 		$view->mkdir('sub');
1652 1652
 
1653 1653
 		$this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point');
@@ -1658,8 +1658,8 @@  discard block
 block discarded – undo
1658 1658
 		self::loginAsUser($this->user);
1659 1659
 
1660 1660
 		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1661
-			$this->user . '/files/mount1',
1662
-			$this->user . '/files/mount2',
1661
+			$this->user.'/files/mount1',
1662
+			$this->user.'/files/mount2',
1663 1663
 		]);
1664 1664
 
1665 1665
 		$mount1->expects($this->never())
@@ -1668,7 +1668,7 @@  discard block
 block discarded – undo
1668 1668
 		$mount2->expects($this->never())
1669 1669
 			->method('moveMount');
1670 1670
 
1671
-		$view = new View('/' . $this->user . '/files/');
1671
+		$view = new View('/'.$this->user.'/files/');
1672 1672
 
1673 1673
 		$this->expectException(ForbiddenException::class);
1674 1674
 		$view->rename('mount1', 'mount2');
@@ -1678,8 +1678,8 @@  discard block
 block discarded – undo
1678 1678
 		self::loginAsUser($this->user);
1679 1679
 
1680 1680
 		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1681
-			$this->user . '/files/mount1',
1682
-			$this->user . '/files/mount2',
1681
+			$this->user.'/files/mount1',
1682
+			$this->user.'/files/mount2',
1683 1683
 		]);
1684 1684
 
1685 1685
 		$mount1->expects($this->never())
@@ -1688,7 +1688,7 @@  discard block
 block discarded – undo
1688 1688
 		$mount2->expects($this->never())
1689 1689
 			->method('moveMount');
1690 1690
 
1691
-		$view = new View('/' . $this->user . '/files/');
1691
+		$view = new View('/'.$this->user.'/files/');
1692 1692
 
1693 1693
 		$this->expectException(ForbiddenException::class);
1694 1694
 		$view->rename('mount1', 'mount2/sub');
@@ -1701,8 +1701,8 @@  discard block
 block discarded – undo
1701 1701
 		self::loginAsUser($this->user);
1702 1702
 
1703 1703
 		[$mount1, $mount2] = $this->createTestMovableMountPoints([
1704
-			$this->user . '/files/mount1',
1705
-			$this->user . '/files/mount2',
1704
+			$this->user.'/files/mount1',
1705
+			$this->user.'/files/mount2',
1706 1706
 		]);
1707 1707
 
1708 1708
 		$mount1->expects($this->never())
@@ -1712,7 +1712,7 @@  discard block
 block discarded – undo
1712 1712
 			->method('moveMount')
1713 1713
 			->willReturn(true);
1714 1714
 
1715
-		$view = new View('/' . $this->user . '/files/');
1715
+		$view = new View('/'.$this->user.'/files/');
1716 1716
 		$view->mkdir('shareddir');
1717 1717
 		$view->mkdir('shareddir/sub');
1718 1718
 		$view->mkdir('shareddir/sub2');
@@ -1938,7 +1938,7 @@  discard block
 block discarded – undo
1938 1938
 		$expectedStrayLock = null,
1939 1939
 		$returnValue = true,
1940 1940
 	): void {
1941
-		$view = new View('/' . $this->user . '/files/');
1941
+		$view = new View('/'.$this->user.'/files/');
1942 1942
 
1943 1943
 		/** @var Temporary&MockObject $storage */
1944 1944
 		$storage = $this->getMockBuilder(Temporary::class)
@@ -1948,19 +1948,19 @@  discard block
 block discarded – undo
1948 1948
 		/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
1949 1949
 		Server::get(ITrashManager::class)->pauseTrash();
1950 1950
 
1951
-		Filesystem::mount($storage, [], $this->user . '/');
1951
+		Filesystem::mount($storage, [], $this->user.'/');
1952 1952
 
1953 1953
 		// work directly on disk because mkdir might be mocked
1954 1954
 		$realPath = $storage->getSourcePath('');
1955
-		mkdir($realPath . '/files');
1956
-		mkdir($realPath . '/files/dir');
1957
-		file_put_contents($realPath . '/files/test.txt', 'blah');
1955
+		mkdir($realPath.'/files');
1956
+		mkdir($realPath.'/files/dir');
1957
+		file_put_contents($realPath.'/files/test.txt', 'blah');
1958 1958
 		$storage->getScanner()->scan('files');
1959 1959
 
1960 1960
 		$storage->expects($this->once())
1961 1961
 			->method($operation)
1962 1962
 			->willReturnCallback(
1963
-				function () use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
1963
+				function() use ($view, $lockedPath, &$lockTypeDuring, $returnValue) {
1964 1964
 					$lockTypeDuring = $this->getFileLockType($view, $lockedPath);
1965 1965
 
1966 1966
 					return $returnValue;
@@ -1993,7 +1993,7 @@  discard block
 block discarded – undo
1993 1993
 	 * This code path uses $storage->fopen instead
1994 1994
 	 */
1995 1995
 	public function testLockFilePutContentWithStream(): void {
1996
-		$view = new View('/' . $this->user . '/files/');
1996
+		$view = new View('/'.$this->user.'/files/');
1997 1997
 
1998 1998
 		$path = 'test_file_put_contents.txt';
1999 1999
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
@@ -2001,13 +2001,13 @@  discard block
 block discarded – undo
2001 2001
 			->onlyMethods(['fopen'])
2002 2002
 			->getMock();
2003 2003
 
2004
-		Filesystem::mount($storage, [], $this->user . '/');
2004
+		Filesystem::mount($storage, [], $this->user.'/');
2005 2005
 		$storage->mkdir('files');
2006 2006
 
2007 2007
 		$storage->expects($this->once())
2008 2008
 			->method('fopen')
2009 2009
 			->willReturnCallback(
2010
-				function () use ($view, $path, &$lockTypeDuring) {
2010
+				function() use ($view, $path, &$lockTypeDuring) {
2011 2011
 					$lockTypeDuring = $this->getFileLockType($view, $path);
2012 2012
 
2013 2013
 					return fopen('php://temp', 'r+');
@@ -2032,7 +2032,7 @@  discard block
 block discarded – undo
2032 2032
 	 * Test locks for fopen with fclose at the end
2033 2033
 	 */
2034 2034
 	public function testLockFopen(): void {
2035
-		$view = new View('/' . $this->user . '/files/');
2035
+		$view = new View('/'.$this->user.'/files/');
2036 2036
 
2037 2037
 		$path = 'test_file_put_contents.txt';
2038 2038
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
@@ -2040,13 +2040,13 @@  discard block
 block discarded – undo
2040 2040
 			->onlyMethods(['fopen'])
2041 2041
 			->getMock();
2042 2042
 
2043
-		Filesystem::mount($storage, [], $this->user . '/');
2043
+		Filesystem::mount($storage, [], $this->user.'/');
2044 2044
 		$storage->mkdir('files');
2045 2045
 
2046 2046
 		$storage->expects($this->once())
2047 2047
 			->method('fopen')
2048 2048
 			->willReturnCallback(
2049
-				function () use ($view, $path, &$lockTypeDuring) {
2049
+				function() use ($view, $path, &$lockTypeDuring) {
2050 2050
 					$lockTypeDuring = $this->getFileLockType($view, $path);
2051 2051
 
2052 2052
 					return fopen('php://temp', 'r+');
@@ -2088,7 +2088,7 @@  discard block
 block discarded – undo
2088 2088
 		if ($operation === 'touch') {
2089 2089
 			$this->markTestSkipped('touch handles storage exceptions internally');
2090 2090
 		}
2091
-		$view = new View('/' . $this->user . '/files/');
2091
+		$view = new View('/'.$this->user.'/files/');
2092 2092
 
2093 2093
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2094 2094
 		$storage = $this->getMockBuilder(Temporary::class)
@@ -2098,19 +2098,19 @@  discard block
 block discarded – undo
2098 2098
 		/* Pause trash to avoid the trashbin intercepting rmdir and unlink calls */
2099 2099
 		Server::get(ITrashManager::class)->pauseTrash();
2100 2100
 
2101
-		Filesystem::mount($storage, [], $this->user . '/');
2101
+		Filesystem::mount($storage, [], $this->user.'/');
2102 2102
 
2103 2103
 		// work directly on disk because mkdir might be mocked
2104 2104
 		$realPath = $storage->getSourcePath('');
2105
-		mkdir($realPath . '/files');
2106
-		mkdir($realPath . '/files/dir');
2107
-		file_put_contents($realPath . '/files/test.txt', 'blah');
2105
+		mkdir($realPath.'/files');
2106
+		mkdir($realPath.'/files/dir');
2107
+		file_put_contents($realPath.'/files/test.txt', 'blah');
2108 2108
 		$storage->getScanner()->scan('files');
2109 2109
 
2110 2110
 		$storage->expects($this->once())
2111 2111
 			->method($operation)
2112 2112
 			->willReturnCallback(
2113
-				function () {
2113
+				function() {
2114 2114
 					throw new \Exception('Simulated exception');
2115 2115
 				}
2116 2116
 			);
@@ -2130,11 +2130,11 @@  discard block
 block discarded – undo
2130 2130
 	}
2131 2131
 
2132 2132
 	public function testLockBasicOperationUnlocksAfterLockException(): void {
2133
-		$view = new View('/' . $this->user . '/files/');
2133
+		$view = new View('/'.$this->user.'/files/');
2134 2134
 
2135 2135
 		$storage = new Temporary([]);
2136 2136
 
2137
-		Filesystem::mount($storage, [], $this->user . '/');
2137
+		Filesystem::mount($storage, [], $this->user.'/');
2138 2138
 
2139 2139
 		$storage->mkdir('files');
2140 2140
 		$storage->mkdir('files/dir');
@@ -2176,14 +2176,14 @@  discard block
 block discarded – undo
2176 2176
 		$path,
2177 2177
 		$hookType,
2178 2178
 	): void {
2179
-		$view = new View('/' . $this->user . '/files/');
2179
+		$view = new View('/'.$this->user.'/files/');
2180 2180
 
2181 2181
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2182 2182
 		$storage = $this->getMockBuilder(Temporary::class)
2183 2183
 			->onlyMethods([$operation])
2184 2184
 			->getMock();
2185 2185
 
2186
-		Filesystem::mount($storage, [], $this->user . '/');
2186
+		Filesystem::mount($storage, [], $this->user.'/');
2187 2187
 		$storage->mkdir('files');
2188 2188
 
2189 2189
 		Util::connectHook(
@@ -2215,7 +2215,7 @@  discard block
 block discarded – undo
2215 2215
 	 *                                          the operation
2216 2216
 	 */
2217 2217
 	public function testLockFileRename($operation, $expectedLockTypeSourceDuring): void {
2218
-		$view = new View('/' . $this->user . '/files/');
2218
+		$view = new View('/'.$this->user.'/files/');
2219 2219
 
2220 2220
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2221 2221
 		$storage = $this->getMockBuilder(Temporary::class)
@@ -2238,14 +2238,14 @@  discard block
 block discarded – undo
2238 2238
 		$sourcePath = 'original.txt';
2239 2239
 		$targetPath = 'target.txt';
2240 2240
 
2241
-		Filesystem::mount($storage, [], $this->user . '/');
2241
+		Filesystem::mount($storage, [], $this->user.'/');
2242 2242
 		$storage->mkdir('files');
2243 2243
 		$view->file_put_contents($sourcePath, 'meh');
2244 2244
 
2245 2245
 		$storage->expects($this->once())
2246 2246
 			->method($operation)
2247 2247
 			->willReturnCallback(
2248
-				function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2248
+				function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2249 2249
 					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2250 2250
 					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2251 2251
 
@@ -2281,7 +2281,7 @@  discard block
 block discarded – undo
2281 2281
 	public function testLockFileCopyException(): void {
2282 2282
 		$this->expectException(\Exception::class);
2283 2283
 
2284
-		$view = new View('/' . $this->user . '/files/');
2284
+		$view = new View('/'.$this->user.'/files/');
2285 2285
 
2286 2286
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2287 2287
 		$storage = $this->getMockBuilder(Temporary::class)
@@ -2291,14 +2291,14 @@  discard block
 block discarded – undo
2291 2291
 		$sourcePath = 'original.txt';
2292 2292
 		$targetPath = 'target.txt';
2293 2293
 
2294
-		Filesystem::mount($storage, [], $this->user . '/');
2294
+		Filesystem::mount($storage, [], $this->user.'/');
2295 2295
 		$storage->mkdir('files');
2296 2296
 		$view->file_put_contents($sourcePath, 'meh');
2297 2297
 
2298 2298
 		$storage->expects($this->once())
2299 2299
 			->method('copy')
2300 2300
 			->willReturnCallback(
2301
-				function () {
2301
+				function() {
2302 2302
 					throw new \Exception();
2303 2303
 				}
2304 2304
 			);
@@ -2324,7 +2324,7 @@  discard block
 block discarded – undo
2324 2324
 	public function testLockFileRenameUnlockOnException(): void {
2325 2325
 		self::loginAsUser('test');
2326 2326
 
2327
-		$view = new View('/' . $this->user . '/files/');
2327
+		$view = new View('/'.$this->user.'/files/');
2328 2328
 
2329 2329
 		$sourcePath = 'original.txt';
2330 2330
 		$targetPath = 'target.txt';
@@ -2365,7 +2365,7 @@  discard block
 block discarded – undo
2365 2365
 		$this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID());
2366 2366
 
2367 2367
 		$folderInfo = $view->getDirectoryContent('');
2368
-		$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2368
+		$folderInfo = array_values(array_filter($folderInfo, function(FileInfo $info) {
2369 2369
 			return $info->getName() === 'foo.txt';
2370 2370
 		}));
2371 2371
 
@@ -2375,7 +2375,7 @@  discard block
 block discarded – undo
2375 2375
 		Filesystem::mount($subStorage, [], '/test/files/asd');
2376 2376
 
2377 2377
 		$folderInfo = $view->getDirectoryContent('');
2378
-		$folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) {
2378
+		$folderInfo = array_values(array_filter($folderInfo, function(FileInfo $info) {
2379 2379
 			return $info->getName() === 'asd';
2380 2380
 		}));
2381 2381
 
@@ -2400,7 +2400,7 @@  discard block
 block discarded – undo
2400 2400
 	 *                                          the operation
2401 2401
 	 */
2402 2402
 	public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring): void {
2403
-		$view = new View('/' . $this->user . '/files/');
2403
+		$view = new View('/'.$this->user.'/files/');
2404 2404
 
2405 2405
 		/** @var Temporary|\PHPUnit\Framework\MockObject\MockObject $storage */
2406 2406
 		$storage = $this->getMockBuilder(Temporary::class)
@@ -2427,8 +2427,8 @@  discard block
 block discarded – undo
2427 2427
 		$sourcePath = 'original.txt';
2428 2428
 		$targetPath = 'substorage/target.txt';
2429 2429
 
2430
-		Filesystem::mount($storage, [], $this->user . '/');
2431
-		Filesystem::mount($storage2, [], $this->user . '/files/substorage');
2430
+		Filesystem::mount($storage, [], $this->user.'/');
2431
+		Filesystem::mount($storage2, [], $this->user.'/files/substorage');
2432 2432
 		$storage->mkdir('files');
2433 2433
 		$view->file_put_contents($sourcePath, 'meh');
2434 2434
 		$storage2->getUpdater()->update('');
@@ -2438,7 +2438,7 @@  discard block
 block discarded – undo
2438 2438
 		$storage2->expects($this->once())
2439 2439
 			->method($storageOperation)
2440 2440
 			->willReturnCallback(
2441
-				function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2441
+				function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) {
2442 2442
 					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
2443 2443
 					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
2444 2444
 
@@ -2473,10 +2473,10 @@  discard block
 block discarded – undo
2473 2473
 		self::loginAsUser('test');
2474 2474
 
2475 2475
 		[$mount] = $this->createTestMovableMountPoints([
2476
-			$this->user . '/files/substorage',
2476
+			$this->user.'/files/substorage',
2477 2477
 		]);
2478 2478
 
2479
-		$view = new View('/' . $this->user . '/files/');
2479
+		$view = new View('/'.$this->user.'/files/');
2480 2480
 		$view->mkdir('subdir');
2481 2481
 
2482 2482
 		$sourcePath = 'substorage';
@@ -2485,7 +2485,7 @@  discard block
 block discarded – undo
2485 2485
 		$mount->expects($this->once())
2486 2486
 			->method('moveMount')
2487 2487
 			->willReturnCallback(
2488
-				function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) {
2488
+				function($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) {
2489 2489
 					$lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true);
2490 2490
 					$lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true);
2491 2491
 
@@ -2550,14 +2550,14 @@  discard block
 block discarded – undo
2550 2550
 		$eventHandler->expects($this->any())
2551 2551
 			->method('preCallback')
2552 2552
 			->willReturnCallback(
2553
-				function () use ($view, $path, $onMountPoint, &$lockTypePre) {
2553
+				function() use ($view, $path, $onMountPoint, &$lockTypePre) {
2554 2554
 					$lockTypePre = $this->getFileLockType($view, $path, $onMountPoint);
2555 2555
 				}
2556 2556
 			);
2557 2557
 		$eventHandler->expects($this->any())
2558 2558
 			->method('postCallback')
2559 2559
 			->willReturnCallback(
2560
-				function () use ($view, $path, $onMountPoint, &$lockTypePost) {
2560
+				function() use ($view, $path, $onMountPoint, &$lockTypePost) {
2561 2561
 					$lockTypePost = $this->getFileLockType($view, $path, $onMountPoint);
2562 2562
 				}
2563 2563
 			);
@@ -2571,7 +2571,7 @@  discard block
 block discarded – undo
2571 2571
 			);
2572 2572
 			Util::connectHook(
2573 2573
 				Filesystem::CLASSNAME,
2574
-				'post_' . $hookType,
2574
+				'post_'.$hookType,
2575 2575
 				$eventHandler,
2576 2576
 				'postCallback'
2577 2577
 			);
@@ -2599,7 +2599,7 @@  discard block
 block discarded – undo
2599 2599
 
2600 2600
 
2601 2601
 	public function testRemoveMoveableMountPoint(): void {
2602
-		$mountPoint = '/' . $this->user . '/files/mount/';
2602
+		$mountPoint = '/'.$this->user.'/files/mount/';
2603 2603
 
2604 2604
 		// Mock the mount point
2605 2605
 		/** @var TestMoveableMountPoint|\PHPUnit\Framework\MockObject\MockObject $mount */
@@ -2641,7 +2641,7 @@  discard block
 block discarded – undo
2641 2641
 		);
2642 2642
 
2643 2643
 		//Delete the mountpoint
2644
-		$view = new View('/' . $this->user . '/files');
2644
+		$view = new View('/'.$this->user.'/files');
2645 2645
 		$this->assertEquals('foo', $view->rmdir('mount'));
2646 2646
 	}
2647 2647
 
@@ -2662,7 +2662,7 @@  discard block
 block discarded – undo
2662 2662
 	public function testGetDirectoryContentMimeFilter($filter, $expected): void {
2663 2663
 		$storage1 = new Temporary();
2664 2664
 		$root = self::getUniqueID('/');
2665
-		Filesystem::mount($storage1, [], $root . '/');
2665
+		Filesystem::mount($storage1, [], $root.'/');
2666 2666
 		$view = new View($root);
2667 2667
 
2668 2668
 		$view->file_put_contents('test1.txt', 'asd');
@@ -2672,7 +2672,7 @@  discard block
 block discarded – undo
2672 2672
 
2673 2673
 		$content = $view->getDirectoryContent('', $filter);
2674 2674
 
2675
-		$files = array_map(function (FileInfo $info) {
2675
+		$files = array_map(function(FileInfo $info) {
2676 2676
 			return $info->getName();
2677 2677
 		}, $content);
2678 2678
 		sort($files);
@@ -2778,7 +2778,7 @@  discard block
 block discarded – undo
2778 2778
 		$calls = ['/new/folder', '/new/folder/structure'];
2779 2779
 		$view->expects($this->exactly(2))
2780 2780
 			->method('mkdir')
2781
-			->willReturnCallback(function ($dir) use (&$calls) {
2781
+			->willReturnCallback(function($dir) use (&$calls) {
2782 2782
 				$expected = array_shift($calls);
2783 2783
 				$this->assertEquals($expected, $dir);
2784 2784
 			});
@@ -2875,7 +2875,7 @@  discard block
 block discarded – undo
2875 2875
 	}
2876 2876
 
2877 2877
 	public function testCopyPreservesContent() {
2878
-		$viewUser1 = new View('/' . 'userId' . '/files');
2878
+		$viewUser1 = new View('/'.'userId'.'/files');
2879 2879
 		$viewUser1->mkdir('');
2880 2880
 		$viewUser1->file_put_contents('foo.txt', 'foo');
2881 2881
 		$viewUser1->copy('foo.txt', 'bar.txt');
Please login to merge, or discard this patch.
tests/lib/Share20/ManagerTest.php 2 patches
Indentation   +4698 added lines, -4698 removed lines patch added patch discarded remove patch
@@ -60,10 +60,10 @@  discard block
 block discarded – undo
60 60
 use Psr\Log\LoggerInterface;
61 61
 
62 62
 class DummyShareManagerListener {
63
-	public function post() {
64
-	}
65
-	public function listener() {
66
-	}
63
+    public function post() {
64
+    }
65
+    public function listener() {
66
+    }
67 67
 }
68 68
 
69 69
 /**
@@ -73,4897 +73,4897 @@  discard block
 block discarded – undo
73 73
  * @group DB
74 74
  */
75 75
 class ManagerTest extends \Test\TestCase {
76
-	/** @var Manager */
77
-	protected $manager;
78
-	/** @var LoggerInterface|MockObject */
79
-	protected $logger;
80
-	/** @var IConfig|MockObject */
81
-	protected $config;
82
-	/** @var ISecureRandom|MockObject */
83
-	protected $secureRandom;
84
-	/** @var IHasher|MockObject */
85
-	protected $hasher;
86
-	/** @var IShareProvider|MockObject */
87
-	protected $defaultProvider;
88
-	/** @var IMountManager|MockObject */
89
-	protected $mountManager;
90
-	/** @var IGroupManager|MockObject */
91
-	protected $groupManager;
92
-	/** @var IL10N|MockObject */
93
-	protected $l;
94
-	/** @var IFactory|MockObject */
95
-	protected $l10nFactory;
96
-	/** @var DummyFactory */
97
-	protected $factory;
98
-	/** @var IUserManager|MockObject */
99
-	protected $userManager;
100
-	/** @var IRootFolder | MockObject */
101
-	protected $rootFolder;
102
-	/** @var IEventDispatcher|MockObject */
103
-	protected $dispatcher;
104
-	/** @var IMailer|MockObject */
105
-	protected $mailer;
106
-	/** @var IURLGenerator|MockObject */
107
-	protected $urlGenerator;
108
-	/** @var \OC_Defaults|MockObject */
109
-	protected $defaults;
110
-	/** @var IUserSession|MockObject */
111
-	protected $userSession;
112
-	/** @var KnownUserService|MockObject */
113
-	protected $knownUserService;
114
-	/** @var ShareDisableChecker|MockObject */
115
-	protected $shareDisabledChecker;
116
-	private DateTimeZone $timezone;
117
-	/** @var IDateTimeZone|MockObject */
118
-	protected $dateTimeZone;
119
-	/** @var IAppConfig|MockObject */
120
-	protected $appConfig;
121
-
122
-	protected function setUp(): void {
123
-		$this->logger = $this->createMock(LoggerInterface::class);
124
-		$this->config = $this->createMock(IConfig::class);
125
-		$this->secureRandom = $this->createMock(ISecureRandom::class);
126
-		$this->hasher = $this->createMock(IHasher::class);
127
-		$this->mountManager = $this->createMock(IMountManager::class);
128
-		$this->groupManager = $this->createMock(IGroupManager::class);
129
-		$this->userManager = $this->createMock(IUserManager::class);
130
-		$this->rootFolder = $this->createMock(IRootFolder::class);
131
-		$this->mailer = $this->createMock(IMailer::class);
132
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
133
-		$this->defaults = $this->createMock(\OC_Defaults::class);
134
-		$this->dispatcher = $this->createMock(IEventDispatcher::class);
135
-		$this->userSession = $this->createMock(IUserSession::class);
136
-		$this->knownUserService = $this->createMock(KnownUserService::class);
137
-
138
-		$this->shareDisabledChecker = new ShareDisableChecker($this->config, $this->userManager, $this->groupManager);
139
-		$this->dateTimeZone = $this->createMock(IDateTimeZone::class);
140
-		$this->timezone = new \DateTimeZone('Pacific/Auckland');
141
-		$this->dateTimeZone->method('getTimeZone')->willReturnCallback(fn () => $this->timezone);
142
-
143
-		$this->appConfig = $this->createMock(IAppConfig::class);
144
-
145
-		$this->l10nFactory = $this->createMock(IFactory::class);
146
-		$this->l = $this->createMock(IL10N::class);
147
-		$this->l->method('t')
148
-			->willReturnCallback(function ($text, $parameters = []) {
149
-				return vsprintf($text, $parameters);
150
-			});
151
-		$this->l->method('n')
152
-			->willReturnCallback(function ($singular, $plural, $count, $parameters = []) {
153
-				return vsprintf(str_replace('%n', $count, ($count === 1) ? $singular : $plural), $parameters);
154
-			});
155
-		$this->l10nFactory->method('get')->willReturn($this->l);
156
-
157
-		$this->factory = new DummyFactory(\OC::$server);
158
-
159
-		$this->manager = $this->createManager($this->factory);
160
-
161
-		$this->defaultProvider = $this->createMock(DefaultShareProvider::class);
162
-		$this->defaultProvider->method('identifier')->willReturn('default');
163
-		$this->factory->setProvider($this->defaultProvider);
164
-	}
165
-
166
-	private function createManager(IProviderFactory $factory): Manager {
167
-		return new Manager(
168
-			$this->logger,
169
-			$this->config,
170
-			$this->secureRandom,
171
-			$this->hasher,
172
-			$this->mountManager,
173
-			$this->groupManager,
174
-			$this->l10nFactory,
175
-			$factory,
176
-			$this->userManager,
177
-			$this->rootFolder,
178
-			$this->mailer,
179
-			$this->urlGenerator,
180
-			$this->defaults,
181
-			$this->dispatcher,
182
-			$this->userSession,
183
-			$this->knownUserService,
184
-			$this->shareDisabledChecker,
185
-			$this->dateTimeZone,
186
-			$this->appConfig,
187
-		);
188
-	}
189
-
190
-	/**
191
-	 * @return MockBuilder
192
-	 */
193
-	private function createManagerMock() {
194
-		return $this->getMockBuilder(Manager::class)
195
-			->setConstructorArgs([
196
-				$this->logger,
197
-				$this->config,
198
-				$this->secureRandom,
199
-				$this->hasher,
200
-				$this->mountManager,
201
-				$this->groupManager,
202
-				$this->l10nFactory,
203
-				$this->factory,
204
-				$this->userManager,
205
-				$this->rootFolder,
206
-				$this->mailer,
207
-				$this->urlGenerator,
208
-				$this->defaults,
209
-				$this->dispatcher,
210
-				$this->userSession,
211
-				$this->knownUserService,
212
-				$this->shareDisabledChecker,
213
-				$this->dateTimeZone,
214
-				$this->appConfig,
215
-			]);
216
-	}
217
-
218
-	private function createFolderMock(string $folderPath): MockObject&Folder {
219
-		$folder = $this->createMock(Folder::class);
220
-		$folder->method('getPath')->willReturn($folderPath);
221
-		$folder->method('getRelativePath')->willReturnCallback(
222
-			fn (string $path): ?string => PathHelper::getRelativePath($folderPath, $path)
223
-		);
224
-		return $folder;
225
-	}
226
-
227
-	public function testDeleteNoShareId(): void {
228
-		$this->expectException(\InvalidArgumentException::class);
229
-
230
-		$share = $this->manager->newShare();
231
-
232
-		$this->manager->deleteShare($share);
233
-	}
234
-
235
-	public static function dataTestDelete(): array {
236
-		return [
237
-			[IShare::TYPE_USER, 'sharedWithUser'],
238
-			[IShare::TYPE_GROUP, 'sharedWithGroup'],
239
-			[IShare::TYPE_LINK, ''],
240
-			[IShare::TYPE_REMOTE, '[email protected]'],
241
-		];
242
-	}
243
-
244
-	/**
245
-	 * @dataProvider dataTestDelete
246
-	 */
247
-	public function testDelete($shareType, $sharedWith): void {
248
-		$manager = $this->createManagerMock()
249
-			->onlyMethods(['getShareById', 'deleteChildren', 'promoteReshares'])
250
-			->getMock();
251
-
252
-		$manager->method('deleteChildren')->willReturn([]);
253
-
254
-		$path = $this->createMock(File::class);
255
-		$path->method('getId')->willReturn(1);
256
-
257
-		$share = $this->manager->newShare();
258
-		$share->setId(42)
259
-			->setProviderId('prov')
260
-			->setShareType($shareType)
261
-			->setSharedWith($sharedWith)
262
-			->setSharedBy('sharedBy')
263
-			->setNode($path)
264
-			->setTarget('myTarget');
265
-
266
-		$manager->expects($this->once())->method('deleteChildren')->with($share);
267
-		$manager->expects($this->once())->method('promoteReshares')->with($share);
268
-
269
-		$this->defaultProvider
270
-			->expects($this->once())
271
-			->method('delete')
272
-			->with($share);
273
-
274
-		$calls = [
275
-			BeforeShareDeletedEvent::class,
276
-			ShareDeletedEvent::class,
277
-		];
278
-		$this->dispatcher->expects($this->exactly(2))
279
-			->method('dispatchTyped')
280
-			->willReturnCallback(function ($event) use (&$calls, $share) {
281
-				$expected = array_shift($calls);
282
-				$this->assertInstanceOf($expected, $event);
283
-				$this->assertEquals($share, $event->getShare());
284
-			});
285
-
286
-		$manager->deleteShare($share);
287
-	}
288
-
289
-	public function testDeleteLazyShare(): void {
290
-		$manager = $this->createManagerMock()
291
-			->onlyMethods(['getShareById', 'deleteChildren', 'promoteReshares'])
292
-			->getMock();
293
-
294
-		$manager->method('deleteChildren')->willReturn([]);
295
-
296
-		$share = $this->manager->newShare();
297
-		$share->setId(42)
298
-			->setProviderId('prov')
299
-			->setShareType(IShare::TYPE_USER)
300
-			->setSharedWith('sharedWith')
301
-			->setSharedBy('sharedBy')
302
-			->setShareOwner('shareOwner')
303
-			->setTarget('myTarget')
304
-			->setNodeId(1)
305
-			->setNodeType('file');
306
-
307
-		$this->rootFolder->expects($this->never())->method($this->anything());
308
-
309
-		$manager->expects($this->once())->method('deleteChildren')->with($share);
310
-		$manager->expects($this->once())->method('promoteReshares')->with($share);
311
-
312
-		$this->defaultProvider
313
-			->expects($this->once())
314
-			->method('delete')
315
-			->with($share);
316
-
317
-		$calls = [
318
-			BeforeShareDeletedEvent::class,
319
-			ShareDeletedEvent::class,
320
-		];
321
-		$this->dispatcher->expects($this->exactly(2))
322
-			->method('dispatchTyped')
323
-			->willReturnCallback(function ($event) use (&$calls, $share) {
324
-				$expected = array_shift($calls);
325
-				$this->assertInstanceOf($expected, $event);
326
-				$this->assertEquals($share, $event->getShare());
327
-			});
328
-
329
-		$manager->deleteShare($share);
330
-	}
331
-
332
-	public function testDeleteNested(): void {
333
-		$manager = $this->createManagerMock()
334
-			->onlyMethods(['getShareById', 'promoteReshares'])
335
-			->getMock();
336
-
337
-		$path = $this->createMock(File::class);
338
-		$path->method('getId')->willReturn(1);
339
-
340
-		$share1 = $this->manager->newShare();
341
-		$share1->setId(42)
342
-			->setProviderId('prov')
343
-			->setShareType(IShare::TYPE_USER)
344
-			->setSharedWith('sharedWith1')
345
-			->setSharedBy('sharedBy1')
346
-			->setNode($path)
347
-			->setTarget('myTarget1');
348
-
349
-		$share2 = $this->manager->newShare();
350
-		$share2->setId(43)
351
-			->setProviderId('prov')
352
-			->setShareType(IShare::TYPE_GROUP)
353
-			->setSharedWith('sharedWith2')
354
-			->setSharedBy('sharedBy2')
355
-			->setNode($path)
356
-			->setTarget('myTarget2')
357
-			->setParent(42);
358
-
359
-		$share3 = $this->manager->newShare();
360
-		$share3->setId(44)
361
-			->setProviderId('prov')
362
-			->setShareType(IShare::TYPE_LINK)
363
-			->setSharedBy('sharedBy3')
364
-			->setNode($path)
365
-			->setTarget('myTarget3')
366
-			->setParent(43);
367
-
368
-		$this->defaultProvider
369
-			->method('getChildren')
370
-			->willReturnMap([
371
-				[$share1, [$share2]],
372
-				[$share2, [$share3]],
373
-				[$share3, []],
374
-			]);
375
-
376
-		$deleteCalls = [
377
-			$share3,
378
-			$share2,
379
-			$share1,
380
-		];
381
-		$this->defaultProvider->expects($this->exactly(3))
382
-			->method('delete')
383
-			->willReturnCallback(function ($share) use (&$deleteCalls) {
384
-				$expected = array_shift($deleteCalls);
385
-				$this->assertEquals($expected, $share);
386
-			});
387
-
388
-		$dispatchCalls = [
389
-			[BeforeShareDeletedEvent::class, $share1],
390
-			[BeforeShareDeletedEvent::class, $share2],
391
-			[BeforeShareDeletedEvent::class, $share3],
392
-			[ShareDeletedEvent::class, $share3],
393
-			[ShareDeletedEvent::class, $share2],
394
-			[ShareDeletedEvent::class, $share1],
395
-		];
396
-		$this->dispatcher->expects($this->exactly(6))
397
-			->method('dispatchTyped')
398
-			->willReturnCallback(function ($event) use (&$dispatchCalls) {
399
-				$expected = array_shift($dispatchCalls);
400
-				$this->assertInstanceOf($expected[0], $event);
401
-				$this->assertEquals($expected[1]->getId(), $event->getShare()->getId());
402
-			});
403
-
404
-		$manager->deleteShare($share1);
405
-	}
406
-
407
-	public function testDeleteFromSelf(): void {
408
-		$manager = $this->createManagerMock()
409
-			->onlyMethods(['getShareById'])
410
-			->getMock();
411
-
412
-		$recipientId = 'unshareFrom';
413
-		$share = $this->manager->newShare();
414
-		$share->setId(42)
415
-			->setProviderId('prov')
416
-			->setShareType(IShare::TYPE_USER)
417
-			->setSharedWith('sharedWith')
418
-			->setSharedBy('sharedBy')
419
-			->setShareOwner('shareOwner')
420
-			->setTarget('myTarget')
421
-			->setNodeId(1)
422
-			->setNodeType('file');
423
-
424
-		$this->defaultProvider
425
-			->expects($this->once())
426
-			->method('deleteFromSelf')
427
-			->with($share, $recipientId);
428
-
429
-		$this->dispatcher->expects($this->once())
430
-			->method('dispatchTyped')
431
-			->with(
432
-				$this->callBack(function (ShareDeletedFromSelfEvent $e) use ($share) {
433
-					return $e->getShare() === $share;
434
-				})
435
-			);
436
-
437
-		$manager->deleteFromSelf($share, $recipientId);
438
-	}
439
-
440
-	public function testDeleteChildren(): void {
441
-		$manager = $this->createManagerMock()
442
-			->onlyMethods(['deleteShare'])
443
-			->getMock();
444
-
445
-		$share = $this->createMock(IShare::class);
446
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
447
-
448
-		$child1 = $this->createMock(IShare::class);
449
-		$child1->method('getShareType')->willReturn(IShare::TYPE_USER);
450
-		$child2 = $this->createMock(IShare::class);
451
-		$child2->method('getShareType')->willReturn(IShare::TYPE_USER);
452
-		$child3 = $this->createMock(IShare::class);
453
-		$child3->method('getShareType')->willReturn(IShare::TYPE_USER);
454
-
455
-		$shares = [
456
-			$child1,
457
-			$child2,
458
-			$child3,
459
-		];
460
-
461
-		$this->defaultProvider
462
-			->expects($this->exactly(4))
463
-			->method('getChildren')
464
-			->willReturnCallback(function ($_share) use ($share, $shares) {
465
-				if ($_share === $share) {
466
-					return $shares;
467
-				}
468
-				return [];
469
-			});
470
-
471
-		$calls = [
472
-			$child1,
473
-			$child2,
474
-			$child3,
475
-		];
476
-		$this->defaultProvider->expects($this->exactly(3))
477
-			->method('delete')
478
-			->willReturnCallback(function ($share) use (&$calls) {
479
-				$expected = array_shift($calls);
480
-				$this->assertEquals($expected, $share);
481
-			});
482
-
483
-		$result = self::invokePrivate($manager, 'deleteChildren', [$share]);
484
-		$this->assertSame($shares, $result);
485
-	}
486
-
487
-	public function testPromoteReshareFile(): void {
488
-		$manager = $this->createManagerMock()
489
-			->onlyMethods(['updateShare', 'getSharesInFolder', 'generalCreateChecks'])
490
-			->getMock();
491
-
492
-		$file = $this->createMock(File::class);
493
-
494
-		$share = $this->createMock(IShare::class);
495
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
496
-		$share->method('getNodeType')->willReturn('folder');
497
-		$share->method('getSharedWith')->willReturn('userB');
498
-		$share->method('getNode')->willReturn($file);
499
-
500
-		$reShare = $this->createMock(IShare::class);
501
-		$reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
502
-		$reShare->method('getSharedBy')->willReturn('userB');
503
-		$reShare->method('getSharedWith')->willReturn('userC');
504
-		$reShare->method('getNode')->willReturn($file);
505
-
506
-		$this->defaultProvider->method('getSharesBy')
507
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $file) {
508
-				$this->assertEquals($file, $node);
509
-				if ($shareType === IShare::TYPE_USER) {
510
-					return match($userId) {
511
-						'userB' => [$reShare],
512
-					};
513
-				} else {
514
-					return [];
515
-				}
516
-			});
517
-		$manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
518
-
519
-		$manager->expects($this->exactly(1))->method('updateShare')->with($reShare);
520
-
521
-		self::invokePrivate($manager, 'promoteReshares', [$share]);
522
-	}
523
-
524
-	public function testPromoteReshare(): void {
525
-		$manager = $this->createManagerMock()
526
-			->onlyMethods(['updateShare', 'getSharesInFolder', 'generalCreateChecks'])
527
-			->getMock();
528
-
529
-		$folder = $this->createFolderMock('/path/to/folder');
530
-
531
-		$subFolder = $this->createFolderMock('/path/to/folder/sub');
532
-
533
-		$otherFolder = $this->createFolderMock('/path/to/otherfolder/');
534
-
535
-		$share = $this->createMock(IShare::class);
536
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
537
-		$share->method('getNodeType')->willReturn('folder');
538
-		$share->method('getSharedWith')->willReturn('userB');
539
-		$share->method('getNode')->willReturn($folder);
540
-
541
-		$reShare = $this->createMock(IShare::class);
542
-		$reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
543
-		$reShare->method('getSharedBy')->willReturn('userB');
544
-		$reShare->method('getSharedWith')->willReturn('userC');
545
-		$reShare->method('getNode')->willReturn($folder);
546
-
547
-		$reShareInSubFolder = $this->createMock(IShare::class);
548
-		$reShareInSubFolder->method('getShareType')->willReturn(IShare::TYPE_USER);
549
-		$reShareInSubFolder->method('getSharedBy')->willReturn('userB');
550
-		$reShareInSubFolder->method('getNode')->willReturn($subFolder);
551
-
552
-		$reShareInOtherFolder = $this->createMock(IShare::class);
553
-		$reShareInOtherFolder->method('getShareType')->willReturn(IShare::TYPE_USER);
554
-		$reShareInOtherFolder->method('getSharedBy')->willReturn('userB');
555
-		$reShareInOtherFolder->method('getNode')->willReturn($otherFolder);
556
-
557
-		$this->defaultProvider->method('getSharesBy')
558
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $reShareInSubFolder, $reShareInOtherFolder) {
559
-				if ($shareType === IShare::TYPE_USER) {
560
-					return match($userId) {
561
-						'userB' => [$reShare,$reShareInSubFolder,$reShareInOtherFolder],
562
-					};
563
-				} else {
564
-					return [];
565
-				}
566
-			});
567
-		$manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
568
-
569
-		$calls = [
570
-			$reShare,
571
-			$reShareInSubFolder,
572
-		];
573
-		$manager->expects($this->exactly(2))
574
-			->method('updateShare')
575
-			->willReturnCallback(function ($share) use (&$calls) {
576
-				$expected = array_shift($calls);
577
-				$this->assertEquals($expected, $share);
578
-			});
579
-
580
-		self::invokePrivate($manager, 'promoteReshares', [$share]);
581
-	}
582
-
583
-	public function testPromoteReshareWhenUserHasAnotherShare(): void {
584
-		$manager = $this->createManagerMock()
585
-			->onlyMethods(['updateShare', 'getSharesInFolder', 'getSharedWith', 'generalCreateChecks'])
586
-			->getMock();
587
-
588
-		$folder = $this->createFolderMock('/path/to/folder');
589
-
590
-		$share = $this->createMock(IShare::class);
591
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
592
-		$share->method('getNodeType')->willReturn('folder');
593
-		$share->method('getSharedWith')->willReturn('userB');
594
-		$share->method('getNode')->willReturn($folder);
595
-
596
-		$reShare = $this->createMock(IShare::class);
597
-		$reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
598
-		$reShare->method('getNodeType')->willReturn('folder');
599
-		$reShare->method('getSharedBy')->willReturn('userB');
600
-		$reShare->method('getNode')->willReturn($folder);
601
-
602
-		$this->defaultProvider->method('getSharesBy')->willReturn([$reShare]);
603
-		$manager->method('generalCreateChecks')->willReturn(true);
604
-
605
-		/* No share is promoted because generalCreateChecks does not throw */
606
-		$manager->expects($this->never())->method('updateShare');
607
-
608
-		self::invokePrivate($manager, 'promoteReshares', [$share]);
609
-	}
610
-
611
-	public function testPromoteReshareOfUsersInGroupShare(): void {
612
-		$manager = $this->createManagerMock()
613
-			->onlyMethods(['updateShare', 'getSharesInFolder', 'getSharedWith', 'generalCreateChecks'])
614
-			->getMock();
615
-
616
-		$folder = $this->createFolderMock('/path/to/folder');
617
-
618
-		$userA = $this->createMock(IUser::class);
619
-		$userA->method('getUID')->willReturn('userA');
620
-
621
-		$share = $this->createMock(IShare::class);
622
-		$share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
623
-		$share->method('getNodeType')->willReturn('folder');
624
-		$share->method('getSharedWith')->willReturn('Group');
625
-		$share->method('getNode')->willReturn($folder);
626
-		$share->method('getShareOwner')->willReturn($userA);
627
-
628
-		$reShare1 = $this->createMock(IShare::class);
629
-		$reShare1->method('getShareType')->willReturn(IShare::TYPE_USER);
630
-		$reShare1->method('getNodeType')->willReturn('folder');
631
-		$reShare1->method('getSharedBy')->willReturn('userB');
632
-		$reShare1->method('getNode')->willReturn($folder);
633
-
634
-		$reShare2 = $this->createMock(IShare::class);
635
-		$reShare2->method('getShareType')->willReturn(IShare::TYPE_USER);
636
-		$reShare2->method('getNodeType')->willReturn('folder');
637
-		$reShare2->method('getSharedBy')->willReturn('userC');
638
-		$reShare2->method('getNode')->willReturn($folder);
639
-
640
-		$userB = $this->createMock(IUser::class);
641
-		$userB->method('getUID')->willReturn('userB');
642
-		$userC = $this->createMock(IUser::class);
643
-		$userC->method('getUID')->willReturn('userC');
644
-		$group = $this->createMock(IGroup::class);
645
-		$group->method('getUsers')->willReturn([$userB, $userC]);
646
-		$this->groupManager->method('get')->with('Group')->willReturn($group);
647
-
648
-		$this->defaultProvider->method('getSharesBy')
649
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare1, $reShare2) {
650
-				if ($shareType === IShare::TYPE_USER) {
651
-					return match($userId) {
652
-						'userB' => [$reShare1],
653
-						'userC' => [$reShare2],
654
-					};
655
-				} else {
656
-					return [];
657
-				}
658
-			});
659
-		$manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
660
-
661
-		$manager->method('getSharedWith')->willReturn([]);
662
-
663
-		$calls = [
664
-			$reShare1,
665
-			$reShare2,
666
-		];
667
-		$manager->expects($this->exactly(2))
668
-			->method('updateShare')
669
-			->willReturnCallback(function ($share) use (&$calls) {
670
-				$expected = array_shift($calls);
671
-				$this->assertEquals($expected, $share);
672
-			});
673
-
674
-		self::invokePrivate($manager, 'promoteReshares', [$share]);
675
-	}
676
-
677
-	public function testGetShareById(): void {
678
-		$share = $this->createMock(IShare::class);
679
-
680
-		$this->defaultProvider
681
-			->expects($this->once())
682
-			->method('getShareById')
683
-			->with(42)
684
-			->willReturn($share);
685
-
686
-		$this->assertEquals($share, $this->manager->getShareById('default:42'));
687
-	}
688
-
689
-
690
-	public function testGetExpiredShareById(): void {
691
-		$this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
692
-
693
-		$manager = $this->createManagerMock()
694
-			->onlyMethods(['deleteShare'])
695
-			->getMock();
696
-
697
-		$date = new \DateTime();
698
-		$date->setTime(0, 0, 0);
699
-
700
-		$share = $this->manager->newShare();
701
-		$share->setExpirationDate($date)
702
-			->setShareType(IShare::TYPE_LINK);
703
-
704
-		$this->defaultProvider->expects($this->once())
705
-			->method('getShareById')
706
-			->with('42')
707
-			->willReturn($share);
708
-
709
-		$manager->expects($this->once())
710
-			->method('deleteShare')
711
-			->with($share);
712
-
713
-		$manager->getShareById('default:42');
714
-	}
715
-
716
-
717
-	public function testVerifyPasswordNullButEnforced(): void {
718
-		$this->expectException(\InvalidArgumentException::class);
719
-		$this->expectExceptionMessage('Passwords are enforced for link and mail shares');
720
-
721
-		$this->config->method('getAppValue')->willReturnMap([
722
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
723
-			['core', 'shareapi_enforce_links_password', 'no', 'yes'],
724
-		]);
725
-
726
-		self::invokePrivate($this->manager, 'verifyPassword', [null]);
727
-	}
728
-
729
-	public function testVerifyPasswordNotEnforcedGroup(): void {
730
-		$this->config->method('getAppValue')->willReturnMap([
731
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin"]'],
732
-			['core', 'shareapi_enforce_links_password', 'no', 'yes'],
733
-		]);
734
-
735
-		// Create admin user
736
-		$user = $this->createMock(IUser::class);
737
-		$this->userSession->method('getUser')->willReturn($user);
738
-		$this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['admin']);
739
-
740
-		$result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
741
-		$this->assertNull($result);
742
-	}
743
-
744
-	public function testVerifyPasswordNotEnforcedMultipleGroups(): void {
745
-		$this->config->method('getAppValue')->willReturnMap([
746
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin", "special"]'],
747
-			['core', 'shareapi_enforce_links_password', 'no', 'yes'],
748
-		]);
749
-
750
-		// Create admin user
751
-		$user = $this->createMock(IUser::class);
752
-		$this->userSession->method('getUser')->willReturn($user);
753
-		$this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['special']);
754
-
755
-		$result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
756
-		$this->assertNull($result);
757
-	}
758
-
759
-	public function testVerifyPasswordNull(): void {
760
-		$this->config->method('getAppValue')->willReturnMap([
761
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
762
-			['core', 'shareapi_enforce_links_password', 'no', 'no'],
763
-		]);
764
-
765
-		$result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
766
-		$this->assertNull($result);
767
-	}
768
-
769
-	public function testVerifyPasswordHook(): void {
770
-		$this->config->method('getAppValue')->willReturnMap([
771
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
772
-			['core', 'shareapi_enforce_links_password', 'no', 'no'],
773
-		]);
774
-
775
-		$this->dispatcher->expects($this->once())->method('dispatchTyped')
776
-			->willReturnCallback(function (Event $event) {
777
-				$this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
778
-				/** @var ValidatePasswordPolicyEvent $event */
779
-				$this->assertSame('password', $event->getPassword());
780
-			}
781
-			);
782
-
783
-		$result = self::invokePrivate($this->manager, 'verifyPassword', ['password']);
784
-		$this->assertNull($result);
785
-	}
786
-
787
-
788
-	public function testVerifyPasswordHookFails(): void {
789
-		$this->expectException(\Exception::class);
790
-		$this->expectExceptionMessage('password not accepted');
791
-
792
-		$this->config->method('getAppValue')->willReturnMap([
793
-			['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
794
-			['core', 'shareapi_enforce_links_password', 'no', 'no'],
795
-		]);
796
-
797
-		$this->dispatcher->expects($this->once())->method('dispatchTyped')
798
-			->willReturnCallback(function (Event $event) {
799
-				$this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
800
-				/** @var ValidatePasswordPolicyEvent $event */
801
-				$this->assertSame('password', $event->getPassword());
802
-				throw new HintException('password not accepted');
803
-			}
804
-			);
805
-
806
-		self::invokePrivate($this->manager, 'verifyPassword', ['password']);
807
-	}
808
-
809
-	public function createShare($id, $type, $node, $sharedWith, $sharedBy, $shareOwner,
810
-		$permissions, $expireDate = null, $password = null, $attributes = null) {
811
-		$share = $this->createMock(IShare::class);
812
-
813
-		$share->method('getShareType')->willReturn($type);
814
-		$share->method('getSharedWith')->willReturn($sharedWith);
815
-		$share->method('getSharedBy')->willReturn($sharedBy);
816
-		$share->method('getShareOwner')->willReturn($shareOwner);
817
-		$share->method('getNode')->willReturn($node);
818
-		if ($node && $node->getId()) {
819
-			$share->method('getNodeId')->willReturn($node->getId());
820
-		}
821
-		$share->method('getPermissions')->willReturn($permissions);
822
-		$share->method('getAttributes')->willReturn($attributes);
823
-		$share->method('getExpirationDate')->willReturn($expireDate);
824
-		$share->method('getPassword')->willReturn($password);
825
-
826
-		return $share;
827
-	}
828
-
829
-	public function dataGeneralChecks() {
830
-		$user0 = 'user0';
831
-		$user2 = 'user1';
832
-		$group0 = 'group0';
833
-		$owner = $this->createMock(IUser::class);
834
-		$owner->method('getUID')
835
-			->willReturn($user0);
836
-
837
-		$file = $this->createMock(File::class);
838
-		$node = $this->createMock(Node::class);
839
-		$storage = $this->createMock(IStorage::class);
840
-		$storage->method('instanceOfStorage')
841
-			->with('\OCA\Files_Sharing\External\Storage')
842
-			->willReturn(false);
843
-		$file->method('getStorage')
844
-			->willReturn($storage);
845
-		$file->method('getId')->willReturn(108);
846
-		$node->method('getStorage')
847
-			->willReturn($storage);
848
-		$node->method('getId')->willReturn(108);
849
-
850
-		$data = [
851
-			[$this->createShare(null, IShare::TYPE_USER, $file, null, $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
852
-			[$this->createShare(null, IShare::TYPE_USER, $file, $group0, $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
853
-			[$this->createShare(null, IShare::TYPE_USER, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
854
-			[$this->createShare(null, IShare::TYPE_GROUP, $file, null, $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
855
-			[$this->createShare(null, IShare::TYPE_GROUP, $file, $user2, $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
856
-			[$this->createShare(null, IShare::TYPE_GROUP, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
857
-			[$this->createShare(null, IShare::TYPE_LINK, $file, $user2, $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
858
-			[$this->createShare(null, IShare::TYPE_LINK, $file, $group0, $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
859
-			[$this->createShare(null, IShare::TYPE_LINK, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
860
-			[$this->createShare(null, -1, $file, null, $user0, $user0, 31, null, null), 'Unknown share type', true],
861
-
862
-			[$this->createShare(null, IShare::TYPE_USER, $file, $user2, null, $user0, 31, null, null), 'Share initiator must be set', true],
863
-			[$this->createShare(null, IShare::TYPE_GROUP, $file, $group0, null, $user0, 31, null, null), 'Share initiator must be set', true],
864
-			[$this->createShare(null, IShare::TYPE_LINK, $file, null, null, $user0, 31, null, null), 'Share initiator must be set', true],
865
-
866
-			[$this->createShare(null, IShare::TYPE_USER, $file, $user0, $user0, $user0, 31, null, null), 'Cannot share with yourself', true],
867
-
868
-			[$this->createShare(null, IShare::TYPE_USER, null, $user2, $user0, $user0, 31, null, null), 'Shared path must be set', true],
869
-			[$this->createShare(null, IShare::TYPE_GROUP, null, $group0, $user0, $user0, 31, null, null), 'Shared path must be set', true],
870
-			[$this->createShare(null, IShare::TYPE_LINK, null, null, $user0, $user0, 31, null, null), 'Shared path must be set', true],
871
-
872
-			[$this->createShare(null, IShare::TYPE_USER, $node, $user2, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
873
-			[$this->createShare(null, IShare::TYPE_GROUP, $node, $group0, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
874
-			[$this->createShare(null, IShare::TYPE_LINK, $node, null, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
875
-		];
876
-
877
-		$nonShareAble = $this->createMock(Folder::class);
878
-		$nonShareAble->method('getId')->willReturn(108);
879
-		$nonShareAble->method('isShareable')->willReturn(false);
880
-		$nonShareAble->method('getPath')->willReturn('path');
881
-		$nonShareAble->method('getName')->willReturn('name');
882
-		$nonShareAble->method('getOwner')
883
-			->willReturn($owner);
884
-		$nonShareAble->method('getStorage')
885
-			->willReturn($storage);
886
-
887
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $nonShareAble, $user2, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
888
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonShareAble, $group0, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
889
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $nonShareAble, null, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
890
-
891
-		$limitedPermssions = $this->createMock(File::class);
892
-		$limitedPermssions->method('isShareable')->willReturn(true);
893
-		$limitedPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
894
-		$limitedPermssions->method('getId')->willReturn(108);
895
-		$limitedPermssions->method('getPath')->willReturn('path');
896
-		$limitedPermssions->method('getName')->willReturn('name');
897
-		$limitedPermssions->method('getOwner')
898
-			->willReturn($owner);
899
-		$limitedPermssions->method('getStorage')
900
-			->willReturn($storage);
901
-
902
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
903
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
904
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
905
-
906
-		$mount = $this->createMock(MoveableMount::class);
907
-		$limitedPermssions->method('getMountPoint')->willReturn($mount);
908
-
909
-		// increase permissions of a re-share
910
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, 17, null, null), 'Cannot increase permissions of path', true];
911
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 3, null, null), 'Cannot increase permissions of path', true];
912
-
913
-		$nonMovableStorage = $this->createMock(IStorage::class);
914
-		$nonMovableStorage->method('instanceOfStorage')
915
-			->with('\OCA\Files_Sharing\External\Storage')
916
-			->willReturn(false);
917
-		$nonMovableStorage->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
918
-		$nonMoveableMountPermssions = $this->createMock(Folder::class);
919
-		$nonMoveableMountPermssions->method('isShareable')->willReturn(true);
920
-		$nonMoveableMountPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
921
-		$nonMoveableMountPermssions->method('getId')->willReturn(108);
922
-		$nonMoveableMountPermssions->method('getPath')->willReturn('path');
923
-		$nonMoveableMountPermssions->method('getName')->willReturn('name');
924
-		$nonMoveableMountPermssions->method('getInternalPath')->willReturn('');
925
-		$nonMoveableMountPermssions->method('getOwner')
926
-			->willReturn($owner);
927
-		$nonMoveableMountPermssions->method('getStorage')
928
-			->willReturn($nonMovableStorage);
929
-
930
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $nonMoveableMountPermssions, $user2, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false];
931
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonMoveableMountPermssions, $group0, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false];
932
-
933
-		$rootFolder = $this->createMock(Folder::class);
934
-		$rootFolder->method('isShareable')->willReturn(true);
935
-		$rootFolder->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
936
-		$rootFolder->method('getId')->willReturn(42);
937
-
938
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $rootFolder, $user2, $user0, $user0, 30, null, null), 'You cannot share your root folder', true];
939
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $rootFolder, $group0, $user0, $user0, 2, null, null), 'You cannot share your root folder', true];
940
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $rootFolder, null, $user0, $user0, 16, null, null), 'You cannot share your root folder', true];
941
-
942
-		$allPermssionsFiles = $this->createMock(File::class);
943
-		$allPermssionsFiles->method('isShareable')->willReturn(true);
944
-		$allPermssionsFiles->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
945
-		$allPermssionsFiles->method('getId')->willReturn(187);
946
-		$allPermssionsFiles->method('getOwner')
947
-			->willReturn($owner);
948
-		$allPermssionsFiles->method('getStorage')
949
-			->willReturn($storage);
950
-
951
-		// test invalid CREATE or DELETE permissions
952
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssionsFiles, $user2, $user0, $user0, \OCP\Constants::PERMISSION_ALL, null, null), 'File shares cannot have create or delete permissions', true];
953
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssionsFiles, $group0, $user0, $user0, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE, null, null), 'File shares cannot have create or delete permissions', true];
954
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssionsFiles, null, $user0, $user0, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_DELETE, null, null), 'File shares cannot have create or delete permissions', true];
955
-
956
-		$allPermssions = $this->createMock(Folder::class);
957
-		$allPermssions->method('isShareable')->willReturn(true);
958
-		$allPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
959
-		$allPermssions->method('getId')->willReturn(108);
960
-		$allPermssions->method('getOwner')
961
-			->willReturn($owner);
962
-		$allPermssions->method('getStorage')
963
-			->willReturn($storage);
964
-
965
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true];
966
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true];
967
-
968
-		// test invalid permissions
969
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 32, null, null), 'Valid permissions are required for sharing', true];
970
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 63, null, null), 'Valid permissions are required for sharing', true];
971
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, -1, null, null), 'Valid permissions are required for sharing', true];
972
-
973
-		// working shares
974
-		$data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 31, null, null), null, false];
975
-		$data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 3, null, null), null, false];
976
-		$data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, 17, null, null), null, false];
977
-
978
-
979
-		$remoteStorage = $this->createMock(IStorage::class);
980
-		$remoteStorage->method('instanceOfStorage')
981
-			->with('\OCA\Files_Sharing\External\Storage')
982
-			->willReturn(true);
983
-		$remoteFile = $this->createMock(Folder::class);
984
-		$remoteFile->method('isShareable')->willReturn(true);
985
-		$remoteFile->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ ^ \OCP\Constants::PERMISSION_UPDATE);
986
-		$remoteFile->method('getId')->willReturn(108);
987
-		$remoteFile->method('getOwner')
988
-			->willReturn($owner);
989
-		$remoteFile->method('getStorage')
990
-			->willReturn($storage);
991
-		$data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 1, null, null), null, false];
992
-		$data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 3, null, null), null, false];
993
-		$data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of ', true];
994
-
995
-		return $data;
996
-	}
997
-
998
-	/**
999
-	 * @dataProvider dataGeneralChecks
1000
-	 *
1001
-	 * @param $share
1002
-	 * @param $exceptionMessage
1003
-	 * @param $exception
1004
-	 */
1005
-	public function testGeneralChecks($share, $exceptionMessage, $exception): void {
1006
-		$thrown = null;
1007
-
1008
-		$this->userManager->method('userExists')->willReturnMap([
1009
-			['user0', true],
1010
-			['user1', true],
1011
-		]);
1012
-
1013
-		$this->groupManager->method('groupExists')->willReturnMap([
1014
-			['group0', true],
1015
-		]);
1016
-
1017
-		$userFolder = $this->createMock(Folder::class);
1018
-		$userFolder->expects($this->any())
1019
-			->method('getId')
1020
-			->willReturn(42);
1021
-		// Id 108 is used in the data to refer to the node of the share.
1022
-		$userFolder->method('getById')
1023
-			->with(108)
1024
-			->willReturn([$share->getNode()]);
1025
-		$userFolder->expects($this->any())
1026
-			->method('getRelativePath')
1027
-			->willReturnArgument(0);
1028
-		$this->rootFolder->method('getUserFolder')->willReturn($userFolder);
1029
-
1030
-
1031
-		try {
1032
-			self::invokePrivate($this->manager, 'generalCreateChecks', [$share]);
1033
-			$thrown = false;
1034
-		} catch (\OCP\Share\Exceptions\GenericShareException $e) {
1035
-			$this->assertEquals($exceptionMessage, $e->getHint());
1036
-			$thrown = true;
1037
-		} catch (\InvalidArgumentException $e) {
1038
-			$this->assertEquals($exceptionMessage, $e->getMessage());
1039
-			$thrown = true;
1040
-		}
1041
-
1042
-		$this->assertSame($exception, $thrown);
1043
-	}
1044
-
1045
-
1046
-	public function testGeneralCheckShareRoot(): void {
1047
-		$this->expectException(\InvalidArgumentException::class);
1048
-		$this->expectExceptionMessage('You cannot share your root folder');
1049
-
1050
-		$thrown = null;
1051
-
1052
-		$this->userManager->method('userExists')->willReturnMap([
1053
-			['user0', true],
1054
-			['user1', true],
1055
-		]);
1056
-
1057
-		$userFolder = $this->createMock(Folder::class);
1058
-		$userFolder->method('isSubNode')->with($userFolder)->willReturn(false);
1059
-		$this->rootFolder->method('getUserFolder')->willReturn($userFolder);
1060
-
1061
-		$share = $this->manager->newShare();
1062
-
1063
-		$share->setShareType(IShare::TYPE_USER)
1064
-			->setSharedWith('user0')
1065
-			->setSharedBy('user1')
1066
-			->setNode($userFolder);
1067
-
1068
-		self::invokePrivate($this->manager, 'generalCreateChecks', [$share]);
1069
-	}
1070
-
1071
-	public static function validateExpirationDateInternalProvider() {
1072
-		return [[IShare::TYPE_USER], [IShare::TYPE_REMOTE], [IShare::TYPE_REMOTE_GROUP]];
1073
-	}
1074
-
1075
-	/**
1076
-	 * @dataProvider validateExpirationDateInternalProvider
1077
-	 */
1078
-	public function testValidateExpirationDateInternalInPast($shareType): void {
1079
-		$this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1080
-		$this->expectExceptionMessage('Expiration date is in the past');
1081
-
1082
-		// Expire date in the past
1083
-		$past = new \DateTime();
1084
-		$past->sub(new \DateInterval('P1D'));
1085
-
1086
-		$share = $this->manager->newShare();
1087
-		$share->setShareType($shareType);
1088
-		$share->setExpirationDate($past);
1089
-
1090
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1091
-	}
1092
-
1093
-	/**
1094
-	 * @dataProvider validateExpirationDateInternalProvider
1095
-	 */
1096
-	public function testValidateExpirationDateInternalEnforceButNotSet($shareType): void {
1097
-		$this->expectException(\InvalidArgumentException::class);
1098
-		$this->expectExceptionMessage('Expiration date is enforced');
1099
-
1100
-		$share = $this->manager->newShare();
1101
-		$share->setProviderId('foo')->setId('bar');
1102
-		$share->setShareType($shareType);
1103
-		if ($shareType === IShare::TYPE_USER) {
1104
-			$this->config->method('getAppValue')
1105
-				->willReturnMap([
1106
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1107
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1108
-				]);
1109
-		} else {
1110
-			$this->config->method('getAppValue')
1111
-				->willReturnMap([
1112
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1113
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1114
-				]);
1115
-		}
1116
-
1117
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1118
-	}
1119
-
1120
-	/**
1121
-	 * @dataProvider validateExpirationDateInternalProvider
1122
-	 */
1123
-	public function testValidateExpirationDateInternalEnforceButNotEnabledAndNotSet($shareType): void {
1124
-		$share = $this->manager->newShare();
1125
-		$share->setProviderId('foo')->setId('bar');
1126
-		$share->setShareType($shareType);
1127
-
1128
-		if ($shareType === IShare::TYPE_USER) {
1129
-			$this->config->method('getAppValue')
1130
-				->willReturnMap([
1131
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1132
-				]);
1133
-		} else {
1134
-			$this->config->method('getAppValue')
1135
-				->willReturnMap([
1136
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1137
-				]);
1138
-		}
1139
-
1140
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1141
-
1142
-		$this->assertNull($share->getExpirationDate());
1143
-	}
1144
-
1145
-	/**
1146
-	 * @dataProvider validateExpirationDateInternalProvider
1147
-	 */
1148
-	public function testValidateExpirationDateInternalEnforceButNotSetNewShare($shareType): void {
1149
-		$share = $this->manager->newShare();
1150
-		$share->setShareType($shareType);
1151
-
1152
-		if ($shareType === IShare::TYPE_USER) {
1153
-			$this->config->method('getAppValue')
1154
-				->willReturnMap([
1155
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1156
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1157
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1158
-					['core', 'internal_defaultExpDays', '3', '3'],
1159
-				]);
1160
-		} else {
1161
-			$this->config->method('getAppValue')
1162
-				->willReturnMap([
1163
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1164
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1165
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1166
-					['core', 'remote_defaultExpDays', '3', '3'],
1167
-				]);
1168
-		}
1169
-
1170
-		$expected = new \DateTime('now', $this->timezone);
1171
-		$expected->setTime(0, 0, 0);
1172
-		$expected->add(new \DateInterval('P3D'));
1173
-
1174
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1175
-
1176
-		$this->assertNotNull($share->getExpirationDate());
1177
-		$this->assertEquals($expected, $share->getExpirationDate());
1178
-	}
1179
-
1180
-	/**
1181
-	 * @dataProvider validateExpirationDateInternalProvider
1182
-	 */
1183
-	public function testValidateExpirationDateInternalEnforceRelaxedDefaultButNotSetNewShare($shareType): void {
1184
-		$share = $this->manager->newShare();
1185
-		$share->setShareType($shareType);
1186
-
1187
-		if ($shareType === IShare::TYPE_USER) {
1188
-			$this->config->method('getAppValue')
1189
-				->willReturnMap([
1190
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1191
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1192
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1193
-					['core', 'internal_defaultExpDays', '3', '1'],
1194
-				]);
1195
-		} else {
1196
-			$this->config->method('getAppValue')
1197
-				->willReturnMap([
1198
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1199
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1200
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1201
-					['core', 'remote_defaultExpDays', '3', '1'],
1202
-				]);
1203
-		}
1204
-
1205
-		$expected = new \DateTime('now', $this->timezone);
1206
-		$expected->setTime(0, 0, 0);
1207
-		$expected->add(new \DateInterval('P1D'));
1208
-
1209
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1210
-
1211
-		$this->assertNotNull($share->getExpirationDate());
1212
-		$this->assertEquals($expected, $share->getExpirationDate());
1213
-	}
1214
-
1215
-	/**
1216
-	 * @dataProvider validateExpirationDateInternalProvider
1217
-	 */
1218
-	public function testValidateExpirationDateInternalEnforceTooFarIntoFuture($shareType): void {
1219
-		$this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1220
-		$this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future');
1221
-
1222
-		$future = new \DateTime();
1223
-		$future->add(new \DateInterval('P7D'));
1224
-
1225
-		$share = $this->manager->newShare();
1226
-		$share->setShareType($shareType);
1227
-		$share->setExpirationDate($future);
1228
-
1229
-		if ($shareType === IShare::TYPE_USER) {
1230
-			$this->config->method('getAppValue')
1231
-				->willReturnMap([
1232
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1233
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1234
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1235
-				]);
1236
-		} else {
1237
-			$this->config->method('getAppValue')
1238
-				->willReturnMap([
1239
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1240
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1241
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1242
-				]);
1243
-		}
1244
-
1245
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1246
-	}
1247
-
1248
-	/**
1249
-	 * @dataProvider validateExpirationDateInternalProvider
1250
-	 */
1251
-	public function testValidateExpirationDateInternalEnforceValid($shareType): void {
1252
-		$future = new \DateTime('now', $this->dateTimeZone->getTimeZone());
1253
-		$future->add(new \DateInterval('P2D'));
1254
-		$future->setTime(1, 2, 3);
1255
-
1256
-		$expected = clone $future;
1257
-		$expected->setTime(0, 0, 0);
1258
-
1259
-		$share = $this->manager->newShare();
1260
-		$share->setShareType($shareType);
1261
-		$share->setExpirationDate($future);
1262
-
1263
-		if ($shareType === IShare::TYPE_USER) {
1264
-			$this->config->method('getAppValue')
1265
-				->willReturnMap([
1266
-					['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1267
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1268
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1269
-				]);
1270
-		} else {
1271
-			$this->config->method('getAppValue')
1272
-				->willReturnMap([
1273
-					['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1274
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1275
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1276
-				]);
1277
-		}
1278
-
1279
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1280
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1281
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1282
-			return $data['expirationDate'] == $future;
1283
-		}));
1284
-
1285
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1286
-
1287
-		$this->assertEquals($expected, $share->getExpirationDate());
1288
-	}
1289
-
1290
-	/**
1291
-	 * @dataProvider validateExpirationDateInternalProvider
1292
-	 */
1293
-	public function testValidateExpirationDateInternalNoDefault($shareType): void {
1294
-		$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
1295
-		$date->add(new \DateInterval('P5D'));
1296
-		$date->setTime(1, 2, 3);
1297
-
1298
-		$expected = clone $date;
1299
-		$expected->setTime(0, 0, 0);
1300
-
1301
-		$share = $this->manager->newShare();
1302
-		$share->setShareType($shareType);
1303
-		$share->setExpirationDate($date);
1304
-
1305
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1306
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1307
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1308
-			return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1309
-		}));
1310
-
1311
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1312
-
1313
-		$this->assertEquals($expected, $share->getExpirationDate());
1314
-	}
1315
-
1316
-	/**
1317
-	 * @dataProvider validateExpirationDateInternalProvider
1318
-	 */
1319
-	public function testValidateExpirationDateInternalNoDateNoDefault($shareType): void {
1320
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1321
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1322
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1323
-			return $data['expirationDate'] === null && $data['passwordSet'] === true;
1324
-		}));
1325
-
1326
-		$share = $this->manager->newShare();
1327
-		$share->setShareType($shareType);
1328
-		$share->setPassword('password');
1329
-
1330
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1331
-
1332
-		$this->assertNull($share->getExpirationDate());
1333
-	}
1334
-
1335
-	/**
1336
-	 * @dataProvider validateExpirationDateInternalProvider
1337
-	 */
1338
-	public function testValidateExpirationDateInternalNoDateDefault($shareType): void {
1339
-		$share = $this->manager->newShare();
1340
-		$share->setShareType($shareType);
1341
-
1342
-		$expected = new \DateTime('now', $this->timezone);
1343
-		$expected->setTime(0, 0);
1344
-		$expected->add(new \DateInterval('P3D'));
1345
-		$expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1346
-
1347
-		if ($shareType === IShare::TYPE_USER) {
1348
-			$this->config->method('getAppValue')
1349
-				->willReturnMap([
1350
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1351
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1352
-					['core', 'internal_defaultExpDays', '3', '3'],
1353
-				]);
1354
-		} else {
1355
-			$this->config->method('getAppValue')
1356
-				->willReturnMap([
1357
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1358
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1359
-					['core', 'remote_defaultExpDays', '3', '3'],
1360
-				]);
1361
-		}
1362
-
1363
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1364
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1365
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1366
-			return $data['expirationDate'] == $expected;
1367
-		}));
1368
-
1369
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1370
-
1371
-		$this->assertEquals($expected, $share->getExpirationDate());
1372
-	}
1373
-
1374
-	/**
1375
-	 * @dataProvider validateExpirationDateInternalProvider
1376
-	 */
1377
-	public function testValidateExpirationDateInternalDefault($shareType): void {
1378
-		$future = new \DateTime('now', $this->timezone);
1379
-		$future->add(new \DateInterval('P5D'));
1380
-		$future->setTime(1, 2, 3);
1381
-
1382
-		$expected = clone $future;
1383
-		$expected->setTime(0, 0);
1384
-
1385
-		$share = $this->manager->newShare();
1386
-		$share->setShareType($shareType);
1387
-		$share->setExpirationDate($future);
1388
-
1389
-		if ($shareType === IShare::TYPE_USER) {
1390
-			$this->config->method('getAppValue')
1391
-				->willReturnMap([
1392
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1393
-					['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1394
-					['core', 'internal_defaultExpDays', '3', '1'],
1395
-				]);
1396
-		} else {
1397
-			$this->config->method('getAppValue')
1398
-				->willReturnMap([
1399
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1400
-					['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1401
-					['core', 'remote_defaultExpDays', '3', '1'],
1402
-				]);
1403
-		}
1404
-
1405
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1406
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1407
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1408
-			return $data['expirationDate'] == $expected;
1409
-		}));
1410
-
1411
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1412
-
1413
-		$this->assertEquals($expected, $share->getExpirationDate());
1414
-	}
1415
-
1416
-	/**
1417
-	 * @dataProvider validateExpirationDateInternalProvider
1418
-	 */
1419
-	public function testValidateExpirationDateInternalHookModification($shareType): void {
1420
-		$nextWeek = new \DateTime('now', $this->timezone);
1421
-		$nextWeek->add(new \DateInterval('P7D'));
1422
-		$nextWeek->setTime(0, 0, 0);
1423
-
1424
-		$save = clone $nextWeek;
1425
-
1426
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1427
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1428
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1429
-			$data['expirationDate']->sub(new \DateInterval('P2D'));
1430
-		});
1431
-
1432
-		$share = $this->manager->newShare();
1433
-		$share->setShareType($shareType);
1434
-		$share->setExpirationDate($nextWeek);
1435
-
1436
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1437
-
1438
-		$save->sub(new \DateInterval('P2D'));
1439
-		$this->assertEquals($save, $share->getExpirationDate());
1440
-	}
1441
-
1442
-	/**
1443
-	 * @dataProvider validateExpirationDateInternalProvider
1444
-	 */
1445
-	public function testValidateExpirationDateInternalHookException($shareType): void {
1446
-		$this->expectException(\Exception::class);
1447
-		$this->expectExceptionMessage('Invalid date!');
1448
-
1449
-		$nextWeek = new \DateTime();
1450
-		$nextWeek->add(new \DateInterval('P7D'));
1451
-		$nextWeek->setTime(0, 0, 0);
1452
-
1453
-		$share = $this->manager->newShare();
1454
-		$share->setShareType($shareType);
1455
-		$share->setExpirationDate($nextWeek);
1456
-
1457
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1458
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1459
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1460
-			$data['accepted'] = false;
1461
-			$data['message'] = 'Invalid date!';
1462
-		});
1463
-
1464
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1465
-	}
1466
-
1467
-	/**
1468
-	 * @dataProvider validateExpirationDateInternalProvider
1469
-	 */
1470
-	public function testValidateExpirationDateInternalExistingShareNoDefault($shareType): void {
1471
-		$share = $this->manager->newShare();
1472
-		$share->setShareType($shareType);
1473
-		$share->setId('42')->setProviderId('foo');
1474
-
1475
-		if ($shareType === IShare::TYPE_USER) {
1476
-			$this->config->method('getAppValue')
1477
-				->willReturnMap([
1478
-					['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1479
-					['core', 'shareapi_internal_expire_after_n_days', '7', '6'],
1480
-				]);
1481
-		} else {
1482
-			$this->config->method('getAppValue')
1483
-				->willReturnMap([
1484
-					['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1485
-					['core', 'shareapi_remote_expire_after_n_days', '7', '6'],
1486
-				]);
1487
-		}
1488
-
1489
-		self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1490
-
1491
-		$this->assertEquals(null, $share->getExpirationDate());
1492
-	}
1493
-
1494
-	public function testValidateExpirationDateInPast(): void {
1495
-		$this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1496
-		$this->expectExceptionMessage('Expiration date is in the past');
1497
-
1498
-		// Expire date in the past
1499
-		$past = new \DateTime();
1500
-		$past->sub(new \DateInterval('P1D'));
1501
-
1502
-		$share = $this->manager->newShare();
1503
-		$share->setExpirationDate($past);
1504
-
1505
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1506
-	}
1507
-
1508
-	public function testValidateExpirationDateEnforceButNotSet(): void {
1509
-		$this->expectException(\InvalidArgumentException::class);
1510
-		$this->expectExceptionMessage('Expiration date is enforced');
1511
-
1512
-		$share = $this->manager->newShare();
1513
-		$share->setProviderId('foo')->setId('bar');
1514
-
1515
-		$this->config->method('getAppValue')
1516
-			->willReturnMap([
1517
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1518
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1519
-			]);
1520
-
1521
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1522
-	}
1523
-
1524
-	public function testValidateExpirationDateEnforceButNotEnabledAndNotSet(): void {
1525
-		$share = $this->manager->newShare();
1526
-		$share->setProviderId('foo')->setId('bar');
1527
-
1528
-		$this->config->method('getAppValue')
1529
-			->willReturnMap([
1530
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1531
-			]);
1532
-
1533
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1534
-
1535
-		$this->assertNull($share->getExpirationDate());
1536
-	}
1537
-
1538
-	public function testValidateExpirationDateEnforceButNotSetNewShare(): void {
1539
-		$share = $this->manager->newShare();
1540
-
1541
-		$this->config->method('getAppValue')
1542
-			->willReturnMap([
1543
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1544
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1545
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1546
-				['core', 'link_defaultExpDays', '3', '3'],
1547
-			]);
1548
-
1549
-		$expected = new \DateTime('now', $this->timezone);
1550
-		$expected->setTime(0, 0, 0);
1551
-		$expected->add(new \DateInterval('P3D'));
1552
-
1553
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1554
-
1555
-		$this->assertNotNull($share->getExpirationDate());
1556
-		$this->assertEquals($expected, $share->getExpirationDate());
1557
-	}
1558
-
1559
-	public function testValidateExpirationDateEnforceRelaxedDefaultButNotSetNewShare(): void {
1560
-		$share = $this->manager->newShare();
1561
-
1562
-		$this->config->method('getAppValue')
1563
-			->willReturnMap([
1564
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1565
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1566
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1567
-				['core', 'link_defaultExpDays', '3', '1'],
1568
-			]);
1569
-
1570
-		$expected = new \DateTime('now', $this->timezone);
1571
-		$expected->setTime(0, 0, 0);
1572
-		$expected->add(new \DateInterval('P1D'));
1573
-
1574
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1575
-
1576
-		$this->assertNotNull($share->getExpirationDate());
1577
-		$this->assertEquals($expected, $share->getExpirationDate());
1578
-	}
1579
-
1580
-	public function testValidateExpirationDateEnforceTooFarIntoFuture(): void {
1581
-		$this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1582
-		$this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future');
76
+    /** @var Manager */
77
+    protected $manager;
78
+    /** @var LoggerInterface|MockObject */
79
+    protected $logger;
80
+    /** @var IConfig|MockObject */
81
+    protected $config;
82
+    /** @var ISecureRandom|MockObject */
83
+    protected $secureRandom;
84
+    /** @var IHasher|MockObject */
85
+    protected $hasher;
86
+    /** @var IShareProvider|MockObject */
87
+    protected $defaultProvider;
88
+    /** @var IMountManager|MockObject */
89
+    protected $mountManager;
90
+    /** @var IGroupManager|MockObject */
91
+    protected $groupManager;
92
+    /** @var IL10N|MockObject */
93
+    protected $l;
94
+    /** @var IFactory|MockObject */
95
+    protected $l10nFactory;
96
+    /** @var DummyFactory */
97
+    protected $factory;
98
+    /** @var IUserManager|MockObject */
99
+    protected $userManager;
100
+    /** @var IRootFolder | MockObject */
101
+    protected $rootFolder;
102
+    /** @var IEventDispatcher|MockObject */
103
+    protected $dispatcher;
104
+    /** @var IMailer|MockObject */
105
+    protected $mailer;
106
+    /** @var IURLGenerator|MockObject */
107
+    protected $urlGenerator;
108
+    /** @var \OC_Defaults|MockObject */
109
+    protected $defaults;
110
+    /** @var IUserSession|MockObject */
111
+    protected $userSession;
112
+    /** @var KnownUserService|MockObject */
113
+    protected $knownUserService;
114
+    /** @var ShareDisableChecker|MockObject */
115
+    protected $shareDisabledChecker;
116
+    private DateTimeZone $timezone;
117
+    /** @var IDateTimeZone|MockObject */
118
+    protected $dateTimeZone;
119
+    /** @var IAppConfig|MockObject */
120
+    protected $appConfig;
121
+
122
+    protected function setUp(): void {
123
+        $this->logger = $this->createMock(LoggerInterface::class);
124
+        $this->config = $this->createMock(IConfig::class);
125
+        $this->secureRandom = $this->createMock(ISecureRandom::class);
126
+        $this->hasher = $this->createMock(IHasher::class);
127
+        $this->mountManager = $this->createMock(IMountManager::class);
128
+        $this->groupManager = $this->createMock(IGroupManager::class);
129
+        $this->userManager = $this->createMock(IUserManager::class);
130
+        $this->rootFolder = $this->createMock(IRootFolder::class);
131
+        $this->mailer = $this->createMock(IMailer::class);
132
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
133
+        $this->defaults = $this->createMock(\OC_Defaults::class);
134
+        $this->dispatcher = $this->createMock(IEventDispatcher::class);
135
+        $this->userSession = $this->createMock(IUserSession::class);
136
+        $this->knownUserService = $this->createMock(KnownUserService::class);
137
+
138
+        $this->shareDisabledChecker = new ShareDisableChecker($this->config, $this->userManager, $this->groupManager);
139
+        $this->dateTimeZone = $this->createMock(IDateTimeZone::class);
140
+        $this->timezone = new \DateTimeZone('Pacific/Auckland');
141
+        $this->dateTimeZone->method('getTimeZone')->willReturnCallback(fn () => $this->timezone);
142
+
143
+        $this->appConfig = $this->createMock(IAppConfig::class);
144
+
145
+        $this->l10nFactory = $this->createMock(IFactory::class);
146
+        $this->l = $this->createMock(IL10N::class);
147
+        $this->l->method('t')
148
+            ->willReturnCallback(function ($text, $parameters = []) {
149
+                return vsprintf($text, $parameters);
150
+            });
151
+        $this->l->method('n')
152
+            ->willReturnCallback(function ($singular, $plural, $count, $parameters = []) {
153
+                return vsprintf(str_replace('%n', $count, ($count === 1) ? $singular : $plural), $parameters);
154
+            });
155
+        $this->l10nFactory->method('get')->willReturn($this->l);
156
+
157
+        $this->factory = new DummyFactory(\OC::$server);
158
+
159
+        $this->manager = $this->createManager($this->factory);
160
+
161
+        $this->defaultProvider = $this->createMock(DefaultShareProvider::class);
162
+        $this->defaultProvider->method('identifier')->willReturn('default');
163
+        $this->factory->setProvider($this->defaultProvider);
164
+    }
165
+
166
+    private function createManager(IProviderFactory $factory): Manager {
167
+        return new Manager(
168
+            $this->logger,
169
+            $this->config,
170
+            $this->secureRandom,
171
+            $this->hasher,
172
+            $this->mountManager,
173
+            $this->groupManager,
174
+            $this->l10nFactory,
175
+            $factory,
176
+            $this->userManager,
177
+            $this->rootFolder,
178
+            $this->mailer,
179
+            $this->urlGenerator,
180
+            $this->defaults,
181
+            $this->dispatcher,
182
+            $this->userSession,
183
+            $this->knownUserService,
184
+            $this->shareDisabledChecker,
185
+            $this->dateTimeZone,
186
+            $this->appConfig,
187
+        );
188
+    }
189
+
190
+    /**
191
+     * @return MockBuilder
192
+     */
193
+    private function createManagerMock() {
194
+        return $this->getMockBuilder(Manager::class)
195
+            ->setConstructorArgs([
196
+                $this->logger,
197
+                $this->config,
198
+                $this->secureRandom,
199
+                $this->hasher,
200
+                $this->mountManager,
201
+                $this->groupManager,
202
+                $this->l10nFactory,
203
+                $this->factory,
204
+                $this->userManager,
205
+                $this->rootFolder,
206
+                $this->mailer,
207
+                $this->urlGenerator,
208
+                $this->defaults,
209
+                $this->dispatcher,
210
+                $this->userSession,
211
+                $this->knownUserService,
212
+                $this->shareDisabledChecker,
213
+                $this->dateTimeZone,
214
+                $this->appConfig,
215
+            ]);
216
+    }
217
+
218
+    private function createFolderMock(string $folderPath): MockObject&Folder {
219
+        $folder = $this->createMock(Folder::class);
220
+        $folder->method('getPath')->willReturn($folderPath);
221
+        $folder->method('getRelativePath')->willReturnCallback(
222
+            fn (string $path): ?string => PathHelper::getRelativePath($folderPath, $path)
223
+        );
224
+        return $folder;
225
+    }
226
+
227
+    public function testDeleteNoShareId(): void {
228
+        $this->expectException(\InvalidArgumentException::class);
229
+
230
+        $share = $this->manager->newShare();
231
+
232
+        $this->manager->deleteShare($share);
233
+    }
234
+
235
+    public static function dataTestDelete(): array {
236
+        return [
237
+            [IShare::TYPE_USER, 'sharedWithUser'],
238
+            [IShare::TYPE_GROUP, 'sharedWithGroup'],
239
+            [IShare::TYPE_LINK, ''],
240
+            [IShare::TYPE_REMOTE, '[email protected]'],
241
+        ];
242
+    }
243
+
244
+    /**
245
+     * @dataProvider dataTestDelete
246
+     */
247
+    public function testDelete($shareType, $sharedWith): void {
248
+        $manager = $this->createManagerMock()
249
+            ->onlyMethods(['getShareById', 'deleteChildren', 'promoteReshares'])
250
+            ->getMock();
251
+
252
+        $manager->method('deleteChildren')->willReturn([]);
253
+
254
+        $path = $this->createMock(File::class);
255
+        $path->method('getId')->willReturn(1);
256
+
257
+        $share = $this->manager->newShare();
258
+        $share->setId(42)
259
+            ->setProviderId('prov')
260
+            ->setShareType($shareType)
261
+            ->setSharedWith($sharedWith)
262
+            ->setSharedBy('sharedBy')
263
+            ->setNode($path)
264
+            ->setTarget('myTarget');
265
+
266
+        $manager->expects($this->once())->method('deleteChildren')->with($share);
267
+        $manager->expects($this->once())->method('promoteReshares')->with($share);
268
+
269
+        $this->defaultProvider
270
+            ->expects($this->once())
271
+            ->method('delete')
272
+            ->with($share);
273
+
274
+        $calls = [
275
+            BeforeShareDeletedEvent::class,
276
+            ShareDeletedEvent::class,
277
+        ];
278
+        $this->dispatcher->expects($this->exactly(2))
279
+            ->method('dispatchTyped')
280
+            ->willReturnCallback(function ($event) use (&$calls, $share) {
281
+                $expected = array_shift($calls);
282
+                $this->assertInstanceOf($expected, $event);
283
+                $this->assertEquals($share, $event->getShare());
284
+            });
285
+
286
+        $manager->deleteShare($share);
287
+    }
288
+
289
+    public function testDeleteLazyShare(): void {
290
+        $manager = $this->createManagerMock()
291
+            ->onlyMethods(['getShareById', 'deleteChildren', 'promoteReshares'])
292
+            ->getMock();
293
+
294
+        $manager->method('deleteChildren')->willReturn([]);
295
+
296
+        $share = $this->manager->newShare();
297
+        $share->setId(42)
298
+            ->setProviderId('prov')
299
+            ->setShareType(IShare::TYPE_USER)
300
+            ->setSharedWith('sharedWith')
301
+            ->setSharedBy('sharedBy')
302
+            ->setShareOwner('shareOwner')
303
+            ->setTarget('myTarget')
304
+            ->setNodeId(1)
305
+            ->setNodeType('file');
306
+
307
+        $this->rootFolder->expects($this->never())->method($this->anything());
308
+
309
+        $manager->expects($this->once())->method('deleteChildren')->with($share);
310
+        $manager->expects($this->once())->method('promoteReshares')->with($share);
311
+
312
+        $this->defaultProvider
313
+            ->expects($this->once())
314
+            ->method('delete')
315
+            ->with($share);
316
+
317
+        $calls = [
318
+            BeforeShareDeletedEvent::class,
319
+            ShareDeletedEvent::class,
320
+        ];
321
+        $this->dispatcher->expects($this->exactly(2))
322
+            ->method('dispatchTyped')
323
+            ->willReturnCallback(function ($event) use (&$calls, $share) {
324
+                $expected = array_shift($calls);
325
+                $this->assertInstanceOf($expected, $event);
326
+                $this->assertEquals($share, $event->getShare());
327
+            });
328
+
329
+        $manager->deleteShare($share);
330
+    }
331
+
332
+    public function testDeleteNested(): void {
333
+        $manager = $this->createManagerMock()
334
+            ->onlyMethods(['getShareById', 'promoteReshares'])
335
+            ->getMock();
336
+
337
+        $path = $this->createMock(File::class);
338
+        $path->method('getId')->willReturn(1);
339
+
340
+        $share1 = $this->manager->newShare();
341
+        $share1->setId(42)
342
+            ->setProviderId('prov')
343
+            ->setShareType(IShare::TYPE_USER)
344
+            ->setSharedWith('sharedWith1')
345
+            ->setSharedBy('sharedBy1')
346
+            ->setNode($path)
347
+            ->setTarget('myTarget1');
348
+
349
+        $share2 = $this->manager->newShare();
350
+        $share2->setId(43)
351
+            ->setProviderId('prov')
352
+            ->setShareType(IShare::TYPE_GROUP)
353
+            ->setSharedWith('sharedWith2')
354
+            ->setSharedBy('sharedBy2')
355
+            ->setNode($path)
356
+            ->setTarget('myTarget2')
357
+            ->setParent(42);
358
+
359
+        $share3 = $this->manager->newShare();
360
+        $share3->setId(44)
361
+            ->setProviderId('prov')
362
+            ->setShareType(IShare::TYPE_LINK)
363
+            ->setSharedBy('sharedBy3')
364
+            ->setNode($path)
365
+            ->setTarget('myTarget3')
366
+            ->setParent(43);
367
+
368
+        $this->defaultProvider
369
+            ->method('getChildren')
370
+            ->willReturnMap([
371
+                [$share1, [$share2]],
372
+                [$share2, [$share3]],
373
+                [$share3, []],
374
+            ]);
375
+
376
+        $deleteCalls = [
377
+            $share3,
378
+            $share2,
379
+            $share1,
380
+        ];
381
+        $this->defaultProvider->expects($this->exactly(3))
382
+            ->method('delete')
383
+            ->willReturnCallback(function ($share) use (&$deleteCalls) {
384
+                $expected = array_shift($deleteCalls);
385
+                $this->assertEquals($expected, $share);
386
+            });
387
+
388
+        $dispatchCalls = [
389
+            [BeforeShareDeletedEvent::class, $share1],
390
+            [BeforeShareDeletedEvent::class, $share2],
391
+            [BeforeShareDeletedEvent::class, $share3],
392
+            [ShareDeletedEvent::class, $share3],
393
+            [ShareDeletedEvent::class, $share2],
394
+            [ShareDeletedEvent::class, $share1],
395
+        ];
396
+        $this->dispatcher->expects($this->exactly(6))
397
+            ->method('dispatchTyped')
398
+            ->willReturnCallback(function ($event) use (&$dispatchCalls) {
399
+                $expected = array_shift($dispatchCalls);
400
+                $this->assertInstanceOf($expected[0], $event);
401
+                $this->assertEquals($expected[1]->getId(), $event->getShare()->getId());
402
+            });
403
+
404
+        $manager->deleteShare($share1);
405
+    }
406
+
407
+    public function testDeleteFromSelf(): void {
408
+        $manager = $this->createManagerMock()
409
+            ->onlyMethods(['getShareById'])
410
+            ->getMock();
411
+
412
+        $recipientId = 'unshareFrom';
413
+        $share = $this->manager->newShare();
414
+        $share->setId(42)
415
+            ->setProviderId('prov')
416
+            ->setShareType(IShare::TYPE_USER)
417
+            ->setSharedWith('sharedWith')
418
+            ->setSharedBy('sharedBy')
419
+            ->setShareOwner('shareOwner')
420
+            ->setTarget('myTarget')
421
+            ->setNodeId(1)
422
+            ->setNodeType('file');
423
+
424
+        $this->defaultProvider
425
+            ->expects($this->once())
426
+            ->method('deleteFromSelf')
427
+            ->with($share, $recipientId);
428
+
429
+        $this->dispatcher->expects($this->once())
430
+            ->method('dispatchTyped')
431
+            ->with(
432
+                $this->callBack(function (ShareDeletedFromSelfEvent $e) use ($share) {
433
+                    return $e->getShare() === $share;
434
+                })
435
+            );
436
+
437
+        $manager->deleteFromSelf($share, $recipientId);
438
+    }
439
+
440
+    public function testDeleteChildren(): void {
441
+        $manager = $this->createManagerMock()
442
+            ->onlyMethods(['deleteShare'])
443
+            ->getMock();
444
+
445
+        $share = $this->createMock(IShare::class);
446
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
447
+
448
+        $child1 = $this->createMock(IShare::class);
449
+        $child1->method('getShareType')->willReturn(IShare::TYPE_USER);
450
+        $child2 = $this->createMock(IShare::class);
451
+        $child2->method('getShareType')->willReturn(IShare::TYPE_USER);
452
+        $child3 = $this->createMock(IShare::class);
453
+        $child3->method('getShareType')->willReturn(IShare::TYPE_USER);
454
+
455
+        $shares = [
456
+            $child1,
457
+            $child2,
458
+            $child3,
459
+        ];
460
+
461
+        $this->defaultProvider
462
+            ->expects($this->exactly(4))
463
+            ->method('getChildren')
464
+            ->willReturnCallback(function ($_share) use ($share, $shares) {
465
+                if ($_share === $share) {
466
+                    return $shares;
467
+                }
468
+                return [];
469
+            });
470
+
471
+        $calls = [
472
+            $child1,
473
+            $child2,
474
+            $child3,
475
+        ];
476
+        $this->defaultProvider->expects($this->exactly(3))
477
+            ->method('delete')
478
+            ->willReturnCallback(function ($share) use (&$calls) {
479
+                $expected = array_shift($calls);
480
+                $this->assertEquals($expected, $share);
481
+            });
482
+
483
+        $result = self::invokePrivate($manager, 'deleteChildren', [$share]);
484
+        $this->assertSame($shares, $result);
485
+    }
486
+
487
+    public function testPromoteReshareFile(): void {
488
+        $manager = $this->createManagerMock()
489
+            ->onlyMethods(['updateShare', 'getSharesInFolder', 'generalCreateChecks'])
490
+            ->getMock();
491
+
492
+        $file = $this->createMock(File::class);
493
+
494
+        $share = $this->createMock(IShare::class);
495
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
496
+        $share->method('getNodeType')->willReturn('folder');
497
+        $share->method('getSharedWith')->willReturn('userB');
498
+        $share->method('getNode')->willReturn($file);
499
+
500
+        $reShare = $this->createMock(IShare::class);
501
+        $reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
502
+        $reShare->method('getSharedBy')->willReturn('userB');
503
+        $reShare->method('getSharedWith')->willReturn('userC');
504
+        $reShare->method('getNode')->willReturn($file);
505
+
506
+        $this->defaultProvider->method('getSharesBy')
507
+            ->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $file) {
508
+                $this->assertEquals($file, $node);
509
+                if ($shareType === IShare::TYPE_USER) {
510
+                    return match($userId) {
511
+                        'userB' => [$reShare],
512
+                    };
513
+                } else {
514
+                    return [];
515
+                }
516
+            });
517
+        $manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
518
+
519
+        $manager->expects($this->exactly(1))->method('updateShare')->with($reShare);
520
+
521
+        self::invokePrivate($manager, 'promoteReshares', [$share]);
522
+    }
523
+
524
+    public function testPromoteReshare(): void {
525
+        $manager = $this->createManagerMock()
526
+            ->onlyMethods(['updateShare', 'getSharesInFolder', 'generalCreateChecks'])
527
+            ->getMock();
528
+
529
+        $folder = $this->createFolderMock('/path/to/folder');
530
+
531
+        $subFolder = $this->createFolderMock('/path/to/folder/sub');
532
+
533
+        $otherFolder = $this->createFolderMock('/path/to/otherfolder/');
534
+
535
+        $share = $this->createMock(IShare::class);
536
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
537
+        $share->method('getNodeType')->willReturn('folder');
538
+        $share->method('getSharedWith')->willReturn('userB');
539
+        $share->method('getNode')->willReturn($folder);
540
+
541
+        $reShare = $this->createMock(IShare::class);
542
+        $reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
543
+        $reShare->method('getSharedBy')->willReturn('userB');
544
+        $reShare->method('getSharedWith')->willReturn('userC');
545
+        $reShare->method('getNode')->willReturn($folder);
546
+
547
+        $reShareInSubFolder = $this->createMock(IShare::class);
548
+        $reShareInSubFolder->method('getShareType')->willReturn(IShare::TYPE_USER);
549
+        $reShareInSubFolder->method('getSharedBy')->willReturn('userB');
550
+        $reShareInSubFolder->method('getNode')->willReturn($subFolder);
551
+
552
+        $reShareInOtherFolder = $this->createMock(IShare::class);
553
+        $reShareInOtherFolder->method('getShareType')->willReturn(IShare::TYPE_USER);
554
+        $reShareInOtherFolder->method('getSharedBy')->willReturn('userB');
555
+        $reShareInOtherFolder->method('getNode')->willReturn($otherFolder);
556
+
557
+        $this->defaultProvider->method('getSharesBy')
558
+            ->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $reShareInSubFolder, $reShareInOtherFolder) {
559
+                if ($shareType === IShare::TYPE_USER) {
560
+                    return match($userId) {
561
+                        'userB' => [$reShare,$reShareInSubFolder,$reShareInOtherFolder],
562
+                    };
563
+                } else {
564
+                    return [];
565
+                }
566
+            });
567
+        $manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
568
+
569
+        $calls = [
570
+            $reShare,
571
+            $reShareInSubFolder,
572
+        ];
573
+        $manager->expects($this->exactly(2))
574
+            ->method('updateShare')
575
+            ->willReturnCallback(function ($share) use (&$calls) {
576
+                $expected = array_shift($calls);
577
+                $this->assertEquals($expected, $share);
578
+            });
579
+
580
+        self::invokePrivate($manager, 'promoteReshares', [$share]);
581
+    }
582
+
583
+    public function testPromoteReshareWhenUserHasAnotherShare(): void {
584
+        $manager = $this->createManagerMock()
585
+            ->onlyMethods(['updateShare', 'getSharesInFolder', 'getSharedWith', 'generalCreateChecks'])
586
+            ->getMock();
587
+
588
+        $folder = $this->createFolderMock('/path/to/folder');
589
+
590
+        $share = $this->createMock(IShare::class);
591
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
592
+        $share->method('getNodeType')->willReturn('folder');
593
+        $share->method('getSharedWith')->willReturn('userB');
594
+        $share->method('getNode')->willReturn($folder);
595
+
596
+        $reShare = $this->createMock(IShare::class);
597
+        $reShare->method('getShareType')->willReturn(IShare::TYPE_USER);
598
+        $reShare->method('getNodeType')->willReturn('folder');
599
+        $reShare->method('getSharedBy')->willReturn('userB');
600
+        $reShare->method('getNode')->willReturn($folder);
601
+
602
+        $this->defaultProvider->method('getSharesBy')->willReturn([$reShare]);
603
+        $manager->method('generalCreateChecks')->willReturn(true);
604
+
605
+        /* No share is promoted because generalCreateChecks does not throw */
606
+        $manager->expects($this->never())->method('updateShare');
607
+
608
+        self::invokePrivate($manager, 'promoteReshares', [$share]);
609
+    }
610
+
611
+    public function testPromoteReshareOfUsersInGroupShare(): void {
612
+        $manager = $this->createManagerMock()
613
+            ->onlyMethods(['updateShare', 'getSharesInFolder', 'getSharedWith', 'generalCreateChecks'])
614
+            ->getMock();
615
+
616
+        $folder = $this->createFolderMock('/path/to/folder');
617
+
618
+        $userA = $this->createMock(IUser::class);
619
+        $userA->method('getUID')->willReturn('userA');
620
+
621
+        $share = $this->createMock(IShare::class);
622
+        $share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
623
+        $share->method('getNodeType')->willReturn('folder');
624
+        $share->method('getSharedWith')->willReturn('Group');
625
+        $share->method('getNode')->willReturn($folder);
626
+        $share->method('getShareOwner')->willReturn($userA);
627
+
628
+        $reShare1 = $this->createMock(IShare::class);
629
+        $reShare1->method('getShareType')->willReturn(IShare::TYPE_USER);
630
+        $reShare1->method('getNodeType')->willReturn('folder');
631
+        $reShare1->method('getSharedBy')->willReturn('userB');
632
+        $reShare1->method('getNode')->willReturn($folder);
633
+
634
+        $reShare2 = $this->createMock(IShare::class);
635
+        $reShare2->method('getShareType')->willReturn(IShare::TYPE_USER);
636
+        $reShare2->method('getNodeType')->willReturn('folder');
637
+        $reShare2->method('getSharedBy')->willReturn('userC');
638
+        $reShare2->method('getNode')->willReturn($folder);
639
+
640
+        $userB = $this->createMock(IUser::class);
641
+        $userB->method('getUID')->willReturn('userB');
642
+        $userC = $this->createMock(IUser::class);
643
+        $userC->method('getUID')->willReturn('userC');
644
+        $group = $this->createMock(IGroup::class);
645
+        $group->method('getUsers')->willReturn([$userB, $userC]);
646
+        $this->groupManager->method('get')->with('Group')->willReturn($group);
647
+
648
+        $this->defaultProvider->method('getSharesBy')
649
+            ->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare1, $reShare2) {
650
+                if ($shareType === IShare::TYPE_USER) {
651
+                    return match($userId) {
652
+                        'userB' => [$reShare1],
653
+                        'userC' => [$reShare2],
654
+                    };
655
+                } else {
656
+                    return [];
657
+                }
658
+            });
659
+        $manager->method('generalCreateChecks')->willThrowException(new GenericShareException());
660
+
661
+        $manager->method('getSharedWith')->willReturn([]);
662
+
663
+        $calls = [
664
+            $reShare1,
665
+            $reShare2,
666
+        ];
667
+        $manager->expects($this->exactly(2))
668
+            ->method('updateShare')
669
+            ->willReturnCallback(function ($share) use (&$calls) {
670
+                $expected = array_shift($calls);
671
+                $this->assertEquals($expected, $share);
672
+            });
673
+
674
+        self::invokePrivate($manager, 'promoteReshares', [$share]);
675
+    }
676
+
677
+    public function testGetShareById(): void {
678
+        $share = $this->createMock(IShare::class);
679
+
680
+        $this->defaultProvider
681
+            ->expects($this->once())
682
+            ->method('getShareById')
683
+            ->with(42)
684
+            ->willReturn($share);
685
+
686
+        $this->assertEquals($share, $this->manager->getShareById('default:42'));
687
+    }
688
+
689
+
690
+    public function testGetExpiredShareById(): void {
691
+        $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
692
+
693
+        $manager = $this->createManagerMock()
694
+            ->onlyMethods(['deleteShare'])
695
+            ->getMock();
696
+
697
+        $date = new \DateTime();
698
+        $date->setTime(0, 0, 0);
699
+
700
+        $share = $this->manager->newShare();
701
+        $share->setExpirationDate($date)
702
+            ->setShareType(IShare::TYPE_LINK);
703
+
704
+        $this->defaultProvider->expects($this->once())
705
+            ->method('getShareById')
706
+            ->with('42')
707
+            ->willReturn($share);
708
+
709
+        $manager->expects($this->once())
710
+            ->method('deleteShare')
711
+            ->with($share);
712
+
713
+        $manager->getShareById('default:42');
714
+    }
715
+
716
+
717
+    public function testVerifyPasswordNullButEnforced(): void {
718
+        $this->expectException(\InvalidArgumentException::class);
719
+        $this->expectExceptionMessage('Passwords are enforced for link and mail shares');
720
+
721
+        $this->config->method('getAppValue')->willReturnMap([
722
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
723
+            ['core', 'shareapi_enforce_links_password', 'no', 'yes'],
724
+        ]);
725
+
726
+        self::invokePrivate($this->manager, 'verifyPassword', [null]);
727
+    }
728
+
729
+    public function testVerifyPasswordNotEnforcedGroup(): void {
730
+        $this->config->method('getAppValue')->willReturnMap([
731
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin"]'],
732
+            ['core', 'shareapi_enforce_links_password', 'no', 'yes'],
733
+        ]);
734
+
735
+        // Create admin user
736
+        $user = $this->createMock(IUser::class);
737
+        $this->userSession->method('getUser')->willReturn($user);
738
+        $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['admin']);
739
+
740
+        $result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
741
+        $this->assertNull($result);
742
+    }
743
+
744
+    public function testVerifyPasswordNotEnforcedMultipleGroups(): void {
745
+        $this->config->method('getAppValue')->willReturnMap([
746
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', '["admin", "special"]'],
747
+            ['core', 'shareapi_enforce_links_password', 'no', 'yes'],
748
+        ]);
749
+
750
+        // Create admin user
751
+        $user = $this->createMock(IUser::class);
752
+        $this->userSession->method('getUser')->willReturn($user);
753
+        $this->groupManager->method('getUserGroupIds')->with($user)->willReturn(['special']);
754
+
755
+        $result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
756
+        $this->assertNull($result);
757
+    }
758
+
759
+    public function testVerifyPasswordNull(): void {
760
+        $this->config->method('getAppValue')->willReturnMap([
761
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
762
+            ['core', 'shareapi_enforce_links_password', 'no', 'no'],
763
+        ]);
764
+
765
+        $result = self::invokePrivate($this->manager, 'verifyPassword', [null]);
766
+        $this->assertNull($result);
767
+    }
768
+
769
+    public function testVerifyPasswordHook(): void {
770
+        $this->config->method('getAppValue')->willReturnMap([
771
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
772
+            ['core', 'shareapi_enforce_links_password', 'no', 'no'],
773
+        ]);
774
+
775
+        $this->dispatcher->expects($this->once())->method('dispatchTyped')
776
+            ->willReturnCallback(function (Event $event) {
777
+                $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
778
+                /** @var ValidatePasswordPolicyEvent $event */
779
+                $this->assertSame('password', $event->getPassword());
780
+            }
781
+            );
782
+
783
+        $result = self::invokePrivate($this->manager, 'verifyPassword', ['password']);
784
+        $this->assertNull($result);
785
+    }
786
+
787
+
788
+    public function testVerifyPasswordHookFails(): void {
789
+        $this->expectException(\Exception::class);
790
+        $this->expectExceptionMessage('password not accepted');
791
+
792
+        $this->config->method('getAppValue')->willReturnMap([
793
+            ['core', 'shareapi_enforce_links_password_excluded_groups', '', ''],
794
+            ['core', 'shareapi_enforce_links_password', 'no', 'no'],
795
+        ]);
796
+
797
+        $this->dispatcher->expects($this->once())->method('dispatchTyped')
798
+            ->willReturnCallback(function (Event $event) {
799
+                $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
800
+                /** @var ValidatePasswordPolicyEvent $event */
801
+                $this->assertSame('password', $event->getPassword());
802
+                throw new HintException('password not accepted');
803
+            }
804
+            );
805
+
806
+        self::invokePrivate($this->manager, 'verifyPassword', ['password']);
807
+    }
808
+
809
+    public function createShare($id, $type, $node, $sharedWith, $sharedBy, $shareOwner,
810
+        $permissions, $expireDate = null, $password = null, $attributes = null) {
811
+        $share = $this->createMock(IShare::class);
812
+
813
+        $share->method('getShareType')->willReturn($type);
814
+        $share->method('getSharedWith')->willReturn($sharedWith);
815
+        $share->method('getSharedBy')->willReturn($sharedBy);
816
+        $share->method('getShareOwner')->willReturn($shareOwner);
817
+        $share->method('getNode')->willReturn($node);
818
+        if ($node && $node->getId()) {
819
+            $share->method('getNodeId')->willReturn($node->getId());
820
+        }
821
+        $share->method('getPermissions')->willReturn($permissions);
822
+        $share->method('getAttributes')->willReturn($attributes);
823
+        $share->method('getExpirationDate')->willReturn($expireDate);
824
+        $share->method('getPassword')->willReturn($password);
825
+
826
+        return $share;
827
+    }
828
+
829
+    public function dataGeneralChecks() {
830
+        $user0 = 'user0';
831
+        $user2 = 'user1';
832
+        $group0 = 'group0';
833
+        $owner = $this->createMock(IUser::class);
834
+        $owner->method('getUID')
835
+            ->willReturn($user0);
836
+
837
+        $file = $this->createMock(File::class);
838
+        $node = $this->createMock(Node::class);
839
+        $storage = $this->createMock(IStorage::class);
840
+        $storage->method('instanceOfStorage')
841
+            ->with('\OCA\Files_Sharing\External\Storage')
842
+            ->willReturn(false);
843
+        $file->method('getStorage')
844
+            ->willReturn($storage);
845
+        $file->method('getId')->willReturn(108);
846
+        $node->method('getStorage')
847
+            ->willReturn($storage);
848
+        $node->method('getId')->willReturn(108);
849
+
850
+        $data = [
851
+            [$this->createShare(null, IShare::TYPE_USER, $file, null, $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
852
+            [$this->createShare(null, IShare::TYPE_USER, $file, $group0, $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
853
+            [$this->createShare(null, IShare::TYPE_USER, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient is not a valid user', true],
854
+            [$this->createShare(null, IShare::TYPE_GROUP, $file, null, $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
855
+            [$this->createShare(null, IShare::TYPE_GROUP, $file, $user2, $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
856
+            [$this->createShare(null, IShare::TYPE_GROUP, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient is not a valid group', true],
857
+            [$this->createShare(null, IShare::TYPE_LINK, $file, $user2, $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
858
+            [$this->createShare(null, IShare::TYPE_LINK, $file, $group0, $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
859
+            [$this->createShare(null, IShare::TYPE_LINK, $file, '[email protected]', $user0, $user0, 31, null, null), 'Share recipient should be empty', true],
860
+            [$this->createShare(null, -1, $file, null, $user0, $user0, 31, null, null), 'Unknown share type', true],
861
+
862
+            [$this->createShare(null, IShare::TYPE_USER, $file, $user2, null, $user0, 31, null, null), 'Share initiator must be set', true],
863
+            [$this->createShare(null, IShare::TYPE_GROUP, $file, $group0, null, $user0, 31, null, null), 'Share initiator must be set', true],
864
+            [$this->createShare(null, IShare::TYPE_LINK, $file, null, null, $user0, 31, null, null), 'Share initiator must be set', true],
865
+
866
+            [$this->createShare(null, IShare::TYPE_USER, $file, $user0, $user0, $user0, 31, null, null), 'Cannot share with yourself', true],
867
+
868
+            [$this->createShare(null, IShare::TYPE_USER, null, $user2, $user0, $user0, 31, null, null), 'Shared path must be set', true],
869
+            [$this->createShare(null, IShare::TYPE_GROUP, null, $group0, $user0, $user0, 31, null, null), 'Shared path must be set', true],
870
+            [$this->createShare(null, IShare::TYPE_LINK, null, null, $user0, $user0, 31, null, null), 'Shared path must be set', true],
871
+
872
+            [$this->createShare(null, IShare::TYPE_USER, $node, $user2, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
873
+            [$this->createShare(null, IShare::TYPE_GROUP, $node, $group0, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
874
+            [$this->createShare(null, IShare::TYPE_LINK, $node, null, $user0, $user0, 31, null, null), 'Shared path must be either a file or a folder', true],
875
+        ];
876
+
877
+        $nonShareAble = $this->createMock(Folder::class);
878
+        $nonShareAble->method('getId')->willReturn(108);
879
+        $nonShareAble->method('isShareable')->willReturn(false);
880
+        $nonShareAble->method('getPath')->willReturn('path');
881
+        $nonShareAble->method('getName')->willReturn('name');
882
+        $nonShareAble->method('getOwner')
883
+            ->willReturn($owner);
884
+        $nonShareAble->method('getStorage')
885
+            ->willReturn($storage);
886
+
887
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonShareAble, $user2, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
888
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonShareAble, $group0, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
889
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $nonShareAble, null, $user0, $user0, 31, null, null), 'You are not allowed to share name', true];
890
+
891
+        $limitedPermssions = $this->createMock(File::class);
892
+        $limitedPermssions->method('isShareable')->willReturn(true);
893
+        $limitedPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
894
+        $limitedPermssions->method('getId')->willReturn(108);
895
+        $limitedPermssions->method('getPath')->willReturn('path');
896
+        $limitedPermssions->method('getName')->willReturn('name');
897
+        $limitedPermssions->method('getOwner')
898
+            ->willReturn($owner);
899
+        $limitedPermssions->method('getStorage')
900
+            ->willReturn($storage);
901
+
902
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
903
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
904
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $limitedPermssions, null, $user0, $user0, null, null, null), 'Valid permissions are required for sharing', true];
905
+
906
+        $mount = $this->createMock(MoveableMount::class);
907
+        $limitedPermssions->method('getMountPoint')->willReturn($mount);
908
+
909
+        // increase permissions of a re-share
910
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $limitedPermssions, $group0, $user0, $user0, 17, null, null), 'Cannot increase permissions of path', true];
911
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $limitedPermssions, $user2, $user0, $user0, 3, null, null), 'Cannot increase permissions of path', true];
912
+
913
+        $nonMovableStorage = $this->createMock(IStorage::class);
914
+        $nonMovableStorage->method('instanceOfStorage')
915
+            ->with('\OCA\Files_Sharing\External\Storage')
916
+            ->willReturn(false);
917
+        $nonMovableStorage->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
918
+        $nonMoveableMountPermssions = $this->createMock(Folder::class);
919
+        $nonMoveableMountPermssions->method('isShareable')->willReturn(true);
920
+        $nonMoveableMountPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
921
+        $nonMoveableMountPermssions->method('getId')->willReturn(108);
922
+        $nonMoveableMountPermssions->method('getPath')->willReturn('path');
923
+        $nonMoveableMountPermssions->method('getName')->willReturn('name');
924
+        $nonMoveableMountPermssions->method('getInternalPath')->willReturn('');
925
+        $nonMoveableMountPermssions->method('getOwner')
926
+            ->willReturn($owner);
927
+        $nonMoveableMountPermssions->method('getStorage')
928
+            ->willReturn($nonMovableStorage);
929
+
930
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $nonMoveableMountPermssions, $user2, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false];
931
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $nonMoveableMountPermssions, $group0, $user0, $user0, 11, null, null), 'Cannot increase permissions of path', false];
932
+
933
+        $rootFolder = $this->createMock(Folder::class);
934
+        $rootFolder->method('isShareable')->willReturn(true);
935
+        $rootFolder->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
936
+        $rootFolder->method('getId')->willReturn(42);
937
+
938
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $rootFolder, $user2, $user0, $user0, 30, null, null), 'You cannot share your root folder', true];
939
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $rootFolder, $group0, $user0, $user0, 2, null, null), 'You cannot share your root folder', true];
940
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $rootFolder, null, $user0, $user0, 16, null, null), 'You cannot share your root folder', true];
941
+
942
+        $allPermssionsFiles = $this->createMock(File::class);
943
+        $allPermssionsFiles->method('isShareable')->willReturn(true);
944
+        $allPermssionsFiles->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
945
+        $allPermssionsFiles->method('getId')->willReturn(187);
946
+        $allPermssionsFiles->method('getOwner')
947
+            ->willReturn($owner);
948
+        $allPermssionsFiles->method('getStorage')
949
+            ->willReturn($storage);
950
+
951
+        // test invalid CREATE or DELETE permissions
952
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssionsFiles, $user2, $user0, $user0, \OCP\Constants::PERMISSION_ALL, null, null), 'File shares cannot have create or delete permissions', true];
953
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssionsFiles, $group0, $user0, $user0, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE, null, null), 'File shares cannot have create or delete permissions', true];
954
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssionsFiles, null, $user0, $user0, \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_DELETE, null, null), 'File shares cannot have create or delete permissions', true];
955
+
956
+        $allPermssions = $this->createMock(Folder::class);
957
+        $allPermssions->method('isShareable')->willReturn(true);
958
+        $allPermssions->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_ALL);
959
+        $allPermssions->method('getId')->willReturn(108);
960
+        $allPermssions->method('getOwner')
961
+            ->willReturn($owner);
962
+        $allPermssions->method('getStorage')
963
+            ->willReturn($storage);
964
+
965
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 30, null, null), 'Shares need at least read permissions', true];
966
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 2, null, null), 'Shares need at least read permissions', true];
967
+
968
+        // test invalid permissions
969
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 32, null, null), 'Valid permissions are required for sharing', true];
970
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 63, null, null), 'Valid permissions are required for sharing', true];
971
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, -1, null, null), 'Valid permissions are required for sharing', true];
972
+
973
+        // working shares
974
+        $data[] = [$this->createShare(null, IShare::TYPE_USER, $allPermssions, $user2, $user0, $user0, 31, null, null), null, false];
975
+        $data[] = [$this->createShare(null, IShare::TYPE_GROUP, $allPermssions, $group0, $user0, $user0, 3, null, null), null, false];
976
+        $data[] = [$this->createShare(null, IShare::TYPE_LINK, $allPermssions, null, $user0, $user0, 17, null, null), null, false];
977
+
978
+
979
+        $remoteStorage = $this->createMock(IStorage::class);
980
+        $remoteStorage->method('instanceOfStorage')
981
+            ->with('\OCA\Files_Sharing\External\Storage')
982
+            ->willReturn(true);
983
+        $remoteFile = $this->createMock(Folder::class);
984
+        $remoteFile->method('isShareable')->willReturn(true);
985
+        $remoteFile->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ ^ \OCP\Constants::PERMISSION_UPDATE);
986
+        $remoteFile->method('getId')->willReturn(108);
987
+        $remoteFile->method('getOwner')
988
+            ->willReturn($owner);
989
+        $remoteFile->method('getStorage')
990
+            ->willReturn($storage);
991
+        $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 1, null, null), null, false];
992
+        $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 3, null, null), null, false];
993
+        $data[] = [$this->createShare(null, IShare::TYPE_REMOTE, $remoteFile, $user2, $user0, $user0, 31, null, null), 'Cannot increase permissions of ', true];
994
+
995
+        return $data;
996
+    }
997
+
998
+    /**
999
+     * @dataProvider dataGeneralChecks
1000
+     *
1001
+     * @param $share
1002
+     * @param $exceptionMessage
1003
+     * @param $exception
1004
+     */
1005
+    public function testGeneralChecks($share, $exceptionMessage, $exception): void {
1006
+        $thrown = null;
1007
+
1008
+        $this->userManager->method('userExists')->willReturnMap([
1009
+            ['user0', true],
1010
+            ['user1', true],
1011
+        ]);
1012
+
1013
+        $this->groupManager->method('groupExists')->willReturnMap([
1014
+            ['group0', true],
1015
+        ]);
1016
+
1017
+        $userFolder = $this->createMock(Folder::class);
1018
+        $userFolder->expects($this->any())
1019
+            ->method('getId')
1020
+            ->willReturn(42);
1021
+        // Id 108 is used in the data to refer to the node of the share.
1022
+        $userFolder->method('getById')
1023
+            ->with(108)
1024
+            ->willReturn([$share->getNode()]);
1025
+        $userFolder->expects($this->any())
1026
+            ->method('getRelativePath')
1027
+            ->willReturnArgument(0);
1028
+        $this->rootFolder->method('getUserFolder')->willReturn($userFolder);
1029
+
1030
+
1031
+        try {
1032
+            self::invokePrivate($this->manager, 'generalCreateChecks', [$share]);
1033
+            $thrown = false;
1034
+        } catch (\OCP\Share\Exceptions\GenericShareException $e) {
1035
+            $this->assertEquals($exceptionMessage, $e->getHint());
1036
+            $thrown = true;
1037
+        } catch (\InvalidArgumentException $e) {
1038
+            $this->assertEquals($exceptionMessage, $e->getMessage());
1039
+            $thrown = true;
1040
+        }
1041
+
1042
+        $this->assertSame($exception, $thrown);
1043
+    }
1044
+
1045
+
1046
+    public function testGeneralCheckShareRoot(): void {
1047
+        $this->expectException(\InvalidArgumentException::class);
1048
+        $this->expectExceptionMessage('You cannot share your root folder');
1049
+
1050
+        $thrown = null;
1051
+
1052
+        $this->userManager->method('userExists')->willReturnMap([
1053
+            ['user0', true],
1054
+            ['user1', true],
1055
+        ]);
1056
+
1057
+        $userFolder = $this->createMock(Folder::class);
1058
+        $userFolder->method('isSubNode')->with($userFolder)->willReturn(false);
1059
+        $this->rootFolder->method('getUserFolder')->willReturn($userFolder);
1060
+
1061
+        $share = $this->manager->newShare();
1062
+
1063
+        $share->setShareType(IShare::TYPE_USER)
1064
+            ->setSharedWith('user0')
1065
+            ->setSharedBy('user1')
1066
+            ->setNode($userFolder);
1067
+
1068
+        self::invokePrivate($this->manager, 'generalCreateChecks', [$share]);
1069
+    }
1070
+
1071
+    public static function validateExpirationDateInternalProvider() {
1072
+        return [[IShare::TYPE_USER], [IShare::TYPE_REMOTE], [IShare::TYPE_REMOTE_GROUP]];
1073
+    }
1074
+
1075
+    /**
1076
+     * @dataProvider validateExpirationDateInternalProvider
1077
+     */
1078
+    public function testValidateExpirationDateInternalInPast($shareType): void {
1079
+        $this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1080
+        $this->expectExceptionMessage('Expiration date is in the past');
1081
+
1082
+        // Expire date in the past
1083
+        $past = new \DateTime();
1084
+        $past->sub(new \DateInterval('P1D'));
1085
+
1086
+        $share = $this->manager->newShare();
1087
+        $share->setShareType($shareType);
1088
+        $share->setExpirationDate($past);
1089
+
1090
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1091
+    }
1092
+
1093
+    /**
1094
+     * @dataProvider validateExpirationDateInternalProvider
1095
+     */
1096
+    public function testValidateExpirationDateInternalEnforceButNotSet($shareType): void {
1097
+        $this->expectException(\InvalidArgumentException::class);
1098
+        $this->expectExceptionMessage('Expiration date is enforced');
1099
+
1100
+        $share = $this->manager->newShare();
1101
+        $share->setProviderId('foo')->setId('bar');
1102
+        $share->setShareType($shareType);
1103
+        if ($shareType === IShare::TYPE_USER) {
1104
+            $this->config->method('getAppValue')
1105
+                ->willReturnMap([
1106
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1107
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1108
+                ]);
1109
+        } else {
1110
+            $this->config->method('getAppValue')
1111
+                ->willReturnMap([
1112
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1113
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1114
+                ]);
1115
+        }
1116
+
1117
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1118
+    }
1119
+
1120
+    /**
1121
+     * @dataProvider validateExpirationDateInternalProvider
1122
+     */
1123
+    public function testValidateExpirationDateInternalEnforceButNotEnabledAndNotSet($shareType): void {
1124
+        $share = $this->manager->newShare();
1125
+        $share->setProviderId('foo')->setId('bar');
1126
+        $share->setShareType($shareType);
1127
+
1128
+        if ($shareType === IShare::TYPE_USER) {
1129
+            $this->config->method('getAppValue')
1130
+                ->willReturnMap([
1131
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1132
+                ]);
1133
+        } else {
1134
+            $this->config->method('getAppValue')
1135
+                ->willReturnMap([
1136
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1137
+                ]);
1138
+        }
1139
+
1140
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1141
+
1142
+        $this->assertNull($share->getExpirationDate());
1143
+    }
1144
+
1145
+    /**
1146
+     * @dataProvider validateExpirationDateInternalProvider
1147
+     */
1148
+    public function testValidateExpirationDateInternalEnforceButNotSetNewShare($shareType): void {
1149
+        $share = $this->manager->newShare();
1150
+        $share->setShareType($shareType);
1151
+
1152
+        if ($shareType === IShare::TYPE_USER) {
1153
+            $this->config->method('getAppValue')
1154
+                ->willReturnMap([
1155
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1156
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1157
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1158
+                    ['core', 'internal_defaultExpDays', '3', '3'],
1159
+                ]);
1160
+        } else {
1161
+            $this->config->method('getAppValue')
1162
+                ->willReturnMap([
1163
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1164
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1165
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1166
+                    ['core', 'remote_defaultExpDays', '3', '3'],
1167
+                ]);
1168
+        }
1169
+
1170
+        $expected = new \DateTime('now', $this->timezone);
1171
+        $expected->setTime(0, 0, 0);
1172
+        $expected->add(new \DateInterval('P3D'));
1173
+
1174
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1175
+
1176
+        $this->assertNotNull($share->getExpirationDate());
1177
+        $this->assertEquals($expected, $share->getExpirationDate());
1178
+    }
1179
+
1180
+    /**
1181
+     * @dataProvider validateExpirationDateInternalProvider
1182
+     */
1183
+    public function testValidateExpirationDateInternalEnforceRelaxedDefaultButNotSetNewShare($shareType): void {
1184
+        $share = $this->manager->newShare();
1185
+        $share->setShareType($shareType);
1186
+
1187
+        if ($shareType === IShare::TYPE_USER) {
1188
+            $this->config->method('getAppValue')
1189
+                ->willReturnMap([
1190
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1191
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1192
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1193
+                    ['core', 'internal_defaultExpDays', '3', '1'],
1194
+                ]);
1195
+        } else {
1196
+            $this->config->method('getAppValue')
1197
+                ->willReturnMap([
1198
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1199
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1200
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1201
+                    ['core', 'remote_defaultExpDays', '3', '1'],
1202
+                ]);
1203
+        }
1204
+
1205
+        $expected = new \DateTime('now', $this->timezone);
1206
+        $expected->setTime(0, 0, 0);
1207
+        $expected->add(new \DateInterval('P1D'));
1208
+
1209
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1210
+
1211
+        $this->assertNotNull($share->getExpirationDate());
1212
+        $this->assertEquals($expected, $share->getExpirationDate());
1213
+    }
1214
+
1215
+    /**
1216
+     * @dataProvider validateExpirationDateInternalProvider
1217
+     */
1218
+    public function testValidateExpirationDateInternalEnforceTooFarIntoFuture($shareType): void {
1219
+        $this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1220
+        $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future');
1221
+
1222
+        $future = new \DateTime();
1223
+        $future->add(new \DateInterval('P7D'));
1224
+
1225
+        $share = $this->manager->newShare();
1226
+        $share->setShareType($shareType);
1227
+        $share->setExpirationDate($future);
1228
+
1229
+        if ($shareType === IShare::TYPE_USER) {
1230
+            $this->config->method('getAppValue')
1231
+                ->willReturnMap([
1232
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1233
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1234
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1235
+                ]);
1236
+        } else {
1237
+            $this->config->method('getAppValue')
1238
+                ->willReturnMap([
1239
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1240
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1241
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1242
+                ]);
1243
+        }
1244
+
1245
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1246
+    }
1247
+
1248
+    /**
1249
+     * @dataProvider validateExpirationDateInternalProvider
1250
+     */
1251
+    public function testValidateExpirationDateInternalEnforceValid($shareType): void {
1252
+        $future = new \DateTime('now', $this->dateTimeZone->getTimeZone());
1253
+        $future->add(new \DateInterval('P2D'));
1254
+        $future->setTime(1, 2, 3);
1255
+
1256
+        $expected = clone $future;
1257
+        $expected->setTime(0, 0, 0);
1258
+
1259
+        $share = $this->manager->newShare();
1260
+        $share->setShareType($shareType);
1261
+        $share->setExpirationDate($future);
1262
+
1263
+        if ($shareType === IShare::TYPE_USER) {
1264
+            $this->config->method('getAppValue')
1265
+                ->willReturnMap([
1266
+                    ['core', 'shareapi_enforce_internal_expire_date', 'no', 'yes'],
1267
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1268
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1269
+                ]);
1270
+        } else {
1271
+            $this->config->method('getAppValue')
1272
+                ->willReturnMap([
1273
+                    ['core', 'shareapi_enforce_remote_expire_date', 'no', 'yes'],
1274
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1275
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1276
+                ]);
1277
+        }
1278
+
1279
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1280
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1281
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1282
+            return $data['expirationDate'] == $future;
1283
+        }));
1284
+
1285
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1286
+
1287
+        $this->assertEquals($expected, $share->getExpirationDate());
1288
+    }
1289
+
1290
+    /**
1291
+     * @dataProvider validateExpirationDateInternalProvider
1292
+     */
1293
+    public function testValidateExpirationDateInternalNoDefault($shareType): void {
1294
+        $date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
1295
+        $date->add(new \DateInterval('P5D'));
1296
+        $date->setTime(1, 2, 3);
1297
+
1298
+        $expected = clone $date;
1299
+        $expected->setTime(0, 0, 0);
1300
+
1301
+        $share = $this->manager->newShare();
1302
+        $share->setShareType($shareType);
1303
+        $share->setExpirationDate($date);
1304
+
1305
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1306
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1307
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1308
+            return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1309
+        }));
1310
+
1311
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1312
+
1313
+        $this->assertEquals($expected, $share->getExpirationDate());
1314
+    }
1315
+
1316
+    /**
1317
+     * @dataProvider validateExpirationDateInternalProvider
1318
+     */
1319
+    public function testValidateExpirationDateInternalNoDateNoDefault($shareType): void {
1320
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1321
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1322
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1323
+            return $data['expirationDate'] === null && $data['passwordSet'] === true;
1324
+        }));
1325
+
1326
+        $share = $this->manager->newShare();
1327
+        $share->setShareType($shareType);
1328
+        $share->setPassword('password');
1329
+
1330
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1331
+
1332
+        $this->assertNull($share->getExpirationDate());
1333
+    }
1334
+
1335
+    /**
1336
+     * @dataProvider validateExpirationDateInternalProvider
1337
+     */
1338
+    public function testValidateExpirationDateInternalNoDateDefault($shareType): void {
1339
+        $share = $this->manager->newShare();
1340
+        $share->setShareType($shareType);
1341
+
1342
+        $expected = new \DateTime('now', $this->timezone);
1343
+        $expected->setTime(0, 0);
1344
+        $expected->add(new \DateInterval('P3D'));
1345
+        $expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1346
+
1347
+        if ($shareType === IShare::TYPE_USER) {
1348
+            $this->config->method('getAppValue')
1349
+                ->willReturnMap([
1350
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1351
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1352
+                    ['core', 'internal_defaultExpDays', '3', '3'],
1353
+                ]);
1354
+        } else {
1355
+            $this->config->method('getAppValue')
1356
+                ->willReturnMap([
1357
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1358
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1359
+                    ['core', 'remote_defaultExpDays', '3', '3'],
1360
+                ]);
1361
+        }
1362
+
1363
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1364
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1365
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1366
+            return $data['expirationDate'] == $expected;
1367
+        }));
1368
+
1369
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1370
+
1371
+        $this->assertEquals($expected, $share->getExpirationDate());
1372
+    }
1373
+
1374
+    /**
1375
+     * @dataProvider validateExpirationDateInternalProvider
1376
+     */
1377
+    public function testValidateExpirationDateInternalDefault($shareType): void {
1378
+        $future = new \DateTime('now', $this->timezone);
1379
+        $future->add(new \DateInterval('P5D'));
1380
+        $future->setTime(1, 2, 3);
1381
+
1382
+        $expected = clone $future;
1383
+        $expected->setTime(0, 0);
1384
+
1385
+        $share = $this->manager->newShare();
1386
+        $share->setShareType($shareType);
1387
+        $share->setExpirationDate($future);
1388
+
1389
+        if ($shareType === IShare::TYPE_USER) {
1390
+            $this->config->method('getAppValue')
1391
+                ->willReturnMap([
1392
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1393
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '3'],
1394
+                    ['core', 'internal_defaultExpDays', '3', '1'],
1395
+                ]);
1396
+        } else {
1397
+            $this->config->method('getAppValue')
1398
+                ->willReturnMap([
1399
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1400
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '3'],
1401
+                    ['core', 'remote_defaultExpDays', '3', '1'],
1402
+                ]);
1403
+        }
1404
+
1405
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1406
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1407
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1408
+            return $data['expirationDate'] == $expected;
1409
+        }));
1410
+
1411
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1412
+
1413
+        $this->assertEquals($expected, $share->getExpirationDate());
1414
+    }
1415
+
1416
+    /**
1417
+     * @dataProvider validateExpirationDateInternalProvider
1418
+     */
1419
+    public function testValidateExpirationDateInternalHookModification($shareType): void {
1420
+        $nextWeek = new \DateTime('now', $this->timezone);
1421
+        $nextWeek->add(new \DateInterval('P7D'));
1422
+        $nextWeek->setTime(0, 0, 0);
1423
+
1424
+        $save = clone $nextWeek;
1425
+
1426
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1427
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1428
+        $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1429
+            $data['expirationDate']->sub(new \DateInterval('P2D'));
1430
+        });
1431
+
1432
+        $share = $this->manager->newShare();
1433
+        $share->setShareType($shareType);
1434
+        $share->setExpirationDate($nextWeek);
1435
+
1436
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1437
+
1438
+        $save->sub(new \DateInterval('P2D'));
1439
+        $this->assertEquals($save, $share->getExpirationDate());
1440
+    }
1441
+
1442
+    /**
1443
+     * @dataProvider validateExpirationDateInternalProvider
1444
+     */
1445
+    public function testValidateExpirationDateInternalHookException($shareType): void {
1446
+        $this->expectException(\Exception::class);
1447
+        $this->expectExceptionMessage('Invalid date!');
1448
+
1449
+        $nextWeek = new \DateTime();
1450
+        $nextWeek->add(new \DateInterval('P7D'));
1451
+        $nextWeek->setTime(0, 0, 0);
1452
+
1453
+        $share = $this->manager->newShare();
1454
+        $share->setShareType($shareType);
1455
+        $share->setExpirationDate($nextWeek);
1456
+
1457
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1458
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1459
+        $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1460
+            $data['accepted'] = false;
1461
+            $data['message'] = 'Invalid date!';
1462
+        });
1463
+
1464
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1465
+    }
1466
+
1467
+    /**
1468
+     * @dataProvider validateExpirationDateInternalProvider
1469
+     */
1470
+    public function testValidateExpirationDateInternalExistingShareNoDefault($shareType): void {
1471
+        $share = $this->manager->newShare();
1472
+        $share->setShareType($shareType);
1473
+        $share->setId('42')->setProviderId('foo');
1474
+
1475
+        if ($shareType === IShare::TYPE_USER) {
1476
+            $this->config->method('getAppValue')
1477
+                ->willReturnMap([
1478
+                    ['core', 'shareapi_default_internal_expire_date', 'no', 'yes'],
1479
+                    ['core', 'shareapi_internal_expire_after_n_days', '7', '6'],
1480
+                ]);
1481
+        } else {
1482
+            $this->config->method('getAppValue')
1483
+                ->willReturnMap([
1484
+                    ['core', 'shareapi_default_remote_expire_date', 'no', 'yes'],
1485
+                    ['core', 'shareapi_remote_expire_after_n_days', '7', '6'],
1486
+                ]);
1487
+        }
1488
+
1489
+        self::invokePrivate($this->manager, 'validateExpirationDateInternal', [$share]);
1490
+
1491
+        $this->assertEquals(null, $share->getExpirationDate());
1492
+    }
1493
+
1494
+    public function testValidateExpirationDateInPast(): void {
1495
+        $this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1496
+        $this->expectExceptionMessage('Expiration date is in the past');
1497
+
1498
+        // Expire date in the past
1499
+        $past = new \DateTime();
1500
+        $past->sub(new \DateInterval('P1D'));
1501
+
1502
+        $share = $this->manager->newShare();
1503
+        $share->setExpirationDate($past);
1504
+
1505
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1506
+    }
1507
+
1508
+    public function testValidateExpirationDateEnforceButNotSet(): void {
1509
+        $this->expectException(\InvalidArgumentException::class);
1510
+        $this->expectExceptionMessage('Expiration date is enforced');
1511
+
1512
+        $share = $this->manager->newShare();
1513
+        $share->setProviderId('foo')->setId('bar');
1514
+
1515
+        $this->config->method('getAppValue')
1516
+            ->willReturnMap([
1517
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1518
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1519
+            ]);
1520
+
1521
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1522
+    }
1523
+
1524
+    public function testValidateExpirationDateEnforceButNotEnabledAndNotSet(): void {
1525
+        $share = $this->manager->newShare();
1526
+        $share->setProviderId('foo')->setId('bar');
1527
+
1528
+        $this->config->method('getAppValue')
1529
+            ->willReturnMap([
1530
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1531
+            ]);
1532
+
1533
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1534
+
1535
+        $this->assertNull($share->getExpirationDate());
1536
+    }
1537
+
1538
+    public function testValidateExpirationDateEnforceButNotSetNewShare(): void {
1539
+        $share = $this->manager->newShare();
1540
+
1541
+        $this->config->method('getAppValue')
1542
+            ->willReturnMap([
1543
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1544
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1545
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1546
+                ['core', 'link_defaultExpDays', '3', '3'],
1547
+            ]);
1548
+
1549
+        $expected = new \DateTime('now', $this->timezone);
1550
+        $expected->setTime(0, 0, 0);
1551
+        $expected->add(new \DateInterval('P3D'));
1552
+
1553
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1554
+
1555
+        $this->assertNotNull($share->getExpirationDate());
1556
+        $this->assertEquals($expected, $share->getExpirationDate());
1557
+    }
1558
+
1559
+    public function testValidateExpirationDateEnforceRelaxedDefaultButNotSetNewShare(): void {
1560
+        $share = $this->manager->newShare();
1561
+
1562
+        $this->config->method('getAppValue')
1563
+            ->willReturnMap([
1564
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1565
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1566
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1567
+                ['core', 'link_defaultExpDays', '3', '1'],
1568
+            ]);
1569
+
1570
+        $expected = new \DateTime('now', $this->timezone);
1571
+        $expected->setTime(0, 0, 0);
1572
+        $expected->add(new \DateInterval('P1D'));
1573
+
1574
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1575
+
1576
+        $this->assertNotNull($share->getExpirationDate());
1577
+        $this->assertEquals($expected, $share->getExpirationDate());
1578
+    }
1579
+
1580
+    public function testValidateExpirationDateEnforceTooFarIntoFuture(): void {
1581
+        $this->expectException(\OCP\Share\Exceptions\GenericShareException::class);
1582
+        $this->expectExceptionMessage('Cannot set expiration date more than 3 days in the future');
1583 1583
 
1584
-		$future = new \DateTime();
1585
-		$future->add(new \DateInterval('P7D'));
1584
+        $future = new \DateTime();
1585
+        $future->add(new \DateInterval('P7D'));
1586 1586
 
1587
-		$share = $this->manager->newShare();
1588
-		$share->setExpirationDate($future);
1587
+        $share = $this->manager->newShare();
1588
+        $share->setExpirationDate($future);
1589 1589
 
1590
-		$this->config->method('getAppValue')
1591
-			->willReturnMap([
1592
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1593
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1594
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1595
-			]);
1590
+        $this->config->method('getAppValue')
1591
+            ->willReturnMap([
1592
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1593
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1594
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1595
+            ]);
1596 1596
 
1597
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1598
-	}
1597
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1598
+    }
1599 1599
 
1600
-	public function testValidateExpirationDateEnforceValid(): void {
1601
-		$future = new \DateTime('now', $this->timezone);
1602
-		$future->add(new \DateInterval('P2D'));
1603
-		$future->setTime(1, 2, 3);
1600
+    public function testValidateExpirationDateEnforceValid(): void {
1601
+        $future = new \DateTime('now', $this->timezone);
1602
+        $future->add(new \DateInterval('P2D'));
1603
+        $future->setTime(1, 2, 3);
1604 1604
 
1605
-		$expected = clone $future;
1606
-		$expected->setTime(0, 0, 0);
1605
+        $expected = clone $future;
1606
+        $expected->setTime(0, 0, 0);
1607 1607
 
1608
-		$share = $this->manager->newShare();
1609
-		$share->setExpirationDate($future);
1610
-
1611
-		$this->config->method('getAppValue')
1612
-			->willReturnMap([
1613
-				['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1614
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1615
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1616
-			]);
1617
-
1618
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1619
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1620
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1621
-			return $data['expirationDate'] == $future;
1622
-		}));
1608
+        $share = $this->manager->newShare();
1609
+        $share->setExpirationDate($future);
1610
+
1611
+        $this->config->method('getAppValue')
1612
+            ->willReturnMap([
1613
+                ['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
1614
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1615
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1616
+            ]);
1617
+
1618
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1619
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1620
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1621
+            return $data['expirationDate'] == $future;
1622
+        }));
1623 1623
 
1624
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1625
-
1626
-		$this->assertEquals($expected, $share->getExpirationDate());
1627
-	}
1628
-
1629
-	public function testValidateExpirationDateNoDefault(): void {
1630
-		$date = new \DateTime('now', $this->timezone);
1631
-		$date->add(new \DateInterval('P5D'));
1632
-		$date->setTime(1, 2, 3);
1633
-
1634
-		$expected = clone $date;
1635
-		$expected->setTime(0, 0);
1636
-		$expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1637
-
1638
-		$share = $this->manager->newShare();
1639
-		$share->setExpirationDate($date);
1640
-
1641
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1642
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1643
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1644
-			return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1645
-		}));
1646
-
1647
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1648
-
1649
-		$this->assertEquals($expected, $share->getExpirationDate());
1650
-	}
1651
-
1652
-	public function testValidateExpirationDateNoDateNoDefault(): void {
1653
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1654
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1655
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1656
-			return $data['expirationDate'] === null && $data['passwordSet'] === true;
1657
-		}));
1658
-
1659
-		$share = $this->manager->newShare();
1660
-		$share->setPassword('password');
1661
-
1662
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1663
-
1664
-		$this->assertNull($share->getExpirationDate());
1665
-	}
1666
-
1667
-	public function testValidateExpirationDateNoDateDefault(): void {
1668
-		$share = $this->manager->newShare();
1669
-
1670
-		$expected = new \DateTime('now', $this->timezone);
1671
-		$expected->add(new \DateInterval('P3D'));
1672
-		$expected->setTime(0, 0);
1673
-		$expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1674
-
1675
-		$this->config->method('getAppValue')
1676
-			->willReturnMap([
1677
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1678
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1679
-				['core', 'link_defaultExpDays', '3', '3'],
1680
-			]);
1681
-
1682
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1683
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1684
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1685
-			return $data['expirationDate'] == $expected;
1686
-		}));
1687
-
1688
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1689
-
1690
-		$this->assertEquals($expected, $share->getExpirationDate());
1691
-	}
1692
-
1693
-	public function testValidateExpirationDateDefault(): void {
1694
-		$future = new \DateTime('now', $this->timezone);
1695
-		$future->add(new \DateInterval('P5D'));
1696
-		$future->setTime(1, 2, 3);
1697
-
1698
-		$expected = clone $future;
1699
-		$expected->setTime(0, 0);
1700
-		$expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1701
-
1702
-		$share = $this->manager->newShare();
1703
-		$share->setExpirationDate($future);
1624
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1625
+
1626
+        $this->assertEquals($expected, $share->getExpirationDate());
1627
+    }
1628
+
1629
+    public function testValidateExpirationDateNoDefault(): void {
1630
+        $date = new \DateTime('now', $this->timezone);
1631
+        $date->add(new \DateInterval('P5D'));
1632
+        $date->setTime(1, 2, 3);
1633
+
1634
+        $expected = clone $date;
1635
+        $expected->setTime(0, 0);
1636
+        $expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1637
+
1638
+        $share = $this->manager->newShare();
1639
+        $share->setExpirationDate($date);
1640
+
1641
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1642
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1643
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1644
+            return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1645
+        }));
1646
+
1647
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1648
+
1649
+        $this->assertEquals($expected, $share->getExpirationDate());
1650
+    }
1651
+
1652
+    public function testValidateExpirationDateNoDateNoDefault(): void {
1653
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1654
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1655
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1656
+            return $data['expirationDate'] === null && $data['passwordSet'] === true;
1657
+        }));
1658
+
1659
+        $share = $this->manager->newShare();
1660
+        $share->setPassword('password');
1661
+
1662
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1663
+
1664
+        $this->assertNull($share->getExpirationDate());
1665
+    }
1666
+
1667
+    public function testValidateExpirationDateNoDateDefault(): void {
1668
+        $share = $this->manager->newShare();
1669
+
1670
+        $expected = new \DateTime('now', $this->timezone);
1671
+        $expected->add(new \DateInterval('P3D'));
1672
+        $expected->setTime(0, 0);
1673
+        $expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1674
+
1675
+        $this->config->method('getAppValue')
1676
+            ->willReturnMap([
1677
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1678
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1679
+                ['core', 'link_defaultExpDays', '3', '3'],
1680
+            ]);
1681
+
1682
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1683
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1684
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1685
+            return $data['expirationDate'] == $expected;
1686
+        }));
1687
+
1688
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1689
+
1690
+        $this->assertEquals($expected, $share->getExpirationDate());
1691
+    }
1692
+
1693
+    public function testValidateExpirationDateDefault(): void {
1694
+        $future = new \DateTime('now', $this->timezone);
1695
+        $future->add(new \DateInterval('P5D'));
1696
+        $future->setTime(1, 2, 3);
1697
+
1698
+        $expected = clone $future;
1699
+        $expected->setTime(0, 0);
1700
+        $expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1701
+
1702
+        $share = $this->manager->newShare();
1703
+        $share->setExpirationDate($future);
1704 1704
 
1705
-		$this->config->method('getAppValue')
1706
-			->willReturnMap([
1707
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1708
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1709
-				['core', 'link_defaultExpDays', '3', '1'],
1710
-			]);
1711
-
1712
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1713
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1714
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1715
-			return $data['expirationDate'] == $expected;
1716
-		}));
1705
+        $this->config->method('getAppValue')
1706
+            ->willReturnMap([
1707
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1708
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1709
+                ['core', 'link_defaultExpDays', '3', '1'],
1710
+            ]);
1711
+
1712
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1713
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1714
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1715
+            return $data['expirationDate'] == $expected;
1716
+        }));
1717 1717
 
1718
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1718
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1719 1719
 
1720
-		$this->assertEquals($expected, $share->getExpirationDate());
1721
-	}
1720
+        $this->assertEquals($expected, $share->getExpirationDate());
1721
+    }
1722 1722
 
1723
-	public function testValidateExpirationNegativeOffsetTimezone(): void {
1724
-		$this->timezone = new \DateTimeZone('Pacific/Tahiti');
1725
-		$future = new \DateTime();
1726
-		$future->add(new \DateInterval('P5D'));
1723
+    public function testValidateExpirationNegativeOffsetTimezone(): void {
1724
+        $this->timezone = new \DateTimeZone('Pacific/Tahiti');
1725
+        $future = new \DateTime();
1726
+        $future->add(new \DateInterval('P5D'));
1727 1727
 
1728
-		$expected = clone $future;
1729
-		$expected->setTimezone($this->timezone);
1730
-		$expected->setTime(0, 0);
1731
-		$expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1728
+        $expected = clone $future;
1729
+        $expected->setTimezone($this->timezone);
1730
+        $expected->setTime(0, 0);
1731
+        $expected->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1732 1732
 
1733
-		$share = $this->manager->newShare();
1734
-		$share->setExpirationDate($future);
1735
-
1736
-		$this->config->method('getAppValue')
1737
-			->willReturnMap([
1738
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1739
-				['core', 'shareapi_expire_after_n_days', '7', '3'],
1740
-				['core', 'link_defaultExpDays', '3', '1'],
1741
-			]);
1742
-
1743
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1744
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1745
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1746
-			return $data['expirationDate'] == $expected;
1747
-		}));
1748
-
1749
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1750
-
1751
-		$this->assertEquals($expected, $share->getExpirationDate());
1752
-	}
1753
-
1754
-	public function testValidateExpirationDateHookModification(): void {
1755
-		$nextWeek = new \DateTime('now', $this->timezone);
1756
-		$nextWeek->add(new \DateInterval('P7D'));
1733
+        $share = $this->manager->newShare();
1734
+        $share->setExpirationDate($future);
1735
+
1736
+        $this->config->method('getAppValue')
1737
+            ->willReturnMap([
1738
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1739
+                ['core', 'shareapi_expire_after_n_days', '7', '3'],
1740
+                ['core', 'link_defaultExpDays', '3', '1'],
1741
+            ]);
1742
+
1743
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1744
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1745
+        $hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1746
+            return $data['expirationDate'] == $expected;
1747
+        }));
1748
+
1749
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1750
+
1751
+        $this->assertEquals($expected, $share->getExpirationDate());
1752
+    }
1753
+
1754
+    public function testValidateExpirationDateHookModification(): void {
1755
+        $nextWeek = new \DateTime('now', $this->timezone);
1756
+        $nextWeek->add(new \DateInterval('P7D'));
1757 1757
 
1758
-		$save = clone $nextWeek;
1759
-		$save->setTime(0, 0);
1760
-		$save->sub(new \DateInterval('P2D'));
1761
-		$save->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1762
-
1763
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1764
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1765
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1766
-			$data['expirationDate']->sub(new \DateInterval('P2D'));
1767
-		});
1768
-
1769
-		$share = $this->manager->newShare();
1770
-		$share->setExpirationDate($nextWeek);
1771
-
1772
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1773
-
1774
-		$this->assertEquals($save, $share->getExpirationDate());
1775
-	}
1776
-
1777
-	public function testValidateExpirationDateHookException(): void {
1778
-		$this->expectException(\Exception::class);
1779
-		$this->expectExceptionMessage('Invalid date!');
1780
-
1781
-		$nextWeek = new \DateTime();
1782
-		$nextWeek->add(new \DateInterval('P7D'));
1783
-		$nextWeek->setTime(0, 0, 0);
1784
-
1785
-		$share = $this->manager->newShare();
1786
-		$share->setExpirationDate($nextWeek);
1787
-
1788
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
1789
-		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1790
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1791
-			$data['accepted'] = false;
1792
-			$data['message'] = 'Invalid date!';
1793
-		});
1794
-
1795
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1796
-	}
1797
-
1798
-	public function testValidateExpirationDateExistingShareNoDefault(): void {
1799
-		$share = $this->manager->newShare();
1800
-
1801
-		$share->setId('42')->setProviderId('foo');
1802
-
1803
-		$this->config->method('getAppValue')
1804
-			->willReturnMap([
1805
-				['core', 'shareapi_default_expire_date', 'no', 'yes'],
1806
-				['core', 'shareapi_expire_after_n_days', '7', '6'],
1807
-			]);
1808
-
1809
-		self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1810
-
1811
-		$this->assertEquals(null, $share->getExpirationDate());
1812
-	}
1813
-
1814
-	public function testUserCreateChecksShareWithGroupMembersOnlyDifferentGroups(): void {
1815
-		$this->expectException(\Exception::class);
1816
-		$this->expectExceptionMessage('Sharing is only allowed with group members');
1758
+        $save = clone $nextWeek;
1759
+        $save->setTime(0, 0);
1760
+        $save->sub(new \DateInterval('P2D'));
1761
+        $save->setTimezone(new \DateTimeZone(date_default_timezone_get()));
1762
+
1763
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1764
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1765
+        $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1766
+            $data['expirationDate']->sub(new \DateInterval('P2D'));
1767
+        });
1768
+
1769
+        $share = $this->manager->newShare();
1770
+        $share->setExpirationDate($nextWeek);
1771
+
1772
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1773
+
1774
+        $this->assertEquals($save, $share->getExpirationDate());
1775
+    }
1776
+
1777
+    public function testValidateExpirationDateHookException(): void {
1778
+        $this->expectException(\Exception::class);
1779
+        $this->expectExceptionMessage('Invalid date!');
1780
+
1781
+        $nextWeek = new \DateTime();
1782
+        $nextWeek->add(new \DateInterval('P7D'));
1783
+        $nextWeek->setTime(0, 0, 0);
1784
+
1785
+        $share = $this->manager->newShare();
1786
+        $share->setExpirationDate($nextWeek);
1787
+
1788
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
1789
+        \OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1790
+        $hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1791
+            $data['accepted'] = false;
1792
+            $data['message'] = 'Invalid date!';
1793
+        });
1794
+
1795
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1796
+    }
1797
+
1798
+    public function testValidateExpirationDateExistingShareNoDefault(): void {
1799
+        $share = $this->manager->newShare();
1800
+
1801
+        $share->setId('42')->setProviderId('foo');
1802
+
1803
+        $this->config->method('getAppValue')
1804
+            ->willReturnMap([
1805
+                ['core', 'shareapi_default_expire_date', 'no', 'yes'],
1806
+                ['core', 'shareapi_expire_after_n_days', '7', '6'],
1807
+            ]);
1808
+
1809
+        self::invokePrivate($this->manager, 'validateExpirationDateLink', [$share]);
1810
+
1811
+        $this->assertEquals(null, $share->getExpirationDate());
1812
+    }
1813
+
1814
+    public function testUserCreateChecksShareWithGroupMembersOnlyDifferentGroups(): void {
1815
+        $this->expectException(\Exception::class);
1816
+        $this->expectExceptionMessage('Sharing is only allowed with group members');
1817 1817
 
1818
-		$share = $this->manager->newShare();
1818
+        $share = $this->manager->newShare();
1819 1819
 
1820
-		$sharedBy = $this->createMock(IUser::class);
1821
-		$sharedWith = $this->createMock(IUser::class);
1822
-		$share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
1820
+        $sharedBy = $this->createMock(IUser::class);
1821
+        $sharedWith = $this->createMock(IUser::class);
1822
+        $share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
1823 1823
 
1824
-		$this->groupManager
1825
-			->method('getUserGroupIds')
1826
-			->willReturnMap(
1827
-				[
1828
-					[$sharedBy, ['group1']],
1829
-					[$sharedWith, ['group2']],
1830
-				]
1831
-			);
1824
+        $this->groupManager
1825
+            ->method('getUserGroupIds')
1826
+            ->willReturnMap(
1827
+                [
1828
+                    [$sharedBy, ['group1']],
1829
+                    [$sharedWith, ['group2']],
1830
+                ]
1831
+            );
1832 1832
 
1833
-		$this->userManager->method('get')->willReturnMap([
1834
-			['sharedBy', $sharedBy],
1835
-			['sharedWith', $sharedWith],
1836
-		]);
1833
+        $this->userManager->method('get')->willReturnMap([
1834
+            ['sharedBy', $sharedBy],
1835
+            ['sharedWith', $sharedWith],
1836
+        ]);
1837 1837
 
1838
-		$this->config
1839
-			->method('getAppValue')
1840
-			->willReturnMap([
1841
-				['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
1842
-				['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
1843
-			]);
1838
+        $this->config
1839
+            ->method('getAppValue')
1840
+            ->willReturnMap([
1841
+                ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
1842
+                ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
1843
+            ]);
1844 1844
 
1845
-		self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1846
-	}
1845
+        self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1846
+    }
1847 1847
 
1848
-	public function testUserCreateChecksShareWithGroupMembersOnlySharedGroup(): void {
1849
-		$share = $this->manager->newShare();
1848
+    public function testUserCreateChecksShareWithGroupMembersOnlySharedGroup(): void {
1849
+        $share = $this->manager->newShare();
1850 1850
 
1851
-		$sharedBy = $this->createMock(IUser::class);
1852
-		$sharedWith = $this->createMock(IUser::class);
1853
-		$share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
1851
+        $sharedBy = $this->createMock(IUser::class);
1852
+        $sharedWith = $this->createMock(IUser::class);
1853
+        $share->setSharedBy('sharedBy')->setSharedWith('sharedWith');
1854 1854
 
1855
-		$path = $this->createMock(Node::class);
1856
-		$share->setNode($path);
1855
+        $path = $this->createMock(Node::class);
1856
+        $share->setNode($path);
1857 1857
 
1858
-		$this->groupManager
1859
-			->method('getUserGroupIds')
1860
-			->willReturnMap(
1861
-				[
1862
-					[$sharedBy, ['group1', 'group3']],
1863
-					[$sharedWith, ['group2', 'group3']],
1864
-				]
1865
-			);
1858
+        $this->groupManager
1859
+            ->method('getUserGroupIds')
1860
+            ->willReturnMap(
1861
+                [
1862
+                    [$sharedBy, ['group1', 'group3']],
1863
+                    [$sharedWith, ['group2', 'group3']],
1864
+                ]
1865
+            );
1866 1866
 
1867
-		$this->userManager->method('get')->willReturnMap([
1868
-			['sharedBy', $sharedBy],
1869
-			['sharedWith', $sharedWith],
1870
-		]);
1867
+        $this->userManager->method('get')->willReturnMap([
1868
+            ['sharedBy', $sharedBy],
1869
+            ['sharedWith', $sharedWith],
1870
+        ]);
1871 1871
 
1872
-		$this->config
1873
-			->method('getAppValue')
1874
-			->willReturnMap([
1875
-				['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
1876
-				['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
1877
-			]);
1872
+        $this->config
1873
+            ->method('getAppValue')
1874
+            ->willReturnMap([
1875
+                ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
1876
+                ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
1877
+            ]);
1878 1878
 
1879
-		$this->defaultProvider
1880
-			->method('getSharesByPath')
1881
-			->with($path)
1882
-			->willReturn([]);
1879
+        $this->defaultProvider
1880
+            ->method('getSharesByPath')
1881
+            ->with($path)
1882
+            ->willReturn([]);
1883 1883
 
1884
-		self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1885
-		$this->addToAssertionCount(1);
1886
-	}
1884
+        self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1885
+        $this->addToAssertionCount(1);
1886
+    }
1887 1887
 
1888 1888
 
1889
-	public function testUserCreateChecksIdenticalShareExists(): void {
1890
-		$this->expectException(AlreadySharedException::class);
1891
-		$this->expectExceptionMessage('Sharing name.txt failed, because this item is already shared with the account user');
1889
+    public function testUserCreateChecksIdenticalShareExists(): void {
1890
+        $this->expectException(AlreadySharedException::class);
1891
+        $this->expectExceptionMessage('Sharing name.txt failed, because this item is already shared with the account user');
1892 1892
 
1893
-		$share = $this->manager->newShare();
1894
-		$share->setSharedWithDisplayName('user');
1895
-		$share2 = $this->manager->newShare();
1893
+        $share = $this->manager->newShare();
1894
+        $share->setSharedWithDisplayName('user');
1895
+        $share2 = $this->manager->newShare();
1896 1896
 
1897
-		$sharedWith = $this->createMock(IUser::class);
1898
-		$path = $this->createMock(Node::class);
1897
+        $sharedWith = $this->createMock(IUser::class);
1898
+        $path = $this->createMock(Node::class);
1899 1899
 
1900
-		$share->setSharedWith('sharedWith')->setNode($path)
1901
-			->setProviderId('foo')->setId('bar');
1900
+        $share->setSharedWith('sharedWith')->setNode($path)
1901
+            ->setProviderId('foo')->setId('bar');
1902 1902
 
1903
-		$share2->setSharedWith('sharedWith')->setNode($path)
1904
-			->setProviderId('foo')->setId('baz');
1903
+        $share2->setSharedWith('sharedWith')->setNode($path)
1904
+            ->setProviderId('foo')->setId('baz');
1905 1905
 
1906
-		$this->defaultProvider
1907
-			->method('getSharesByPath')
1908
-			->with($path)
1909
-			->willReturn([$share2]);
1906
+        $this->defaultProvider
1907
+            ->method('getSharesByPath')
1908
+            ->with($path)
1909
+            ->willReturn([$share2]);
1910 1910
 
1911
-		$path->method('getName')
1912
-			->willReturn('name.txt');
1911
+        $path->method('getName')
1912
+            ->willReturn('name.txt');
1913 1913
 
1914
-		self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1915
-	}
1916
-
1917
-
1918
-	public function testUserCreateChecksIdenticalPathSharedViaGroup(): void {
1919
-		$this->expectException(AlreadySharedException::class);
1920
-		$this->expectExceptionMessage('Sharing name2.txt failed, because this item is already shared with the account userName');
1921
-
1922
-		$share = $this->manager->newShare();
1914
+        self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1915
+    }
1916
+
1917
+
1918
+    public function testUserCreateChecksIdenticalPathSharedViaGroup(): void {
1919
+        $this->expectException(AlreadySharedException::class);
1920
+        $this->expectExceptionMessage('Sharing name2.txt failed, because this item is already shared with the account userName');
1921
+
1922
+        $share = $this->manager->newShare();
1923 1923
 
1924
-		$sharedWith = $this->createMock(IUser::class);
1925
-		$sharedWith->method('getUID')->willReturn('sharedWith');
1926
-
1927
-		$this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
1924
+        $sharedWith = $this->createMock(IUser::class);
1925
+        $sharedWith->method('getUID')->willReturn('sharedWith');
1926
+
1927
+        $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
1928 1928
 
1929
-		$path = $this->createMock(Node::class);
1929
+        $path = $this->createMock(Node::class);
1930 1930
 
1931
-		$share->setSharedWith('sharedWith')
1932
-			->setNode($path)
1933
-			->setShareOwner('shareOwner')
1934
-			->setSharedWithDisplayName('userName')
1935
-			->setProviderId('foo')
1936
-			->setId('bar');
1931
+        $share->setSharedWith('sharedWith')
1932
+            ->setNode($path)
1933
+            ->setShareOwner('shareOwner')
1934
+            ->setSharedWithDisplayName('userName')
1935
+            ->setProviderId('foo')
1936
+            ->setId('bar');
1937 1937
 
1938
-		$share2 = $this->manager->newShare();
1939
-		$share2->setShareType(IShare::TYPE_GROUP)
1940
-			->setShareOwner('shareOwner2')
1941
-			->setProviderId('foo')
1942
-			->setId('baz')
1943
-			->setSharedWith('group');
1938
+        $share2 = $this->manager->newShare();
1939
+        $share2->setShareType(IShare::TYPE_GROUP)
1940
+            ->setShareOwner('shareOwner2')
1941
+            ->setProviderId('foo')
1942
+            ->setId('baz')
1943
+            ->setSharedWith('group');
1944 1944
 
1945
-		$group = $this->createMock(IGroup::class);
1946
-		$group->method('inGroup')
1947
-			->with($sharedWith)
1948
-			->willReturn(true);
1945
+        $group = $this->createMock(IGroup::class);
1946
+        $group->method('inGroup')
1947
+            ->with($sharedWith)
1948
+            ->willReturn(true);
1949 1949
 
1950
-		$this->groupManager->method('get')->with('group')->willReturn($group);
1950
+        $this->groupManager->method('get')->with('group')->willReturn($group);
1951 1951
 
1952
-		$this->defaultProvider
1953
-			->method('getSharesByPath')
1954
-			->with($path)
1955
-			->willReturn([$share2]);
1952
+        $this->defaultProvider
1953
+            ->method('getSharesByPath')
1954
+            ->with($path)
1955
+            ->willReturn([$share2]);
1956 1956
 
1957
-		$path->method('getName')
1958
-			->willReturn('name2.txt');
1957
+        $path->method('getName')
1958
+            ->willReturn('name2.txt');
1959 1959
 
1960
-		self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1961
-	}
1960
+        self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
1961
+    }
1962 1962
 
1963
-	public function testUserCreateChecksIdenticalPathSharedViaDeletedGroup(): void {
1964
-		$share = $this->manager->newShare();
1963
+    public function testUserCreateChecksIdenticalPathSharedViaDeletedGroup(): void {
1964
+        $share = $this->manager->newShare();
1965 1965
 
1966
-		$sharedWith = $this->createMock(IUser::class);
1967
-		$sharedWith->method('getUID')->willReturn('sharedWith');
1966
+        $sharedWith = $this->createMock(IUser::class);
1967
+        $sharedWith->method('getUID')->willReturn('sharedWith');
1968 1968
 
1969
-		$this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
1969
+        $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
1970 1970
 
1971
-		$path = $this->createMock(Node::class);
1971
+        $path = $this->createMock(Node::class);
1972 1972
 
1973
-		$share->setSharedWith('sharedWith')
1974
-			->setNode($path)
1975
-			->setShareOwner('shareOwner')
1976
-			->setProviderId('foo')
1977
-			->setId('bar');
1973
+        $share->setSharedWith('sharedWith')
1974
+            ->setNode($path)
1975
+            ->setShareOwner('shareOwner')
1976
+            ->setProviderId('foo')
1977
+            ->setId('bar');
1978 1978
 
1979
-		$share2 = $this->manager->newShare();
1980
-		$share2->setShareType(IShare::TYPE_GROUP)
1981
-			->setShareOwner('shareOwner2')
1982
-			->setProviderId('foo')
1983
-			->setId('baz')
1984
-			->setSharedWith('group');
1979
+        $share2 = $this->manager->newShare();
1980
+        $share2->setShareType(IShare::TYPE_GROUP)
1981
+            ->setShareOwner('shareOwner2')
1982
+            ->setProviderId('foo')
1983
+            ->setId('baz')
1984
+            ->setSharedWith('group');
1985 1985
 
1986
-		$this->groupManager->method('get')->with('group')->willReturn(null);
1986
+        $this->groupManager->method('get')->with('group')->willReturn(null);
1987 1987
 
1988
-		$this->defaultProvider
1989
-			->method('getSharesByPath')
1990
-			->with($path)
1991
-			->willReturn([$share2]);
1988
+        $this->defaultProvider
1989
+            ->method('getSharesByPath')
1990
+            ->with($path)
1991
+            ->willReturn([$share2]);
1992 1992
 
1993
-		$this->assertNull($this->invokePrivate($this->manager, 'userCreateChecks', [$share]));
1994
-	}
1993
+        $this->assertNull($this->invokePrivate($this->manager, 'userCreateChecks', [$share]));
1994
+    }
1995 1995
 
1996
-	public function testUserCreateChecksIdenticalPathNotSharedWithUser(): void {
1997
-		$share = $this->manager->newShare();
1998
-		$sharedWith = $this->createMock(IUser::class);
1999
-		$path = $this->createMock(Node::class);
2000
-		$share->setSharedWith('sharedWith')
2001
-			->setNode($path)
2002
-			->setShareOwner('shareOwner')
2003
-			->setProviderId('foo')
2004
-			->setId('bar');
1996
+    public function testUserCreateChecksIdenticalPathNotSharedWithUser(): void {
1997
+        $share = $this->manager->newShare();
1998
+        $sharedWith = $this->createMock(IUser::class);
1999
+        $path = $this->createMock(Node::class);
2000
+        $share->setSharedWith('sharedWith')
2001
+            ->setNode($path)
2002
+            ->setShareOwner('shareOwner')
2003
+            ->setProviderId('foo')
2004
+            ->setId('bar');
2005 2005
 
2006
-		$this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
2006
+        $this->userManager->method('get')->with('sharedWith')->willReturn($sharedWith);
2007 2007
 
2008
-		$share2 = $this->manager->newShare();
2009
-		$share2->setShareType(IShare::TYPE_GROUP)
2010
-			->setShareOwner('shareOwner2')
2011
-			->setProviderId('foo')
2012
-			->setId('baz');
2008
+        $share2 = $this->manager->newShare();
2009
+        $share2->setShareType(IShare::TYPE_GROUP)
2010
+            ->setShareOwner('shareOwner2')
2011
+            ->setProviderId('foo')
2012
+            ->setId('baz');
2013 2013
 
2014
-		$group = $this->createMock(IGroup::class);
2015
-		$group->method('inGroup')
2016
-			->with($sharedWith)
2017
-			->willReturn(false);
2014
+        $group = $this->createMock(IGroup::class);
2015
+        $group->method('inGroup')
2016
+            ->with($sharedWith)
2017
+            ->willReturn(false);
2018 2018
 
2019
-		$this->groupManager->method('get')->with('group')->willReturn($group);
2019
+        $this->groupManager->method('get')->with('group')->willReturn($group);
2020 2020
 
2021
-		$share2->setSharedWith('group');
2021
+        $share2->setSharedWith('group');
2022 2022
 
2023
-		$this->defaultProvider
2024
-			->method('getSharesByPath')
2025
-			->with($path)
2026
-			->willReturn([$share2]);
2023
+        $this->defaultProvider
2024
+            ->method('getSharesByPath')
2025
+            ->with($path)
2026
+            ->willReturn([$share2]);
2027 2027
 
2028
-		self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
2029
-		$this->addToAssertionCount(1);
2030
-	}
2028
+        self::invokePrivate($this->manager, 'userCreateChecks', [$share]);
2029
+        $this->addToAssertionCount(1);
2030
+    }
2031 2031
 
2032 2032
 
2033
-	public function testGroupCreateChecksShareWithGroupMembersGroupSharingNotAllowed(): void {
2034
-		$this->expectException(\Exception::class);
2035
-		$this->expectExceptionMessage('Group sharing is now allowed');
2033
+    public function testGroupCreateChecksShareWithGroupMembersGroupSharingNotAllowed(): void {
2034
+        $this->expectException(\Exception::class);
2035
+        $this->expectExceptionMessage('Group sharing is now allowed');
2036 2036
 
2037
-		$share = $this->manager->newShare();
2037
+        $share = $this->manager->newShare();
2038 2038
 
2039
-		$this->config
2040
-			->method('getAppValue')
2041
-			->willReturnMap([
2042
-				['core', 'shareapi_allow_group_sharing', 'yes', 'no'],
2043
-			]);
2039
+        $this->config
2040
+            ->method('getAppValue')
2041
+            ->willReturnMap([
2042
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'no'],
2043
+            ]);
2044 2044
 
2045
-		self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2046
-	}
2045
+        self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2046
+    }
2047 2047
 
2048 2048
 
2049
-	public function testGroupCreateChecksShareWithGroupMembersOnlyNotInGroup(): void {
2050
-		$this->expectException(\Exception::class);
2051
-		$this->expectExceptionMessage('Sharing is only allowed within your own groups');
2049
+    public function testGroupCreateChecksShareWithGroupMembersOnlyNotInGroup(): void {
2050
+        $this->expectException(\Exception::class);
2051
+        $this->expectExceptionMessage('Sharing is only allowed within your own groups');
2052 2052
 
2053
-		$share = $this->manager->newShare();
2053
+        $share = $this->manager->newShare();
2054 2054
 
2055
-		$user = $this->createMock(IUser::class);
2056
-		$group = $this->createMock(IGroup::class);
2057
-		$share->setSharedBy('user')->setSharedWith('group');
2055
+        $user = $this->createMock(IUser::class);
2056
+        $group = $this->createMock(IGroup::class);
2057
+        $share->setSharedBy('user')->setSharedWith('group');
2058 2058
 
2059
-		$group->method('inGroup')->with($user)->willReturn(false);
2059
+        $group->method('inGroup')->with($user)->willReturn(false);
2060 2060
 
2061
-		$this->groupManager->method('get')->with('group')->willReturn($group);
2062
-		$this->userManager->method('get')->with('user')->willReturn($user);
2061
+        $this->groupManager->method('get')->with('group')->willReturn($group);
2062
+        $this->userManager->method('get')->with('user')->willReturn($user);
2063 2063
 
2064
-		$this->config
2065
-			->method('getAppValue')
2066
-			->willReturnMap([
2067
-				['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2068
-				['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2069
-				['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2070
-			]);
2064
+        $this->config
2065
+            ->method('getAppValue')
2066
+            ->willReturnMap([
2067
+                ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2068
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2069
+                ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2070
+            ]);
2071 2071
 
2072
-		self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2073
-	}
2072
+        self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2073
+    }
2074 2074
 
2075 2075
 
2076
-	public function testGroupCreateChecksShareWithGroupMembersOnlyNullGroup(): void {
2077
-		$this->expectException(\Exception::class);
2078
-		$this->expectExceptionMessage('Sharing is only allowed within your own groups');
2076
+    public function testGroupCreateChecksShareWithGroupMembersOnlyNullGroup(): void {
2077
+        $this->expectException(\Exception::class);
2078
+        $this->expectExceptionMessage('Sharing is only allowed within your own groups');
2079 2079
 
2080
-		$share = $this->manager->newShare();
2080
+        $share = $this->manager->newShare();
2081 2081
 
2082
-		$user = $this->createMock(IUser::class);
2083
-		$share->setSharedBy('user')->setSharedWith('group');
2082
+        $user = $this->createMock(IUser::class);
2083
+        $share->setSharedBy('user')->setSharedWith('group');
2084 2084
 
2085
-		$this->groupManager->method('get')->with('group')->willReturn(null);
2086
-		$this->userManager->method('get')->with('user')->willReturn($user);
2085
+        $this->groupManager->method('get')->with('group')->willReturn(null);
2086
+        $this->userManager->method('get')->with('user')->willReturn($user);
2087 2087
 
2088
-		$this->config
2089
-			->method('getAppValue')
2090
-			->willReturnMap([
2091
-				['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2092
-				['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2093
-				['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2094
-			]);
2088
+        $this->config
2089
+            ->method('getAppValue')
2090
+            ->willReturnMap([
2091
+                ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2092
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2093
+                ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2094
+            ]);
2095 2095
 
2096
-		$this->assertNull($this->invokePrivate($this->manager, 'groupCreateChecks', [$share]));
2097
-	}
2096
+        $this->assertNull($this->invokePrivate($this->manager, 'groupCreateChecks', [$share]));
2097
+    }
2098 2098
 
2099
-	public function testGroupCreateChecksShareWithGroupMembersOnlyInGroup(): void {
2100
-		$share = $this->manager->newShare();
2099
+    public function testGroupCreateChecksShareWithGroupMembersOnlyInGroup(): void {
2100
+        $share = $this->manager->newShare();
2101 2101
 
2102
-		$user = $this->createMock(IUser::class);
2103
-		$group = $this->createMock(IGroup::class);
2104
-		$share->setSharedBy('user')->setSharedWith('group');
2102
+        $user = $this->createMock(IUser::class);
2103
+        $group = $this->createMock(IGroup::class);
2104
+        $share->setSharedBy('user')->setSharedWith('group');
2105 2105
 
2106
-		$this->userManager->method('get')->with('user')->willReturn($user);
2107
-		$this->groupManager->method('get')->with('group')->willReturn($group);
2106
+        $this->userManager->method('get')->with('user')->willReturn($user);
2107
+        $this->groupManager->method('get')->with('group')->willReturn($group);
2108 2108
 
2109
-		$group->method('inGroup')->with($user)->willReturn(true);
2109
+        $group->method('inGroup')->with($user)->willReturn(true);
2110 2110
 
2111
-		$path = $this->createMock(Node::class);
2112
-		$share->setNode($path);
2111
+        $path = $this->createMock(Node::class);
2112
+        $share->setNode($path);
2113 2113
 
2114
-		$this->defaultProvider->method('getSharesByPath')
2115
-			->with($path)
2116
-			->willReturn([]);
2114
+        $this->defaultProvider->method('getSharesByPath')
2115
+            ->with($path)
2116
+            ->willReturn([]);
2117 2117
 
2118
-		$this->config
2119
-			->method('getAppValue')
2120
-			->willReturnMap([
2121
-				['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2122
-				['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2123
-				['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2124
-			]);
2118
+        $this->config
2119
+            ->method('getAppValue')
2120
+            ->willReturnMap([
2121
+                ['core', 'shareapi_only_share_with_group_members', 'no', 'yes'],
2122
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2123
+                ['core', 'shareapi_only_share_with_group_members_exclude_group_list', '', '[]'],
2124
+            ]);
2125 2125
 
2126
-		self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2127
-		$this->addToAssertionCount(1);
2128
-	}
2126
+        self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2127
+        $this->addToAssertionCount(1);
2128
+    }
2129 2129
 
2130 2130
 
2131
-	public function testGroupCreateChecksPathAlreadySharedWithSameGroup(): void {
2132
-		$this->expectException(\Exception::class);
2133
-		$this->expectExceptionMessage('Path is already shared with this group');
2131
+    public function testGroupCreateChecksPathAlreadySharedWithSameGroup(): void {
2132
+        $this->expectException(\Exception::class);
2133
+        $this->expectExceptionMessage('Path is already shared with this group');
2134 2134
 
2135
-		$share = $this->manager->newShare();
2135
+        $share = $this->manager->newShare();
2136 2136
 
2137
-		$path = $this->createMock(Node::class);
2138
-		$share->setSharedWith('sharedWith')
2139
-			->setNode($path)
2140
-			->setProviderId('foo')
2141
-			->setId('bar');
2137
+        $path = $this->createMock(Node::class);
2138
+        $share->setSharedWith('sharedWith')
2139
+            ->setNode($path)
2140
+            ->setProviderId('foo')
2141
+            ->setId('bar');
2142 2142
 
2143
-		$share2 = $this->manager->newShare();
2144
-		$share2->setSharedWith('sharedWith')
2145
-			->setProviderId('foo')
2146
-			->setId('baz');
2143
+        $share2 = $this->manager->newShare();
2144
+        $share2->setSharedWith('sharedWith')
2145
+            ->setProviderId('foo')
2146
+            ->setId('baz');
2147 2147
 
2148
-		$this->defaultProvider->method('getSharesByPath')
2149
-			->with($path)
2150
-			->willReturn([$share2]);
2148
+        $this->defaultProvider->method('getSharesByPath')
2149
+            ->with($path)
2150
+            ->willReturn([$share2]);
2151 2151
 
2152
-		$this->config
2153
-			->method('getAppValue')
2154
-			->willReturnMap([
2155
-				['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2156
-			]);
2152
+        $this->config
2153
+            ->method('getAppValue')
2154
+            ->willReturnMap([
2155
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2156
+            ]);
2157 2157
 
2158
-		self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2159
-	}
2158
+        self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2159
+    }
2160 2160
 
2161
-	public function testGroupCreateChecksPathAlreadySharedWithDifferentGroup(): void {
2162
-		$share = $this->manager->newShare();
2161
+    public function testGroupCreateChecksPathAlreadySharedWithDifferentGroup(): void {
2162
+        $share = $this->manager->newShare();
2163 2163
 
2164
-		$share->setSharedWith('sharedWith');
2164
+        $share->setSharedWith('sharedWith');
2165 2165
 
2166
-		$path = $this->createMock(Node::class);
2167
-		$share->setNode($path);
2166
+        $path = $this->createMock(Node::class);
2167
+        $share->setNode($path);
2168 2168
 
2169
-		$share2 = $this->manager->newShare();
2170
-		$share2->setSharedWith('sharedWith2');
2169
+        $share2 = $this->manager->newShare();
2170
+        $share2->setSharedWith('sharedWith2');
2171 2171
 
2172
-		$this->defaultProvider->method('getSharesByPath')
2173
-			->with($path)
2174
-			->willReturn([$share2]);
2172
+        $this->defaultProvider->method('getSharesByPath')
2173
+            ->with($path)
2174
+            ->willReturn([$share2]);
2175 2175
 
2176
-		$this->config
2177
-			->method('getAppValue')
2178
-			->willReturnMap([
2179
-				['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2180
-			]);
2176
+        $this->config
2177
+            ->method('getAppValue')
2178
+            ->willReturnMap([
2179
+                ['core', 'shareapi_allow_group_sharing', 'yes', 'yes'],
2180
+            ]);
2181 2181
 
2182
-		self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2183
-		$this->addToAssertionCount(1);
2184
-	}
2182
+        self::invokePrivate($this->manager, 'groupCreateChecks', [$share]);
2183
+        $this->addToAssertionCount(1);
2184
+    }
2185 2185
 
2186 2186
 
2187
-	public function testLinkCreateChecksNoLinkSharesAllowed(): void {
2188
-		$this->expectException(\Exception::class);
2189
-		$this->expectExceptionMessage('Link sharing is not allowed');
2187
+    public function testLinkCreateChecksNoLinkSharesAllowed(): void {
2188
+        $this->expectException(\Exception::class);
2189
+        $this->expectExceptionMessage('Link sharing is not allowed');
2190 2190
 
2191
-		$share = $this->manager->newShare();
2191
+        $share = $this->manager->newShare();
2192 2192
 
2193
-		$this->config
2194
-			->method('getAppValue')
2195
-			->willReturnMap([
2196
-				['core', 'shareapi_allow_links', 'yes', 'no'],
2197
-			]);
2193
+        $this->config
2194
+            ->method('getAppValue')
2195
+            ->willReturnMap([
2196
+                ['core', 'shareapi_allow_links', 'yes', 'no'],
2197
+            ]);
2198 2198
 
2199
-		self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2200
-	}
2199
+        self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2200
+    }
2201 2201
 
2202 2202
 
2203
-	public function testFileLinkCreateChecksNoPublicUpload(): void {
2204
-		$share = $this->manager->newShare();
2203
+    public function testFileLinkCreateChecksNoPublicUpload(): void {
2204
+        $share = $this->manager->newShare();
2205 2205
 
2206
-		$share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2207
-		$share->setNodeType('file');
2206
+        $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2207
+        $share->setNodeType('file');
2208 2208
 
2209
-		$this->config
2210
-			->method('getAppValue')
2211
-			->willReturnMap([
2212
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
2213
-				['core', 'shareapi_allow_public_upload', 'yes', 'no']
2214
-			]);
2209
+        $this->config
2210
+            ->method('getAppValue')
2211
+            ->willReturnMap([
2212
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
2213
+                ['core', 'shareapi_allow_public_upload', 'yes', 'no']
2214
+            ]);
2215 2215
 
2216
-		self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2217
-		$this->addToAssertionCount(1);
2218
-	}
2216
+        self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2217
+        $this->addToAssertionCount(1);
2218
+    }
2219 2219
 
2220
-	public function testFolderLinkCreateChecksNoPublicUpload(): void {
2221
-		$this->expectException(\Exception::class);
2222
-		$this->expectExceptionMessage('Public upload is not allowed');
2220
+    public function testFolderLinkCreateChecksNoPublicUpload(): void {
2221
+        $this->expectException(\Exception::class);
2222
+        $this->expectExceptionMessage('Public upload is not allowed');
2223 2223
 
2224
-		$share = $this->manager->newShare();
2224
+        $share = $this->manager->newShare();
2225 2225
 
2226
-		$share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2227
-		$share->setNodeType('folder');
2226
+        $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2227
+        $share->setNodeType('folder');
2228 2228
 
2229
-		$this->config
2230
-			->method('getAppValue')
2231
-			->willReturnMap([
2232
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
2233
-				['core', 'shareapi_allow_public_upload', 'yes', 'no']
2234
-			]);
2229
+        $this->config
2230
+            ->method('getAppValue')
2231
+            ->willReturnMap([
2232
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
2233
+                ['core', 'shareapi_allow_public_upload', 'yes', 'no']
2234
+            ]);
2235 2235
 
2236
-		self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2237
-	}
2236
+        self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2237
+    }
2238 2238
 
2239
-	public function testLinkCreateChecksPublicUpload(): void {
2240
-		$share = $this->manager->newShare();
2239
+    public function testLinkCreateChecksPublicUpload(): void {
2240
+        $share = $this->manager->newShare();
2241 2241
 
2242
-		$share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2243
-		$share->setSharedWith('sharedWith');
2244
-		$folder = $this->createMock(\OC\Files\Node\Folder::class);
2245
-		$share->setNode($folder);
2242
+        $share->setPermissions(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
2243
+        $share->setSharedWith('sharedWith');
2244
+        $folder = $this->createMock(\OC\Files\Node\Folder::class);
2245
+        $share->setNode($folder);
2246 2246
 
2247
-		$this->config
2248
-			->method('getAppValue')
2249
-			->willReturnMap([
2250
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
2251
-				['core', 'shareapi_allow_public_upload', 'yes', 'yes']
2252
-			]);
2247
+        $this->config
2248
+            ->method('getAppValue')
2249
+            ->willReturnMap([
2250
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
2251
+                ['core', 'shareapi_allow_public_upload', 'yes', 'yes']
2252
+            ]);
2253 2253
 
2254
-		self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2255
-		$this->addToAssertionCount(1);
2256
-	}
2254
+        self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2255
+        $this->addToAssertionCount(1);
2256
+    }
2257 2257
 
2258
-	public function testLinkCreateChecksReadOnly(): void {
2259
-		$share = $this->manager->newShare();
2258
+    public function testLinkCreateChecksReadOnly(): void {
2259
+        $share = $this->manager->newShare();
2260 2260
 
2261
-		$share->setPermissions(\OCP\Constants::PERMISSION_READ);
2262
-		$share->setSharedWith('sharedWith');
2263
-		$folder = $this->createMock(\OC\Files\Node\Folder::class);
2264
-		$share->setNode($folder);
2261
+        $share->setPermissions(\OCP\Constants::PERMISSION_READ);
2262
+        $share->setSharedWith('sharedWith');
2263
+        $folder = $this->createMock(\OC\Files\Node\Folder::class);
2264
+        $share->setNode($folder);
2265 2265
 
2266
-		$this->config
2267
-			->method('getAppValue')
2268
-			->willReturnMap([
2269
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
2270
-				['core', 'shareapi_allow_public_upload', 'yes', 'no']
2271
-			]);
2266
+        $this->config
2267
+            ->method('getAppValue')
2268
+            ->willReturnMap([
2269
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
2270
+                ['core', 'shareapi_allow_public_upload', 'yes', 'no']
2271
+            ]);
2272 2272
 
2273
-		self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2274
-		$this->addToAssertionCount(1);
2275
-	}
2276
-
2277
-
2278
-	public function testPathCreateChecksContainsSharedMount(): void {
2279
-		$this->expectException(\InvalidArgumentException::class);
2280
-		$this->expectExceptionMessage('You cannot share a folder that contains other shares');
2273
+        self::invokePrivate($this->manager, 'linkCreateChecks', [$share]);
2274
+        $this->addToAssertionCount(1);
2275
+    }
2276
+
2277
+
2278
+    public function testPathCreateChecksContainsSharedMount(): void {
2279
+        $this->expectException(\InvalidArgumentException::class);
2280
+        $this->expectExceptionMessage('You cannot share a folder that contains other shares');
2281 2281
 
2282
-		$path = $this->createMock(Folder::class);
2283
-		$path->method('getPath')->willReturn('path');
2282
+        $path = $this->createMock(Folder::class);
2283
+        $path->method('getPath')->willReturn('path');
2284 2284
 
2285
-		$mount = $this->createMock(IMountPoint::class);
2286
-		$storage = $this->createMock(IStorage::class);
2287
-		$mount->method('getStorage')->willReturn($storage);
2288
-		$storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(true);
2289
-
2290
-		$this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
2291
-
2292
-		self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2293
-	}
2294
-
2295
-	public function testPathCreateChecksContainsNoSharedMount(): void {
2296
-		$path = $this->createMock(Folder::class);
2297
-		$path->method('getPath')->willReturn('path');
2285
+        $mount = $this->createMock(IMountPoint::class);
2286
+        $storage = $this->createMock(IStorage::class);
2287
+        $mount->method('getStorage')->willReturn($storage);
2288
+        $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(true);
2289
+
2290
+        $this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
2291
+
2292
+        self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2293
+    }
2294
+
2295
+    public function testPathCreateChecksContainsNoSharedMount(): void {
2296
+        $path = $this->createMock(Folder::class);
2297
+        $path->method('getPath')->willReturn('path');
2298 2298
 
2299
-		$mount = $this->createMock(IMountPoint::class);
2300
-		$storage = $this->createMock(IStorage::class);
2301
-		$mount->method('getStorage')->willReturn($storage);
2302
-		$storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(false);
2303
-
2304
-		$this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
2305
-
2306
-		self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2307
-		$this->addToAssertionCount(1);
2308
-	}
2309
-
2310
-	public function testPathCreateChecksContainsNoFolder(): void {
2311
-		$path = $this->createMock(File::class);
2312
-
2313
-		self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2314
-		$this->addToAssertionCount(1);
2315
-	}
2316
-
2317
-	public static function dataIsSharingDisabledForUser() {
2318
-		$data = [];
2319
-
2320
-		// No exclude groups
2321
-		$data[] = ['no', null, null, [], false];
2322
-
2323
-		// empty exclude / allow list, user no groups
2324
-		$data[] = ['yes', '', json_encode(['']), [], false];
2325
-		$data[] = ['allow', '', json_encode(['']), [], true];
2326
-
2327
-		// empty exclude / allow list, user groups
2328
-		$data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false];
2329
-		$data[] = ['allow', '', json_encode(['']), ['group1', 'group2'], true];
2330
-
2331
-		// Convert old list to json
2332
-		$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false];
2333
-		$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), [], true];
2334
-
2335
-		// Old list partly groups in common
2336
-		$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false];
2337
-		$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false];
2338
-
2339
-		// Old list only groups in common
2340
-		$data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true];
2341
-		$data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], false];
2342
-
2343
-		// New list partly in common
2344
-		$data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false];
2345
-		$data[] = ['allow', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false];
2346
-
2347
-		// New list only groups in common
2348
-		$data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true];
2349
-		$data[] = ['allow', json_encode(['group1', 'group2']), null, ['group2'], false];
2350
-
2351
-		return $data;
2352
-	}
2299
+        $mount = $this->createMock(IMountPoint::class);
2300
+        $storage = $this->createMock(IStorage::class);
2301
+        $mount->method('getStorage')->willReturn($storage);
2302
+        $storage->method('instanceOfStorage')->with('\OCA\Files_Sharing\ISharedStorage')->willReturn(false);
2303
+
2304
+        $this->mountManager->method('findIn')->with('path')->willReturn([$mount]);
2305
+
2306
+        self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2307
+        $this->addToAssertionCount(1);
2308
+    }
2309
+
2310
+    public function testPathCreateChecksContainsNoFolder(): void {
2311
+        $path = $this->createMock(File::class);
2312
+
2313
+        self::invokePrivate($this->manager, 'pathCreateChecks', [$path]);
2314
+        $this->addToAssertionCount(1);
2315
+    }
2316
+
2317
+    public static function dataIsSharingDisabledForUser() {
2318
+        $data = [];
2319
+
2320
+        // No exclude groups
2321
+        $data[] = ['no', null, null, [], false];
2322
+
2323
+        // empty exclude / allow list, user no groups
2324
+        $data[] = ['yes', '', json_encode(['']), [], false];
2325
+        $data[] = ['allow', '', json_encode(['']), [], true];
2326
+
2327
+        // empty exclude / allow list, user groups
2328
+        $data[] = ['yes', '', json_encode(['']), ['group1', 'group2'], false];
2329
+        $data[] = ['allow', '', json_encode(['']), ['group1', 'group2'], true];
2330
+
2331
+        // Convert old list to json
2332
+        $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), [], false];
2333
+        $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), [], true];
2334
+
2335
+        // Old list partly groups in common
2336
+        $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false];
2337
+        $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1', 'group3'], false];
2338
+
2339
+        // Old list only groups in common
2340
+        $data[] = ['yes', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], true];
2341
+        $data[] = ['allow', 'group1,group2', json_encode(['group1', 'group2']), ['group1'], false];
2342
+
2343
+        // New list partly in common
2344
+        $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false];
2345
+        $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group1', 'group3'], false];
2346
+
2347
+        // New list only groups in common
2348
+        $data[] = ['yes', json_encode(['group1', 'group2']), null, ['group2'], true];
2349
+        $data[] = ['allow', json_encode(['group1', 'group2']), null, ['group2'], false];
2350
+
2351
+        return $data;
2352
+    }
2353 2353
 
2354
-	/**
2355
-	 * @dataProvider dataIsSharingDisabledForUser
2356
-	 *
2357
-	 * @param string $excludeGroups
2358
-	 * @param string $groupList
2359
-	 * @param string $setList
2360
-	 * @param string[] $groupIds
2361
-	 * @param bool $expected
2362
-	 */
2363
-	public function testIsSharingDisabledForUser($excludeGroups, $groupList, $setList, $groupIds, $expected): void {
2364
-		$user = $this->createMock(IUser::class);
2354
+    /**
2355
+     * @dataProvider dataIsSharingDisabledForUser
2356
+     *
2357
+     * @param string $excludeGroups
2358
+     * @param string $groupList
2359
+     * @param string $setList
2360
+     * @param string[] $groupIds
2361
+     * @param bool $expected
2362
+     */
2363
+    public function testIsSharingDisabledForUser($excludeGroups, $groupList, $setList, $groupIds, $expected): void {
2364
+        $user = $this->createMock(IUser::class);
2365 2365
 
2366
-		$this->config->method('getAppValue')
2367
-			->willReturnMap([
2368
-				['core', 'shareapi_exclude_groups', 'no', $excludeGroups],
2369
-				['core', 'shareapi_exclude_groups_list', '', $groupList],
2370
-			]);
2366
+        $this->config->method('getAppValue')
2367
+            ->willReturnMap([
2368
+                ['core', 'shareapi_exclude_groups', 'no', $excludeGroups],
2369
+                ['core', 'shareapi_exclude_groups_list', '', $groupList],
2370
+            ]);
2371 2371
 
2372
-		if ($setList !== null) {
2373
-			$this->config->expects($this->once())
2374
-				->method('setAppValue')
2375
-				->with('core', 'shareapi_exclude_groups_list', $setList);
2376
-		} else {
2377
-			$this->config->expects($this->never())
2378
-				->method('setAppValue');
2379
-		}
2372
+        if ($setList !== null) {
2373
+            $this->config->expects($this->once())
2374
+                ->method('setAppValue')
2375
+                ->with('core', 'shareapi_exclude_groups_list', $setList);
2376
+        } else {
2377
+            $this->config->expects($this->never())
2378
+                ->method('setAppValue');
2379
+        }
2380 2380
 
2381
-		$this->groupManager->method('getUserGroupIds')
2382
-			->with($user)
2383
-			->willReturn($groupIds);
2381
+        $this->groupManager->method('getUserGroupIds')
2382
+            ->with($user)
2383
+            ->willReturn($groupIds);
2384 2384
 
2385
-		$this->userManager->method('get')->with('user')->willReturn($user);
2386
-
2387
-		$res = $this->manager->sharingDisabledForUser('user');
2388
-		$this->assertEquals($expected, $res);
2389
-	}
2390
-
2391
-	public static function dataCanShare() {
2392
-		$data = [];
2393
-
2394
-		/*
2385
+        $this->userManager->method('get')->with('user')->willReturn($user);
2386
+
2387
+        $res = $this->manager->sharingDisabledForUser('user');
2388
+        $this->assertEquals($expected, $res);
2389
+    }
2390
+
2391
+    public static function dataCanShare() {
2392
+        $data = [];
2393
+
2394
+        /*
2395 2395
 		 * [expected, sharing enabled, disabled for user]
2396 2396
 		 */
2397 2397
 
2398
-		$data[] = [false, 'no', false];
2399
-		$data[] = [false, 'no', true];
2400
-		$data[] = [true, 'yes', false];
2401
-		$data[] = [false, 'yes', true];
2402
-
2403
-		return $data;
2404
-	}
2405
-
2406
-	/**
2407
-	 * @dataProvider dataCanShare
2408
-	 *
2409
-	 * @param bool $expected
2410
-	 * @param string $sharingEnabled
2411
-	 * @param bool $disabledForUser
2412
-	 */
2413
-	public function testCanShare($expected, $sharingEnabled, $disabledForUser): void {
2414
-		$this->config->method('getAppValue')
2415
-			->willReturnMap([
2416
-				['core', 'shareapi_enabled', 'yes', $sharingEnabled],
2417
-			]);
2418
-
2419
-		$manager = $this->createManagerMock()
2420
-			->onlyMethods(['sharingDisabledForUser'])
2421
-			->getMock();
2422
-
2423
-		$manager->method('sharingDisabledForUser')
2424
-			->with('user')
2425
-			->willReturn($disabledForUser);
2426
-
2427
-		$share = $this->manager->newShare();
2428
-		$share->setSharedBy('user');
2429
-
2430
-		$exception = false;
2431
-		try {
2432
-			$res = self::invokePrivate($manager, 'canShare', [$share]);
2433
-		} catch (\Exception $e) {
2434
-			$exception = true;
2435
-		}
2436
-
2437
-		$this->assertEquals($expected, !$exception);
2438
-	}
2439
-
2440
-	public function testCreateShareUser(): void {
2441
-		/** @var Manager&MockObject $manager */
2442
-		$manager = $this->createManagerMock()
2443
-			->onlyMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks'])
2444
-			->getMock();
2445
-
2446
-		$shareOwner = $this->createMock(IUser::class);
2447
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2448
-
2449
-		$storage = $this->createMock(IStorage::class);
2450
-		$path = $this->createMock(File::class);
2451
-		$path->method('getOwner')->willReturn($shareOwner);
2452
-		$path->method('getName')->willReturn('target');
2453
-		$path->method('getStorage')->willReturn($storage);
2454
-
2455
-		$share = $this->createShare(
2456
-			null,
2457
-			IShare::TYPE_USER,
2458
-			$path,
2459
-			'sharedWith',
2460
-			'sharedBy',
2461
-			null,
2462
-			\OCP\Constants::PERMISSION_ALL);
2463
-
2464
-		$manager->expects($this->once())
2465
-			->method('canShare')
2466
-			->with($share)
2467
-			->willReturn(true);
2468
-		$manager->expects($this->once())
2469
-			->method('generalCreateChecks')
2470
-			->with($share);
2471
-		;
2472
-		$manager->expects($this->once())
2473
-			->method('userCreateChecks')
2474
-			->with($share);
2475
-		;
2476
-		$manager->expects($this->once())
2477
-			->method('pathCreateChecks')
2478
-			->with($path);
2479
-
2480
-		$this->defaultProvider
2481
-			->expects($this->once())
2482
-			->method('create')
2483
-			->with($share)
2484
-			->willReturnArgument(0);
2485
-
2486
-		$share->expects($this->once())
2487
-			->method('setShareOwner')
2488
-			->with('shareOwner');
2489
-		$share->expects($this->once())
2490
-			->method('setTarget')
2491
-			->with('/target');
2492
-
2493
-		$manager->createShare($share);
2494
-	}
2495
-
2496
-	public function testCreateShareGroup(): void {
2497
-		$manager = $this->createManagerMock()
2498
-			->onlyMethods(['canShare', 'generalCreateChecks', 'groupCreateChecks', 'pathCreateChecks'])
2499
-			->getMock();
2500
-
2501
-		$shareOwner = $this->createMock(IUser::class);
2502
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2503
-
2504
-		$storage = $this->createMock(IStorage::class);
2505
-		$path = $this->createMock(File::class);
2506
-		$path->method('getOwner')->willReturn($shareOwner);
2507
-		$path->method('getName')->willReturn('target');
2508
-		$path->method('getStorage')->willReturn($storage);
2509
-
2510
-		$share = $this->createShare(
2511
-			null,
2512
-			IShare::TYPE_GROUP,
2513
-			$path,
2514
-			'sharedWith',
2515
-			'sharedBy',
2516
-			null,
2517
-			\OCP\Constants::PERMISSION_ALL);
2518
-
2519
-		$manager->expects($this->once())
2520
-			->method('canShare')
2521
-			->with($share)
2522
-			->willReturn(true);
2523
-		$manager->expects($this->once())
2524
-			->method('generalCreateChecks')
2525
-			->with($share);
2526
-		;
2527
-		$manager->expects($this->once())
2528
-			->method('groupCreateChecks')
2529
-			->with($share);
2530
-		;
2531
-		$manager->expects($this->once())
2532
-			->method('pathCreateChecks')
2533
-			->with($path);
2534
-
2535
-		$this->defaultProvider
2536
-			->expects($this->once())
2537
-			->method('create')
2538
-			->with($share)
2539
-			->willReturnArgument(0);
2540
-
2541
-		$share->expects($this->once())
2542
-			->method('setShareOwner')
2543
-			->with('shareOwner');
2544
-		$share->expects($this->once())
2545
-			->method('setTarget')
2546
-			->with('/target');
2547
-
2548
-		$manager->createShare($share);
2549
-	}
2550
-
2551
-	public function testCreateShareLink(): void {
2552
-		$manager = $this->createManagerMock()
2553
-			->onlyMethods([
2554
-				'canShare',
2555
-				'generalCreateChecks',
2556
-				'linkCreateChecks',
2557
-				'pathCreateChecks',
2558
-				'validateExpirationDateLink',
2559
-				'verifyPassword',
2560
-				'setLinkParent',
2561
-			])
2562
-			->getMock();
2563
-
2564
-		$shareOwner = $this->createMock(IUser::class);
2565
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2566
-
2567
-		$storage = $this->createMock(IStorage::class);
2568
-		$path = $this->createMock(File::class);
2569
-		$path->method('getOwner')->willReturn($shareOwner);
2570
-		$path->method('getName')->willReturn('target');
2571
-		$path->method('getId')->willReturn(1);
2572
-		$path->method('getStorage')->willReturn($storage);
2573
-
2574
-		$date = new \DateTime();
2575
-
2576
-		$share = $this->manager->newShare();
2577
-		$share->setShareType(IShare::TYPE_LINK)
2578
-			->setNode($path)
2579
-			->setSharedBy('sharedBy')
2580
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
2581
-			->setExpirationDate($date)
2582
-			->setPassword('password');
2583
-
2584
-		$manager->expects($this->once())
2585
-			->method('canShare')
2586
-			->with($share)
2587
-			->willReturn(true);
2588
-		$manager->expects($this->once())
2589
-			->method('generalCreateChecks')
2590
-			->with($share);
2591
-		;
2592
-		$manager->expects($this->once())
2593
-			->method('linkCreateChecks')
2594
-			->with($share);
2595
-		;
2596
-		$manager->expects($this->once())
2597
-			->method('pathCreateChecks')
2598
-			->with($path);
2599
-		$manager->expects($this->once())
2600
-			->method('validateExpirationDateLink')
2601
-			->with($share)
2602
-			->willReturn($share);
2603
-		$manager->expects($this->once())
2604
-			->method('verifyPassword')
2605
-			->with('password');
2606
-		$manager->expects($this->once())
2607
-			->method('setLinkParent')
2608
-			->with($share);
2609
-
2610
-		$this->hasher->expects($this->once())
2611
-			->method('hash')
2612
-			->with('password')
2613
-			->willReturn('hashed');
2614
-
2615
-		$this->secureRandom->method('generate')
2616
-			->willReturn('token');
2617
-
2618
-		$this->defaultProvider
2619
-			->expects($this->once())
2620
-			->method('create')
2621
-			->with($share)
2622
-			->willReturnCallback(function (Share $share) {
2623
-				return $share->setId(42);
2624
-			});
2625
-
2626
-		$calls = [
2627
-			BeforeShareCreatedEvent::class,
2628
-			ShareCreatedEvent::class,
2629
-		];
2630
-		$this->dispatcher->expects($this->exactly(2))
2631
-			->method('dispatchTyped')
2632
-			->willReturnCallback(function ($event) use (&$calls, $date, $path) {
2633
-				$expected = array_shift($calls);
2634
-				$this->assertInstanceOf($expected, $event);
2635
-				$share = $event->getShare();
2636
-
2637
-				$this->assertEquals(IShare::TYPE_LINK, $share->getShareType(), 'getShareType');
2638
-				$this->assertEquals($path, $share->getNode(), 'getNode');
2639
-				$this->assertEquals('sharedBy', $share->getSharedBy(), 'getSharedBy');
2640
-				$this->assertEquals(\OCP\Constants::PERMISSION_ALL, $share->getPermissions(), 'getPermissions');
2641
-				$this->assertEquals($date, $share->getExpirationDate(), 'getExpirationDate');
2642
-				$this->assertEquals('hashed', $share->getPassword(), 'getPassword');
2643
-				$this->assertEquals('token', $share->getToken(), 'getToken');
2644
-
2645
-				if ($expected === ShareCreatedEvent::class) {
2646
-					$this->assertEquals('42', $share->getId(), 'getId');
2647
-					$this->assertEquals('/target', $share->getTarget(), 'getTarget');
2648
-				}
2649
-			});
2650
-
2651
-		/** @var IShare $share */
2652
-		$share = $manager->createShare($share);
2653
-
2654
-		$this->assertSame('shareOwner', $share->getShareOwner());
2655
-		$this->assertEquals('/target', $share->getTarget());
2656
-		$this->assertSame($date, $share->getExpirationDate());
2657
-		$this->assertEquals('token', $share->getToken());
2658
-		$this->assertEquals('hashed', $share->getPassword());
2659
-	}
2660
-
2661
-	public function testCreateShareMail(): void {
2662
-		$manager = $this->createManagerMock()
2663
-			->onlyMethods([
2664
-				'canShare',
2665
-				'generalCreateChecks',
2666
-				'linkCreateChecks',
2667
-				'pathCreateChecks',
2668
-				'validateExpirationDateLink',
2669
-				'verifyPassword',
2670
-				'setLinkParent',
2671
-			])
2672
-			->getMock();
2673
-
2674
-		$shareOwner = $this->createMock(IUser::class);
2675
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2676
-
2677
-		$storage = $this->createMock(IStorage::class);
2678
-		$path = $this->createMock(File::class);
2679
-		$path->method('getOwner')->willReturn($shareOwner);
2680
-		$path->method('getName')->willReturn('target');
2681
-		$path->method('getId')->willReturn(1);
2682
-		$path->method('getStorage')->willReturn($storage);
2683
-
2684
-		$share = $this->manager->newShare();
2685
-		$share->setShareType(IShare::TYPE_EMAIL)
2686
-			->setNode($path)
2687
-			->setSharedBy('sharedBy')
2688
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
2689
-
2690
-		$manager->expects($this->once())
2691
-			->method('canShare')
2692
-			->with($share)
2693
-			->willReturn(true);
2694
-		$manager->expects($this->once())
2695
-			->method('generalCreateChecks')
2696
-			->with($share);
2697
-
2698
-		$manager->expects($this->once())
2699
-			->method('linkCreateChecks');
2700
-		$manager->expects($this->once())
2701
-			->method('pathCreateChecks')
2702
-			->with($path);
2703
-		$manager->expects($this->once())
2704
-			->method('validateExpirationDateLink')
2705
-			->with($share)
2706
-			->willReturn($share);
2707
-		$manager->expects($this->once())
2708
-			->method('verifyPassword');
2709
-		$manager->expects($this->once())
2710
-			->method('setLinkParent');
2711
-
2712
-		$this->secureRandom->method('generate')
2713
-			->willReturn('token');
2714
-
2715
-		$this->defaultProvider
2716
-			->expects($this->once())
2717
-			->method('create')
2718
-			->with($share)
2719
-			->willReturnCallback(function (Share $share) {
2720
-				return $share->setId(42);
2721
-			});
2722
-
2723
-		$calls = [
2724
-			BeforeShareCreatedEvent::class,
2725
-			ShareCreatedEvent::class,
2726
-		];
2727
-		$this->dispatcher->expects($this->exactly(2))
2728
-			->method('dispatchTyped')
2729
-			->willReturnCallback(function ($event) use (&$calls, $path) {
2730
-				$expected = array_shift($calls);
2731
-				$this->assertInstanceOf($expected, $event);
2732
-				$share = $event->getShare();
2733
-
2734
-				$this->assertEquals(IShare::TYPE_EMAIL, $share->getShareType(), 'getShareType');
2735
-				$this->assertEquals($path, $share->getNode(), 'getNode');
2736
-				$this->assertEquals('sharedBy', $share->getSharedBy(), 'getSharedBy');
2737
-				$this->assertEquals(\OCP\Constants::PERMISSION_ALL, $share->getPermissions(), 'getPermissions');
2738
-				$this->assertNull($share->getExpirationDate(), 'getExpirationDate');
2739
-				$this->assertNull($share->getPassword(), 'getPassword');
2740
-				$this->assertEquals('token', $share->getToken(), 'getToken');
2741
-
2742
-				if ($expected === ShareCreatedEvent::class) {
2743
-					$this->assertEquals('42', $share->getId(), 'getId');
2744
-					$this->assertEquals('/target', $share->getTarget(), 'getTarget');
2745
-				}
2746
-			});
2747
-
2748
-		/** @var IShare $share */
2749
-		$share = $manager->createShare($share);
2750
-
2751
-		$this->assertSame('shareOwner', $share->getShareOwner());
2752
-		$this->assertEquals('/target', $share->getTarget());
2753
-		$this->assertEquals('token', $share->getToken());
2754
-	}
2755
-
2756
-
2757
-	public function testCreateShareHookError(): void {
2758
-		$this->expectException(\Exception::class);
2759
-		$this->expectExceptionMessage('I won\'t let you share');
2760
-
2761
-		$manager = $this->createManagerMock()
2762
-			->onlyMethods([
2763
-				'canShare',
2764
-				'generalCreateChecks',
2765
-				'userCreateChecks',
2766
-				'pathCreateChecks',
2767
-			])
2768
-			->getMock();
2769
-
2770
-		$shareOwner = $this->createMock(IUser::class);
2771
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2772
-
2773
-		$storage = $this->createMock(IStorage::class);
2774
-		$path = $this->createMock(File::class);
2775
-		$path->method('getOwner')->willReturn($shareOwner);
2776
-		$path->method('getName')->willReturn('target');
2777
-		$path->method('getStorage')->willReturn($storage);
2778
-
2779
-		$share = $this->createShare(
2780
-			null,
2781
-			IShare::TYPE_USER,
2782
-			$path,
2783
-			'sharedWith',
2784
-			'sharedBy',
2785
-			null,
2786
-			\OCP\Constants::PERMISSION_ALL);
2787
-
2788
-		$manager->expects($this->once())
2789
-			->method('canShare')
2790
-			->with($share)
2791
-			->willReturn(true);
2792
-		$manager->expects($this->once())
2793
-			->method('generalCreateChecks')
2794
-			->with($share);
2795
-		;
2796
-		$manager->expects($this->once())
2797
-			->method('userCreateChecks')
2798
-			->with($share);
2799
-		;
2800
-		$manager->expects($this->once())
2801
-			->method('pathCreateChecks')
2802
-			->with($path);
2803
-
2804
-		$share->expects($this->once())
2805
-			->method('setShareOwner')
2806
-			->with('shareOwner');
2807
-		$share->expects($this->once())
2808
-			->method('setTarget')
2809
-			->with('/target');
2810
-
2811
-		// Pre share
2812
-		$this->dispatcher->expects($this->once())
2813
-			->method('dispatchTyped')
2814
-			->with(
2815
-				$this->isInstanceOf(BeforeShareCreatedEvent::class)
2816
-			)->willReturnCallback(function (BeforeShareCreatedEvent $e) {
2817
-				$e->setError('I won\'t let you share!');
2818
-				$e->stopPropagation();
2819
-			}
2820
-			);
2821
-
2822
-		$manager->createShare($share);
2823
-	}
2824
-
2825
-	public function testCreateShareOfIncomingFederatedShare(): void {
2826
-		$manager = $this->createManagerMock()
2827
-			->onlyMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks'])
2828
-			->getMock();
2829
-
2830
-		$shareOwner = $this->createMock(IUser::class);
2831
-		$shareOwner->method('getUID')->willReturn('shareOwner');
2832
-
2833
-		$storage = $this->createMock(IStorage::class);
2834
-		$storage->method('instanceOfStorage')
2835
-			->with('OCA\Files_Sharing\External\Storage')
2836
-			->willReturn(true);
2837
-
2838
-		$storage2 = $this->createMock(IStorage::class);
2839
-		$storage2->method('instanceOfStorage')
2840
-			->with('OCA\Files_Sharing\External\Storage')
2841
-			->willReturn(false);
2842
-
2843
-		$path = $this->createMock(File::class);
2844
-		$path->expects($this->never())->method('getOwner');
2845
-		$path->method('getName')->willReturn('target');
2846
-		$path->method('getStorage')->willReturn($storage);
2847
-
2848
-		$parent = $this->createMock(Folder::class);
2849
-		$parent->method('getStorage')->willReturn($storage);
2850
-
2851
-		$parentParent = $this->createMock(Folder::class);
2852
-		$parentParent->method('getStorage')->willReturn($storage2);
2853
-		$parentParent->method('getOwner')->willReturn($shareOwner);
2854
-
2855
-		$path->method('getParent')->willReturn($parent);
2856
-		$parent->method('getParent')->willReturn($parentParent);
2857
-
2858
-		$share = $this->createShare(
2859
-			null,
2860
-			IShare::TYPE_USER,
2861
-			$path,
2862
-			'sharedWith',
2863
-			'sharedBy',
2864
-			null,
2865
-			\OCP\Constants::PERMISSION_ALL);
2866
-
2867
-		$manager->expects($this->once())
2868
-			->method('canShare')
2869
-			->with($share)
2870
-			->willReturn(true);
2871
-		$manager->expects($this->once())
2872
-			->method('generalCreateChecks')
2873
-			->with($share);
2874
-		;
2875
-		$manager->expects($this->once())
2876
-			->method('userCreateChecks')
2877
-			->with($share);
2878
-		;
2879
-		$manager->expects($this->once())
2880
-			->method('pathCreateChecks')
2881
-			->with($path);
2882
-
2883
-		$this->defaultProvider
2884
-			->expects($this->once())
2885
-			->method('create')
2886
-			->with($share)
2887
-			->willReturnArgument(0);
2888
-
2889
-		$share->expects($this->once())
2890
-			->method('setShareOwner')
2891
-			->with('shareOwner');
2892
-		$share->expects($this->once())
2893
-			->method('setTarget')
2894
-			->with('/target');
2895
-
2896
-		$manager->createShare($share);
2897
-	}
2898
-
2899
-	public function testGetSharesBy(): void {
2900
-		$share = $this->manager->newShare();
2901
-
2902
-		$node = $this->createMock(Folder::class);
2903
-
2904
-		$this->defaultProvider->expects($this->once())
2905
-			->method('getSharesBy')
2906
-			->with(
2907
-				$this->equalTo('user'),
2908
-				$this->equalTo(IShare::TYPE_USER),
2909
-				$this->equalTo($node),
2910
-				$this->equalTo(true),
2911
-				$this->equalTo(1),
2912
-				$this->equalTo(1)
2913
-			)->willReturn([$share]);
2914
-
2915
-		$shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1);
2916
-
2917
-		$this->assertCount(1, $shares);
2918
-		$this->assertSame($share, $shares[0]);
2919
-	}
2920
-
2921
-	public function testGetSharesByOwnerless(): void {
2922
-		$mount = $this->createMock(IShareOwnerlessMount::class);
2923
-
2924
-		$node = $this->createMock(Folder::class);
2925
-		$node
2926
-			->expects($this->once())
2927
-			->method('getMountPoint')
2928
-			->willReturn($mount);
2929
-
2930
-		$share = $this->manager->newShare();
2931
-		$share->setNode($node);
2932
-		$share->setShareType(IShare::TYPE_USER);
2933
-
2934
-		$this->defaultProvider
2935
-			->expects($this->once())
2936
-			->method('getSharesByPath')
2937
-			->with($this->equalTo($node))
2938
-			->willReturn([$share]);
2939
-
2940
-		$shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1);
2941
-
2942
-		$this->assertCount(1, $shares);
2943
-		$this->assertSame($share, $shares[0]);
2944
-	}
2945
-
2946
-	/**
2947
-	 * Test to ensure we correctly remove expired link shares
2948
-	 *
2949
-	 * We have 8 Shares and we want the 3 first valid shares.
2950
-	 * share 3-6 and 8 are expired. Thus at the end of this test we should
2951
-	 * have received share 1,2 and 7. And from the manager. Share 3-6 should be
2952
-	 * deleted (as they are evaluated). but share 8 should still be there.
2953
-	 */
2954
-	public function testGetSharesByExpiredLinkShares(): void {
2955
-		$manager = $this->createManagerMock()
2956
-			->onlyMethods(['deleteShare'])
2957
-			->getMock();
2958
-
2959
-		/** @var \OCP\Share\IShare[] $shares */
2960
-		$shares = [];
2961
-
2962
-		/*
2398
+        $data[] = [false, 'no', false];
2399
+        $data[] = [false, 'no', true];
2400
+        $data[] = [true, 'yes', false];
2401
+        $data[] = [false, 'yes', true];
2402
+
2403
+        return $data;
2404
+    }
2405
+
2406
+    /**
2407
+     * @dataProvider dataCanShare
2408
+     *
2409
+     * @param bool $expected
2410
+     * @param string $sharingEnabled
2411
+     * @param bool $disabledForUser
2412
+     */
2413
+    public function testCanShare($expected, $sharingEnabled, $disabledForUser): void {
2414
+        $this->config->method('getAppValue')
2415
+            ->willReturnMap([
2416
+                ['core', 'shareapi_enabled', 'yes', $sharingEnabled],
2417
+            ]);
2418
+
2419
+        $manager = $this->createManagerMock()
2420
+            ->onlyMethods(['sharingDisabledForUser'])
2421
+            ->getMock();
2422
+
2423
+        $manager->method('sharingDisabledForUser')
2424
+            ->with('user')
2425
+            ->willReturn($disabledForUser);
2426
+
2427
+        $share = $this->manager->newShare();
2428
+        $share->setSharedBy('user');
2429
+
2430
+        $exception = false;
2431
+        try {
2432
+            $res = self::invokePrivate($manager, 'canShare', [$share]);
2433
+        } catch (\Exception $e) {
2434
+            $exception = true;
2435
+        }
2436
+
2437
+        $this->assertEquals($expected, !$exception);
2438
+    }
2439
+
2440
+    public function testCreateShareUser(): void {
2441
+        /** @var Manager&MockObject $manager */
2442
+        $manager = $this->createManagerMock()
2443
+            ->onlyMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks'])
2444
+            ->getMock();
2445
+
2446
+        $shareOwner = $this->createMock(IUser::class);
2447
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2448
+
2449
+        $storage = $this->createMock(IStorage::class);
2450
+        $path = $this->createMock(File::class);
2451
+        $path->method('getOwner')->willReturn($shareOwner);
2452
+        $path->method('getName')->willReturn('target');
2453
+        $path->method('getStorage')->willReturn($storage);
2454
+
2455
+        $share = $this->createShare(
2456
+            null,
2457
+            IShare::TYPE_USER,
2458
+            $path,
2459
+            'sharedWith',
2460
+            'sharedBy',
2461
+            null,
2462
+            \OCP\Constants::PERMISSION_ALL);
2463
+
2464
+        $manager->expects($this->once())
2465
+            ->method('canShare')
2466
+            ->with($share)
2467
+            ->willReturn(true);
2468
+        $manager->expects($this->once())
2469
+            ->method('generalCreateChecks')
2470
+            ->with($share);
2471
+        ;
2472
+        $manager->expects($this->once())
2473
+            ->method('userCreateChecks')
2474
+            ->with($share);
2475
+        ;
2476
+        $manager->expects($this->once())
2477
+            ->method('pathCreateChecks')
2478
+            ->with($path);
2479
+
2480
+        $this->defaultProvider
2481
+            ->expects($this->once())
2482
+            ->method('create')
2483
+            ->with($share)
2484
+            ->willReturnArgument(0);
2485
+
2486
+        $share->expects($this->once())
2487
+            ->method('setShareOwner')
2488
+            ->with('shareOwner');
2489
+        $share->expects($this->once())
2490
+            ->method('setTarget')
2491
+            ->with('/target');
2492
+
2493
+        $manager->createShare($share);
2494
+    }
2495
+
2496
+    public function testCreateShareGroup(): void {
2497
+        $manager = $this->createManagerMock()
2498
+            ->onlyMethods(['canShare', 'generalCreateChecks', 'groupCreateChecks', 'pathCreateChecks'])
2499
+            ->getMock();
2500
+
2501
+        $shareOwner = $this->createMock(IUser::class);
2502
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2503
+
2504
+        $storage = $this->createMock(IStorage::class);
2505
+        $path = $this->createMock(File::class);
2506
+        $path->method('getOwner')->willReturn($shareOwner);
2507
+        $path->method('getName')->willReturn('target');
2508
+        $path->method('getStorage')->willReturn($storage);
2509
+
2510
+        $share = $this->createShare(
2511
+            null,
2512
+            IShare::TYPE_GROUP,
2513
+            $path,
2514
+            'sharedWith',
2515
+            'sharedBy',
2516
+            null,
2517
+            \OCP\Constants::PERMISSION_ALL);
2518
+
2519
+        $manager->expects($this->once())
2520
+            ->method('canShare')
2521
+            ->with($share)
2522
+            ->willReturn(true);
2523
+        $manager->expects($this->once())
2524
+            ->method('generalCreateChecks')
2525
+            ->with($share);
2526
+        ;
2527
+        $manager->expects($this->once())
2528
+            ->method('groupCreateChecks')
2529
+            ->with($share);
2530
+        ;
2531
+        $manager->expects($this->once())
2532
+            ->method('pathCreateChecks')
2533
+            ->with($path);
2534
+
2535
+        $this->defaultProvider
2536
+            ->expects($this->once())
2537
+            ->method('create')
2538
+            ->with($share)
2539
+            ->willReturnArgument(0);
2540
+
2541
+        $share->expects($this->once())
2542
+            ->method('setShareOwner')
2543
+            ->with('shareOwner');
2544
+        $share->expects($this->once())
2545
+            ->method('setTarget')
2546
+            ->with('/target');
2547
+
2548
+        $manager->createShare($share);
2549
+    }
2550
+
2551
+    public function testCreateShareLink(): void {
2552
+        $manager = $this->createManagerMock()
2553
+            ->onlyMethods([
2554
+                'canShare',
2555
+                'generalCreateChecks',
2556
+                'linkCreateChecks',
2557
+                'pathCreateChecks',
2558
+                'validateExpirationDateLink',
2559
+                'verifyPassword',
2560
+                'setLinkParent',
2561
+            ])
2562
+            ->getMock();
2563
+
2564
+        $shareOwner = $this->createMock(IUser::class);
2565
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2566
+
2567
+        $storage = $this->createMock(IStorage::class);
2568
+        $path = $this->createMock(File::class);
2569
+        $path->method('getOwner')->willReturn($shareOwner);
2570
+        $path->method('getName')->willReturn('target');
2571
+        $path->method('getId')->willReturn(1);
2572
+        $path->method('getStorage')->willReturn($storage);
2573
+
2574
+        $date = new \DateTime();
2575
+
2576
+        $share = $this->manager->newShare();
2577
+        $share->setShareType(IShare::TYPE_LINK)
2578
+            ->setNode($path)
2579
+            ->setSharedBy('sharedBy')
2580
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
2581
+            ->setExpirationDate($date)
2582
+            ->setPassword('password');
2583
+
2584
+        $manager->expects($this->once())
2585
+            ->method('canShare')
2586
+            ->with($share)
2587
+            ->willReturn(true);
2588
+        $manager->expects($this->once())
2589
+            ->method('generalCreateChecks')
2590
+            ->with($share);
2591
+        ;
2592
+        $manager->expects($this->once())
2593
+            ->method('linkCreateChecks')
2594
+            ->with($share);
2595
+        ;
2596
+        $manager->expects($this->once())
2597
+            ->method('pathCreateChecks')
2598
+            ->with($path);
2599
+        $manager->expects($this->once())
2600
+            ->method('validateExpirationDateLink')
2601
+            ->with($share)
2602
+            ->willReturn($share);
2603
+        $manager->expects($this->once())
2604
+            ->method('verifyPassword')
2605
+            ->with('password');
2606
+        $manager->expects($this->once())
2607
+            ->method('setLinkParent')
2608
+            ->with($share);
2609
+
2610
+        $this->hasher->expects($this->once())
2611
+            ->method('hash')
2612
+            ->with('password')
2613
+            ->willReturn('hashed');
2614
+
2615
+        $this->secureRandom->method('generate')
2616
+            ->willReturn('token');
2617
+
2618
+        $this->defaultProvider
2619
+            ->expects($this->once())
2620
+            ->method('create')
2621
+            ->with($share)
2622
+            ->willReturnCallback(function (Share $share) {
2623
+                return $share->setId(42);
2624
+            });
2625
+
2626
+        $calls = [
2627
+            BeforeShareCreatedEvent::class,
2628
+            ShareCreatedEvent::class,
2629
+        ];
2630
+        $this->dispatcher->expects($this->exactly(2))
2631
+            ->method('dispatchTyped')
2632
+            ->willReturnCallback(function ($event) use (&$calls, $date, $path) {
2633
+                $expected = array_shift($calls);
2634
+                $this->assertInstanceOf($expected, $event);
2635
+                $share = $event->getShare();
2636
+
2637
+                $this->assertEquals(IShare::TYPE_LINK, $share->getShareType(), 'getShareType');
2638
+                $this->assertEquals($path, $share->getNode(), 'getNode');
2639
+                $this->assertEquals('sharedBy', $share->getSharedBy(), 'getSharedBy');
2640
+                $this->assertEquals(\OCP\Constants::PERMISSION_ALL, $share->getPermissions(), 'getPermissions');
2641
+                $this->assertEquals($date, $share->getExpirationDate(), 'getExpirationDate');
2642
+                $this->assertEquals('hashed', $share->getPassword(), 'getPassword');
2643
+                $this->assertEquals('token', $share->getToken(), 'getToken');
2644
+
2645
+                if ($expected === ShareCreatedEvent::class) {
2646
+                    $this->assertEquals('42', $share->getId(), 'getId');
2647
+                    $this->assertEquals('/target', $share->getTarget(), 'getTarget');
2648
+                }
2649
+            });
2650
+
2651
+        /** @var IShare $share */
2652
+        $share = $manager->createShare($share);
2653
+
2654
+        $this->assertSame('shareOwner', $share->getShareOwner());
2655
+        $this->assertEquals('/target', $share->getTarget());
2656
+        $this->assertSame($date, $share->getExpirationDate());
2657
+        $this->assertEquals('token', $share->getToken());
2658
+        $this->assertEquals('hashed', $share->getPassword());
2659
+    }
2660
+
2661
+    public function testCreateShareMail(): void {
2662
+        $manager = $this->createManagerMock()
2663
+            ->onlyMethods([
2664
+                'canShare',
2665
+                'generalCreateChecks',
2666
+                'linkCreateChecks',
2667
+                'pathCreateChecks',
2668
+                'validateExpirationDateLink',
2669
+                'verifyPassword',
2670
+                'setLinkParent',
2671
+            ])
2672
+            ->getMock();
2673
+
2674
+        $shareOwner = $this->createMock(IUser::class);
2675
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2676
+
2677
+        $storage = $this->createMock(IStorage::class);
2678
+        $path = $this->createMock(File::class);
2679
+        $path->method('getOwner')->willReturn($shareOwner);
2680
+        $path->method('getName')->willReturn('target');
2681
+        $path->method('getId')->willReturn(1);
2682
+        $path->method('getStorage')->willReturn($storage);
2683
+
2684
+        $share = $this->manager->newShare();
2685
+        $share->setShareType(IShare::TYPE_EMAIL)
2686
+            ->setNode($path)
2687
+            ->setSharedBy('sharedBy')
2688
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
2689
+
2690
+        $manager->expects($this->once())
2691
+            ->method('canShare')
2692
+            ->with($share)
2693
+            ->willReturn(true);
2694
+        $manager->expects($this->once())
2695
+            ->method('generalCreateChecks')
2696
+            ->with($share);
2697
+
2698
+        $manager->expects($this->once())
2699
+            ->method('linkCreateChecks');
2700
+        $manager->expects($this->once())
2701
+            ->method('pathCreateChecks')
2702
+            ->with($path);
2703
+        $manager->expects($this->once())
2704
+            ->method('validateExpirationDateLink')
2705
+            ->with($share)
2706
+            ->willReturn($share);
2707
+        $manager->expects($this->once())
2708
+            ->method('verifyPassword');
2709
+        $manager->expects($this->once())
2710
+            ->method('setLinkParent');
2711
+
2712
+        $this->secureRandom->method('generate')
2713
+            ->willReturn('token');
2714
+
2715
+        $this->defaultProvider
2716
+            ->expects($this->once())
2717
+            ->method('create')
2718
+            ->with($share)
2719
+            ->willReturnCallback(function (Share $share) {
2720
+                return $share->setId(42);
2721
+            });
2722
+
2723
+        $calls = [
2724
+            BeforeShareCreatedEvent::class,
2725
+            ShareCreatedEvent::class,
2726
+        ];
2727
+        $this->dispatcher->expects($this->exactly(2))
2728
+            ->method('dispatchTyped')
2729
+            ->willReturnCallback(function ($event) use (&$calls, $path) {
2730
+                $expected = array_shift($calls);
2731
+                $this->assertInstanceOf($expected, $event);
2732
+                $share = $event->getShare();
2733
+
2734
+                $this->assertEquals(IShare::TYPE_EMAIL, $share->getShareType(), 'getShareType');
2735
+                $this->assertEquals($path, $share->getNode(), 'getNode');
2736
+                $this->assertEquals('sharedBy', $share->getSharedBy(), 'getSharedBy');
2737
+                $this->assertEquals(\OCP\Constants::PERMISSION_ALL, $share->getPermissions(), 'getPermissions');
2738
+                $this->assertNull($share->getExpirationDate(), 'getExpirationDate');
2739
+                $this->assertNull($share->getPassword(), 'getPassword');
2740
+                $this->assertEquals('token', $share->getToken(), 'getToken');
2741
+
2742
+                if ($expected === ShareCreatedEvent::class) {
2743
+                    $this->assertEquals('42', $share->getId(), 'getId');
2744
+                    $this->assertEquals('/target', $share->getTarget(), 'getTarget');
2745
+                }
2746
+            });
2747
+
2748
+        /** @var IShare $share */
2749
+        $share = $manager->createShare($share);
2750
+
2751
+        $this->assertSame('shareOwner', $share->getShareOwner());
2752
+        $this->assertEquals('/target', $share->getTarget());
2753
+        $this->assertEquals('token', $share->getToken());
2754
+    }
2755
+
2756
+
2757
+    public function testCreateShareHookError(): void {
2758
+        $this->expectException(\Exception::class);
2759
+        $this->expectExceptionMessage('I won\'t let you share');
2760
+
2761
+        $manager = $this->createManagerMock()
2762
+            ->onlyMethods([
2763
+                'canShare',
2764
+                'generalCreateChecks',
2765
+                'userCreateChecks',
2766
+                'pathCreateChecks',
2767
+            ])
2768
+            ->getMock();
2769
+
2770
+        $shareOwner = $this->createMock(IUser::class);
2771
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2772
+
2773
+        $storage = $this->createMock(IStorage::class);
2774
+        $path = $this->createMock(File::class);
2775
+        $path->method('getOwner')->willReturn($shareOwner);
2776
+        $path->method('getName')->willReturn('target');
2777
+        $path->method('getStorage')->willReturn($storage);
2778
+
2779
+        $share = $this->createShare(
2780
+            null,
2781
+            IShare::TYPE_USER,
2782
+            $path,
2783
+            'sharedWith',
2784
+            'sharedBy',
2785
+            null,
2786
+            \OCP\Constants::PERMISSION_ALL);
2787
+
2788
+        $manager->expects($this->once())
2789
+            ->method('canShare')
2790
+            ->with($share)
2791
+            ->willReturn(true);
2792
+        $manager->expects($this->once())
2793
+            ->method('generalCreateChecks')
2794
+            ->with($share);
2795
+        ;
2796
+        $manager->expects($this->once())
2797
+            ->method('userCreateChecks')
2798
+            ->with($share);
2799
+        ;
2800
+        $manager->expects($this->once())
2801
+            ->method('pathCreateChecks')
2802
+            ->with($path);
2803
+
2804
+        $share->expects($this->once())
2805
+            ->method('setShareOwner')
2806
+            ->with('shareOwner');
2807
+        $share->expects($this->once())
2808
+            ->method('setTarget')
2809
+            ->with('/target');
2810
+
2811
+        // Pre share
2812
+        $this->dispatcher->expects($this->once())
2813
+            ->method('dispatchTyped')
2814
+            ->with(
2815
+                $this->isInstanceOf(BeforeShareCreatedEvent::class)
2816
+            )->willReturnCallback(function (BeforeShareCreatedEvent $e) {
2817
+                $e->setError('I won\'t let you share!');
2818
+                $e->stopPropagation();
2819
+            }
2820
+            );
2821
+
2822
+        $manager->createShare($share);
2823
+    }
2824
+
2825
+    public function testCreateShareOfIncomingFederatedShare(): void {
2826
+        $manager = $this->createManagerMock()
2827
+            ->onlyMethods(['canShare', 'generalCreateChecks', 'userCreateChecks', 'pathCreateChecks'])
2828
+            ->getMock();
2829
+
2830
+        $shareOwner = $this->createMock(IUser::class);
2831
+        $shareOwner->method('getUID')->willReturn('shareOwner');
2832
+
2833
+        $storage = $this->createMock(IStorage::class);
2834
+        $storage->method('instanceOfStorage')
2835
+            ->with('OCA\Files_Sharing\External\Storage')
2836
+            ->willReturn(true);
2837
+
2838
+        $storage2 = $this->createMock(IStorage::class);
2839
+        $storage2->method('instanceOfStorage')
2840
+            ->with('OCA\Files_Sharing\External\Storage')
2841
+            ->willReturn(false);
2842
+
2843
+        $path = $this->createMock(File::class);
2844
+        $path->expects($this->never())->method('getOwner');
2845
+        $path->method('getName')->willReturn('target');
2846
+        $path->method('getStorage')->willReturn($storage);
2847
+
2848
+        $parent = $this->createMock(Folder::class);
2849
+        $parent->method('getStorage')->willReturn($storage);
2850
+
2851
+        $parentParent = $this->createMock(Folder::class);
2852
+        $parentParent->method('getStorage')->willReturn($storage2);
2853
+        $parentParent->method('getOwner')->willReturn($shareOwner);
2854
+
2855
+        $path->method('getParent')->willReturn($parent);
2856
+        $parent->method('getParent')->willReturn($parentParent);
2857
+
2858
+        $share = $this->createShare(
2859
+            null,
2860
+            IShare::TYPE_USER,
2861
+            $path,
2862
+            'sharedWith',
2863
+            'sharedBy',
2864
+            null,
2865
+            \OCP\Constants::PERMISSION_ALL);
2866
+
2867
+        $manager->expects($this->once())
2868
+            ->method('canShare')
2869
+            ->with($share)
2870
+            ->willReturn(true);
2871
+        $manager->expects($this->once())
2872
+            ->method('generalCreateChecks')
2873
+            ->with($share);
2874
+        ;
2875
+        $manager->expects($this->once())
2876
+            ->method('userCreateChecks')
2877
+            ->with($share);
2878
+        ;
2879
+        $manager->expects($this->once())
2880
+            ->method('pathCreateChecks')
2881
+            ->with($path);
2882
+
2883
+        $this->defaultProvider
2884
+            ->expects($this->once())
2885
+            ->method('create')
2886
+            ->with($share)
2887
+            ->willReturnArgument(0);
2888
+
2889
+        $share->expects($this->once())
2890
+            ->method('setShareOwner')
2891
+            ->with('shareOwner');
2892
+        $share->expects($this->once())
2893
+            ->method('setTarget')
2894
+            ->with('/target');
2895
+
2896
+        $manager->createShare($share);
2897
+    }
2898
+
2899
+    public function testGetSharesBy(): void {
2900
+        $share = $this->manager->newShare();
2901
+
2902
+        $node = $this->createMock(Folder::class);
2903
+
2904
+        $this->defaultProvider->expects($this->once())
2905
+            ->method('getSharesBy')
2906
+            ->with(
2907
+                $this->equalTo('user'),
2908
+                $this->equalTo(IShare::TYPE_USER),
2909
+                $this->equalTo($node),
2910
+                $this->equalTo(true),
2911
+                $this->equalTo(1),
2912
+                $this->equalTo(1)
2913
+            )->willReturn([$share]);
2914
+
2915
+        $shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1);
2916
+
2917
+        $this->assertCount(1, $shares);
2918
+        $this->assertSame($share, $shares[0]);
2919
+    }
2920
+
2921
+    public function testGetSharesByOwnerless(): void {
2922
+        $mount = $this->createMock(IShareOwnerlessMount::class);
2923
+
2924
+        $node = $this->createMock(Folder::class);
2925
+        $node
2926
+            ->expects($this->once())
2927
+            ->method('getMountPoint')
2928
+            ->willReturn($mount);
2929
+
2930
+        $share = $this->manager->newShare();
2931
+        $share->setNode($node);
2932
+        $share->setShareType(IShare::TYPE_USER);
2933
+
2934
+        $this->defaultProvider
2935
+            ->expects($this->once())
2936
+            ->method('getSharesByPath')
2937
+            ->with($this->equalTo($node))
2938
+            ->willReturn([$share]);
2939
+
2940
+        $shares = $this->manager->getSharesBy('user', IShare::TYPE_USER, $node, true, 1, 1);
2941
+
2942
+        $this->assertCount(1, $shares);
2943
+        $this->assertSame($share, $shares[0]);
2944
+    }
2945
+
2946
+    /**
2947
+     * Test to ensure we correctly remove expired link shares
2948
+     *
2949
+     * We have 8 Shares and we want the 3 first valid shares.
2950
+     * share 3-6 and 8 are expired. Thus at the end of this test we should
2951
+     * have received share 1,2 and 7. And from the manager. Share 3-6 should be
2952
+     * deleted (as they are evaluated). but share 8 should still be there.
2953
+     */
2954
+    public function testGetSharesByExpiredLinkShares(): void {
2955
+        $manager = $this->createManagerMock()
2956
+            ->onlyMethods(['deleteShare'])
2957
+            ->getMock();
2958
+
2959
+        /** @var \OCP\Share\IShare[] $shares */
2960
+        $shares = [];
2961
+
2962
+        /*
2963 2963
 		 * This results in an array of 8 IShare elements
2964 2964
 		 */
2965
-		for ($i = 0; $i < 8; $i++) {
2966
-			$share = $this->manager->newShare();
2967
-			$share->setId($i);
2968
-			$shares[] = $share;
2969
-		}
2965
+        for ($i = 0; $i < 8; $i++) {
2966
+            $share = $this->manager->newShare();
2967
+            $share->setId($i);
2968
+            $shares[] = $share;
2969
+        }
2970 2970
 
2971
-		$today = new \DateTime();
2972
-		$today->setTime(0, 0, 0);
2971
+        $today = new \DateTime();
2972
+        $today->setTime(0, 0, 0);
2973 2973
 
2974
-		/*
2974
+        /*
2975 2975
 		 * Set the expiration date to today for some shares
2976 2976
 		 */
2977
-		$shares[2]->setExpirationDate($today);
2978
-		$shares[3]->setExpirationDate($today);
2979
-		$shares[4]->setExpirationDate($today);
2980
-		$shares[5]->setExpirationDate($today);
2977
+        $shares[2]->setExpirationDate($today);
2978
+        $shares[3]->setExpirationDate($today);
2979
+        $shares[4]->setExpirationDate($today);
2980
+        $shares[5]->setExpirationDate($today);
2981 2981
 
2982
-		/** @var \OCP\Share\IShare[] $i */
2983
-		$shares2 = [];
2984
-		for ($i = 0; $i < 8; $i++) {
2985
-			$shares2[] = clone $shares[$i];
2986
-		}
2982
+        /** @var \OCP\Share\IShare[] $i */
2983
+        $shares2 = [];
2984
+        for ($i = 0; $i < 8; $i++) {
2985
+            $shares2[] = clone $shares[$i];
2986
+        }
2987 2987
 
2988
-		$node = $this->createMock(File::class);
2988
+        $node = $this->createMock(File::class);
2989 2989
 
2990
-		/*
2990
+        /*
2991 2991
 		 * Simulate the getSharesBy call.
2992 2992
 		 */
2993
-		$this->defaultProvider
2994
-			->method('getSharesBy')
2995
-			->willReturnCallback(function ($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) {
2996
-				return array_slice($shares2, $offset, $limit);
2997
-			});
2993
+        $this->defaultProvider
2994
+            ->method('getSharesBy')
2995
+            ->willReturnCallback(function ($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) {
2996
+                return array_slice($shares2, $offset, $limit);
2997
+            });
2998 2998
 
2999
-		/*
2999
+        /*
3000 3000
 		 * Simulate the deleteShare call.
3001 3001
 		 */
3002
-		$manager->method('deleteShare')
3003
-			->willReturnCallback(function ($share) use (&$shares2) {
3004
-				for ($i = 0; $i < count($shares2); $i++) {
3005
-					if ($shares2[$i]->getId() === $share->getId()) {
3006
-						array_splice($shares2, $i, 1);
3007
-						break;
3008
-					}
3009
-				}
3010
-			});
3011
-
3012
-		$res = $manager->getSharesBy('user', IShare::TYPE_LINK, $node, true, 3, 0);
3013
-
3014
-		$this->assertCount(3, $res);
3015
-		$this->assertEquals($shares[0]->getId(), $res[0]->getId());
3016
-		$this->assertEquals($shares[1]->getId(), $res[1]->getId());
3017
-		$this->assertEquals($shares[6]->getId(), $res[2]->getId());
3018
-
3019
-		$this->assertCount(4, $shares2);
3020
-		$this->assertEquals(0, $shares2[0]->getId());
3021
-		$this->assertEquals(1, $shares2[1]->getId());
3022
-		$this->assertEquals(6, $shares2[2]->getId());
3023
-		$this->assertEquals(7, $shares2[3]->getId());
3024
-		$this->assertSame($today, $shares[3]->getExpirationDate());
3025
-	}
3026
-
3027
-	public function testGetShareByToken(): void {
3028
-		$this->config
3029
-			->expects($this->exactly(2))
3030
-			->method('getAppValue')
3031
-			->willReturnMap([
3032
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
3033
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3034
-			]);
3035
-
3036
-		$factory = $this->createMock(IProviderFactory::class);
3037
-
3038
-		$manager = $this->createManager($factory);
3039
-
3040
-		$share = $this->createMock(IShare::class);
3041
-
3042
-		$factory->expects($this->once())
3043
-			->method('getProviderForType')
3044
-			->with(IShare::TYPE_LINK)
3045
-			->willReturn($this->defaultProvider);
3046
-
3047
-		$this->defaultProvider->expects($this->once())
3048
-			->method('getShareByToken')
3049
-			->with('token')
3050
-			->willReturn($share);
3051
-
3052
-		$ret = $manager->getShareByToken('token');
3053
-		$this->assertSame($share, $ret);
3054
-	}
3055
-
3056
-	public function testGetShareByTokenRoom(): void {
3057
-		$this->config
3058
-			->expects($this->exactly(2))
3059
-			->method('getAppValue')
3060
-			->willReturnMap([
3061
-				['core', 'shareapi_allow_links', 'yes', 'no'],
3062
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3063
-			]);
3064
-
3065
-		$factory = $this->createMock(IProviderFactory::class);
3066
-
3067
-		$manager = $this->createManager($factory);
3068
-
3069
-		$share = $this->createMock(IShare::class);
3070
-
3071
-		$roomShareProvider = $this->createMock(IShareProvider::class);
3072
-
3073
-		$factory->expects($this->any())
3074
-			->method('getProviderForType')
3075
-			->willReturnCallback(function ($shareType) use ($roomShareProvider) {
3076
-				if ($shareType !== IShare::TYPE_ROOM) {
3077
-					throw new Exception\ProviderException();
3078
-				}
3079
-
3080
-				return $roomShareProvider;
3081
-			});
3082
-
3083
-		$roomShareProvider->expects($this->once())
3084
-			->method('getShareByToken')
3085
-			->with('token')
3086
-			->willReturn($share);
3087
-
3088
-		$ret = $manager->getShareByToken('token');
3089
-		$this->assertSame($share, $ret);
3090
-	}
3091
-
3092
-	public function testGetShareByTokenWithException(): void {
3093
-		$this->config
3094
-			->expects($this->exactly(2))
3095
-			->method('getAppValue')
3096
-			->willReturnMap([
3097
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
3098
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3099
-			]);
3100
-
3101
-		$factory = $this->createMock(IProviderFactory::class);
3102
-
3103
-		$manager = $this->createManager($factory);
3104
-
3105
-		$share = $this->createMock(IShare::class);
3106
-
3107
-		$calls = [
3108
-			[IShare::TYPE_LINK],
3109
-			[IShare::TYPE_REMOTE],
3110
-		];
3111
-		$factory->expects($this->exactly(2))
3112
-			->method('getProviderForType')
3113
-			->willReturnCallback(function () use (&$calls) {
3114
-				$expected = array_shift($calls);
3115
-				$this->assertEquals($expected, func_get_args());
3116
-				return $this->defaultProvider;
3117
-			});
3118
-
3119
-		$this->defaultProvider->expects($this->exactly(2))
3120
-			->method('getShareByToken')
3121
-			->with('token')
3122
-			->willReturnOnConsecutiveCalls(
3123
-				$this->throwException(new ShareNotFound()),
3124
-				$share
3125
-			);
3126
-
3127
-		$ret = $manager->getShareByToken('token');
3128
-		$this->assertSame($share, $ret);
3129
-	}
3130
-
3131
-
3132
-	public function testGetShareByTokenHideDisabledUser(): void {
3133
-		$this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3134
-		$this->expectExceptionMessage('The requested share comes from a disabled user');
3135
-
3136
-		$this->config
3137
-			->expects($this->exactly(2))
3138
-			->method('getAppValue')
3139
-			->willReturnMap([
3140
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
3141
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'yes'],
3142
-			]);
3143
-
3144
-		$this->l->expects($this->once())
3145
-			->method('t')
3146
-			->willReturnArgument(0);
3147
-
3148
-		$manager = $this->createManagerMock()
3149
-			->onlyMethods(['deleteShare'])
3150
-			->getMock();
3151
-
3152
-		$date = new \DateTime();
3153
-		$date->setTime(0, 0, 0);
3154
-		$date->add(new \DateInterval('P2D'));
3155
-		$share = $this->manager->newShare();
3156
-		$share->setExpirationDate($date);
3157
-		$share->setShareOwner('owner');
3158
-		$share->setSharedBy('sharedBy');
3159
-
3160
-		$sharedBy = $this->createMock(IUser::class);
3161
-		$owner = $this->createMock(IUser::class);
3162
-
3163
-		$this->userManager->method('get')->willReturnMap([
3164
-			['sharedBy', $sharedBy],
3165
-			['owner', $owner],
3166
-		]);
3167
-
3168
-		$owner->expects($this->once())
3169
-			->method('isEnabled')
3170
-			->willReturn(true);
3171
-		$sharedBy->expects($this->once())
3172
-			->method('isEnabled')
3173
-			->willReturn(false);
3174
-
3175
-		$this->defaultProvider->expects($this->once())
3176
-			->method('getShareByToken')
3177
-			->with('expiredToken')
3178
-			->willReturn($share);
3179
-
3180
-		$manager->expects($this->never())
3181
-			->method('deleteShare');
3182
-
3183
-		$manager->getShareByToken('expiredToken');
3184
-	}
3185
-
3186
-
3187
-	public function testGetShareByTokenExpired(): void {
3188
-		$this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3189
-		$this->expectExceptionMessage('The requested share does not exist anymore');
3190
-
3191
-		$this->config
3192
-			->expects($this->once())
3193
-			->method('getAppValue')
3194
-			->with('core', 'shareapi_allow_links', 'yes')
3195
-			->willReturn('yes');
3196
-
3197
-		$this->l->expects($this->once())
3198
-			->method('t')
3199
-			->willReturnArgument(0);
3200
-
3201
-		$manager = $this->createManagerMock()
3202
-			->onlyMethods(['deleteShare'])
3203
-			->getMock();
3204
-
3205
-		$date = new \DateTime();
3206
-		$date->setTime(0, 0, 0);
3207
-		$share = $this->manager->newShare();
3208
-		$share->setExpirationDate($date);
3209
-
3210
-		$this->defaultProvider->expects($this->once())
3211
-			->method('getShareByToken')
3212
-			->with('expiredToken')
3213
-			->willReturn($share);
3214
-
3215
-		$manager->expects($this->once())
3216
-			->method('deleteShare')
3217
-			->with($this->equalTo($share));
3218
-
3219
-		$manager->getShareByToken('expiredToken');
3220
-	}
3221
-
3222
-	public function testGetShareByTokenNotExpired(): void {
3223
-		$this->config
3224
-			->expects($this->exactly(2))
3225
-			->method('getAppValue')
3226
-			->willReturnMap([
3227
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
3228
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3229
-			]);
3230
-
3231
-		$date = new \DateTime();
3232
-		$date->setTime(0, 0, 0);
3233
-		$date->add(new \DateInterval('P2D'));
3234
-		$share = $this->manager->newShare();
3235
-		$share->setExpirationDate($date);
3236
-
3237
-		$this->defaultProvider->expects($this->once())
3238
-			->method('getShareByToken')
3239
-			->with('expiredToken')
3240
-			->willReturn($share);
3241
-
3242
-		$res = $this->manager->getShareByToken('expiredToken');
3243
-
3244
-		$this->assertSame($share, $res);
3245
-	}
3246
-
3247
-
3248
-	public function testGetShareByTokenWithPublicLinksDisabled(): void {
3249
-		$this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3250
-
3251
-		$this->config
3252
-			->expects($this->once())
3253
-			->method('getAppValue')
3254
-			->with('core', 'shareapi_allow_links', 'yes')
3255
-			->willReturn('no');
3256
-		$this->manager->getShareByToken('validToken');
3257
-	}
3258
-
3259
-	public function testGetShareByTokenPublicUploadDisabled(): void {
3260
-		$this->config
3261
-			->expects($this->exactly(3))
3262
-			->method('getAppValue')
3263
-			->willReturnMap([
3264
-				['core', 'shareapi_allow_links', 'yes', 'yes'],
3265
-				['core', 'shareapi_allow_public_upload', 'yes', 'no'],
3266
-				['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3267
-			]);
3268
-
3269
-		$share = $this->manager->newShare();
3270
-		$share->setShareType(IShare::TYPE_LINK)
3271
-			->setPermissions(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
3272
-		$share->setSharedWith('sharedWith');
3273
-		$folder = $this->createMock(\OC\Files\Node\Folder::class);
3274
-		$share->setNode($folder);
3275
-
3276
-		$this->defaultProvider->expects($this->once())
3277
-			->method('getShareByToken')
3278
-			->willReturn('validToken')
3279
-			->willReturn($share);
3280
-
3281
-		$res = $this->manager->getShareByToken('validToken');
3282
-
3283
-		$this->assertSame(\OCP\Constants::PERMISSION_READ, $res->getPermissions());
3284
-	}
3285
-
3286
-	public function testCheckPasswordNoLinkShare(): void {
3287
-		$share = $this->createMock(IShare::class);
3288
-		$share->method('getShareType')->willReturn(IShare::TYPE_USER);
3289
-		$this->assertFalse($this->manager->checkPassword($share, 'password'));
3290
-	}
3291
-
3292
-	public function testCheckPasswordNoPassword(): void {
3293
-		$share = $this->createMock(IShare::class);
3294
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3295
-		$this->assertFalse($this->manager->checkPassword($share, 'password'));
3296
-
3297
-		$share->method('getPassword')->willReturn('password');
3298
-		$this->assertFalse($this->manager->checkPassword($share, null));
3299
-	}
3300
-
3301
-	public function testCheckPasswordInvalidPassword(): void {
3302
-		$share = $this->createMock(IShare::class);
3303
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3304
-		$share->method('getPassword')->willReturn('password');
3305
-
3306
-		$this->hasher->method('verify')->with('invalidpassword', 'password', '')->willReturn(false);
3307
-
3308
-		$this->assertFalse($this->manager->checkPassword($share, 'invalidpassword'));
3309
-	}
3310
-
3311
-	public function testCheckPasswordValidPassword(): void {
3312
-		$share = $this->createMock(IShare::class);
3313
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3314
-		$share->method('getPassword')->willReturn('passwordHash');
3315
-
3316
-		$this->hasher->method('verify')->with('password', 'passwordHash', '')->willReturn(true);
3317
-
3318
-		$this->assertTrue($this->manager->checkPassword($share, 'password'));
3319
-	}
3320
-
3321
-	public function testCheckPasswordUpdateShare(): void {
3322
-		$share = $this->manager->newShare();
3323
-		$share->setShareType(IShare::TYPE_LINK)
3324
-			->setPassword('passwordHash');
3325
-
3326
-		$this->hasher->method('verify')->with('password', 'passwordHash', '')
3327
-			->willReturnCallback(function ($pass, $hash, &$newHash) {
3328
-				$newHash = 'newHash';
3329
-
3330
-				return true;
3331
-			});
3332
-
3333
-		$this->defaultProvider->expects($this->once())
3334
-			->method('update')
3335
-			->with($this->callback(function (\OCP\Share\IShare $share) {
3336
-				return $share->getPassword() === 'newHash';
3337
-			}));
3338
-
3339
-		$this->assertTrue($this->manager->checkPassword($share, 'password'));
3340
-	}
3341
-
3342
-
3343
-	public function testUpdateShareCantChangeShareType(): void {
3344
-		$this->expectException(\Exception::class);
3345
-		$this->expectExceptionMessage('Cannot change share type');
3346
-
3347
-		$manager = $this->createManagerMock()
3348
-			->onlyMethods([
3349
-				'canShare',
3350
-				'getShareById'
3351
-			])
3352
-			->getMock();
3353
-
3354
-		$originalShare = $this->manager->newShare();
3355
-		$originalShare->setShareType(IShare::TYPE_GROUP);
3356
-
3357
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3358
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3359
-
3360
-		$share = $this->manager->newShare();
3361
-		$attrs = $this->manager->newShare()->newAttributes();
3362
-		$attrs->setAttribute('app1', 'perm1', true);
3363
-		$share->setProviderId('foo')
3364
-			->setId('42')
3365
-			->setShareType(IShare::TYPE_USER);
3366
-
3367
-		$manager->updateShare($share);
3368
-	}
3369
-
3370
-
3371
-	public function testUpdateShareCantChangeRecipientForGroupShare(): void {
3372
-		$this->expectException(\Exception::class);
3373
-		$this->expectExceptionMessage('Can only update recipient on user shares');
3374
-
3375
-		$manager = $this->createManagerMock()
3376
-			->onlyMethods([
3377
-				'canShare',
3378
-				'getShareById'
3379
-			])
3380
-			->getMock();
3381
-
3382
-		$originalShare = $this->manager->newShare();
3383
-		$originalShare->setShareType(IShare::TYPE_GROUP)
3384
-			->setSharedWith('origGroup');
3385
-
3386
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3387
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3388
-
3389
-		$share = $this->manager->newShare();
3390
-		$share->setProviderId('foo')
3391
-			->setId('42')
3392
-			->setShareType(IShare::TYPE_GROUP)
3393
-			->setSharedWith('newGroup');
3394
-
3395
-		$manager->updateShare($share);
3396
-	}
3397
-
3398
-
3399
-	public function testUpdateShareCantShareWithOwner(): void {
3400
-		$this->expectException(\Exception::class);
3401
-		$this->expectExceptionMessage('Cannot share with the share owner');
3402
-
3403
-		$manager = $this->createManagerMock()
3404
-			->onlyMethods([
3405
-				'canShare',
3406
-				'getShareById'
3407
-			])
3408
-			->getMock();
3409
-
3410
-		$originalShare = $this->manager->newShare();
3411
-		$originalShare->setShareType(IShare::TYPE_USER)
3412
-			->setSharedWith('sharedWith');
3413
-
3414
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3415
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3416
-
3417
-		$share = $this->manager->newShare();
3418
-		$share->setProviderId('foo')
3419
-			->setId('42')
3420
-			->setShareType(IShare::TYPE_USER)
3421
-			->setSharedWith('newUser')
3422
-			->setShareOwner('newUser');
3423
-
3424
-		$manager->updateShare($share);
3425
-	}
3426
-
3427
-	public function testUpdateShareUser(): void {
3428
-		$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
3429
-
3430
-		$manager = $this->createManagerMock()
3431
-			->onlyMethods([
3432
-				'canShare',
3433
-				'getShareById',
3434
-				'generalCreateChecks',
3435
-				'userCreateChecks',
3436
-				'pathCreateChecks',
3437
-			])
3438
-			->getMock();
3439
-
3440
-		$originalShare = $this->manager->newShare();
3441
-		$originalShare->setShareType(IShare::TYPE_USER)
3442
-			->setSharedWith('origUser')
3443
-			->setPermissions(1);
3444
-
3445
-		$node = $this->createMock(File::class);
3446
-		$node->method('getId')->willReturn(100);
3447
-		$node->method('getPath')->willReturn('/newUser/files/myPath');
3448
-
3449
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3450
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3451
-
3452
-		$share = $this->manager->newShare();
3453
-		$attrs = $this->manager->newShare()->newAttributes();
3454
-		$attrs->setAttribute('app1', 'perm1', true);
3455
-		$share->setProviderId('foo')
3456
-			->setId('42')
3457
-			->setShareType(IShare::TYPE_USER)
3458
-			->setSharedWith('origUser')
3459
-			->setShareOwner('newUser')
3460
-			->setSharedBy('sharer')
3461
-			->setPermissions(31)
3462
-			->setAttributes($attrs)
3463
-			->setNode($node);
3464
-
3465
-		$this->defaultProvider->expects($this->once())
3466
-			->method('update')
3467
-			->with($share)
3468
-			->willReturn($share);
3469
-
3470
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3471
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3472
-		$hookListener->expects($this->never())->method('post');
3473
-
3474
-		$this->rootFolder->method('getUserFolder')->with('newUser')->willReturnSelf();
3475
-		$this->rootFolder->method('getRelativePath')->with('/newUser/files/myPath')->willReturn('/myPath');
3476
-
3477
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3478
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post');
3479
-		$hookListener2->expects($this->once())->method('post')->with([
3480
-			'itemType' => 'file',
3481
-			'itemSource' => 100,
3482
-			'shareType' => IShare::TYPE_USER,
3483
-			'shareWith' => 'origUser',
3484
-			'uidOwner' => 'sharer',
3485
-			'permissions' => 31,
3486
-			'path' => '/myPath',
3487
-			'attributes' => $attrs->toArray(),
3488
-		]);
3489
-
3490
-		$manager->updateShare($share);
3491
-	}
3492
-
3493
-	public function testUpdateShareGroup(): void {
3494
-		$manager = $this->createManagerMock()
3495
-			->onlyMethods([
3496
-				'canShare',
3497
-				'getShareById',
3498
-				'generalCreateChecks',
3499
-				'groupCreateChecks',
3500
-				'pathCreateChecks',
3501
-			])
3502
-			->getMock();
3503
-
3504
-		$originalShare = $this->manager->newShare();
3505
-		$originalShare->setShareType(IShare::TYPE_GROUP)
3506
-			->setSharedWith('origUser')
3507
-			->setPermissions(31);
3508
-
3509
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3510
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3511
-
3512
-		$node = $this->createMock(File::class);
3513
-
3514
-		$share = $this->manager->newShare();
3515
-		$share->setProviderId('foo')
3516
-			->setId('42')
3517
-			->setShareType(IShare::TYPE_GROUP)
3518
-			->setSharedWith('origUser')
3519
-			->setShareOwner('owner')
3520
-			->setNode($node)
3521
-			->setPermissions(31);
3522
-
3523
-		$this->defaultProvider->expects($this->once())
3524
-			->method('update')
3525
-			->with($share)
3526
-			->willReturn($share);
3527
-
3528
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3529
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3530
-		$hookListener->expects($this->never())->method('post');
3531
-
3532
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3533
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post');
3534
-		$hookListener2->expects($this->never())->method('post');
3535
-
3536
-		$manager->updateShare($share);
3537
-	}
3538
-
3539
-	public function testUpdateShareLink(): void {
3540
-		$manager = $this->createManagerMock()
3541
-			->onlyMethods([
3542
-				'canShare',
3543
-				'getShareById',
3544
-				'generalCreateChecks',
3545
-				'linkCreateChecks',
3546
-				'pathCreateChecks',
3547
-				'verifyPassword',
3548
-				'validateExpirationDateLink',
3549
-			])
3550
-			->getMock();
3551
-
3552
-		$originalShare = $this->manager->newShare();
3553
-		$originalShare->setShareType(IShare::TYPE_LINK)
3554
-			->setPermissions(15);
3555
-
3556
-		$tomorrow = new \DateTime();
3557
-		$tomorrow->setTime(0, 0, 0);
3558
-		$tomorrow->add(new \DateInterval('P1D'));
3559
-
3560
-		$file = $this->createMock(File::class);
3561
-		$file->method('getId')->willReturn(100);
3562
-
3563
-		$share = $this->manager->newShare();
3564
-		$share->setProviderId('foo')
3565
-			->setId('42')
3566
-			->setShareType(IShare::TYPE_LINK)
3567
-			->setToken('token')
3568
-			->setSharedBy('owner')
3569
-			->setShareOwner('owner')
3570
-			->setPassword('password')
3571
-			->setExpirationDate($tomorrow)
3572
-			->setNode($file)
3573
-			->setPermissions(15);
3574
-
3575
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3576
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3577
-		$manager->expects($this->once())->method('validateExpirationDateLink')->with($share);
3578
-		$manager->expects($this->once())->method('verifyPassword')->with('password');
3579
-
3580
-		$this->hasher->expects($this->once())
3581
-			->method('hash')
3582
-			->with('password')
3583
-			->willReturn('hashed');
3584
-
3585
-		$this->defaultProvider->expects($this->once())
3586
-			->method('update')
3587
-			->with($share)
3588
-			->willReturn($share);
3589
-
3590
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3591
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3592
-		$hookListener->expects($this->once())->method('post')->with([
3593
-			'itemType' => 'file',
3594
-			'itemSource' => 100,
3595
-			'date' => $tomorrow,
3596
-			'uidOwner' => 'owner',
3597
-		]);
3598
-
3599
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3600
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3601
-		$hookListener2->expects($this->once())->method('post')->with([
3602
-			'itemType' => 'file',
3603
-			'itemSource' => 100,
3604
-			'uidOwner' => 'owner',
3605
-			'token' => 'token',
3606
-			'disabled' => false,
3607
-		]);
3608
-
3609
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
3610
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3611
-		$hookListener3->expects($this->never())->method('post');
3612
-
3613
-
3614
-		$manager->updateShare($share);
3615
-	}
3616
-
3617
-	public function testUpdateShareLinkEnableSendPasswordByTalkWithNoPassword(): void {
3618
-		$this->expectException(\InvalidArgumentException::class);
3619
-		$this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
3620
-
3621
-		$manager = $this->createManagerMock()
3622
-			->onlyMethods([
3623
-				'canShare',
3624
-				'getShareById',
3625
-				'generalCreateChecks',
3626
-				'linkCreateChecks',
3627
-				'pathCreateChecks',
3628
-				'verifyPassword',
3629
-				'validateExpirationDateLink',
3630
-			])
3631
-			->getMock();
3632
-
3633
-		$originalShare = $this->manager->newShare();
3634
-		$originalShare->setShareType(IShare::TYPE_LINK)
3635
-			->setPermissions(15);
3636
-
3637
-		$tomorrow = new \DateTime();
3638
-		$tomorrow->setTime(0, 0, 0);
3639
-		$tomorrow->add(new \DateInterval('P1D'));
3640
-
3641
-		$file = $this->createMock(File::class);
3642
-		$file->method('getId')->willReturn(100);
3643
-
3644
-		$share = $this->manager->newShare();
3645
-		$share->setProviderId('foo')
3646
-			->setId('42')
3647
-			->setShareType(IShare::TYPE_LINK)
3648
-			->setToken('token')
3649
-			->setSharedBy('owner')
3650
-			->setShareOwner('owner')
3651
-			->setPassword(null)
3652
-			->setSendPasswordByTalk(true)
3653
-			->setExpirationDate($tomorrow)
3654
-			->setNode($file)
3655
-			->setPermissions(15);
3656
-
3657
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3658
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3659
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
3660
-		$manager->expects($this->once())->method('linkCreateChecks')->with($share);
3661
-		$manager->expects($this->never())->method('verifyPassword');
3662
-		$manager->expects($this->never())->method('pathCreateChecks');
3663
-		$manager->expects($this->never())->method('validateExpirationDateLink');
3664
-
3665
-		$this->hasher->expects($this->never())
3666
-			->method('hash');
3667
-
3668
-		$this->defaultProvider->expects($this->never())
3669
-			->method('update');
3670
-
3671
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3672
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3673
-		$hookListener->expects($this->never())->method('post');
3674
-
3675
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3676
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3677
-		$hookListener2->expects($this->never())->method('post');
3678
-
3679
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
3680
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3681
-		$hookListener3->expects($this->never())->method('post');
3682
-
3683
-		$manager->updateShare($share);
3684
-	}
3685
-
3686
-	public function testUpdateShareMail(): void {
3687
-		$manager = $this->createManagerMock()
3688
-			->onlyMethods([
3689
-				'canShare',
3690
-				'getShareById',
3691
-				'generalCreateChecks',
3692
-				'verifyPassword',
3693
-				'pathCreateChecks',
3694
-				'linkCreateChecks',
3695
-				'validateExpirationDateLink',
3696
-			])
3697
-			->getMock();
3698
-
3699
-		$originalShare = $this->manager->newShare();
3700
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
3701
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
3702
-
3703
-		$tomorrow = new \DateTime();
3704
-		$tomorrow->setTime(0, 0, 0);
3705
-		$tomorrow->add(new \DateInterval('P1D'));
3706
-
3707
-		$file = $this->createMock(File::class);
3708
-		$file->method('getId')->willReturn(100);
3709
-
3710
-		$share = $this->manager->newShare();
3711
-		$share->setProviderId('foo')
3712
-			->setId('42')
3713
-			->setShareType(IShare::TYPE_EMAIL)
3714
-			->setToken('token')
3715
-			->setSharedBy('owner')
3716
-			->setShareOwner('owner')
3717
-			->setPassword('password')
3718
-			->setExpirationDate($tomorrow)
3719
-			->setNode($file)
3720
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
3721
-
3722
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3723
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3724
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
3725
-		$manager->expects($this->once())->method('verifyPassword')->with('password');
3726
-		$manager->expects($this->once())->method('pathCreateChecks')->with($file);
3727
-		$manager->expects($this->once())->method('linkCreateChecks');
3728
-		$manager->expects($this->once())->method('validateExpirationDateLink');
3729
-
3730
-		$this->hasher->expects($this->once())
3731
-			->method('hash')
3732
-			->with('password')
3733
-			->willReturn('hashed');
3734
-
3735
-		$this->defaultProvider->expects($this->once())
3736
-			->method('update')
3737
-			->with($share, 'password')
3738
-			->willReturn($share);
3739
-
3740
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3741
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3742
-		$hookListener->expects($this->once())->method('post')->with([
3743
-			'itemType' => 'file',
3744
-			'itemSource' => 100,
3745
-			'date' => $tomorrow,
3746
-			'uidOwner' => 'owner',
3747
-		]);
3748
-
3749
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3750
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3751
-		$hookListener2->expects($this->once())->method('post')->with([
3752
-			'itemType' => 'file',
3753
-			'itemSource' => 100,
3754
-			'uidOwner' => 'owner',
3755
-			'token' => 'token',
3756
-			'disabled' => false,
3757
-		]);
3758
-
3759
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
3760
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3761
-		$hookListener3->expects($this->never())->method('post');
3762
-
3763
-		$manager->updateShare($share);
3764
-	}
3765
-
3766
-	public function testUpdateShareMailEnableSendPasswordByTalk(): void {
3767
-		$manager = $this->createManagerMock()
3768
-			->onlyMethods([
3769
-				'canShare',
3770
-				'getShareById',
3771
-				'generalCreateChecks',
3772
-				'verifyPassword',
3773
-				'pathCreateChecks',
3774
-				'linkCreateChecks',
3775
-				'validateExpirationDateLink',
3776
-			])
3777
-			->getMock();
3778
-
3779
-		$originalShare = $this->manager->newShare();
3780
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
3781
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
3782
-			->setPassword(null)
3783
-			->setSendPasswordByTalk(false);
3784
-
3785
-		$tomorrow = new \DateTime();
3786
-		$tomorrow->setTime(0, 0, 0);
3787
-		$tomorrow->add(new \DateInterval('P1D'));
3788
-
3789
-		$file = $this->createMock(File::class);
3790
-		$file->method('getId')->willReturn(100);
3791
-
3792
-		$share = $this->manager->newShare();
3793
-		$share->setProviderId('foo')
3794
-			->setId('42')
3795
-			->setShareType(IShare::TYPE_EMAIL)
3796
-			->setToken('token')
3797
-			->setSharedBy('owner')
3798
-			->setShareOwner('owner')
3799
-			->setPassword('password')
3800
-			->setSendPasswordByTalk(true)
3801
-			->setExpirationDate($tomorrow)
3802
-			->setNode($file)
3803
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
3804
-
3805
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3806
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3807
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
3808
-		$manager->expects($this->once())->method('verifyPassword')->with('password');
3809
-		$manager->expects($this->once())->method('pathCreateChecks')->with($file);
3810
-		$manager->expects($this->once())->method('linkCreateChecks');
3811
-		$manager->expects($this->once())->method('validateExpirationDateLink');
3812
-
3813
-		$this->hasher->expects($this->once())
3814
-			->method('hash')
3815
-			->with('password')
3816
-			->willReturn('hashed');
3817
-
3818
-		$this->defaultProvider->expects($this->once())
3819
-			->method('update')
3820
-			->with($share, 'password')
3821
-			->willReturn($share);
3822
-
3823
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3824
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3825
-		$hookListener->expects($this->once())->method('post')->with([
3826
-			'itemType' => 'file',
3827
-			'itemSource' => 100,
3828
-			'date' => $tomorrow,
3829
-			'uidOwner' => 'owner',
3830
-		]);
3831
-
3832
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3833
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3834
-		$hookListener2->expects($this->once())->method('post')->with([
3835
-			'itemType' => 'file',
3836
-			'itemSource' => 100,
3837
-			'uidOwner' => 'owner',
3838
-			'token' => 'token',
3839
-			'disabled' => false,
3840
-		]);
3841
-
3842
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
3843
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3844
-		$hookListener3->expects($this->never())->method('post');
3845
-
3846
-		$manager->updateShare($share);
3847
-	}
3848
-
3849
-	public function testUpdateShareMailEnableSendPasswordByTalkWithDifferentPassword(): void {
3850
-		$manager = $this->createManagerMock()
3851
-			->onlyMethods([
3852
-				'canShare',
3853
-				'getShareById',
3854
-				'generalCreateChecks',
3855
-				'verifyPassword',
3856
-				'pathCreateChecks',
3857
-				'linkCreateChecks',
3858
-				'validateExpirationDateLink',
3859
-			])
3860
-			->getMock();
3861
-
3862
-		$originalShare = $this->manager->newShare();
3863
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
3864
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
3865
-			->setPassword('anotherPasswordHash')
3866
-			->setSendPasswordByTalk(false);
3867
-
3868
-		$tomorrow = new \DateTime();
3869
-		$tomorrow->setTime(0, 0, 0);
3870
-		$tomorrow->add(new \DateInterval('P1D'));
3871
-
3872
-		$file = $this->createMock(File::class);
3873
-		$file->method('getId')->willReturn(100);
3874
-
3875
-		$share = $this->manager->newShare();
3876
-		$share->setProviderId('foo')
3877
-			->setId('42')
3878
-			->setShareType(IShare::TYPE_EMAIL)
3879
-			->setToken('token')
3880
-			->setSharedBy('owner')
3881
-			->setShareOwner('owner')
3882
-			->setPassword('password')
3883
-			->setSendPasswordByTalk(true)
3884
-			->setExpirationDate($tomorrow)
3885
-			->setNode($file)
3886
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
3887
-
3888
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3889
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3890
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
3891
-		$manager->expects($this->once())->method('verifyPassword')->with('password');
3892
-		$manager->expects($this->once())->method('pathCreateChecks')->with($file);
3893
-		$manager->expects($this->once())->method('linkCreateChecks');
3894
-		$manager->expects($this->once())->method('validateExpirationDateLink');
3895
-
3896
-		$this->hasher->expects($this->once())
3897
-			->method('verify')
3898
-			->with('password', 'anotherPasswordHash')
3899
-			->willReturn(false);
3900
-
3901
-		$this->hasher->expects($this->once())
3902
-			->method('hash')
3903
-			->with('password')
3904
-			->willReturn('hashed');
3905
-
3906
-		$this->defaultProvider->expects($this->once())
3907
-			->method('update')
3908
-			->with($share, 'password')
3909
-			->willReturn($share);
3910
-
3911
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3912
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3913
-		$hookListener->expects($this->once())->method('post')->with([
3914
-			'itemType' => 'file',
3915
-			'itemSource' => 100,
3916
-			'date' => $tomorrow,
3917
-			'uidOwner' => 'owner',
3918
-		]);
3919
-
3920
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3921
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3922
-		$hookListener2->expects($this->once())->method('post')->with([
3923
-			'itemType' => 'file',
3924
-			'itemSource' => 100,
3925
-			'uidOwner' => 'owner',
3926
-			'token' => 'token',
3927
-			'disabled' => false,
3928
-		]);
3929
-
3930
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
3931
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3932
-		$hookListener3->expects($this->never())->method('post');
3933
-
3934
-		$manager->updateShare($share);
3935
-	}
3936
-
3937
-	public function testUpdateShareMailEnableSendPasswordByTalkWithNoPassword(): void {
3938
-		$this->expectException(\InvalidArgumentException::class);
3939
-		$this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
3940
-
3941
-		$manager = $this->createManagerMock()
3942
-			->onlyMethods([
3943
-				'canShare',
3944
-				'getShareById',
3945
-				'generalCreateChecks',
3946
-				'verifyPassword',
3947
-				'pathCreateChecks',
3948
-				'linkCreateChecks',
3949
-				'validateExpirationDateLink',
3950
-			])
3951
-			->getMock();
3952
-
3953
-		$originalShare = $this->manager->newShare();
3954
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
3955
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
3956
-			->setPassword(null)
3957
-			->setSendPasswordByTalk(false);
3958
-
3959
-		$tomorrow = new \DateTime();
3960
-		$tomorrow->setTime(0, 0, 0);
3961
-		$tomorrow->add(new \DateInterval('P1D'));
3962
-
3963
-		$file = $this->createMock(File::class);
3964
-		$file->method('getId')->willReturn(100);
3965
-
3966
-		$share = $this->manager->newShare();
3967
-		$share->setProviderId('foo')
3968
-			->setId('42')
3969
-			->setShareType(IShare::TYPE_EMAIL)
3970
-			->setToken('token')
3971
-			->setSharedBy('owner')
3972
-			->setShareOwner('owner')
3973
-			->setPassword(null)
3974
-			->setSendPasswordByTalk(true)
3975
-			->setExpirationDate($tomorrow)
3976
-			->setNode($file)
3977
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
3978
-
3979
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
3980
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3981
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
3982
-		$manager->expects($this->never())->method('verifyPassword');
3983
-		$manager->expects($this->never())->method('pathCreateChecks');
3984
-		$manager->expects($this->once())->method('linkCreateChecks');
3985
-		$manager->expects($this->never())->method('validateExpirationDateLink');
3986
-
3987
-		// If the password is empty, we have nothing to hash
3988
-		$this->hasher->expects($this->never())
3989
-			->method('hash');
3990
-
3991
-		$this->defaultProvider->expects($this->never())
3992
-			->method('update');
3993
-
3994
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
3995
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3996
-		$hookListener->expects($this->never())->method('post');
3997
-
3998
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
3999
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4000
-		$hookListener2->expects($this->never())->method('post');
4001
-
4002
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4003
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4004
-		$hookListener3->expects($this->never())->method('post');
4005
-
4006
-		$manager->updateShare($share);
4007
-	}
4008
-
4009
-
4010
-	public function testUpdateShareMailEnableSendPasswordByTalkRemovingPassword(): void {
4011
-		$this->expectException(\InvalidArgumentException::class);
4012
-		$this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
4013
-
4014
-		$manager = $this->createManagerMock()
4015
-			->onlyMethods([
4016
-				'canShare',
4017
-				'getShareById',
4018
-				'generalCreateChecks',
4019
-				'verifyPassword',
4020
-				'pathCreateChecks',
4021
-				'linkCreateChecks',
4022
-				'validateExpirationDateLink',
4023
-			])
4024
-			->getMock();
4025
-
4026
-		$originalShare = $this->manager->newShare();
4027
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
4028
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
4029
-			->setPassword('passwordHash')
4030
-			->setSendPasswordByTalk(false);
4031
-
4032
-		$tomorrow = new \DateTime();
4033
-		$tomorrow->setTime(0, 0, 0);
4034
-		$tomorrow->add(new \DateInterval('P1D'));
4035
-
4036
-		$file = $this->createMock(File::class);
4037
-		$file->method('getId')->willReturn(100);
4038
-
4039
-		$share = $this->manager->newShare();
4040
-		$share->setProviderId('foo')
4041
-			->setId('42')
4042
-			->setShareType(IShare::TYPE_EMAIL)
4043
-			->setToken('token')
4044
-			->setSharedBy('owner')
4045
-			->setShareOwner('owner')
4046
-			->setPassword(null)
4047
-			->setSendPasswordByTalk(true)
4048
-			->setExpirationDate($tomorrow)
4049
-			->setNode($file)
4050
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
4051
-
4052
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
4053
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4054
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
4055
-		$manager->expects($this->once())->method('verifyPassword');
4056
-		$manager->expects($this->never())->method('pathCreateChecks');
4057
-		$manager->expects($this->once())->method('linkCreateChecks');
4058
-		$manager->expects($this->never())->method('validateExpirationDateLink');
4059
-
4060
-		// If the password is empty, we have nothing to hash
4061
-		$this->hasher->expects($this->never())
4062
-			->method('hash');
4063
-
4064
-		$this->defaultProvider->expects($this->never())
4065
-			->method('update');
4066
-
4067
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
4068
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4069
-		$hookListener->expects($this->never())->method('post');
4070
-
4071
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
4072
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4073
-		$hookListener2->expects($this->never())->method('post');
4074
-
4075
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4076
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4077
-		$hookListener3->expects($this->never())->method('post');
4078
-
4079
-		$manager->updateShare($share);
4080
-	}
4081
-
4082
-
4083
-	public function testUpdateShareMailEnableSendPasswordByTalkRemovingPasswordWithEmptyString(): void {
4084
-		$this->expectException(\InvalidArgumentException::class);
4085
-		$this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
4086
-
4087
-		$manager = $this->createManagerMock()
4088
-			->onlyMethods([
4089
-				'canShare',
4090
-				'getShareById',
4091
-				'generalCreateChecks',
4092
-				'verifyPassword',
4093
-				'pathCreateChecks',
4094
-				'linkCreateChecks',
4095
-				'validateExpirationDateLink',
4096
-			])
4097
-			->getMock();
4098
-
4099
-		$originalShare = $this->manager->newShare();
4100
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
4101
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
4102
-			->setPassword('passwordHash')
4103
-			->setSendPasswordByTalk(false);
4104
-
4105
-		$tomorrow = new \DateTime();
4106
-		$tomorrow->setTime(0, 0, 0);
4107
-		$tomorrow->add(new \DateInterval('P1D'));
4108
-
4109
-		$file = $this->createMock(File::class);
4110
-		$file->method('getId')->willReturn(100);
4111
-
4112
-		$share = $this->manager->newShare();
4113
-		$share->setProviderId('foo')
4114
-			->setId('42')
4115
-			->setShareType(IShare::TYPE_EMAIL)
4116
-			->setToken('token')
4117
-			->setSharedBy('owner')
4118
-			->setShareOwner('owner')
4119
-			->setPassword('')
4120
-			->setSendPasswordByTalk(true)
4121
-			->setExpirationDate($tomorrow)
4122
-			->setNode($file)
4123
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
4124
-
4125
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
4126
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4127
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
4128
-		$manager->expects($this->once())->method('verifyPassword');
4129
-		$manager->expects($this->never())->method('pathCreateChecks');
4130
-		$manager->expects($this->once())->method('linkCreateChecks');
4131
-		$manager->expects($this->never())->method('validateExpirationDateLink');
4132
-
4133
-		// If the password is empty, we have nothing to hash
4134
-		$this->hasher->expects($this->never())
4135
-			->method('hash');
4136
-
4137
-		$this->defaultProvider->expects($this->never())
4138
-			->method('update');
4139
-
4140
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
4141
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4142
-		$hookListener->expects($this->never())->method('post');
4143
-
4144
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
4145
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4146
-		$hookListener2->expects($this->never())->method('post');
4147
-
4148
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4149
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4150
-		$hookListener3->expects($this->never())->method('post');
4151
-
4152
-		$manager->updateShare($share);
4153
-	}
4154
-
4155
-
4156
-	public function testUpdateShareMailEnableSendPasswordByTalkWithPreviousPassword(): void {
4157
-		$this->expectException(\InvalidArgumentException::class);
4158
-		$this->expectExceptionMessage('Cannot enable sending the password by Talk without setting a new password');
4159
-
4160
-		$manager = $this->createManagerMock()
4161
-			->onlyMethods([
4162
-				'canShare',
4163
-				'getShareById',
4164
-				'generalCreateChecks',
4165
-				'verifyPassword',
4166
-				'pathCreateChecks',
4167
-				'linkCreateChecks',
4168
-				'validateExpirationDateLink',
4169
-			])
4170
-			->getMock();
4171
-
4172
-		$originalShare = $this->manager->newShare();
4173
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
4174
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
4175
-			->setPassword('password')
4176
-			->setSendPasswordByTalk(false);
4177
-
4178
-		$tomorrow = new \DateTime();
4179
-		$tomorrow->setTime(0, 0, 0);
4180
-		$tomorrow->add(new \DateInterval('P1D'));
4181
-
4182
-		$file = $this->createMock(File::class);
4183
-		$file->method('getId')->willReturn(100);
4184
-
4185
-		$share = $this->manager->newShare();
4186
-		$share->setProviderId('foo')
4187
-			->setId('42')
4188
-			->setShareType(IShare::TYPE_EMAIL)
4189
-			->setToken('token')
4190
-			->setSharedBy('owner')
4191
-			->setShareOwner('owner')
4192
-			->setPassword('password')
4193
-			->setSendPasswordByTalk(true)
4194
-			->setExpirationDate($tomorrow)
4195
-			->setNode($file)
4196
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
4197
-
4198
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
4199
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4200
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
4201
-		$manager->expects($this->never())->method('verifyPassword');
4202
-		$manager->expects($this->never())->method('pathCreateChecks');
4203
-		$manager->expects($this->once())->method('linkCreateChecks');
4204
-		$manager->expects($this->never())->method('validateExpirationDateLink');
4205
-
4206
-		// If the old & new passwords are the same, we don't do anything
4207
-		$this->hasher->expects($this->never())
4208
-			->method('verify');
4209
-		$this->hasher->expects($this->never())
4210
-			->method('hash');
4211
-
4212
-		$this->defaultProvider->expects($this->never())
4213
-			->method('update');
4214
-
4215
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
4216
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4217
-		$hookListener->expects($this->never())->method('post');
4218
-
4219
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
4220
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4221
-		$hookListener2->expects($this->never())->method('post');
4222
-
4223
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4224
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4225
-		$hookListener3->expects($this->never())->method('post');
4226
-
4227
-		$manager->updateShare($share);
4228
-	}
4229
-
4230
-	public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword(): void {
4231
-		$this->expectException(\InvalidArgumentException::class);
4232
-		$this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password');
4233
-
4234
-		$manager = $this->createManagerMock()
4235
-			->onlyMethods([
4236
-				'canShare',
4237
-				'getShareById',
4238
-				'generalCreateChecks',
4239
-				'verifyPassword',
4240
-				'pathCreateChecks',
4241
-				'linkCreateChecks',
4242
-				'validateExpirationDateLink',
4243
-			])
4244
-			->getMock();
4245
-
4246
-		$originalShare = $this->manager->newShare();
4247
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
4248
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
4249
-			->setPassword('passwordHash')
4250
-			->setSendPasswordByTalk(true);
4251
-
4252
-		$tomorrow = new \DateTime();
4253
-		$tomorrow->setTime(0, 0, 0);
4254
-		$tomorrow->add(new \DateInterval('P1D'));
4255
-
4256
-		$file = $this->createMock(File::class);
4257
-		$file->method('getId')->willReturn(100);
4258
-
4259
-		$share = $this->manager->newShare();
4260
-		$share->setProviderId('foo')
4261
-			->setId('42')
4262
-			->setShareType(IShare::TYPE_EMAIL)
4263
-			->setToken('token')
4264
-			->setSharedBy('owner')
4265
-			->setShareOwner('owner')
4266
-			->setPassword('passwordHash')
4267
-			->setSendPasswordByTalk(false)
4268
-			->setExpirationDate($tomorrow)
4269
-			->setNode($file)
4270
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
4271
-
4272
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
4273
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4274
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
4275
-		$manager->expects($this->never())->method('verifyPassword');
4276
-		$manager->expects($this->never())->method('pathCreateChecks');
4277
-		$manager->expects($this->once())->method('linkCreateChecks');
4278
-		$manager->expects($this->never())->method('validateExpirationDateLink');
4279
-
4280
-		// If the old & new passwords are the same, we don't do anything
4281
-		$this->hasher->expects($this->never())
4282
-			->method('verify');
4283
-		$this->hasher->expects($this->never())
4284
-			->method('hash');
4285
-
4286
-		$this->defaultProvider->expects($this->never())
4287
-			->method('update');
4288
-
4289
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
4290
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4291
-		$hookListener->expects($this->never())->method('post');
4292
-
4293
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
4294
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4295
-		$hookListener2->expects($this->never())->method('post');
4296
-
4297
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4298
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4299
-		$hookListener3->expects($this->never())->method('post');
4300
-
4301
-		$manager->updateShare($share);
4302
-	}
4303
-
4304
-	public function testUpdateShareMailDisableSendPasswordByTalkWithoutChangingPassword(): void {
4305
-		$this->expectException(\InvalidArgumentException::class);
4306
-		$this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password');
4307
-
4308
-		$manager = $this->createManagerMock()
4309
-			->onlyMethods([
4310
-				'canShare',
4311
-				'getShareById',
4312
-				'generalCreateChecks',
4313
-				'verifyPassword',
4314
-				'pathCreateChecks',
4315
-				'linkCreateChecks',
4316
-				'validateExpirationDateLink',
4317
-			])
4318
-			->getMock();
4319
-
4320
-		$originalShare = $this->manager->newShare();
4321
-		$originalShare->setShareType(IShare::TYPE_EMAIL)
4322
-			->setPermissions(\OCP\Constants::PERMISSION_ALL)
4323
-			->setPassword('passwordHash')
4324
-			->setSendPasswordByTalk(true);
4325
-
4326
-		$tomorrow = new \DateTime();
4327
-		$tomorrow->setTime(0, 0, 0);
4328
-		$tomorrow->add(new \DateInterval('P1D'));
4329
-
4330
-		$file = $this->createMock(File::class);
4331
-		$file->method('getId')->willReturn(100);
4332
-
4333
-		$share = $this->manager->newShare();
4334
-		$share->setProviderId('foo')
4335
-			->setId('42')
4336
-			->setShareType(IShare::TYPE_EMAIL)
4337
-			->setToken('token')
4338
-			->setSharedBy('owner')
4339
-			->setShareOwner('owner')
4340
-			->setPassword('passwordHash')
4341
-			->setSendPasswordByTalk(false)
4342
-			->setExpirationDate($tomorrow)
4343
-			->setNode($file)
4344
-			->setPermissions(\OCP\Constants::PERMISSION_ALL);
4345
-
4346
-		$manager->expects($this->once())->method('canShare')->willReturn(true);
4347
-		$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4348
-		$manager->expects($this->once())->method('generalCreateChecks')->with($share);
4349
-		$manager->expects($this->never())->method('verifyPassword');
4350
-		$manager->expects($this->never())->method('pathCreateChecks');
4351
-		$manager->expects($this->once())->method('linkCreateChecks');
4352
-		$manager->expects($this->never())->method('validateExpirationDateLink');
4353
-
4354
-		// If the old & new passwords are the same, we don't do anything
4355
-		$this->hasher->expects($this->never())
4356
-			->method('verify');
4357
-		$this->hasher->expects($this->never())
4358
-			->method('hash');
4359
-
4360
-		$this->defaultProvider->expects($this->never())
4361
-			->method('update');
4362
-
4363
-		$hookListener = $this->createMock(DummyShareManagerListener::class);
4364
-		\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4365
-		$hookListener->expects($this->never())->method('post');
3002
+        $manager->method('deleteShare')
3003
+            ->willReturnCallback(function ($share) use (&$shares2) {
3004
+                for ($i = 0; $i < count($shares2); $i++) {
3005
+                    if ($shares2[$i]->getId() === $share->getId()) {
3006
+                        array_splice($shares2, $i, 1);
3007
+                        break;
3008
+                    }
3009
+                }
3010
+            });
3011
+
3012
+        $res = $manager->getSharesBy('user', IShare::TYPE_LINK, $node, true, 3, 0);
3013
+
3014
+        $this->assertCount(3, $res);
3015
+        $this->assertEquals($shares[0]->getId(), $res[0]->getId());
3016
+        $this->assertEquals($shares[1]->getId(), $res[1]->getId());
3017
+        $this->assertEquals($shares[6]->getId(), $res[2]->getId());
3018
+
3019
+        $this->assertCount(4, $shares2);
3020
+        $this->assertEquals(0, $shares2[0]->getId());
3021
+        $this->assertEquals(1, $shares2[1]->getId());
3022
+        $this->assertEquals(6, $shares2[2]->getId());
3023
+        $this->assertEquals(7, $shares2[3]->getId());
3024
+        $this->assertSame($today, $shares[3]->getExpirationDate());
3025
+    }
3026
+
3027
+    public function testGetShareByToken(): void {
3028
+        $this->config
3029
+            ->expects($this->exactly(2))
3030
+            ->method('getAppValue')
3031
+            ->willReturnMap([
3032
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
3033
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3034
+            ]);
3035
+
3036
+        $factory = $this->createMock(IProviderFactory::class);
3037
+
3038
+        $manager = $this->createManager($factory);
3039
+
3040
+        $share = $this->createMock(IShare::class);
3041
+
3042
+        $factory->expects($this->once())
3043
+            ->method('getProviderForType')
3044
+            ->with(IShare::TYPE_LINK)
3045
+            ->willReturn($this->defaultProvider);
3046
+
3047
+        $this->defaultProvider->expects($this->once())
3048
+            ->method('getShareByToken')
3049
+            ->with('token')
3050
+            ->willReturn($share);
3051
+
3052
+        $ret = $manager->getShareByToken('token');
3053
+        $this->assertSame($share, $ret);
3054
+    }
3055
+
3056
+    public function testGetShareByTokenRoom(): void {
3057
+        $this->config
3058
+            ->expects($this->exactly(2))
3059
+            ->method('getAppValue')
3060
+            ->willReturnMap([
3061
+                ['core', 'shareapi_allow_links', 'yes', 'no'],
3062
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3063
+            ]);
3064
+
3065
+        $factory = $this->createMock(IProviderFactory::class);
3066
+
3067
+        $manager = $this->createManager($factory);
3068
+
3069
+        $share = $this->createMock(IShare::class);
3070
+
3071
+        $roomShareProvider = $this->createMock(IShareProvider::class);
3072
+
3073
+        $factory->expects($this->any())
3074
+            ->method('getProviderForType')
3075
+            ->willReturnCallback(function ($shareType) use ($roomShareProvider) {
3076
+                if ($shareType !== IShare::TYPE_ROOM) {
3077
+                    throw new Exception\ProviderException();
3078
+                }
3079
+
3080
+                return $roomShareProvider;
3081
+            });
3082
+
3083
+        $roomShareProvider->expects($this->once())
3084
+            ->method('getShareByToken')
3085
+            ->with('token')
3086
+            ->willReturn($share);
3087
+
3088
+        $ret = $manager->getShareByToken('token');
3089
+        $this->assertSame($share, $ret);
3090
+    }
3091
+
3092
+    public function testGetShareByTokenWithException(): void {
3093
+        $this->config
3094
+            ->expects($this->exactly(2))
3095
+            ->method('getAppValue')
3096
+            ->willReturnMap([
3097
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
3098
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3099
+            ]);
3100
+
3101
+        $factory = $this->createMock(IProviderFactory::class);
3102
+
3103
+        $manager = $this->createManager($factory);
3104
+
3105
+        $share = $this->createMock(IShare::class);
3106
+
3107
+        $calls = [
3108
+            [IShare::TYPE_LINK],
3109
+            [IShare::TYPE_REMOTE],
3110
+        ];
3111
+        $factory->expects($this->exactly(2))
3112
+            ->method('getProviderForType')
3113
+            ->willReturnCallback(function () use (&$calls) {
3114
+                $expected = array_shift($calls);
3115
+                $this->assertEquals($expected, func_get_args());
3116
+                return $this->defaultProvider;
3117
+            });
3118
+
3119
+        $this->defaultProvider->expects($this->exactly(2))
3120
+            ->method('getShareByToken')
3121
+            ->with('token')
3122
+            ->willReturnOnConsecutiveCalls(
3123
+                $this->throwException(new ShareNotFound()),
3124
+                $share
3125
+            );
3126
+
3127
+        $ret = $manager->getShareByToken('token');
3128
+        $this->assertSame($share, $ret);
3129
+    }
3130
+
3131
+
3132
+    public function testGetShareByTokenHideDisabledUser(): void {
3133
+        $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3134
+        $this->expectExceptionMessage('The requested share comes from a disabled user');
3135
+
3136
+        $this->config
3137
+            ->expects($this->exactly(2))
3138
+            ->method('getAppValue')
3139
+            ->willReturnMap([
3140
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
3141
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'yes'],
3142
+            ]);
3143
+
3144
+        $this->l->expects($this->once())
3145
+            ->method('t')
3146
+            ->willReturnArgument(0);
3147
+
3148
+        $manager = $this->createManagerMock()
3149
+            ->onlyMethods(['deleteShare'])
3150
+            ->getMock();
3151
+
3152
+        $date = new \DateTime();
3153
+        $date->setTime(0, 0, 0);
3154
+        $date->add(new \DateInterval('P2D'));
3155
+        $share = $this->manager->newShare();
3156
+        $share->setExpirationDate($date);
3157
+        $share->setShareOwner('owner');
3158
+        $share->setSharedBy('sharedBy');
3159
+
3160
+        $sharedBy = $this->createMock(IUser::class);
3161
+        $owner = $this->createMock(IUser::class);
3162
+
3163
+        $this->userManager->method('get')->willReturnMap([
3164
+            ['sharedBy', $sharedBy],
3165
+            ['owner', $owner],
3166
+        ]);
3167
+
3168
+        $owner->expects($this->once())
3169
+            ->method('isEnabled')
3170
+            ->willReturn(true);
3171
+        $sharedBy->expects($this->once())
3172
+            ->method('isEnabled')
3173
+            ->willReturn(false);
3174
+
3175
+        $this->defaultProvider->expects($this->once())
3176
+            ->method('getShareByToken')
3177
+            ->with('expiredToken')
3178
+            ->willReturn($share);
3179
+
3180
+        $manager->expects($this->never())
3181
+            ->method('deleteShare');
3182
+
3183
+        $manager->getShareByToken('expiredToken');
3184
+    }
3185
+
3186
+
3187
+    public function testGetShareByTokenExpired(): void {
3188
+        $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3189
+        $this->expectExceptionMessage('The requested share does not exist anymore');
3190
+
3191
+        $this->config
3192
+            ->expects($this->once())
3193
+            ->method('getAppValue')
3194
+            ->with('core', 'shareapi_allow_links', 'yes')
3195
+            ->willReturn('yes');
3196
+
3197
+        $this->l->expects($this->once())
3198
+            ->method('t')
3199
+            ->willReturnArgument(0);
3200
+
3201
+        $manager = $this->createManagerMock()
3202
+            ->onlyMethods(['deleteShare'])
3203
+            ->getMock();
3204
+
3205
+        $date = new \DateTime();
3206
+        $date->setTime(0, 0, 0);
3207
+        $share = $this->manager->newShare();
3208
+        $share->setExpirationDate($date);
3209
+
3210
+        $this->defaultProvider->expects($this->once())
3211
+            ->method('getShareByToken')
3212
+            ->with('expiredToken')
3213
+            ->willReturn($share);
3214
+
3215
+        $manager->expects($this->once())
3216
+            ->method('deleteShare')
3217
+            ->with($this->equalTo($share));
3218
+
3219
+        $manager->getShareByToken('expiredToken');
3220
+    }
3221
+
3222
+    public function testGetShareByTokenNotExpired(): void {
3223
+        $this->config
3224
+            ->expects($this->exactly(2))
3225
+            ->method('getAppValue')
3226
+            ->willReturnMap([
3227
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
3228
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3229
+            ]);
3230
+
3231
+        $date = new \DateTime();
3232
+        $date->setTime(0, 0, 0);
3233
+        $date->add(new \DateInterval('P2D'));
3234
+        $share = $this->manager->newShare();
3235
+        $share->setExpirationDate($date);
3236
+
3237
+        $this->defaultProvider->expects($this->once())
3238
+            ->method('getShareByToken')
3239
+            ->with('expiredToken')
3240
+            ->willReturn($share);
3241
+
3242
+        $res = $this->manager->getShareByToken('expiredToken');
3243
+
3244
+        $this->assertSame($share, $res);
3245
+    }
3246
+
3247
+
3248
+    public function testGetShareByTokenWithPublicLinksDisabled(): void {
3249
+        $this->expectException(\OCP\Share\Exceptions\ShareNotFound::class);
3250
+
3251
+        $this->config
3252
+            ->expects($this->once())
3253
+            ->method('getAppValue')
3254
+            ->with('core', 'shareapi_allow_links', 'yes')
3255
+            ->willReturn('no');
3256
+        $this->manager->getShareByToken('validToken');
3257
+    }
3258
+
3259
+    public function testGetShareByTokenPublicUploadDisabled(): void {
3260
+        $this->config
3261
+            ->expects($this->exactly(3))
3262
+            ->method('getAppValue')
3263
+            ->willReturnMap([
3264
+                ['core', 'shareapi_allow_links', 'yes', 'yes'],
3265
+                ['core', 'shareapi_allow_public_upload', 'yes', 'no'],
3266
+                ['files_sharing', 'hide_disabled_user_shares', 'no', 'no'],
3267
+            ]);
3268
+
3269
+        $share = $this->manager->newShare();
3270
+        $share->setShareType(IShare::TYPE_LINK)
3271
+            ->setPermissions(\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE);
3272
+        $share->setSharedWith('sharedWith');
3273
+        $folder = $this->createMock(\OC\Files\Node\Folder::class);
3274
+        $share->setNode($folder);
3275
+
3276
+        $this->defaultProvider->expects($this->once())
3277
+            ->method('getShareByToken')
3278
+            ->willReturn('validToken')
3279
+            ->willReturn($share);
3280
+
3281
+        $res = $this->manager->getShareByToken('validToken');
3282
+
3283
+        $this->assertSame(\OCP\Constants::PERMISSION_READ, $res->getPermissions());
3284
+    }
3285
+
3286
+    public function testCheckPasswordNoLinkShare(): void {
3287
+        $share = $this->createMock(IShare::class);
3288
+        $share->method('getShareType')->willReturn(IShare::TYPE_USER);
3289
+        $this->assertFalse($this->manager->checkPassword($share, 'password'));
3290
+    }
3291
+
3292
+    public function testCheckPasswordNoPassword(): void {
3293
+        $share = $this->createMock(IShare::class);
3294
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3295
+        $this->assertFalse($this->manager->checkPassword($share, 'password'));
3296
+
3297
+        $share->method('getPassword')->willReturn('password');
3298
+        $this->assertFalse($this->manager->checkPassword($share, null));
3299
+    }
3300
+
3301
+    public function testCheckPasswordInvalidPassword(): void {
3302
+        $share = $this->createMock(IShare::class);
3303
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3304
+        $share->method('getPassword')->willReturn('password');
3305
+
3306
+        $this->hasher->method('verify')->with('invalidpassword', 'password', '')->willReturn(false);
3307
+
3308
+        $this->assertFalse($this->manager->checkPassword($share, 'invalidpassword'));
3309
+    }
3310
+
3311
+    public function testCheckPasswordValidPassword(): void {
3312
+        $share = $this->createMock(IShare::class);
3313
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
3314
+        $share->method('getPassword')->willReturn('passwordHash');
3315
+
3316
+        $this->hasher->method('verify')->with('password', 'passwordHash', '')->willReturn(true);
3317
+
3318
+        $this->assertTrue($this->manager->checkPassword($share, 'password'));
3319
+    }
3320
+
3321
+    public function testCheckPasswordUpdateShare(): void {
3322
+        $share = $this->manager->newShare();
3323
+        $share->setShareType(IShare::TYPE_LINK)
3324
+            ->setPassword('passwordHash');
3325
+
3326
+        $this->hasher->method('verify')->with('password', 'passwordHash', '')
3327
+            ->willReturnCallback(function ($pass, $hash, &$newHash) {
3328
+                $newHash = 'newHash';
3329
+
3330
+                return true;
3331
+            });
3332
+
3333
+        $this->defaultProvider->expects($this->once())
3334
+            ->method('update')
3335
+            ->with($this->callback(function (\OCP\Share\IShare $share) {
3336
+                return $share->getPassword() === 'newHash';
3337
+            }));
3338
+
3339
+        $this->assertTrue($this->manager->checkPassword($share, 'password'));
3340
+    }
3341
+
3342
+
3343
+    public function testUpdateShareCantChangeShareType(): void {
3344
+        $this->expectException(\Exception::class);
3345
+        $this->expectExceptionMessage('Cannot change share type');
3346
+
3347
+        $manager = $this->createManagerMock()
3348
+            ->onlyMethods([
3349
+                'canShare',
3350
+                'getShareById'
3351
+            ])
3352
+            ->getMock();
3353
+
3354
+        $originalShare = $this->manager->newShare();
3355
+        $originalShare->setShareType(IShare::TYPE_GROUP);
3356
+
3357
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3358
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3359
+
3360
+        $share = $this->manager->newShare();
3361
+        $attrs = $this->manager->newShare()->newAttributes();
3362
+        $attrs->setAttribute('app1', 'perm1', true);
3363
+        $share->setProviderId('foo')
3364
+            ->setId('42')
3365
+            ->setShareType(IShare::TYPE_USER);
3366
+
3367
+        $manager->updateShare($share);
3368
+    }
3369
+
3370
+
3371
+    public function testUpdateShareCantChangeRecipientForGroupShare(): void {
3372
+        $this->expectException(\Exception::class);
3373
+        $this->expectExceptionMessage('Can only update recipient on user shares');
3374
+
3375
+        $manager = $this->createManagerMock()
3376
+            ->onlyMethods([
3377
+                'canShare',
3378
+                'getShareById'
3379
+            ])
3380
+            ->getMock();
3381
+
3382
+        $originalShare = $this->manager->newShare();
3383
+        $originalShare->setShareType(IShare::TYPE_GROUP)
3384
+            ->setSharedWith('origGroup');
3385
+
3386
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3387
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3388
+
3389
+        $share = $this->manager->newShare();
3390
+        $share->setProviderId('foo')
3391
+            ->setId('42')
3392
+            ->setShareType(IShare::TYPE_GROUP)
3393
+            ->setSharedWith('newGroup');
3394
+
3395
+        $manager->updateShare($share);
3396
+    }
3397
+
3398
+
3399
+    public function testUpdateShareCantShareWithOwner(): void {
3400
+        $this->expectException(\Exception::class);
3401
+        $this->expectExceptionMessage('Cannot share with the share owner');
3402
+
3403
+        $manager = $this->createManagerMock()
3404
+            ->onlyMethods([
3405
+                'canShare',
3406
+                'getShareById'
3407
+            ])
3408
+            ->getMock();
3409
+
3410
+        $originalShare = $this->manager->newShare();
3411
+        $originalShare->setShareType(IShare::TYPE_USER)
3412
+            ->setSharedWith('sharedWith');
3413
+
3414
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3415
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3416
+
3417
+        $share = $this->manager->newShare();
3418
+        $share->setProviderId('foo')
3419
+            ->setId('42')
3420
+            ->setShareType(IShare::TYPE_USER)
3421
+            ->setSharedWith('newUser')
3422
+            ->setShareOwner('newUser');
3423
+
3424
+        $manager->updateShare($share);
3425
+    }
3426
+
3427
+    public function testUpdateShareUser(): void {
3428
+        $this->userManager->expects($this->any())->method('userExists')->willReturn(true);
3429
+
3430
+        $manager = $this->createManagerMock()
3431
+            ->onlyMethods([
3432
+                'canShare',
3433
+                'getShareById',
3434
+                'generalCreateChecks',
3435
+                'userCreateChecks',
3436
+                'pathCreateChecks',
3437
+            ])
3438
+            ->getMock();
3439
+
3440
+        $originalShare = $this->manager->newShare();
3441
+        $originalShare->setShareType(IShare::TYPE_USER)
3442
+            ->setSharedWith('origUser')
3443
+            ->setPermissions(1);
3444
+
3445
+        $node = $this->createMock(File::class);
3446
+        $node->method('getId')->willReturn(100);
3447
+        $node->method('getPath')->willReturn('/newUser/files/myPath');
3448
+
3449
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3450
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3451
+
3452
+        $share = $this->manager->newShare();
3453
+        $attrs = $this->manager->newShare()->newAttributes();
3454
+        $attrs->setAttribute('app1', 'perm1', true);
3455
+        $share->setProviderId('foo')
3456
+            ->setId('42')
3457
+            ->setShareType(IShare::TYPE_USER)
3458
+            ->setSharedWith('origUser')
3459
+            ->setShareOwner('newUser')
3460
+            ->setSharedBy('sharer')
3461
+            ->setPermissions(31)
3462
+            ->setAttributes($attrs)
3463
+            ->setNode($node);
3464
+
3465
+        $this->defaultProvider->expects($this->once())
3466
+            ->method('update')
3467
+            ->with($share)
3468
+            ->willReturn($share);
3469
+
3470
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3471
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3472
+        $hookListener->expects($this->never())->method('post');
3473
+
3474
+        $this->rootFolder->method('getUserFolder')->with('newUser')->willReturnSelf();
3475
+        $this->rootFolder->method('getRelativePath')->with('/newUser/files/myPath')->willReturn('/myPath');
3476
+
3477
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3478
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post');
3479
+        $hookListener2->expects($this->once())->method('post')->with([
3480
+            'itemType' => 'file',
3481
+            'itemSource' => 100,
3482
+            'shareType' => IShare::TYPE_USER,
3483
+            'shareWith' => 'origUser',
3484
+            'uidOwner' => 'sharer',
3485
+            'permissions' => 31,
3486
+            'path' => '/myPath',
3487
+            'attributes' => $attrs->toArray(),
3488
+        ]);
3489
+
3490
+        $manager->updateShare($share);
3491
+    }
3492
+
3493
+    public function testUpdateShareGroup(): void {
3494
+        $manager = $this->createManagerMock()
3495
+            ->onlyMethods([
3496
+                'canShare',
3497
+                'getShareById',
3498
+                'generalCreateChecks',
3499
+                'groupCreateChecks',
3500
+                'pathCreateChecks',
3501
+            ])
3502
+            ->getMock();
3503
+
3504
+        $originalShare = $this->manager->newShare();
3505
+        $originalShare->setShareType(IShare::TYPE_GROUP)
3506
+            ->setSharedWith('origUser')
3507
+            ->setPermissions(31);
3508
+
3509
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3510
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3511
+
3512
+        $node = $this->createMock(File::class);
3513
+
3514
+        $share = $this->manager->newShare();
3515
+        $share->setProviderId('foo')
3516
+            ->setId('42')
3517
+            ->setShareType(IShare::TYPE_GROUP)
3518
+            ->setSharedWith('origUser')
3519
+            ->setShareOwner('owner')
3520
+            ->setNode($node)
3521
+            ->setPermissions(31);
3522
+
3523
+        $this->defaultProvider->expects($this->once())
3524
+            ->method('update')
3525
+            ->with($share)
3526
+            ->willReturn($share);
3527
+
3528
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3529
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3530
+        $hookListener->expects($this->never())->method('post');
3531
+
3532
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3533
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener2, 'post');
3534
+        $hookListener2->expects($this->never())->method('post');
3535
+
3536
+        $manager->updateShare($share);
3537
+    }
3538
+
3539
+    public function testUpdateShareLink(): void {
3540
+        $manager = $this->createManagerMock()
3541
+            ->onlyMethods([
3542
+                'canShare',
3543
+                'getShareById',
3544
+                'generalCreateChecks',
3545
+                'linkCreateChecks',
3546
+                'pathCreateChecks',
3547
+                'verifyPassword',
3548
+                'validateExpirationDateLink',
3549
+            ])
3550
+            ->getMock();
3551
+
3552
+        $originalShare = $this->manager->newShare();
3553
+        $originalShare->setShareType(IShare::TYPE_LINK)
3554
+            ->setPermissions(15);
3555
+
3556
+        $tomorrow = new \DateTime();
3557
+        $tomorrow->setTime(0, 0, 0);
3558
+        $tomorrow->add(new \DateInterval('P1D'));
3559
+
3560
+        $file = $this->createMock(File::class);
3561
+        $file->method('getId')->willReturn(100);
3562
+
3563
+        $share = $this->manager->newShare();
3564
+        $share->setProviderId('foo')
3565
+            ->setId('42')
3566
+            ->setShareType(IShare::TYPE_LINK)
3567
+            ->setToken('token')
3568
+            ->setSharedBy('owner')
3569
+            ->setShareOwner('owner')
3570
+            ->setPassword('password')
3571
+            ->setExpirationDate($tomorrow)
3572
+            ->setNode($file)
3573
+            ->setPermissions(15);
3574
+
3575
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3576
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3577
+        $manager->expects($this->once())->method('validateExpirationDateLink')->with($share);
3578
+        $manager->expects($this->once())->method('verifyPassword')->with('password');
3579
+
3580
+        $this->hasher->expects($this->once())
3581
+            ->method('hash')
3582
+            ->with('password')
3583
+            ->willReturn('hashed');
3584
+
3585
+        $this->defaultProvider->expects($this->once())
3586
+            ->method('update')
3587
+            ->with($share)
3588
+            ->willReturn($share);
3589
+
3590
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3591
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3592
+        $hookListener->expects($this->once())->method('post')->with([
3593
+            'itemType' => 'file',
3594
+            'itemSource' => 100,
3595
+            'date' => $tomorrow,
3596
+            'uidOwner' => 'owner',
3597
+        ]);
3598
+
3599
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3600
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3601
+        $hookListener2->expects($this->once())->method('post')->with([
3602
+            'itemType' => 'file',
3603
+            'itemSource' => 100,
3604
+            'uidOwner' => 'owner',
3605
+            'token' => 'token',
3606
+            'disabled' => false,
3607
+        ]);
3608
+
3609
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
3610
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3611
+        $hookListener3->expects($this->never())->method('post');
3612
+
3613
+
3614
+        $manager->updateShare($share);
3615
+    }
3616
+
3617
+    public function testUpdateShareLinkEnableSendPasswordByTalkWithNoPassword(): void {
3618
+        $this->expectException(\InvalidArgumentException::class);
3619
+        $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
3620
+
3621
+        $manager = $this->createManagerMock()
3622
+            ->onlyMethods([
3623
+                'canShare',
3624
+                'getShareById',
3625
+                'generalCreateChecks',
3626
+                'linkCreateChecks',
3627
+                'pathCreateChecks',
3628
+                'verifyPassword',
3629
+                'validateExpirationDateLink',
3630
+            ])
3631
+            ->getMock();
3632
+
3633
+        $originalShare = $this->manager->newShare();
3634
+        $originalShare->setShareType(IShare::TYPE_LINK)
3635
+            ->setPermissions(15);
3636
+
3637
+        $tomorrow = new \DateTime();
3638
+        $tomorrow->setTime(0, 0, 0);
3639
+        $tomorrow->add(new \DateInterval('P1D'));
3640
+
3641
+        $file = $this->createMock(File::class);
3642
+        $file->method('getId')->willReturn(100);
3643
+
3644
+        $share = $this->manager->newShare();
3645
+        $share->setProviderId('foo')
3646
+            ->setId('42')
3647
+            ->setShareType(IShare::TYPE_LINK)
3648
+            ->setToken('token')
3649
+            ->setSharedBy('owner')
3650
+            ->setShareOwner('owner')
3651
+            ->setPassword(null)
3652
+            ->setSendPasswordByTalk(true)
3653
+            ->setExpirationDate($tomorrow)
3654
+            ->setNode($file)
3655
+            ->setPermissions(15);
3656
+
3657
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3658
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3659
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
3660
+        $manager->expects($this->once())->method('linkCreateChecks')->with($share);
3661
+        $manager->expects($this->never())->method('verifyPassword');
3662
+        $manager->expects($this->never())->method('pathCreateChecks');
3663
+        $manager->expects($this->never())->method('validateExpirationDateLink');
3664
+
3665
+        $this->hasher->expects($this->never())
3666
+            ->method('hash');
3667
+
3668
+        $this->defaultProvider->expects($this->never())
3669
+            ->method('update');
3670
+
3671
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3672
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3673
+        $hookListener->expects($this->never())->method('post');
3674
+
3675
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3676
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3677
+        $hookListener2->expects($this->never())->method('post');
3678
+
3679
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
3680
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3681
+        $hookListener3->expects($this->never())->method('post');
3682
+
3683
+        $manager->updateShare($share);
3684
+    }
3685
+
3686
+    public function testUpdateShareMail(): void {
3687
+        $manager = $this->createManagerMock()
3688
+            ->onlyMethods([
3689
+                'canShare',
3690
+                'getShareById',
3691
+                'generalCreateChecks',
3692
+                'verifyPassword',
3693
+                'pathCreateChecks',
3694
+                'linkCreateChecks',
3695
+                'validateExpirationDateLink',
3696
+            ])
3697
+            ->getMock();
3698
+
3699
+        $originalShare = $this->manager->newShare();
3700
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
3701
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
3702
+
3703
+        $tomorrow = new \DateTime();
3704
+        $tomorrow->setTime(0, 0, 0);
3705
+        $tomorrow->add(new \DateInterval('P1D'));
3706
+
3707
+        $file = $this->createMock(File::class);
3708
+        $file->method('getId')->willReturn(100);
3709
+
3710
+        $share = $this->manager->newShare();
3711
+        $share->setProviderId('foo')
3712
+            ->setId('42')
3713
+            ->setShareType(IShare::TYPE_EMAIL)
3714
+            ->setToken('token')
3715
+            ->setSharedBy('owner')
3716
+            ->setShareOwner('owner')
3717
+            ->setPassword('password')
3718
+            ->setExpirationDate($tomorrow)
3719
+            ->setNode($file)
3720
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
3721
+
3722
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3723
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3724
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
3725
+        $manager->expects($this->once())->method('verifyPassword')->with('password');
3726
+        $manager->expects($this->once())->method('pathCreateChecks')->with($file);
3727
+        $manager->expects($this->once())->method('linkCreateChecks');
3728
+        $manager->expects($this->once())->method('validateExpirationDateLink');
3729
+
3730
+        $this->hasher->expects($this->once())
3731
+            ->method('hash')
3732
+            ->with('password')
3733
+            ->willReturn('hashed');
3734
+
3735
+        $this->defaultProvider->expects($this->once())
3736
+            ->method('update')
3737
+            ->with($share, 'password')
3738
+            ->willReturn($share);
3739
+
3740
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3741
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3742
+        $hookListener->expects($this->once())->method('post')->with([
3743
+            'itemType' => 'file',
3744
+            'itemSource' => 100,
3745
+            'date' => $tomorrow,
3746
+            'uidOwner' => 'owner',
3747
+        ]);
3748
+
3749
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3750
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3751
+        $hookListener2->expects($this->once())->method('post')->with([
3752
+            'itemType' => 'file',
3753
+            'itemSource' => 100,
3754
+            'uidOwner' => 'owner',
3755
+            'token' => 'token',
3756
+            'disabled' => false,
3757
+        ]);
3758
+
3759
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
3760
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3761
+        $hookListener3->expects($this->never())->method('post');
3762
+
3763
+        $manager->updateShare($share);
3764
+    }
3765
+
3766
+    public function testUpdateShareMailEnableSendPasswordByTalk(): void {
3767
+        $manager = $this->createManagerMock()
3768
+            ->onlyMethods([
3769
+                'canShare',
3770
+                'getShareById',
3771
+                'generalCreateChecks',
3772
+                'verifyPassword',
3773
+                'pathCreateChecks',
3774
+                'linkCreateChecks',
3775
+                'validateExpirationDateLink',
3776
+            ])
3777
+            ->getMock();
3778
+
3779
+        $originalShare = $this->manager->newShare();
3780
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
3781
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
3782
+            ->setPassword(null)
3783
+            ->setSendPasswordByTalk(false);
3784
+
3785
+        $tomorrow = new \DateTime();
3786
+        $tomorrow->setTime(0, 0, 0);
3787
+        $tomorrow->add(new \DateInterval('P1D'));
3788
+
3789
+        $file = $this->createMock(File::class);
3790
+        $file->method('getId')->willReturn(100);
3791
+
3792
+        $share = $this->manager->newShare();
3793
+        $share->setProviderId('foo')
3794
+            ->setId('42')
3795
+            ->setShareType(IShare::TYPE_EMAIL)
3796
+            ->setToken('token')
3797
+            ->setSharedBy('owner')
3798
+            ->setShareOwner('owner')
3799
+            ->setPassword('password')
3800
+            ->setSendPasswordByTalk(true)
3801
+            ->setExpirationDate($tomorrow)
3802
+            ->setNode($file)
3803
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
3804
+
3805
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3806
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3807
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
3808
+        $manager->expects($this->once())->method('verifyPassword')->with('password');
3809
+        $manager->expects($this->once())->method('pathCreateChecks')->with($file);
3810
+        $manager->expects($this->once())->method('linkCreateChecks');
3811
+        $manager->expects($this->once())->method('validateExpirationDateLink');
3812
+
3813
+        $this->hasher->expects($this->once())
3814
+            ->method('hash')
3815
+            ->with('password')
3816
+            ->willReturn('hashed');
3817
+
3818
+        $this->defaultProvider->expects($this->once())
3819
+            ->method('update')
3820
+            ->with($share, 'password')
3821
+            ->willReturn($share);
3822
+
3823
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3824
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3825
+        $hookListener->expects($this->once())->method('post')->with([
3826
+            'itemType' => 'file',
3827
+            'itemSource' => 100,
3828
+            'date' => $tomorrow,
3829
+            'uidOwner' => 'owner',
3830
+        ]);
3831
+
3832
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3833
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3834
+        $hookListener2->expects($this->once())->method('post')->with([
3835
+            'itemType' => 'file',
3836
+            'itemSource' => 100,
3837
+            'uidOwner' => 'owner',
3838
+            'token' => 'token',
3839
+            'disabled' => false,
3840
+        ]);
3841
+
3842
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
3843
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3844
+        $hookListener3->expects($this->never())->method('post');
3845
+
3846
+        $manager->updateShare($share);
3847
+    }
3848
+
3849
+    public function testUpdateShareMailEnableSendPasswordByTalkWithDifferentPassword(): void {
3850
+        $manager = $this->createManagerMock()
3851
+            ->onlyMethods([
3852
+                'canShare',
3853
+                'getShareById',
3854
+                'generalCreateChecks',
3855
+                'verifyPassword',
3856
+                'pathCreateChecks',
3857
+                'linkCreateChecks',
3858
+                'validateExpirationDateLink',
3859
+            ])
3860
+            ->getMock();
3861
+
3862
+        $originalShare = $this->manager->newShare();
3863
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
3864
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
3865
+            ->setPassword('anotherPasswordHash')
3866
+            ->setSendPasswordByTalk(false);
3867
+
3868
+        $tomorrow = new \DateTime();
3869
+        $tomorrow->setTime(0, 0, 0);
3870
+        $tomorrow->add(new \DateInterval('P1D'));
3871
+
3872
+        $file = $this->createMock(File::class);
3873
+        $file->method('getId')->willReturn(100);
3874
+
3875
+        $share = $this->manager->newShare();
3876
+        $share->setProviderId('foo')
3877
+            ->setId('42')
3878
+            ->setShareType(IShare::TYPE_EMAIL)
3879
+            ->setToken('token')
3880
+            ->setSharedBy('owner')
3881
+            ->setShareOwner('owner')
3882
+            ->setPassword('password')
3883
+            ->setSendPasswordByTalk(true)
3884
+            ->setExpirationDate($tomorrow)
3885
+            ->setNode($file)
3886
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
3887
+
3888
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3889
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3890
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
3891
+        $manager->expects($this->once())->method('verifyPassword')->with('password');
3892
+        $manager->expects($this->once())->method('pathCreateChecks')->with($file);
3893
+        $manager->expects($this->once())->method('linkCreateChecks');
3894
+        $manager->expects($this->once())->method('validateExpirationDateLink');
3895
+
3896
+        $this->hasher->expects($this->once())
3897
+            ->method('verify')
3898
+            ->with('password', 'anotherPasswordHash')
3899
+            ->willReturn(false);
3900
+
3901
+        $this->hasher->expects($this->once())
3902
+            ->method('hash')
3903
+            ->with('password')
3904
+            ->willReturn('hashed');
3905
+
3906
+        $this->defaultProvider->expects($this->once())
3907
+            ->method('update')
3908
+            ->with($share, 'password')
3909
+            ->willReturn($share);
3910
+
3911
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3912
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3913
+        $hookListener->expects($this->once())->method('post')->with([
3914
+            'itemType' => 'file',
3915
+            'itemSource' => 100,
3916
+            'date' => $tomorrow,
3917
+            'uidOwner' => 'owner',
3918
+        ]);
3919
+
3920
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3921
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
3922
+        $hookListener2->expects($this->once())->method('post')->with([
3923
+            'itemType' => 'file',
3924
+            'itemSource' => 100,
3925
+            'uidOwner' => 'owner',
3926
+            'token' => 'token',
3927
+            'disabled' => false,
3928
+        ]);
3929
+
3930
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
3931
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
3932
+        $hookListener3->expects($this->never())->method('post');
3933
+
3934
+        $manager->updateShare($share);
3935
+    }
3936
+
3937
+    public function testUpdateShareMailEnableSendPasswordByTalkWithNoPassword(): void {
3938
+        $this->expectException(\InvalidArgumentException::class);
3939
+        $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
3940
+
3941
+        $manager = $this->createManagerMock()
3942
+            ->onlyMethods([
3943
+                'canShare',
3944
+                'getShareById',
3945
+                'generalCreateChecks',
3946
+                'verifyPassword',
3947
+                'pathCreateChecks',
3948
+                'linkCreateChecks',
3949
+                'validateExpirationDateLink',
3950
+            ])
3951
+            ->getMock();
3952
+
3953
+        $originalShare = $this->manager->newShare();
3954
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
3955
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
3956
+            ->setPassword(null)
3957
+            ->setSendPasswordByTalk(false);
3958
+
3959
+        $tomorrow = new \DateTime();
3960
+        $tomorrow->setTime(0, 0, 0);
3961
+        $tomorrow->add(new \DateInterval('P1D'));
3962
+
3963
+        $file = $this->createMock(File::class);
3964
+        $file->method('getId')->willReturn(100);
3965
+
3966
+        $share = $this->manager->newShare();
3967
+        $share->setProviderId('foo')
3968
+            ->setId('42')
3969
+            ->setShareType(IShare::TYPE_EMAIL)
3970
+            ->setToken('token')
3971
+            ->setSharedBy('owner')
3972
+            ->setShareOwner('owner')
3973
+            ->setPassword(null)
3974
+            ->setSendPasswordByTalk(true)
3975
+            ->setExpirationDate($tomorrow)
3976
+            ->setNode($file)
3977
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
3978
+
3979
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
3980
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
3981
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
3982
+        $manager->expects($this->never())->method('verifyPassword');
3983
+        $manager->expects($this->never())->method('pathCreateChecks');
3984
+        $manager->expects($this->once())->method('linkCreateChecks');
3985
+        $manager->expects($this->never())->method('validateExpirationDateLink');
3986
+
3987
+        // If the password is empty, we have nothing to hash
3988
+        $this->hasher->expects($this->never())
3989
+            ->method('hash');
3990
+
3991
+        $this->defaultProvider->expects($this->never())
3992
+            ->method('update');
3993
+
3994
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
3995
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
3996
+        $hookListener->expects($this->never())->method('post');
3997
+
3998
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
3999
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4000
+        $hookListener2->expects($this->never())->method('post');
4001
+
4002
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4003
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4004
+        $hookListener3->expects($this->never())->method('post');
4005
+
4006
+        $manager->updateShare($share);
4007
+    }
4008
+
4009
+
4010
+    public function testUpdateShareMailEnableSendPasswordByTalkRemovingPassword(): void {
4011
+        $this->expectException(\InvalidArgumentException::class);
4012
+        $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
4013
+
4014
+        $manager = $this->createManagerMock()
4015
+            ->onlyMethods([
4016
+                'canShare',
4017
+                'getShareById',
4018
+                'generalCreateChecks',
4019
+                'verifyPassword',
4020
+                'pathCreateChecks',
4021
+                'linkCreateChecks',
4022
+                'validateExpirationDateLink',
4023
+            ])
4024
+            ->getMock();
4025
+
4026
+        $originalShare = $this->manager->newShare();
4027
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
4028
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
4029
+            ->setPassword('passwordHash')
4030
+            ->setSendPasswordByTalk(false);
4031
+
4032
+        $tomorrow = new \DateTime();
4033
+        $tomorrow->setTime(0, 0, 0);
4034
+        $tomorrow->add(new \DateInterval('P1D'));
4035
+
4036
+        $file = $this->createMock(File::class);
4037
+        $file->method('getId')->willReturn(100);
4038
+
4039
+        $share = $this->manager->newShare();
4040
+        $share->setProviderId('foo')
4041
+            ->setId('42')
4042
+            ->setShareType(IShare::TYPE_EMAIL)
4043
+            ->setToken('token')
4044
+            ->setSharedBy('owner')
4045
+            ->setShareOwner('owner')
4046
+            ->setPassword(null)
4047
+            ->setSendPasswordByTalk(true)
4048
+            ->setExpirationDate($tomorrow)
4049
+            ->setNode($file)
4050
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
4051
+
4052
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
4053
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4054
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
4055
+        $manager->expects($this->once())->method('verifyPassword');
4056
+        $manager->expects($this->never())->method('pathCreateChecks');
4057
+        $manager->expects($this->once())->method('linkCreateChecks');
4058
+        $manager->expects($this->never())->method('validateExpirationDateLink');
4059
+
4060
+        // If the password is empty, we have nothing to hash
4061
+        $this->hasher->expects($this->never())
4062
+            ->method('hash');
4063
+
4064
+        $this->defaultProvider->expects($this->never())
4065
+            ->method('update');
4066
+
4067
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
4068
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4069
+        $hookListener->expects($this->never())->method('post');
4070
+
4071
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
4072
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4073
+        $hookListener2->expects($this->never())->method('post');
4074
+
4075
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4076
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4077
+        $hookListener3->expects($this->never())->method('post');
4078
+
4079
+        $manager->updateShare($share);
4080
+    }
4081
+
4082
+
4083
+    public function testUpdateShareMailEnableSendPasswordByTalkRemovingPasswordWithEmptyString(): void {
4084
+        $this->expectException(\InvalidArgumentException::class);
4085
+        $this->expectExceptionMessage('Cannot enable sending the password by Talk with an empty password');
4086
+
4087
+        $manager = $this->createManagerMock()
4088
+            ->onlyMethods([
4089
+                'canShare',
4090
+                'getShareById',
4091
+                'generalCreateChecks',
4092
+                'verifyPassword',
4093
+                'pathCreateChecks',
4094
+                'linkCreateChecks',
4095
+                'validateExpirationDateLink',
4096
+            ])
4097
+            ->getMock();
4098
+
4099
+        $originalShare = $this->manager->newShare();
4100
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
4101
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
4102
+            ->setPassword('passwordHash')
4103
+            ->setSendPasswordByTalk(false);
4104
+
4105
+        $tomorrow = new \DateTime();
4106
+        $tomorrow->setTime(0, 0, 0);
4107
+        $tomorrow->add(new \DateInterval('P1D'));
4108
+
4109
+        $file = $this->createMock(File::class);
4110
+        $file->method('getId')->willReturn(100);
4111
+
4112
+        $share = $this->manager->newShare();
4113
+        $share->setProviderId('foo')
4114
+            ->setId('42')
4115
+            ->setShareType(IShare::TYPE_EMAIL)
4116
+            ->setToken('token')
4117
+            ->setSharedBy('owner')
4118
+            ->setShareOwner('owner')
4119
+            ->setPassword('')
4120
+            ->setSendPasswordByTalk(true)
4121
+            ->setExpirationDate($tomorrow)
4122
+            ->setNode($file)
4123
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
4124
+
4125
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
4126
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4127
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
4128
+        $manager->expects($this->once())->method('verifyPassword');
4129
+        $manager->expects($this->never())->method('pathCreateChecks');
4130
+        $manager->expects($this->once())->method('linkCreateChecks');
4131
+        $manager->expects($this->never())->method('validateExpirationDateLink');
4132
+
4133
+        // If the password is empty, we have nothing to hash
4134
+        $this->hasher->expects($this->never())
4135
+            ->method('hash');
4136
+
4137
+        $this->defaultProvider->expects($this->never())
4138
+            ->method('update');
4139
+
4140
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
4141
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4142
+        $hookListener->expects($this->never())->method('post');
4143
+
4144
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
4145
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4146
+        $hookListener2->expects($this->never())->method('post');
4147
+
4148
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4149
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4150
+        $hookListener3->expects($this->never())->method('post');
4151
+
4152
+        $manager->updateShare($share);
4153
+    }
4154
+
4155
+
4156
+    public function testUpdateShareMailEnableSendPasswordByTalkWithPreviousPassword(): void {
4157
+        $this->expectException(\InvalidArgumentException::class);
4158
+        $this->expectExceptionMessage('Cannot enable sending the password by Talk without setting a new password');
4159
+
4160
+        $manager = $this->createManagerMock()
4161
+            ->onlyMethods([
4162
+                'canShare',
4163
+                'getShareById',
4164
+                'generalCreateChecks',
4165
+                'verifyPassword',
4166
+                'pathCreateChecks',
4167
+                'linkCreateChecks',
4168
+                'validateExpirationDateLink',
4169
+            ])
4170
+            ->getMock();
4171
+
4172
+        $originalShare = $this->manager->newShare();
4173
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
4174
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
4175
+            ->setPassword('password')
4176
+            ->setSendPasswordByTalk(false);
4177
+
4178
+        $tomorrow = new \DateTime();
4179
+        $tomorrow->setTime(0, 0, 0);
4180
+        $tomorrow->add(new \DateInterval('P1D'));
4181
+
4182
+        $file = $this->createMock(File::class);
4183
+        $file->method('getId')->willReturn(100);
4184
+
4185
+        $share = $this->manager->newShare();
4186
+        $share->setProviderId('foo')
4187
+            ->setId('42')
4188
+            ->setShareType(IShare::TYPE_EMAIL)
4189
+            ->setToken('token')
4190
+            ->setSharedBy('owner')
4191
+            ->setShareOwner('owner')
4192
+            ->setPassword('password')
4193
+            ->setSendPasswordByTalk(true)
4194
+            ->setExpirationDate($tomorrow)
4195
+            ->setNode($file)
4196
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
4197
+
4198
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
4199
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4200
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
4201
+        $manager->expects($this->never())->method('verifyPassword');
4202
+        $manager->expects($this->never())->method('pathCreateChecks');
4203
+        $manager->expects($this->once())->method('linkCreateChecks');
4204
+        $manager->expects($this->never())->method('validateExpirationDateLink');
4205
+
4206
+        // If the old & new passwords are the same, we don't do anything
4207
+        $this->hasher->expects($this->never())
4208
+            ->method('verify');
4209
+        $this->hasher->expects($this->never())
4210
+            ->method('hash');
4211
+
4212
+        $this->defaultProvider->expects($this->never())
4213
+            ->method('update');
4214
+
4215
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
4216
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4217
+        $hookListener->expects($this->never())->method('post');
4218
+
4219
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
4220
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4221
+        $hookListener2->expects($this->never())->method('post');
4222
+
4223
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4224
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4225
+        $hookListener3->expects($this->never())->method('post');
4226
+
4227
+        $manager->updateShare($share);
4228
+    }
4229
+
4230
+    public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword(): void {
4231
+        $this->expectException(\InvalidArgumentException::class);
4232
+        $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password');
4233
+
4234
+        $manager = $this->createManagerMock()
4235
+            ->onlyMethods([
4236
+                'canShare',
4237
+                'getShareById',
4238
+                'generalCreateChecks',
4239
+                'verifyPassword',
4240
+                'pathCreateChecks',
4241
+                'linkCreateChecks',
4242
+                'validateExpirationDateLink',
4243
+            ])
4244
+            ->getMock();
4245
+
4246
+        $originalShare = $this->manager->newShare();
4247
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
4248
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
4249
+            ->setPassword('passwordHash')
4250
+            ->setSendPasswordByTalk(true);
4251
+
4252
+        $tomorrow = new \DateTime();
4253
+        $tomorrow->setTime(0, 0, 0);
4254
+        $tomorrow->add(new \DateInterval('P1D'));
4255
+
4256
+        $file = $this->createMock(File::class);
4257
+        $file->method('getId')->willReturn(100);
4258
+
4259
+        $share = $this->manager->newShare();
4260
+        $share->setProviderId('foo')
4261
+            ->setId('42')
4262
+            ->setShareType(IShare::TYPE_EMAIL)
4263
+            ->setToken('token')
4264
+            ->setSharedBy('owner')
4265
+            ->setShareOwner('owner')
4266
+            ->setPassword('passwordHash')
4267
+            ->setSendPasswordByTalk(false)
4268
+            ->setExpirationDate($tomorrow)
4269
+            ->setNode($file)
4270
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
4271
+
4272
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
4273
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4274
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
4275
+        $manager->expects($this->never())->method('verifyPassword');
4276
+        $manager->expects($this->never())->method('pathCreateChecks');
4277
+        $manager->expects($this->once())->method('linkCreateChecks');
4278
+        $manager->expects($this->never())->method('validateExpirationDateLink');
4279
+
4280
+        // If the old & new passwords are the same, we don't do anything
4281
+        $this->hasher->expects($this->never())
4282
+            ->method('verify');
4283
+        $this->hasher->expects($this->never())
4284
+            ->method('hash');
4285
+
4286
+        $this->defaultProvider->expects($this->never())
4287
+            ->method('update');
4288
+
4289
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
4290
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4291
+        $hookListener->expects($this->never())->method('post');
4292
+
4293
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
4294
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4295
+        $hookListener2->expects($this->never())->method('post');
4296
+
4297
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4298
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4299
+        $hookListener3->expects($this->never())->method('post');
4300
+
4301
+        $manager->updateShare($share);
4302
+    }
4303
+
4304
+    public function testUpdateShareMailDisableSendPasswordByTalkWithoutChangingPassword(): void {
4305
+        $this->expectException(\InvalidArgumentException::class);
4306
+        $this->expectExceptionMessage('Cannot disable sending the password by Talk without setting a new password');
4307
+
4308
+        $manager = $this->createManagerMock()
4309
+            ->onlyMethods([
4310
+                'canShare',
4311
+                'getShareById',
4312
+                'generalCreateChecks',
4313
+                'verifyPassword',
4314
+                'pathCreateChecks',
4315
+                'linkCreateChecks',
4316
+                'validateExpirationDateLink',
4317
+            ])
4318
+            ->getMock();
4319
+
4320
+        $originalShare = $this->manager->newShare();
4321
+        $originalShare->setShareType(IShare::TYPE_EMAIL)
4322
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL)
4323
+            ->setPassword('passwordHash')
4324
+            ->setSendPasswordByTalk(true);
4325
+
4326
+        $tomorrow = new \DateTime();
4327
+        $tomorrow->setTime(0, 0, 0);
4328
+        $tomorrow->add(new \DateInterval('P1D'));
4329
+
4330
+        $file = $this->createMock(File::class);
4331
+        $file->method('getId')->willReturn(100);
4332
+
4333
+        $share = $this->manager->newShare();
4334
+        $share->setProviderId('foo')
4335
+            ->setId('42')
4336
+            ->setShareType(IShare::TYPE_EMAIL)
4337
+            ->setToken('token')
4338
+            ->setSharedBy('owner')
4339
+            ->setShareOwner('owner')
4340
+            ->setPassword('passwordHash')
4341
+            ->setSendPasswordByTalk(false)
4342
+            ->setExpirationDate($tomorrow)
4343
+            ->setNode($file)
4344
+            ->setPermissions(\OCP\Constants::PERMISSION_ALL);
4345
+
4346
+        $manager->expects($this->once())->method('canShare')->willReturn(true);
4347
+        $manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
4348
+        $manager->expects($this->once())->method('generalCreateChecks')->with($share);
4349
+        $manager->expects($this->never())->method('verifyPassword');
4350
+        $manager->expects($this->never())->method('pathCreateChecks');
4351
+        $manager->expects($this->once())->method('linkCreateChecks');
4352
+        $manager->expects($this->never())->method('validateExpirationDateLink');
4353
+
4354
+        // If the old & new passwords are the same, we don't do anything
4355
+        $this->hasher->expects($this->never())
4356
+            ->method('verify');
4357
+        $this->hasher->expects($this->never())
4358
+            ->method('hash');
4359
+
4360
+        $this->defaultProvider->expects($this->never())
4361
+            ->method('update');
4362
+
4363
+        $hookListener = $this->createMock(DummyShareManagerListener::class);
4364
+        \OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListener, 'post');
4365
+        $hookListener->expects($this->never())->method('post');
4366 4366
 
4367
-		$hookListener2 = $this->createMock(DummyShareManagerListener::class);
4368
-		\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4369
-		$hookListener2->expects($this->never())->method('post');
4367
+        $hookListener2 = $this->createMock(DummyShareManagerListener::class);
4368
+        \OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListener2, 'post');
4369
+        $hookListener2->expects($this->never())->method('post');
4370 4370
 
4371
-		$hookListener3 = $this->createMock(DummyShareManagerListener::class);
4372
-		\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4373
-		$hookListener3->expects($this->never())->method('post');
4371
+        $hookListener3 = $this->createMock(DummyShareManagerListener::class);
4372
+        \OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListener3, 'post');
4373
+        $hookListener3->expects($this->never())->method('post');
4374 4374
 
4375
-		$manager->updateShare($share);
4376
-	}
4375
+        $manager->updateShare($share);
4376
+    }
4377 4377
 
4378
-	public function testMoveShareLink(): void {
4379
-		$this->expectException(\InvalidArgumentException::class);
4380
-		$this->expectExceptionMessage('Cannot change target of link share');
4378
+    public function testMoveShareLink(): void {
4379
+        $this->expectException(\InvalidArgumentException::class);
4380
+        $this->expectExceptionMessage('Cannot change target of link share');
4381 4381
 
4382
-		$share = $this->manager->newShare();
4383
-		$share->setShareType(IShare::TYPE_LINK);
4382
+        $share = $this->manager->newShare();
4383
+        $share->setShareType(IShare::TYPE_LINK);
4384 4384
 
4385
-		$recipient = $this->createMock(IUser::class);
4385
+        $recipient = $this->createMock(IUser::class);
4386 4386
 
4387
-		$this->manager->moveShare($share, $recipient);
4388
-	}
4387
+        $this->manager->moveShare($share, $recipient);
4388
+    }
4389 4389
 
4390 4390
 
4391
-	public function testMoveShareUserNotRecipient(): void {
4392
-		$this->expectException(\InvalidArgumentException::class);
4393
-		$this->expectExceptionMessage('Invalid share recipient');
4391
+    public function testMoveShareUserNotRecipient(): void {
4392
+        $this->expectException(\InvalidArgumentException::class);
4393
+        $this->expectExceptionMessage('Invalid share recipient');
4394 4394
 
4395
-		$share = $this->manager->newShare();
4396
-		$share->setShareType(IShare::TYPE_USER);
4397
-
4398
-		$share->setSharedWith('sharedWith');
4399
-
4400
-		$this->manager->moveShare($share, 'recipient');
4401
-	}
4402
-
4403
-	public function testMoveShareUser(): void {
4404
-		$share = $this->manager->newShare();
4405
-		$share->setShareType(IShare::TYPE_USER)
4406
-			->setId('42')
4407
-			->setProviderId('foo');
4408
-
4409
-		$share->setSharedWith('recipient');
4395
+        $share = $this->manager->newShare();
4396
+        $share->setShareType(IShare::TYPE_USER);
4397
+
4398
+        $share->setSharedWith('sharedWith');
4399
+
4400
+        $this->manager->moveShare($share, 'recipient');
4401
+    }
4402
+
4403
+    public function testMoveShareUser(): void {
4404
+        $share = $this->manager->newShare();
4405
+        $share->setShareType(IShare::TYPE_USER)
4406
+            ->setId('42')
4407
+            ->setProviderId('foo');
4408
+
4409
+        $share->setSharedWith('recipient');
4410 4410
 
4411
-		$this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0);
4411
+        $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0);
4412 4412
 
4413
-		$this->manager->moveShare($share, 'recipient');
4414
-		$this->addToAssertionCount(1);
4415
-	}
4413
+        $this->manager->moveShare($share, 'recipient');
4414
+        $this->addToAssertionCount(1);
4415
+    }
4416 4416
 
4417 4417
 
4418
-	public function testMoveShareGroupNotRecipient(): void {
4419
-		$this->expectException(\InvalidArgumentException::class);
4420
-		$this->expectExceptionMessage('Invalid share recipient');
4418
+    public function testMoveShareGroupNotRecipient(): void {
4419
+        $this->expectException(\InvalidArgumentException::class);
4420
+        $this->expectExceptionMessage('Invalid share recipient');
4421 4421
 
4422
-		$share = $this->manager->newShare();
4423
-		$share->setShareType(IShare::TYPE_GROUP);
4422
+        $share = $this->manager->newShare();
4423
+        $share->setShareType(IShare::TYPE_GROUP);
4424 4424
 
4425
-		$sharedWith = $this->createMock(IGroup::class);
4426
-		$share->setSharedWith('shareWith');
4425
+        $sharedWith = $this->createMock(IGroup::class);
4426
+        $share->setSharedWith('shareWith');
4427 4427
 
4428
-		$recipient = $this->createMock(IUser::class);
4429
-		$sharedWith->method('inGroup')->with($recipient)->willReturn(false);
4428
+        $recipient = $this->createMock(IUser::class);
4429
+        $sharedWith->method('inGroup')->with($recipient)->willReturn(false);
4430 4430
 
4431
-		$this->groupManager->method('get')->with('shareWith')->willReturn($sharedWith);
4432
-		$this->userManager->method('get')->with('recipient')->willReturn($recipient);
4433
-
4434
-		$this->manager->moveShare($share, 'recipient');
4435
-	}
4431
+        $this->groupManager->method('get')->with('shareWith')->willReturn($sharedWith);
4432
+        $this->userManager->method('get')->with('recipient')->willReturn($recipient);
4433
+
4434
+        $this->manager->moveShare($share, 'recipient');
4435
+    }
4436 4436
 
4437 4437
 
4438
-	public function testMoveShareGroupNull(): void {
4439
-		$this->expectException(\InvalidArgumentException::class);
4440
-		$this->expectExceptionMessage('Group "shareWith" does not exist');
4438
+    public function testMoveShareGroupNull(): void {
4439
+        $this->expectException(\InvalidArgumentException::class);
4440
+        $this->expectExceptionMessage('Group "shareWith" does not exist');
4441 4441
 
4442
-		$share = $this->manager->newShare();
4443
-		$share->setShareType(IShare::TYPE_GROUP);
4444
-		$share->setSharedWith('shareWith');
4442
+        $share = $this->manager->newShare();
4443
+        $share->setShareType(IShare::TYPE_GROUP);
4444
+        $share->setSharedWith('shareWith');
4445 4445
 
4446
-		$recipient = $this->createMock(IUser::class);
4446
+        $recipient = $this->createMock(IUser::class);
4447 4447
 
4448
-		$this->groupManager->method('get')->with('shareWith')->willReturn(null);
4449
-		$this->userManager->method('get')->with('recipient')->willReturn($recipient);
4448
+        $this->groupManager->method('get')->with('shareWith')->willReturn(null);
4449
+        $this->userManager->method('get')->with('recipient')->willReturn($recipient);
4450 4450
 
4451
-		$this->manager->moveShare($share, 'recipient');
4452
-	}
4451
+        $this->manager->moveShare($share, 'recipient');
4452
+    }
4453 4453
 
4454
-	public function testMoveShareGroup(): void {
4455
-		$share = $this->manager->newShare();
4456
-		$share->setShareType(IShare::TYPE_GROUP)
4457
-			->setId('42')
4458
-			->setProviderId('foo');
4454
+    public function testMoveShareGroup(): void {
4455
+        $share = $this->manager->newShare();
4456
+        $share->setShareType(IShare::TYPE_GROUP)
4457
+            ->setId('42')
4458
+            ->setProviderId('foo');
4459 4459
 
4460
-		$group = $this->createMock(IGroup::class);
4461
-		$share->setSharedWith('group');
4460
+        $group = $this->createMock(IGroup::class);
4461
+        $share->setSharedWith('group');
4462 4462
 
4463
-		$recipient = $this->createMock(IUser::class);
4464
-		$group->method('inGroup')->with($recipient)->willReturn(true);
4463
+        $recipient = $this->createMock(IUser::class);
4464
+        $group->method('inGroup')->with($recipient)->willReturn(true);
4465 4465
 
4466
-		$this->groupManager->method('get')->with('group')->willReturn($group);
4467
-		$this->userManager->method('get')->with('recipient')->willReturn($recipient);
4466
+        $this->groupManager->method('get')->with('group')->willReturn($group);
4467
+        $this->userManager->method('get')->with('recipient')->willReturn($recipient);
4468 4468
 
4469
-		$this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0);
4469
+        $this->defaultProvider->method('move')->with($share, 'recipient')->willReturnArgument(0);
4470 4470
 
4471
-		$this->manager->moveShare($share, 'recipient');
4472
-		$this->addToAssertionCount(1);
4473
-	}
4471
+        $this->manager->moveShare($share, 'recipient');
4472
+        $this->addToAssertionCount(1);
4473
+    }
4474 4474
 
4475
-	/**
4476
-	 * @dataProvider dataTestShareProviderExists
4477
-	 */
4478
-	public function testShareProviderExists($shareType, $expected): void {
4479
-		$factory = $this->getMockBuilder('OCP\Share\IProviderFactory')->getMock();
4480
-		$factory->expects($this->any())->method('getProviderForType')
4481
-			->willReturnCallback(function ($id) {
4482
-				if ($id === IShare::TYPE_USER) {
4483
-					return true;
4484
-				}
4485
-				throw new Exception\ProviderException();
4486
-			});
4475
+    /**
4476
+     * @dataProvider dataTestShareProviderExists
4477
+     */
4478
+    public function testShareProviderExists($shareType, $expected): void {
4479
+        $factory = $this->getMockBuilder('OCP\Share\IProviderFactory')->getMock();
4480
+        $factory->expects($this->any())->method('getProviderForType')
4481
+            ->willReturnCallback(function ($id) {
4482
+                if ($id === IShare::TYPE_USER) {
4483
+                    return true;
4484
+                }
4485
+                throw new Exception\ProviderException();
4486
+            });
4487 4487
 
4488
-		$manager = $this->createManager($factory);
4489
-		$this->assertSame($expected,
4490
-			$manager->shareProviderExists($shareType)
4491
-		);
4492
-	}
4488
+        $manager = $this->createManager($factory);
4489
+        $this->assertSame($expected,
4490
+            $manager->shareProviderExists($shareType)
4491
+        );
4492
+    }
4493 4493
 
4494
-	public static function dataTestShareProviderExists() {
4495
-		return [
4496
-			[IShare::TYPE_USER, true],
4497
-			[42, false],
4498
-		];
4499
-	}
4494
+    public static function dataTestShareProviderExists() {
4495
+        return [
4496
+            [IShare::TYPE_USER, true],
4497
+            [42, false],
4498
+        ];
4499
+    }
4500 4500
 
4501
-	public function testGetSharesInFolder(): void {
4502
-		$factory = new DummyFactory2($this->createMock(IServerContainer::class));
4501
+    public function testGetSharesInFolder(): void {
4502
+        $factory = new DummyFactory2($this->createMock(IServerContainer::class));
4503 4503
 
4504
-		$manager = $this->createManager($factory);
4504
+        $manager = $this->createManager($factory);
4505 4505
 
4506
-		$factory->setProvider($this->defaultProvider);
4507
-		$extraProvider = $this->createMock(IShareProvider::class);
4508
-		$factory->setSecondProvider($extraProvider);
4506
+        $factory->setProvider($this->defaultProvider);
4507
+        $extraProvider = $this->createMock(IShareProvider::class);
4508
+        $factory->setSecondProvider($extraProvider);
4509 4509
 
4510
-		$share1 = $this->createMock(IShare::class);
4511
-		$share2 = $this->createMock(IShare::class);
4512
-		$share3 = $this->createMock(IShare::class);
4513
-		$share4 = $this->createMock(IShare::class);
4514
-
4515
-		$folder = $this->createMock(Folder::class);
4510
+        $share1 = $this->createMock(IShare::class);
4511
+        $share2 = $this->createMock(IShare::class);
4512
+        $share3 = $this->createMock(IShare::class);
4513
+        $share4 = $this->createMock(IShare::class);
4514
+
4515
+        $folder = $this->createMock(Folder::class);
4516 4516
 
4517
-		$this->defaultProvider->method('getSharesInFolder')
4518
-			->with(
4519
-				$this->equalTo('user'),
4520
-				$this->equalTo($folder),
4521
-				$this->equalTo(false)
4522
-			)->willReturn([
4523
-				1 => [$share1],
4524
-				2 => [$share2],
4525
-			]);
4526
-
4527
-		$extraProvider->method('getSharesInFolder')
4528
-			->with(
4529
-				$this->equalTo('user'),
4530
-				$this->equalTo($folder),
4531
-				$this->equalTo(false)
4532
-			)->willReturn([
4533
-				2 => [$share3],
4534
-				3 => [$share4],
4535
-			]);
4536
-
4537
-		$result = $manager->getSharesInFolder('user', $folder, false);
4538
-
4539
-		$expects = [
4540
-			1 => [$share1],
4541
-			2 => [$share2, $share3],
4542
-			3 => [$share4],
4543
-		];
4544
-
4545
-		$this->assertSame($expects, $result);
4546
-	}
4547
-
4548
-	public function testGetSharesInFolderOwnerless(): void {
4549
-		$factory = new DummyFactory2($this->createMock(IServerContainer::class));
4550
-
4551
-		$manager = $this->createManager($factory);
4552
-
4553
-		$factory->setProvider($this->defaultProvider);
4554
-		$extraProvider = $this->createMock(IShareProvider::class);
4555
-		$factory->setSecondProvider($extraProvider);
4556
-
4557
-		$share1 = $this->createMock(IShare::class);
4558
-		$share2 = $this->createMock(IShare::class);
4559
-
4560
-		$mount = $this->createMock(IShareOwnerlessMount::class);
4561
-
4562
-		$file = $this->createMock(File::class);
4563
-		$file
4564
-			->method('getId')
4565
-			->willReturn(1);
4566
-
4567
-		$folder = $this->createMock(Folder::class);
4568
-		$folder
4569
-			->method('getMountPoint')
4570
-			->willReturn($mount);
4571
-		$folder
4572
-			->method('getDirectoryListing')
4573
-			->willReturn([$file]);
4574
-
4575
-		$this->defaultProvider
4576
-			->method('getSharesByPath')
4577
-			->with($file)
4578
-			->willReturn([$share1]);
4579
-
4580
-		$extraProvider
4581
-			->method('getSharesByPath')
4582
-			->with($file)
4583
-			->willReturn([$share2]);
4584
-
4585
-		$this->assertSame([
4586
-			1 => [$share1, $share2],
4587
-		], $manager->getSharesInFolder('user', $folder));
4588
-	}
4589
-
4590
-
4591
-	public function testGetAccessList(): void {
4592
-		$factory = new DummyFactory2($this->createMock(IServerContainer::class));
4593
-
4594
-		$manager = $this->createManager($factory);
4595
-
4596
-		$factory->setProvider($this->defaultProvider);
4597
-		$extraProvider = $this->createMock(IShareProvider::class);
4598
-		$factory->setSecondProvider($extraProvider);
4599
-
4600
-		$nodeOwner = $this->createMock(IUser::class);
4601
-		$nodeOwner->expects($this->once())
4602
-			->method('getUID')
4603
-			->willReturn('user1');
4604
-
4605
-		$node = $this->createMock(Node::class);
4606
-		$node->expects($this->once())
4607
-			->method('getOwner')
4608
-			->willReturn($nodeOwner);
4609
-		$node->method('getId')
4610
-			->willReturn(42);
4611
-
4612
-		$userFolder = $this->createMock(Folder::class);
4613
-		$file = $this->createMock(File::class);
4614
-		$folder = $this->createMock(Folder::class);
4615
-
4616
-		$owner = $this->createMock(IUser::class);
4617
-		$owner->expects($this->once())
4618
-			->method('getUID')
4619
-			->willReturn('owner');
4620
-
4621
-		$file->method('getParent')
4622
-			->willReturn($folder);
4623
-		$file->method('getPath')
4624
-			->willReturn('/owner/files/folder/file');
4625
-		$file->method('getOwner')
4626
-			->willReturn($owner);
4627
-		$file->method('getId')
4628
-			->willReturn(23);
4629
-		$folder->method('getParent')
4630
-			->willReturn($userFolder);
4631
-		$folder->method('getPath')
4632
-			->willReturn('/owner/files/folder');
4633
-		$userFolder->method('getFirstNodeById')
4634
-			->with($this->equalTo(42))
4635
-			->willReturn($file);
4636
-		$userFolder->method('getPath')
4637
-			->willReturn('/user1/files');
4638
-
4639
-		$this->userManager->method('userExists')
4640
-			->with($this->equalTo('user1'))
4641
-			->willReturn(true);
4642
-
4643
-		$this->defaultProvider->method('getAccessList')
4644
-			->with(
4645
-				$this->equalTo([$file, $folder]),
4646
-				false
4647
-			)
4648
-			->willReturn([
4649
-				'users' => [
4650
-					'user1',
4651
-					'user2',
4652
-					'user3',
4653
-					'123456',
4654
-				],
4655
-				'public' => true,
4656
-			]);
4657
-
4658
-		$extraProvider->method('getAccessList')
4659
-			->with(
4660
-				$this->equalTo([$file, $folder]),
4661
-				false
4662
-			)
4663
-			->willReturn([
4664
-				'users' => [
4665
-					'user3',
4666
-					'user4',
4667
-					'user5',
4668
-					'234567',
4669
-				],
4670
-				'remote' => true,
4671
-			]);
4672
-
4673
-		$this->rootFolder->method('getUserFolder')
4674
-			->with($this->equalTo('user1'))
4675
-			->willReturn($userFolder);
4676
-
4677
-		$expected = [
4678
-			'users' => ['owner', 'user1', 'user2', 'user3', '123456','user4', 'user5', '234567'],
4679
-			'remote' => true,
4680
-			'public' => true,
4681
-		];
4682
-
4683
-		$result = $manager->getAccessList($node, true, false);
4684
-
4685
-		$this->assertSame($expected['public'], $result['public']);
4686
-		$this->assertSame($expected['remote'], $result['remote']);
4687
-		$this->assertSame($expected['users'], $result['users']);
4688
-	}
4689
-
4690
-	public function testGetAccessListWithCurrentAccess(): void {
4691
-		$factory = new DummyFactory2($this->createMock(IServerContainer::class));
4692
-
4693
-		$manager = $this->createManager($factory);
4694
-
4695
-		$factory->setProvider($this->defaultProvider);
4696
-		$extraProvider = $this->createMock(IShareProvider::class);
4697
-		$factory->setSecondProvider($extraProvider);
4698
-
4699
-		$nodeOwner = $this->createMock(IUser::class);
4700
-		$nodeOwner->expects($this->once())
4701
-			->method('getUID')
4702
-			->willReturn('user1');
4703
-
4704
-		$node = $this->createMock(Node::class);
4705
-		$node->expects($this->once())
4706
-			->method('getOwner')
4707
-			->willReturn($nodeOwner);
4708
-		$node->method('getId')
4709
-			->willReturn(42);
4710
-
4711
-		$userFolder = $this->createMock(Folder::class);
4712
-		$file = $this->createMock(File::class);
4713
-
4714
-		$owner = $this->createMock(IUser::class);
4715
-		$owner->expects($this->once())
4716
-			->method('getUID')
4717
-			->willReturn('owner');
4718
-		$folder = $this->createMock(Folder::class);
4719
-
4720
-		$file->method('getParent')
4721
-			->willReturn($folder);
4722
-		$file->method('getPath')
4723
-			->willReturn('/owner/files/folder/file');
4724
-		$file->method('getOwner')
4725
-			->willReturn($owner);
4726
-		$file->method('getId')
4727
-			->willReturn(23);
4728
-		$folder->method('getParent')
4729
-			->willReturn($userFolder);
4730
-		$folder->method('getPath')
4731
-			->willReturn('/owner/files/folder');
4732
-		$userFolder->method('getFirstNodeById')
4733
-			->with($this->equalTo(42))
4734
-			->willReturn($file);
4735
-		$userFolder->method('getPath')
4736
-			->willReturn('/user1/files');
4737
-
4738
-		$this->userManager->method('userExists')
4739
-			->with($this->equalTo('user1'))
4740
-			->willReturn(true);
4741
-
4742
-		$this->defaultProvider->method('getAccessList')
4743
-			->with(
4744
-				$this->equalTo([$file, $folder]),
4745
-				true
4746
-			)
4747
-			->willReturn([
4748
-				'users' => [
4749
-					'user1' => [],
4750
-					'user2' => [],
4751
-					'user3' => [],
4752
-					'123456' => [],
4753
-				],
4754
-				'public' => true,
4755
-			]);
4756
-
4757
-		$extraProvider->method('getAccessList')
4758
-			->with(
4759
-				$this->equalTo([$file, $folder]),
4760
-				true
4761
-			)
4762
-			->willReturn([
4763
-				'users' => [
4764
-					'user3' => [],
4765
-					'user4' => [],
4766
-					'user5' => [],
4767
-					'234567' => [],
4768
-				],
4769
-				'remote' => [
4770
-					'remote1',
4771
-				],
4772
-			]);
4773
-
4774
-		$this->rootFolder->method('getUserFolder')
4775
-			->with($this->equalTo('user1'))
4776
-			->willReturn($userFolder);
4777
-
4778
-		$expected = [
4779
-			'users' => [
4780
-				'owner' => [
4781
-					'node_id' => 23,
4782
-					'node_path' => '/folder/file'
4783
-				]
4784
-				, 'user1' => [], 'user2' => [], 'user3' => [], '123456' => [], 'user4' => [], 'user5' => [], '234567' => []],
4785
-			'remote' => [
4786
-				'remote1',
4787
-			],
4788
-			'public' => true,
4789
-		];
4790
-
4791
-		$result = $manager->getAccessList($node, true, true);
4792
-
4793
-		$this->assertSame($expected['public'], $result['public']);
4794
-		$this->assertSame($expected['remote'], $result['remote']);
4795
-		$this->assertSame($expected['users'], $result['users']);
4796
-	}
4797
-
4798
-	public function testGetAllShares(): void {
4799
-		$factory = new DummyFactory2($this->createMock(IServerContainer::class));
4800
-
4801
-		$manager = $this->createManager($factory);
4802
-
4803
-		$factory->setProvider($this->defaultProvider);
4804
-		$extraProvider = $this->createMock(IShareProvider::class);
4805
-		$factory->setSecondProvider($extraProvider);
4806
-
4807
-		$share1 = $this->createMock(IShare::class);
4808
-		$share2 = $this->createMock(IShare::class);
4809
-		$share3 = $this->createMock(IShare::class);
4810
-		$share4 = $this->createMock(IShare::class);
4811
-
4812
-		$this->defaultProvider->method('getAllShares')
4813
-			->willReturnCallback(function () use ($share1, $share2) {
4814
-				yield $share1;
4815
-				yield $share2;
4816
-			});
4817
-		$extraProvider->method('getAllShares')
4818
-			->willReturnCallback(function () use ($share3, $share4) {
4819
-				yield $share3;
4820
-				yield $share4;
4821
-			});
4822
-
4823
-		// "yield from", used in "getAllShares()", does not reset the keys, so
4824
-		// "use_keys" has to be disabled to collect all the values while
4825
-		// ignoring the keys returned by the generator.
4826
-		$result = iterator_to_array($manager->getAllShares(), $use_keys = false);
4827
-
4828
-		$expects = [$share1, $share2, $share3, $share4];
4829
-
4830
-		$this->assertSame($expects, $result);
4831
-	}
4832
-
4833
-	public static function dataCurrentUserCanEnumerateTargetUser(): array {
4834
-		return [
4835
-			'Full match guest' => [true, true, false, false, false, false, false, true],
4836
-			'Full match user' => [false, true, false, false, false, false, false, true],
4837
-			'Enumeration off guest' => [true, false, false, false, false, false, false, false],
4838
-			'Enumeration off user' => [false, false, false, false, false, false, false, false],
4839
-			'Enumeration guest' => [true, false, true, false, false, false, false, true],
4840
-			'Enumeration user' => [false, false, true, false, false, false, false, true],
4841
-
4842
-			// Restricted enumerations guests never works
4843
-			'Guest phone' => [true, false, true, true, false, false, false, false],
4844
-			'Guest group' => [true, false, true, false, true, false, false, false],
4845
-			'Guest both' => [true, false, true, true, true, false, false, false],
4846
-
4847
-			// Restricted enumerations users
4848
-			'User phone but not known' => [false, false, true, true, false, false, false, false],
4849
-			'User phone known' => [false, false, true, true, false, true, false, true],
4850
-			'User group but no match' => [false, false, true, false, true, false, false, false],
4851
-			'User group with match' => [false, false, true, false, true, false, true, true],
4852
-		];
4853
-	}
4854
-
4855
-	/**
4856
-	 * @dataProvider dataCurrentUserCanEnumerateTargetUser
4857
-	 * @param bool $expected
4858
-	 */
4859
-	public function testCurrentUserCanEnumerateTargetUser(bool $currentUserIsGuest, bool $allowEnumerationFullMatch, bool $allowEnumeration, bool $limitEnumerationToPhone, bool $limitEnumerationToGroups, bool $isKnownToUser, bool $haveCommonGroup, bool $expected): void {
4860
-		/** @var IManager|MockObject $manager */
4861
-		$manager = $this->createManagerMock()
4862
-			->onlyMethods([
4863
-				'allowEnumerationFullMatch',
4864
-				'allowEnumeration',
4865
-				'limitEnumerationToPhone',
4866
-				'limitEnumerationToGroups',
4867
-			])
4868
-			->getMock();
4869
-
4870
-		$manager->method('allowEnumerationFullMatch')
4871
-			->willReturn($allowEnumerationFullMatch);
4872
-		$manager->method('allowEnumeration')
4873
-			->willReturn($allowEnumeration);
4874
-		$manager->method('limitEnumerationToPhone')
4875
-			->willReturn($limitEnumerationToPhone);
4876
-		$manager->method('limitEnumerationToGroups')
4877
-			->willReturn($limitEnumerationToGroups);
4878
-
4879
-		$this->knownUserService->method('isKnownToUser')
4880
-			->with('current', 'target')
4881
-			->willReturn($isKnownToUser);
4882
-
4883
-		$currentUser = null;
4884
-		if (!$currentUserIsGuest) {
4885
-			$currentUser = $this->createMock(IUser::class);
4886
-			$currentUser->method('getUID')
4887
-				->willReturn('current');
4888
-		}
4889
-		$targetUser = $this->createMock(IUser::class);
4890
-		$targetUser->method('getUID')
4891
-			->willReturn('target');
4892
-
4893
-		if ($haveCommonGroup) {
4894
-			$this->groupManager->method('getUserGroupIds')
4895
-				->willReturnMap([
4896
-					[$targetUser, ['gid1', 'gid2']],
4897
-					[$currentUser, ['gid2', 'gid3']],
4898
-				]);
4899
-		} else {
4900
-			$this->groupManager->method('getUserGroupIds')
4901
-				->willReturnMap([
4902
-					[$targetUser, ['gid1', 'gid2']],
4903
-					[$currentUser, ['gid3', 'gid4']],
4904
-				]);
4905
-		}
4906
-
4907
-		$this->assertSame($expected, $manager->currentUserCanEnumerateTargetUser($currentUser, $targetUser));
4908
-	}
4517
+        $this->defaultProvider->method('getSharesInFolder')
4518
+            ->with(
4519
+                $this->equalTo('user'),
4520
+                $this->equalTo($folder),
4521
+                $this->equalTo(false)
4522
+            )->willReturn([
4523
+                1 => [$share1],
4524
+                2 => [$share2],
4525
+            ]);
4526
+
4527
+        $extraProvider->method('getSharesInFolder')
4528
+            ->with(
4529
+                $this->equalTo('user'),
4530
+                $this->equalTo($folder),
4531
+                $this->equalTo(false)
4532
+            )->willReturn([
4533
+                2 => [$share3],
4534
+                3 => [$share4],
4535
+            ]);
4536
+
4537
+        $result = $manager->getSharesInFolder('user', $folder, false);
4538
+
4539
+        $expects = [
4540
+            1 => [$share1],
4541
+            2 => [$share2, $share3],
4542
+            3 => [$share4],
4543
+        ];
4544
+
4545
+        $this->assertSame($expects, $result);
4546
+    }
4547
+
4548
+    public function testGetSharesInFolderOwnerless(): void {
4549
+        $factory = new DummyFactory2($this->createMock(IServerContainer::class));
4550
+
4551
+        $manager = $this->createManager($factory);
4552
+
4553
+        $factory->setProvider($this->defaultProvider);
4554
+        $extraProvider = $this->createMock(IShareProvider::class);
4555
+        $factory->setSecondProvider($extraProvider);
4556
+
4557
+        $share1 = $this->createMock(IShare::class);
4558
+        $share2 = $this->createMock(IShare::class);
4559
+
4560
+        $mount = $this->createMock(IShareOwnerlessMount::class);
4561
+
4562
+        $file = $this->createMock(File::class);
4563
+        $file
4564
+            ->method('getId')
4565
+            ->willReturn(1);
4566
+
4567
+        $folder = $this->createMock(Folder::class);
4568
+        $folder
4569
+            ->method('getMountPoint')
4570
+            ->willReturn($mount);
4571
+        $folder
4572
+            ->method('getDirectoryListing')
4573
+            ->willReturn([$file]);
4574
+
4575
+        $this->defaultProvider
4576
+            ->method('getSharesByPath')
4577
+            ->with($file)
4578
+            ->willReturn([$share1]);
4579
+
4580
+        $extraProvider
4581
+            ->method('getSharesByPath')
4582
+            ->with($file)
4583
+            ->willReturn([$share2]);
4584
+
4585
+        $this->assertSame([
4586
+            1 => [$share1, $share2],
4587
+        ], $manager->getSharesInFolder('user', $folder));
4588
+    }
4589
+
4590
+
4591
+    public function testGetAccessList(): void {
4592
+        $factory = new DummyFactory2($this->createMock(IServerContainer::class));
4593
+
4594
+        $manager = $this->createManager($factory);
4595
+
4596
+        $factory->setProvider($this->defaultProvider);
4597
+        $extraProvider = $this->createMock(IShareProvider::class);
4598
+        $factory->setSecondProvider($extraProvider);
4599
+
4600
+        $nodeOwner = $this->createMock(IUser::class);
4601
+        $nodeOwner->expects($this->once())
4602
+            ->method('getUID')
4603
+            ->willReturn('user1');
4604
+
4605
+        $node = $this->createMock(Node::class);
4606
+        $node->expects($this->once())
4607
+            ->method('getOwner')
4608
+            ->willReturn($nodeOwner);
4609
+        $node->method('getId')
4610
+            ->willReturn(42);
4611
+
4612
+        $userFolder = $this->createMock(Folder::class);
4613
+        $file = $this->createMock(File::class);
4614
+        $folder = $this->createMock(Folder::class);
4615
+
4616
+        $owner = $this->createMock(IUser::class);
4617
+        $owner->expects($this->once())
4618
+            ->method('getUID')
4619
+            ->willReturn('owner');
4620
+
4621
+        $file->method('getParent')
4622
+            ->willReturn($folder);
4623
+        $file->method('getPath')
4624
+            ->willReturn('/owner/files/folder/file');
4625
+        $file->method('getOwner')
4626
+            ->willReturn($owner);
4627
+        $file->method('getId')
4628
+            ->willReturn(23);
4629
+        $folder->method('getParent')
4630
+            ->willReturn($userFolder);
4631
+        $folder->method('getPath')
4632
+            ->willReturn('/owner/files/folder');
4633
+        $userFolder->method('getFirstNodeById')
4634
+            ->with($this->equalTo(42))
4635
+            ->willReturn($file);
4636
+        $userFolder->method('getPath')
4637
+            ->willReturn('/user1/files');
4638
+
4639
+        $this->userManager->method('userExists')
4640
+            ->with($this->equalTo('user1'))
4641
+            ->willReturn(true);
4642
+
4643
+        $this->defaultProvider->method('getAccessList')
4644
+            ->with(
4645
+                $this->equalTo([$file, $folder]),
4646
+                false
4647
+            )
4648
+            ->willReturn([
4649
+                'users' => [
4650
+                    'user1',
4651
+                    'user2',
4652
+                    'user3',
4653
+                    '123456',
4654
+                ],
4655
+                'public' => true,
4656
+            ]);
4657
+
4658
+        $extraProvider->method('getAccessList')
4659
+            ->with(
4660
+                $this->equalTo([$file, $folder]),
4661
+                false
4662
+            )
4663
+            ->willReturn([
4664
+                'users' => [
4665
+                    'user3',
4666
+                    'user4',
4667
+                    'user5',
4668
+                    '234567',
4669
+                ],
4670
+                'remote' => true,
4671
+            ]);
4672
+
4673
+        $this->rootFolder->method('getUserFolder')
4674
+            ->with($this->equalTo('user1'))
4675
+            ->willReturn($userFolder);
4676
+
4677
+        $expected = [
4678
+            'users' => ['owner', 'user1', 'user2', 'user3', '123456','user4', 'user5', '234567'],
4679
+            'remote' => true,
4680
+            'public' => true,
4681
+        ];
4682
+
4683
+        $result = $manager->getAccessList($node, true, false);
4684
+
4685
+        $this->assertSame($expected['public'], $result['public']);
4686
+        $this->assertSame($expected['remote'], $result['remote']);
4687
+        $this->assertSame($expected['users'], $result['users']);
4688
+    }
4689
+
4690
+    public function testGetAccessListWithCurrentAccess(): void {
4691
+        $factory = new DummyFactory2($this->createMock(IServerContainer::class));
4692
+
4693
+        $manager = $this->createManager($factory);
4694
+
4695
+        $factory->setProvider($this->defaultProvider);
4696
+        $extraProvider = $this->createMock(IShareProvider::class);
4697
+        $factory->setSecondProvider($extraProvider);
4698
+
4699
+        $nodeOwner = $this->createMock(IUser::class);
4700
+        $nodeOwner->expects($this->once())
4701
+            ->method('getUID')
4702
+            ->willReturn('user1');
4703
+
4704
+        $node = $this->createMock(Node::class);
4705
+        $node->expects($this->once())
4706
+            ->method('getOwner')
4707
+            ->willReturn($nodeOwner);
4708
+        $node->method('getId')
4709
+            ->willReturn(42);
4710
+
4711
+        $userFolder = $this->createMock(Folder::class);
4712
+        $file = $this->createMock(File::class);
4713
+
4714
+        $owner = $this->createMock(IUser::class);
4715
+        $owner->expects($this->once())
4716
+            ->method('getUID')
4717
+            ->willReturn('owner');
4718
+        $folder = $this->createMock(Folder::class);
4719
+
4720
+        $file->method('getParent')
4721
+            ->willReturn($folder);
4722
+        $file->method('getPath')
4723
+            ->willReturn('/owner/files/folder/file');
4724
+        $file->method('getOwner')
4725
+            ->willReturn($owner);
4726
+        $file->method('getId')
4727
+            ->willReturn(23);
4728
+        $folder->method('getParent')
4729
+            ->willReturn($userFolder);
4730
+        $folder->method('getPath')
4731
+            ->willReturn('/owner/files/folder');
4732
+        $userFolder->method('getFirstNodeById')
4733
+            ->with($this->equalTo(42))
4734
+            ->willReturn($file);
4735
+        $userFolder->method('getPath')
4736
+            ->willReturn('/user1/files');
4737
+
4738
+        $this->userManager->method('userExists')
4739
+            ->with($this->equalTo('user1'))
4740
+            ->willReturn(true);
4741
+
4742
+        $this->defaultProvider->method('getAccessList')
4743
+            ->with(
4744
+                $this->equalTo([$file, $folder]),
4745
+                true
4746
+            )
4747
+            ->willReturn([
4748
+                'users' => [
4749
+                    'user1' => [],
4750
+                    'user2' => [],
4751
+                    'user3' => [],
4752
+                    '123456' => [],
4753
+                ],
4754
+                'public' => true,
4755
+            ]);
4756
+
4757
+        $extraProvider->method('getAccessList')
4758
+            ->with(
4759
+                $this->equalTo([$file, $folder]),
4760
+                true
4761
+            )
4762
+            ->willReturn([
4763
+                'users' => [
4764
+                    'user3' => [],
4765
+                    'user4' => [],
4766
+                    'user5' => [],
4767
+                    '234567' => [],
4768
+                ],
4769
+                'remote' => [
4770
+                    'remote1',
4771
+                ],
4772
+            ]);
4773
+
4774
+        $this->rootFolder->method('getUserFolder')
4775
+            ->with($this->equalTo('user1'))
4776
+            ->willReturn($userFolder);
4777
+
4778
+        $expected = [
4779
+            'users' => [
4780
+                'owner' => [
4781
+                    'node_id' => 23,
4782
+                    'node_path' => '/folder/file'
4783
+                ]
4784
+                , 'user1' => [], 'user2' => [], 'user3' => [], '123456' => [], 'user4' => [], 'user5' => [], '234567' => []],
4785
+            'remote' => [
4786
+                'remote1',
4787
+            ],
4788
+            'public' => true,
4789
+        ];
4790
+
4791
+        $result = $manager->getAccessList($node, true, true);
4792
+
4793
+        $this->assertSame($expected['public'], $result['public']);
4794
+        $this->assertSame($expected['remote'], $result['remote']);
4795
+        $this->assertSame($expected['users'], $result['users']);
4796
+    }
4797
+
4798
+    public function testGetAllShares(): void {
4799
+        $factory = new DummyFactory2($this->createMock(IServerContainer::class));
4800
+
4801
+        $manager = $this->createManager($factory);
4802
+
4803
+        $factory->setProvider($this->defaultProvider);
4804
+        $extraProvider = $this->createMock(IShareProvider::class);
4805
+        $factory->setSecondProvider($extraProvider);
4806
+
4807
+        $share1 = $this->createMock(IShare::class);
4808
+        $share2 = $this->createMock(IShare::class);
4809
+        $share3 = $this->createMock(IShare::class);
4810
+        $share4 = $this->createMock(IShare::class);
4811
+
4812
+        $this->defaultProvider->method('getAllShares')
4813
+            ->willReturnCallback(function () use ($share1, $share2) {
4814
+                yield $share1;
4815
+                yield $share2;
4816
+            });
4817
+        $extraProvider->method('getAllShares')
4818
+            ->willReturnCallback(function () use ($share3, $share4) {
4819
+                yield $share3;
4820
+                yield $share4;
4821
+            });
4822
+
4823
+        // "yield from", used in "getAllShares()", does not reset the keys, so
4824
+        // "use_keys" has to be disabled to collect all the values while
4825
+        // ignoring the keys returned by the generator.
4826
+        $result = iterator_to_array($manager->getAllShares(), $use_keys = false);
4827
+
4828
+        $expects = [$share1, $share2, $share3, $share4];
4829
+
4830
+        $this->assertSame($expects, $result);
4831
+    }
4832
+
4833
+    public static function dataCurrentUserCanEnumerateTargetUser(): array {
4834
+        return [
4835
+            'Full match guest' => [true, true, false, false, false, false, false, true],
4836
+            'Full match user' => [false, true, false, false, false, false, false, true],
4837
+            'Enumeration off guest' => [true, false, false, false, false, false, false, false],
4838
+            'Enumeration off user' => [false, false, false, false, false, false, false, false],
4839
+            'Enumeration guest' => [true, false, true, false, false, false, false, true],
4840
+            'Enumeration user' => [false, false, true, false, false, false, false, true],
4841
+
4842
+            // Restricted enumerations guests never works
4843
+            'Guest phone' => [true, false, true, true, false, false, false, false],
4844
+            'Guest group' => [true, false, true, false, true, false, false, false],
4845
+            'Guest both' => [true, false, true, true, true, false, false, false],
4846
+
4847
+            // Restricted enumerations users
4848
+            'User phone but not known' => [false, false, true, true, false, false, false, false],
4849
+            'User phone known' => [false, false, true, true, false, true, false, true],
4850
+            'User group but no match' => [false, false, true, false, true, false, false, false],
4851
+            'User group with match' => [false, false, true, false, true, false, true, true],
4852
+        ];
4853
+    }
4854
+
4855
+    /**
4856
+     * @dataProvider dataCurrentUserCanEnumerateTargetUser
4857
+     * @param bool $expected
4858
+     */
4859
+    public function testCurrentUserCanEnumerateTargetUser(bool $currentUserIsGuest, bool $allowEnumerationFullMatch, bool $allowEnumeration, bool $limitEnumerationToPhone, bool $limitEnumerationToGroups, bool $isKnownToUser, bool $haveCommonGroup, bool $expected): void {
4860
+        /** @var IManager|MockObject $manager */
4861
+        $manager = $this->createManagerMock()
4862
+            ->onlyMethods([
4863
+                'allowEnumerationFullMatch',
4864
+                'allowEnumeration',
4865
+                'limitEnumerationToPhone',
4866
+                'limitEnumerationToGroups',
4867
+            ])
4868
+            ->getMock();
4869
+
4870
+        $manager->method('allowEnumerationFullMatch')
4871
+            ->willReturn($allowEnumerationFullMatch);
4872
+        $manager->method('allowEnumeration')
4873
+            ->willReturn($allowEnumeration);
4874
+        $manager->method('limitEnumerationToPhone')
4875
+            ->willReturn($limitEnumerationToPhone);
4876
+        $manager->method('limitEnumerationToGroups')
4877
+            ->willReturn($limitEnumerationToGroups);
4878
+
4879
+        $this->knownUserService->method('isKnownToUser')
4880
+            ->with('current', 'target')
4881
+            ->willReturn($isKnownToUser);
4882
+
4883
+        $currentUser = null;
4884
+        if (!$currentUserIsGuest) {
4885
+            $currentUser = $this->createMock(IUser::class);
4886
+            $currentUser->method('getUID')
4887
+                ->willReturn('current');
4888
+        }
4889
+        $targetUser = $this->createMock(IUser::class);
4890
+        $targetUser->method('getUID')
4891
+            ->willReturn('target');
4892
+
4893
+        if ($haveCommonGroup) {
4894
+            $this->groupManager->method('getUserGroupIds')
4895
+                ->willReturnMap([
4896
+                    [$targetUser, ['gid1', 'gid2']],
4897
+                    [$currentUser, ['gid2', 'gid3']],
4898
+                ]);
4899
+        } else {
4900
+            $this->groupManager->method('getUserGroupIds')
4901
+                ->willReturnMap([
4902
+                    [$targetUser, ['gid1', 'gid2']],
4903
+                    [$currentUser, ['gid3', 'gid4']],
4904
+                ]);
4905
+        }
4906
+
4907
+        $this->assertSame($expected, $manager->currentUserCanEnumerateTargetUser($currentUser, $targetUser));
4908
+    }
4909 4909
 }
4910 4910
 
4911 4911
 class DummyFactory implements IProviderFactory {
4912
-	/** @var IShareProvider */
4913
-	protected $provider;
4914
-
4915
-	public function __construct(\OCP\IServerContainer $serverContainer) {
4916
-	}
4917
-
4918
-	/**
4919
-	 * @param IShareProvider $provider
4920
-	 */
4921
-	public function setProvider($provider) {
4922
-		$this->provider = $provider;
4923
-	}
4924
-
4925
-	/**
4926
-	 * @param string $id
4927
-	 * @return IShareProvider
4928
-	 */
4929
-	public function getProvider($id) {
4930
-		return $this->provider;
4931
-	}
4932
-
4933
-	/**
4934
-	 * @param int $shareType
4935
-	 * @return IShareProvider
4936
-	 */
4937
-	public function getProviderForType($shareType) {
4938
-		return $this->provider;
4939
-	}
4940
-
4941
-	/**
4942
-	 * @return IShareProvider[]
4943
-	 */
4944
-	public function getAllProviders() {
4945
-		return [$this->provider];
4946
-	}
4947
-
4948
-	public function registerProvider(string $shareProvier): void {
4949
-	}
4912
+    /** @var IShareProvider */
4913
+    protected $provider;
4914
+
4915
+    public function __construct(\OCP\IServerContainer $serverContainer) {
4916
+    }
4917
+
4918
+    /**
4919
+     * @param IShareProvider $provider
4920
+     */
4921
+    public function setProvider($provider) {
4922
+        $this->provider = $provider;
4923
+    }
4924
+
4925
+    /**
4926
+     * @param string $id
4927
+     * @return IShareProvider
4928
+     */
4929
+    public function getProvider($id) {
4930
+        return $this->provider;
4931
+    }
4932
+
4933
+    /**
4934
+     * @param int $shareType
4935
+     * @return IShareProvider
4936
+     */
4937
+    public function getProviderForType($shareType) {
4938
+        return $this->provider;
4939
+    }
4940
+
4941
+    /**
4942
+     * @return IShareProvider[]
4943
+     */
4944
+    public function getAllProviders() {
4945
+        return [$this->provider];
4946
+    }
4947
+
4948
+    public function registerProvider(string $shareProvier): void {
4949
+    }
4950 4950
 }
4951 4951
 
4952 4952
 class DummyFactory2 extends DummyFactory {
4953
-	/** @var IShareProvider */
4954
-	private $provider2;
4955
-
4956
-	/**
4957
-	 * @param IShareProvider $provider
4958
-	 */
4959
-	public function setSecondProvider($provider) {
4960
-		$this->provider2 = $provider;
4961
-	}
4962
-
4963
-	public function getAllProviders() {
4964
-		return [$this->provider, $this->provider2];
4965
-	}
4966
-
4967
-	public function registerProvider(string $shareProvier): void {
4968
-	}
4953
+    /** @var IShareProvider */
4954
+    private $provider2;
4955
+
4956
+    /**
4957
+     * @param IShareProvider $provider
4958
+     */
4959
+    public function setSecondProvider($provider) {
4960
+        $this->provider2 = $provider;
4961
+    }
4962
+
4963
+    public function getAllProviders() {
4964
+        return [$this->provider, $this->provider2];
4965
+    }
4966
+
4967
+    public function registerProvider(string $shareProvier): void {
4968
+    }
4969 4969
 }
Please login to merge, or discard this patch.
Spacing   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -145,11 +145,11 @@  discard block
 block discarded – undo
145 145
 		$this->l10nFactory = $this->createMock(IFactory::class);
146 146
 		$this->l = $this->createMock(IL10N::class);
147 147
 		$this->l->method('t')
148
-			->willReturnCallback(function ($text, $parameters = []) {
148
+			->willReturnCallback(function($text, $parameters = []) {
149 149
 				return vsprintf($text, $parameters);
150 150
 			});
151 151
 		$this->l->method('n')
152
-			->willReturnCallback(function ($singular, $plural, $count, $parameters = []) {
152
+			->willReturnCallback(function($singular, $plural, $count, $parameters = []) {
153 153
 				return vsprintf(str_replace('%n', $count, ($count === 1) ? $singular : $plural), $parameters);
154 154
 			});
155 155
 		$this->l10nFactory->method('get')->willReturn($this->l);
@@ -277,7 +277,7 @@  discard block
 block discarded – undo
277 277
 		];
278 278
 		$this->dispatcher->expects($this->exactly(2))
279 279
 			->method('dispatchTyped')
280
-			->willReturnCallback(function ($event) use (&$calls, $share) {
280
+			->willReturnCallback(function($event) use (&$calls, $share) {
281 281
 				$expected = array_shift($calls);
282 282
 				$this->assertInstanceOf($expected, $event);
283 283
 				$this->assertEquals($share, $event->getShare());
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 		];
321 321
 		$this->dispatcher->expects($this->exactly(2))
322 322
 			->method('dispatchTyped')
323
-			->willReturnCallback(function ($event) use (&$calls, $share) {
323
+			->willReturnCallback(function($event) use (&$calls, $share) {
324 324
 				$expected = array_shift($calls);
325 325
 				$this->assertInstanceOf($expected, $event);
326 326
 				$this->assertEquals($share, $event->getShare());
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
 		];
381 381
 		$this->defaultProvider->expects($this->exactly(3))
382 382
 			->method('delete')
383
-			->willReturnCallback(function ($share) use (&$deleteCalls) {
383
+			->willReturnCallback(function($share) use (&$deleteCalls) {
384 384
 				$expected = array_shift($deleteCalls);
385 385
 				$this->assertEquals($expected, $share);
386 386
 			});
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 		];
396 396
 		$this->dispatcher->expects($this->exactly(6))
397 397
 			->method('dispatchTyped')
398
-			->willReturnCallback(function ($event) use (&$dispatchCalls) {
398
+			->willReturnCallback(function($event) use (&$dispatchCalls) {
399 399
 				$expected = array_shift($dispatchCalls);
400 400
 				$this->assertInstanceOf($expected[0], $event);
401 401
 				$this->assertEquals($expected[1]->getId(), $event->getShare()->getId());
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
 		$this->dispatcher->expects($this->once())
430 430
 			->method('dispatchTyped')
431 431
 			->with(
432
-				$this->callBack(function (ShareDeletedFromSelfEvent $e) use ($share) {
432
+				$this->callBack(function(ShareDeletedFromSelfEvent $e) use ($share) {
433 433
 					return $e->getShare() === $share;
434 434
 				})
435 435
 			);
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
 		$this->defaultProvider
462 462
 			->expects($this->exactly(4))
463 463
 			->method('getChildren')
464
-			->willReturnCallback(function ($_share) use ($share, $shares) {
464
+			->willReturnCallback(function($_share) use ($share, $shares) {
465 465
 				if ($_share === $share) {
466 466
 					return $shares;
467 467
 				}
@@ -475,7 +475,7 @@  discard block
 block discarded – undo
475 475
 		];
476 476
 		$this->defaultProvider->expects($this->exactly(3))
477 477
 			->method('delete')
478
-			->willReturnCallback(function ($share) use (&$calls) {
478
+			->willReturnCallback(function($share) use (&$calls) {
479 479
 				$expected = array_shift($calls);
480 480
 				$this->assertEquals($expected, $share);
481 481
 			});
@@ -504,7 +504,7 @@  discard block
 block discarded – undo
504 504
 		$reShare->method('getNode')->willReturn($file);
505 505
 
506 506
 		$this->defaultProvider->method('getSharesBy')
507
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $file) {
507
+			->willReturnCallback(function($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $file) {
508 508
 				$this->assertEquals($file, $node);
509 509
 				if ($shareType === IShare::TYPE_USER) {
510 510
 					return match($userId) {
@@ -555,10 +555,10 @@  discard block
 block discarded – undo
555 555
 		$reShareInOtherFolder->method('getNode')->willReturn($otherFolder);
556 556
 
557 557
 		$this->defaultProvider->method('getSharesBy')
558
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $reShareInSubFolder, $reShareInOtherFolder) {
558
+			->willReturnCallback(function($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare, $reShareInSubFolder, $reShareInOtherFolder) {
559 559
 				if ($shareType === IShare::TYPE_USER) {
560 560
 					return match($userId) {
561
-						'userB' => [$reShare,$reShareInSubFolder,$reShareInOtherFolder],
561
+						'userB' => [$reShare, $reShareInSubFolder, $reShareInOtherFolder],
562 562
 					};
563 563
 				} else {
564 564
 					return [];
@@ -572,7 +572,7 @@  discard block
 block discarded – undo
572 572
 		];
573 573
 		$manager->expects($this->exactly(2))
574 574
 			->method('updateShare')
575
-			->willReturnCallback(function ($share) use (&$calls) {
575
+			->willReturnCallback(function($share) use (&$calls) {
576 576
 				$expected = array_shift($calls);
577 577
 				$this->assertEquals($expected, $share);
578 578
 			});
@@ -646,7 +646,7 @@  discard block
 block discarded – undo
646 646
 		$this->groupManager->method('get')->with('Group')->willReturn($group);
647 647
 
648 648
 		$this->defaultProvider->method('getSharesBy')
649
-			->willReturnCallback(function ($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare1, $reShare2) {
649
+			->willReturnCallback(function($userId, $shareType, $node, $reshares, $limit, $offset) use ($reShare1, $reShare2) {
650 650
 				if ($shareType === IShare::TYPE_USER) {
651 651
 					return match($userId) {
652 652
 						'userB' => [$reShare1],
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
 		];
667 667
 		$manager->expects($this->exactly(2))
668 668
 			->method('updateShare')
669
-			->willReturnCallback(function ($share) use (&$calls) {
669
+			->willReturnCallback(function($share) use (&$calls) {
670 670
 				$expected = array_shift($calls);
671 671
 				$this->assertEquals($expected, $share);
672 672
 			});
@@ -773,7 +773,7 @@  discard block
 block discarded – undo
773 773
 		]);
774 774
 
775 775
 		$this->dispatcher->expects($this->once())->method('dispatchTyped')
776
-			->willReturnCallback(function (Event $event) {
776
+			->willReturnCallback(function(Event $event) {
777 777
 				$this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
778 778
 				/** @var ValidatePasswordPolicyEvent $event */
779 779
 				$this->assertSame('password', $event->getPassword());
@@ -795,7 +795,7 @@  discard block
 block discarded – undo
795 795
 		]);
796 796
 
797 797
 		$this->dispatcher->expects($this->once())->method('dispatchTyped')
798
-			->willReturnCallback(function (Event $event) {
798
+			->willReturnCallback(function(Event $event) {
799 799
 				$this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
800 800
 				/** @var ValidatePasswordPolicyEvent $event */
801 801
 				$this->assertSame('password', $event->getPassword());
@@ -1278,7 +1278,7 @@  discard block
 block discarded – undo
1278 1278
 
1279 1279
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1280 1280
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1281
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1281
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($future) {
1282 1282
 			return $data['expirationDate'] == $future;
1283 1283
 		}));
1284 1284
 
@@ -1304,7 +1304,7 @@  discard block
 block discarded – undo
1304 1304
 
1305 1305
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1306 1306
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1307
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1307
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1308 1308
 			return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1309 1309
 		}));
1310 1310
 
@@ -1319,7 +1319,7 @@  discard block
 block discarded – undo
1319 1319
 	public function testValidateExpirationDateInternalNoDateNoDefault($shareType): void {
1320 1320
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1321 1321
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1322
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1322
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) {
1323 1323
 			return $data['expirationDate'] === null && $data['passwordSet'] === true;
1324 1324
 		}));
1325 1325
 
@@ -1362,7 +1362,7 @@  discard block
 block discarded – undo
1362 1362
 
1363 1363
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1364 1364
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1365
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1365
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1366 1366
 			return $data['expirationDate'] == $expected;
1367 1367
 		}));
1368 1368
 
@@ -1404,7 +1404,7 @@  discard block
 block discarded – undo
1404 1404
 
1405 1405
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1406 1406
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1407
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1407
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1408 1408
 			return $data['expirationDate'] == $expected;
1409 1409
 		}));
1410 1410
 
@@ -1425,7 +1425,7 @@  discard block
 block discarded – undo
1425 1425
 
1426 1426
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1427 1427
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1428
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1428
+		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function($data) {
1429 1429
 			$data['expirationDate']->sub(new \DateInterval('P2D'));
1430 1430
 		});
1431 1431
 
@@ -1456,7 +1456,7 @@  discard block
 block discarded – undo
1456 1456
 
1457 1457
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1458 1458
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1459
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1459
+		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function($data) {
1460 1460
 			$data['accepted'] = false;
1461 1461
 			$data['message'] = 'Invalid date!';
1462 1462
 		});
@@ -1617,7 +1617,7 @@  discard block
 block discarded – undo
1617 1617
 
1618 1618
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1619 1619
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1620
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($future) {
1620
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($future) {
1621 1621
 			return $data['expirationDate'] == $future;
1622 1622
 		}));
1623 1623
 
@@ -1640,7 +1640,7 @@  discard block
 block discarded – undo
1640 1640
 
1641 1641
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1642 1642
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1643
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1643
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1644 1644
 			return $data['expirationDate'] == $expected && $data['passwordSet'] === false;
1645 1645
 		}));
1646 1646
 
@@ -1652,7 +1652,7 @@  discard block
 block discarded – undo
1652 1652
 	public function testValidateExpirationDateNoDateNoDefault(): void {
1653 1653
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1654 1654
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1655
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) {
1655
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) {
1656 1656
 			return $data['expirationDate'] === null && $data['passwordSet'] === true;
1657 1657
 		}));
1658 1658
 
@@ -1681,7 +1681,7 @@  discard block
 block discarded – undo
1681 1681
 
1682 1682
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1683 1683
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1684
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1684
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1685 1685
 			return $data['expirationDate'] == $expected;
1686 1686
 		}));
1687 1687
 
@@ -1711,7 +1711,7 @@  discard block
 block discarded – undo
1711 1711
 
1712 1712
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1713 1713
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1714
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1714
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1715 1715
 			return $data['expirationDate'] == $expected;
1716 1716
 		}));
1717 1717
 
@@ -1742,7 +1742,7 @@  discard block
 block discarded – undo
1742 1742
 
1743 1743
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1744 1744
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1745
-		$hookListener->expects($this->once())->method('listener')->with($this->callback(function ($data) use ($expected) {
1745
+		$hookListener->expects($this->once())->method('listener')->with($this->callback(function($data) use ($expected) {
1746 1746
 			return $data['expirationDate'] == $expected;
1747 1747
 		}));
1748 1748
 
@@ -1762,7 +1762,7 @@  discard block
 block discarded – undo
1762 1762
 
1763 1763
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1764 1764
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1765
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1765
+		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function($data) {
1766 1766
 			$data['expirationDate']->sub(new \DateInterval('P2D'));
1767 1767
 		});
1768 1768
 
@@ -1787,7 +1787,7 @@  discard block
 block discarded – undo
1787 1787
 
1788 1788
 		$hookListener = $this->createMock(DummyShareManagerListener::class);
1789 1789
 		\OCP\Util::connectHook('\OC\Share', 'verifyExpirationDate', $hookListener, 'listener');
1790
-		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function ($data) {
1790
+		$hookListener->expects($this->once())->method('listener')->willReturnCallback(function($data) {
1791 1791
 			$data['accepted'] = false;
1792 1792
 			$data['message'] = 'Invalid date!';
1793 1793
 		});
@@ -2619,7 +2619,7 @@  discard block
 block discarded – undo
2619 2619
 			->expects($this->once())
2620 2620
 			->method('create')
2621 2621
 			->with($share)
2622
-			->willReturnCallback(function (Share $share) {
2622
+			->willReturnCallback(function(Share $share) {
2623 2623
 				return $share->setId(42);
2624 2624
 			});
2625 2625
 
@@ -2629,7 +2629,7 @@  discard block
 block discarded – undo
2629 2629
 		];
2630 2630
 		$this->dispatcher->expects($this->exactly(2))
2631 2631
 			->method('dispatchTyped')
2632
-			->willReturnCallback(function ($event) use (&$calls, $date, $path) {
2632
+			->willReturnCallback(function($event) use (&$calls, $date, $path) {
2633 2633
 				$expected = array_shift($calls);
2634 2634
 				$this->assertInstanceOf($expected, $event);
2635 2635
 				$share = $event->getShare();
@@ -2716,7 +2716,7 @@  discard block
 block discarded – undo
2716 2716
 			->expects($this->once())
2717 2717
 			->method('create')
2718 2718
 			->with($share)
2719
-			->willReturnCallback(function (Share $share) {
2719
+			->willReturnCallback(function(Share $share) {
2720 2720
 				return $share->setId(42);
2721 2721
 			});
2722 2722
 
@@ -2726,7 +2726,7 @@  discard block
 block discarded – undo
2726 2726
 		];
2727 2727
 		$this->dispatcher->expects($this->exactly(2))
2728 2728
 			->method('dispatchTyped')
2729
-			->willReturnCallback(function ($event) use (&$calls, $path) {
2729
+			->willReturnCallback(function($event) use (&$calls, $path) {
2730 2730
 				$expected = array_shift($calls);
2731 2731
 				$this->assertInstanceOf($expected, $event);
2732 2732
 				$share = $event->getShare();
@@ -2813,7 +2813,7 @@  discard block
 block discarded – undo
2813 2813
 			->method('dispatchTyped')
2814 2814
 			->with(
2815 2815
 				$this->isInstanceOf(BeforeShareCreatedEvent::class)
2816
-			)->willReturnCallback(function (BeforeShareCreatedEvent $e) {
2816
+			)->willReturnCallback(function(BeforeShareCreatedEvent $e) {
2817 2817
 				$e->setError('I won\'t let you share!');
2818 2818
 				$e->stopPropagation();
2819 2819
 			}
@@ -2992,7 +2992,7 @@  discard block
 block discarded – undo
2992 2992
 		 */
2993 2993
 		$this->defaultProvider
2994 2994
 			->method('getSharesBy')
2995
-			->willReturnCallback(function ($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) {
2995
+			->willReturnCallback(function($uid, $type, $node, $reshares, $limit, $offset) use (&$shares2) {
2996 2996
 				return array_slice($shares2, $offset, $limit);
2997 2997
 			});
2998 2998
 
@@ -3000,7 +3000,7 @@  discard block
 block discarded – undo
3000 3000
 		 * Simulate the deleteShare call.
3001 3001
 		 */
3002 3002
 		$manager->method('deleteShare')
3003
-			->willReturnCallback(function ($share) use (&$shares2) {
3003
+			->willReturnCallback(function($share) use (&$shares2) {
3004 3004
 				for ($i = 0; $i < count($shares2); $i++) {
3005 3005
 					if ($shares2[$i]->getId() === $share->getId()) {
3006 3006
 						array_splice($shares2, $i, 1);
@@ -3072,7 +3072,7 @@  discard block
 block discarded – undo
3072 3072
 
3073 3073
 		$factory->expects($this->any())
3074 3074
 			->method('getProviderForType')
3075
-			->willReturnCallback(function ($shareType) use ($roomShareProvider) {
3075
+			->willReturnCallback(function($shareType) use ($roomShareProvider) {
3076 3076
 				if ($shareType !== IShare::TYPE_ROOM) {
3077 3077
 					throw new Exception\ProviderException();
3078 3078
 				}
@@ -3110,7 +3110,7 @@  discard block
 block discarded – undo
3110 3110
 		];
3111 3111
 		$factory->expects($this->exactly(2))
3112 3112
 			->method('getProviderForType')
3113
-			->willReturnCallback(function () use (&$calls) {
3113
+			->willReturnCallback(function() use (&$calls) {
3114 3114
 				$expected = array_shift($calls);
3115 3115
 				$this->assertEquals($expected, func_get_args());
3116 3116
 				return $this->defaultProvider;
@@ -3324,7 +3324,7 @@  discard block
 block discarded – undo
3324 3324
 			->setPassword('passwordHash');
3325 3325
 
3326 3326
 		$this->hasher->method('verify')->with('password', 'passwordHash', '')
3327
-			->willReturnCallback(function ($pass, $hash, &$newHash) {
3327
+			->willReturnCallback(function($pass, $hash, &$newHash) {
3328 3328
 				$newHash = 'newHash';
3329 3329
 
3330 3330
 				return true;
@@ -3332,7 +3332,7 @@  discard block
 block discarded – undo
3332 3332
 
3333 3333
 		$this->defaultProvider->expects($this->once())
3334 3334
 			->method('update')
3335
-			->with($this->callback(function (\OCP\Share\IShare $share) {
3335
+			->with($this->callback(function(\OCP\Share\IShare $share) {
3336 3336
 				return $share->getPassword() === 'newHash';
3337 3337
 			}));
3338 3338
 
@@ -4478,7 +4478,7 @@  discard block
 block discarded – undo
4478 4478
 	public function testShareProviderExists($shareType, $expected): void {
4479 4479
 		$factory = $this->getMockBuilder('OCP\Share\IProviderFactory')->getMock();
4480 4480
 		$factory->expects($this->any())->method('getProviderForType')
4481
-			->willReturnCallback(function ($id) {
4481
+			->willReturnCallback(function($id) {
4482 4482
 				if ($id === IShare::TYPE_USER) {
4483 4483
 					return true;
4484 4484
 				}
@@ -4675,7 +4675,7 @@  discard block
 block discarded – undo
4675 4675
 			->willReturn($userFolder);
4676 4676
 
4677 4677
 		$expected = [
4678
-			'users' => ['owner', 'user1', 'user2', 'user3', '123456','user4', 'user5', '234567'],
4678
+			'users' => ['owner', 'user1', 'user2', 'user3', '123456', 'user4', 'user5', '234567'],
4679 4679
 			'remote' => true,
4680 4680
 			'public' => true,
4681 4681
 		];
@@ -4810,12 +4810,12 @@  discard block
 block discarded – undo
4810 4810
 		$share4 = $this->createMock(IShare::class);
4811 4811
 
4812 4812
 		$this->defaultProvider->method('getAllShares')
4813
-			->willReturnCallback(function () use ($share1, $share2) {
4813
+			->willReturnCallback(function() use ($share1, $share2) {
4814 4814
 				yield $share1;
4815 4815
 				yield $share2;
4816 4816
 			});
4817 4817
 		$extraProvider->method('getAllShares')
4818
-			->willReturnCallback(function () use ($share3, $share4) {
4818
+			->willReturnCallback(function() use ($share3, $share4) {
4819 4819
 				yield $share3;
4820 4820
 				yield $share4;
4821 4821
 			});
Please login to merge, or discard this patch.
tests/Core/Command/Apps/AppsDisableTest.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -18,52 +18,52 @@
 block discarded – undo
18 18
  * @group DB
19 19
  */
20 20
 class AppsDisableTest extends TestCase {
21
-	/** @var CommandTester */
22
-	private $commandTester;
21
+    /** @var CommandTester */
22
+    private $commandTester;
23 23
 
24
-	protected function setUp(): void {
25
-		parent::setUp();
24
+    protected function setUp(): void {
25
+        parent::setUp();
26 26
 
27
-		$command = new Disable(
28
-			\OC::$server->getAppManager()
29
-		);
27
+        $command = new Disable(
28
+            \OC::$server->getAppManager()
29
+        );
30 30
 
31
-		$this->commandTester = new CommandTester($command);
31
+        $this->commandTester = new CommandTester($command);
32 32
 
33
-		\OC::$server->getAppManager()->enableApp('admin_audit');
34
-		\OC::$server->getAppManager()->enableApp('comments');
35
-	}
33
+        \OC::$server->getAppManager()->enableApp('admin_audit');
34
+        \OC::$server->getAppManager()->enableApp('comments');
35
+    }
36 36
 
37
-	/**
38
-	 * @dataProvider dataCommandInput
39
-	 * @param $appId
40
-	 * @param $groups
41
-	 * @param $statusCode
42
-	 * @param $pattern
43
-	 */
44
-	public function testCommandInput($appId, $statusCode, $pattern): void {
45
-		$input = ['app-id' => $appId];
37
+    /**
38
+     * @dataProvider dataCommandInput
39
+     * @param $appId
40
+     * @param $groups
41
+     * @param $statusCode
42
+     * @param $pattern
43
+     */
44
+    public function testCommandInput($appId, $statusCode, $pattern): void {
45
+        $input = ['app-id' => $appId];
46 46
 
47
-		$this->commandTester->execute($input);
47
+        $this->commandTester->execute($input);
48 48
 
49
-		$this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
50
-		$this->assertSame($statusCode, $this->commandTester->getStatusCode());
51
-	}
49
+        $this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
50
+        $this->assertSame($statusCode, $this->commandTester->getStatusCode());
51
+    }
52 52
 
53
-	public static function dataCommandInput(): array {
54
-		return [
55
-			[['admin_audit'], 0, 'admin_audit ([\d\.]*) disabled'],
56
-			[['comments'], 0, 'comments ([\d\.]*) disabled'],
57
-			[['invalid_app'], 0, 'No such app enabled: invalid_app'],
53
+    public static function dataCommandInput(): array {
54
+        return [
55
+            [['admin_audit'], 0, 'admin_audit ([\d\.]*) disabled'],
56
+            [['comments'], 0, 'comments ([\d\.]*) disabled'],
57
+            [['invalid_app'], 0, 'No such app enabled: invalid_app'],
58 58
 
59
-			[['admin_audit', 'comments'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled"],
60
-			[['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled\nNo such app enabled: invalid_app"],
59
+            [['admin_audit', 'comments'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled"],
60
+            [['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled\nNo such app enabled: invalid_app"],
61 61
 
62
-			[['files'], 2, "files can't be disabled"],
63
-			[['provisioning_api'], 2, "provisioning_api can't be disabled"],
62
+            [['files'], 2, "files can't be disabled"],
63
+            [['provisioning_api'], 2, "provisioning_api can't be disabled"],
64 64
 
65
-			[['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit ([\d\.]*) disabled"],
66
-			[['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments ([\d\.]*) disabled"],
67
-		];
68
-	}
65
+            [['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit ([\d\.]*) disabled"],
66
+            [['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments ([\d\.]*) disabled"],
67
+        ];
68
+    }
69 69
 }
Please login to merge, or discard this patch.
tests/Core/Command/Apps/AppsEnableTest.php 1 patch
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -19,63 +19,63 @@
 block discarded – undo
19 19
  * @group DB
20 20
  */
21 21
 class AppsEnableTest extends TestCase {
22
-	/** @var CommandTester */
23
-	private $commandTester;
24
-
25
-	protected function setUp(): void {
26
-		parent::setUp();
27
-
28
-		$command = new Enable(
29
-			\OC::$server->getAppManager(),
30
-			\OC::$server->getGroupManager(),
31
-			\OC::$server->get(Installer::class),
32
-		);
33
-
34
-		$this->commandTester = new CommandTester($command);
35
-
36
-		\OC::$server->getAppManager()->disableApp('admin_audit');
37
-		\OC::$server->getAppManager()->disableApp('comments');
38
-	}
39
-
40
-	/**
41
-	 * @dataProvider dataCommandInput
42
-	 * @param $appId
43
-	 * @param $groups
44
-	 * @param $statusCode
45
-	 * @param $pattern
46
-	 */
47
-	public function testCommandInput($appId, $groups, $statusCode, $pattern): void {
48
-		$input = ['app-id' => $appId];
49
-
50
-		if (is_array($groups)) {
51
-			$input['--groups'] = $groups;
52
-		}
53
-
54
-		$this->commandTester->execute($input);
55
-
56
-		$this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
57
-		$this->assertSame($statusCode, $this->commandTester->getStatusCode());
58
-	}
59
-
60
-	public static function dataCommandInput(): array {
61
-		return [
62
-			[['admin_audit'], null, 0, 'admin_audit ([\d\.]*) enabled'],
63
-			[['comments'], null, 0, 'comments ([\d\.]*) enabled'],
64
-			[['comments', 'comments'], null, 0, "comments ([\d\.]*) enabled\ncomments already enabled"],
65
-			[['invalid_app'], null, 1, 'Could not download app invalid_app'],
66
-
67
-			[['admin_audit', 'comments'], null, 0, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled"],
68
-			[['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled\nCould not download app invalid_app"],
69
-
70
-			[['admin_audit'], ['admin'], 1, "admin_audit can't be enabled for groups"],
71
-			[['comments'], ['admin'], 1, "comments can't be enabled for groups"],
72
-
73
-			[['updatenotification'], ['admin'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
74
-			[['updatenotification', 'dashboard'], ['admin'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
75
-
76
-			[['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
77
-			[['updatenotification', 'dashboard'], ['admin', 'invalid_group'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
78
-			[['updatenotification', 'dashboard', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin\nCould not download app invalid_app"],
79
-		];
80
-	}
22
+    /** @var CommandTester */
23
+    private $commandTester;
24
+
25
+    protected function setUp(): void {
26
+        parent::setUp();
27
+
28
+        $command = new Enable(
29
+            \OC::$server->getAppManager(),
30
+            \OC::$server->getGroupManager(),
31
+            \OC::$server->get(Installer::class),
32
+        );
33
+
34
+        $this->commandTester = new CommandTester($command);
35
+
36
+        \OC::$server->getAppManager()->disableApp('admin_audit');
37
+        \OC::$server->getAppManager()->disableApp('comments');
38
+    }
39
+
40
+    /**
41
+     * @dataProvider dataCommandInput
42
+     * @param $appId
43
+     * @param $groups
44
+     * @param $statusCode
45
+     * @param $pattern
46
+     */
47
+    public function testCommandInput($appId, $groups, $statusCode, $pattern): void {
48
+        $input = ['app-id' => $appId];
49
+
50
+        if (is_array($groups)) {
51
+            $input['--groups'] = $groups;
52
+        }
53
+
54
+        $this->commandTester->execute($input);
55
+
56
+        $this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
57
+        $this->assertSame($statusCode, $this->commandTester->getStatusCode());
58
+    }
59
+
60
+    public static function dataCommandInput(): array {
61
+        return [
62
+            [['admin_audit'], null, 0, 'admin_audit ([\d\.]*) enabled'],
63
+            [['comments'], null, 0, 'comments ([\d\.]*) enabled'],
64
+            [['comments', 'comments'], null, 0, "comments ([\d\.]*) enabled\ncomments already enabled"],
65
+            [['invalid_app'], null, 1, 'Could not download app invalid_app'],
66
+
67
+            [['admin_audit', 'comments'], null, 0, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled"],
68
+            [['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled\nCould not download app invalid_app"],
69
+
70
+            [['admin_audit'], ['admin'], 1, "admin_audit can't be enabled for groups"],
71
+            [['comments'], ['admin'], 1, "comments can't be enabled for groups"],
72
+
73
+            [['updatenotification'], ['admin'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
74
+            [['updatenotification', 'dashboard'], ['admin'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
75
+
76
+            [['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
77
+            [['updatenotification', 'dashboard'], ['admin', 'invalid_group'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
78
+            [['updatenotification', 'dashboard', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin\nCould not download app invalid_app"],
79
+        ];
80
+    }
81 81
 }
Please login to merge, or discard this patch.
tests/Core/Command/Encryption/SetDefaultModuleTest.php 2 patches
Indentation   +111 added lines, -111 removed lines patch added patch discarded remove patch
@@ -15,115 +15,115 @@
 block discarded – undo
15 15
 use Test\TestCase;
16 16
 
17 17
 class SetDefaultModuleTest extends TestCase {
18
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IManager */
19
-	protected $manager;
20
-	/** @var \PHPUnit\Framework\MockObject\MockObject|IConfig */
21
-	protected $config;
22
-	/** @var \PHPUnit\Framework\MockObject\MockObject */
23
-	protected $consoleInput;
24
-	/** @var \PHPUnit\Framework\MockObject\MockObject */
25
-	protected $consoleOutput;
26
-
27
-	/** @var \Symfony\Component\Console\Command\Command */
28
-	protected $command;
29
-
30
-	protected function setUp(): void {
31
-		parent::setUp();
32
-
33
-		$this->manager = $this->getMockBuilder(IManager::class)
34
-			->disableOriginalConstructor()
35
-			->getMock();
36
-		$this->config = $this->getMockBuilder(IConfig::class)
37
-			->getMock();
38
-
39
-		$this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
40
-		$this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
41
-
42
-		$this->command = new SetDefaultModule($this->manager, $this->config);
43
-	}
44
-
45
-
46
-	public static function dataSetDefaultModule(): array {
47
-		return [
48
-			['ID0', 'ID0', null, null, 'already'],
49
-			['ID0', 'ID1', 'ID1', true, 'info'],
50
-			['ID0', 'ID1', 'ID1', false, 'error'],
51
-		];
52
-	}
53
-
54
-	/**
55
-	 * @dataProvider dataSetDefaultModule
56
-	 *
57
-	 * @param string $oldModule
58
-	 * @param string $newModule
59
-	 * @param string $updateModule
60
-	 * @param bool $updateSuccess
61
-	 * @param string $expectedString
62
-	 */
63
-	public function testSetDefaultModule($oldModule, $newModule, $updateModule, $updateSuccess, $expectedString): void {
64
-		$this->consoleInput->expects($this->once())
65
-			->method('getArgument')
66
-			->with('module')
67
-			->willReturn($newModule);
68
-
69
-		$this->manager->expects($this->once())
70
-			->method('getDefaultEncryptionModuleId')
71
-			->willReturn($oldModule);
72
-
73
-		$this->config->expects($this->once())
74
-			->method('getSystemValue')
75
-			->with('maintenance', false)
76
-			->willReturn(false);
77
-
78
-		if ($updateModule) {
79
-			$this->manager->expects($this->once())
80
-				->method('setDefaultEncryptionModule')
81
-				->with($updateModule)
82
-				->willReturn($updateSuccess);
83
-		}
84
-
85
-		$this->consoleOutput->expects($this->once())
86
-			->method('writeln')
87
-			->with($this->stringContains($expectedString));
88
-
89
-		self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
90
-	}
91
-
92
-	/**
93
-	 * @dataProvider dataSetDefaultModule
94
-	 *
95
-	 * @param string $oldModule
96
-	 * @param string $newModule
97
-	 * @param string $updateModule
98
-	 * @param bool $updateSuccess
99
-	 * @param string $expectedString
100
-	 */
101
-	public function testMaintenanceMode($oldModule, $newModule, $updateModule, $updateSuccess, $expectedString): void {
102
-		$this->consoleInput->expects($this->never())
103
-			->method('getArgument')
104
-			->with('module')
105
-			->willReturn($newModule);
106
-
107
-		$this->manager->expects($this->never())
108
-			->method('getDefaultEncryptionModuleId')
109
-			->willReturn($oldModule);
110
-
111
-		$this->config->expects($this->once())
112
-			->method('getSystemValue')
113
-			->with('maintenance', false)
114
-			->willReturn(true);
115
-
116
-		$calls = [
117
-			'Maintenance mode must be disabled when setting default module,',
118
-			'in order to load the relevant encryption modules correctly.',
119
-		];
120
-		$this->consoleOutput->expects($this->exactly(2))
121
-			->method('writeln')
122
-			->willReturnCallback(function ($message) use (&$calls) {
123
-				$expected = array_shift($calls);
124
-				$this->assertStringContainsString($expected, $message);
125
-			});
126
-
127
-		self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
128
-	}
18
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IManager */
19
+    protected $manager;
20
+    /** @var \PHPUnit\Framework\MockObject\MockObject|IConfig */
21
+    protected $config;
22
+    /** @var \PHPUnit\Framework\MockObject\MockObject */
23
+    protected $consoleInput;
24
+    /** @var \PHPUnit\Framework\MockObject\MockObject */
25
+    protected $consoleOutput;
26
+
27
+    /** @var \Symfony\Component\Console\Command\Command */
28
+    protected $command;
29
+
30
+    protected function setUp(): void {
31
+        parent::setUp();
32
+
33
+        $this->manager = $this->getMockBuilder(IManager::class)
34
+            ->disableOriginalConstructor()
35
+            ->getMock();
36
+        $this->config = $this->getMockBuilder(IConfig::class)
37
+            ->getMock();
38
+
39
+        $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
40
+        $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
41
+
42
+        $this->command = new SetDefaultModule($this->manager, $this->config);
43
+    }
44
+
45
+
46
+    public static function dataSetDefaultModule(): array {
47
+        return [
48
+            ['ID0', 'ID0', null, null, 'already'],
49
+            ['ID0', 'ID1', 'ID1', true, 'info'],
50
+            ['ID0', 'ID1', 'ID1', false, 'error'],
51
+        ];
52
+    }
53
+
54
+    /**
55
+     * @dataProvider dataSetDefaultModule
56
+     *
57
+     * @param string $oldModule
58
+     * @param string $newModule
59
+     * @param string $updateModule
60
+     * @param bool $updateSuccess
61
+     * @param string $expectedString
62
+     */
63
+    public function testSetDefaultModule($oldModule, $newModule, $updateModule, $updateSuccess, $expectedString): void {
64
+        $this->consoleInput->expects($this->once())
65
+            ->method('getArgument')
66
+            ->with('module')
67
+            ->willReturn($newModule);
68
+
69
+        $this->manager->expects($this->once())
70
+            ->method('getDefaultEncryptionModuleId')
71
+            ->willReturn($oldModule);
72
+
73
+        $this->config->expects($this->once())
74
+            ->method('getSystemValue')
75
+            ->with('maintenance', false)
76
+            ->willReturn(false);
77
+
78
+        if ($updateModule) {
79
+            $this->manager->expects($this->once())
80
+                ->method('setDefaultEncryptionModule')
81
+                ->with($updateModule)
82
+                ->willReturn($updateSuccess);
83
+        }
84
+
85
+        $this->consoleOutput->expects($this->once())
86
+            ->method('writeln')
87
+            ->with($this->stringContains($expectedString));
88
+
89
+        self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
90
+    }
91
+
92
+    /**
93
+     * @dataProvider dataSetDefaultModule
94
+     *
95
+     * @param string $oldModule
96
+     * @param string $newModule
97
+     * @param string $updateModule
98
+     * @param bool $updateSuccess
99
+     * @param string $expectedString
100
+     */
101
+    public function testMaintenanceMode($oldModule, $newModule, $updateModule, $updateSuccess, $expectedString): void {
102
+        $this->consoleInput->expects($this->never())
103
+            ->method('getArgument')
104
+            ->with('module')
105
+            ->willReturn($newModule);
106
+
107
+        $this->manager->expects($this->never())
108
+            ->method('getDefaultEncryptionModuleId')
109
+            ->willReturn($oldModule);
110
+
111
+        $this->config->expects($this->once())
112
+            ->method('getSystemValue')
113
+            ->with('maintenance', false)
114
+            ->willReturn(true);
115
+
116
+        $calls = [
117
+            'Maintenance mode must be disabled when setting default module,',
118
+            'in order to load the relevant encryption modules correctly.',
119
+        ];
120
+        $this->consoleOutput->expects($this->exactly(2))
121
+            ->method('writeln')
122
+            ->willReturnCallback(function ($message) use (&$calls) {
123
+                $expected = array_shift($calls);
124
+                $this->assertStringContainsString($expected, $message);
125
+            });
126
+
127
+        self::invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
128
+    }
129 129
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -119,7 +119,7 @@
 block discarded – undo
119 119
 		];
120 120
 		$this->consoleOutput->expects($this->exactly(2))
121 121
 			->method('writeln')
122
-			->willReturnCallback(function ($message) use (&$calls) {
122
+			->willReturnCallback(function($message) use (&$calls) {
123 123
 				$expected = array_shift($calls);
124 124
 				$this->assertStringContainsString($expected, $message);
125 125
 			});
Please login to merge, or discard this patch.
tests/Core/Command/Encryption/EncryptAllTest.php 1 patch
Indentation   +97 added lines, -97 removed lines patch added patch discarded remove patch
@@ -18,101 +18,101 @@
 block discarded – undo
18 18
 use Test\TestCase;
19 19
 
20 20
 class EncryptAllTest extends TestCase {
21
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\IConfig */
22
-	protected $config;
23
-
24
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IManager */
25
-	protected $encryptionManager;
26
-
27
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\App\IAppManager */
28
-	protected $appManager;
29
-
30
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Input\InputInterface */
31
-	protected $consoleInput;
32
-
33
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Output\OutputInterface */
34
-	protected $consoleOutput;
35
-
36
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Helper\QuestionHelper */
37
-	protected $questionHelper;
38
-
39
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IEncryptionModule */
40
-	protected $encryptionModule;
41
-
42
-	/** @var EncryptAll */
43
-	protected $command;
44
-
45
-	protected function setUp(): void {
46
-		parent::setUp();
47
-
48
-		$this->config = $this->getMockBuilder(IConfig::class)
49
-			->disableOriginalConstructor()
50
-			->getMock();
51
-		$this->encryptionManager = $this->getMockBuilder(IManager::class)
52
-			->disableOriginalConstructor()
53
-			->getMock();
54
-		$this->appManager = $this->getMockBuilder(IAppManager::class)
55
-			->disableOriginalConstructor()
56
-			->getMock();
57
-		$this->encryptionModule = $this->getMockBuilder(IEncryptionModule::class)
58
-			->disableOriginalConstructor()
59
-			->getMock();
60
-		$this->questionHelper = $this->getMockBuilder(QuestionHelper::class)
61
-			->disableOriginalConstructor()
62
-			->getMock();
63
-		$this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
64
-		$this->consoleInput->expects($this->any())
65
-			->method('isInteractive')
66
-			->willReturn(true);
67
-		$this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
68
-	}
69
-
70
-	public function testEncryptAll(): void {
71
-		// trash bin needs to be disabled in order to avoid adding dummy files to the users
72
-		// trash bin which gets deleted during the encryption process
73
-		$this->appManager->expects($this->once())->method('disableApp')->with('files_trashbin');
74
-
75
-		$instance = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
76
-		$this->invokePrivate($instance, 'forceMaintenanceAndTrashbin');
77
-		$this->invokePrivate($instance, 'resetMaintenanceAndTrashbin');
78
-	}
79
-
80
-	/**
81
-	 * @dataProvider dataTestExecute
82
-	 */
83
-	public function testExecute($answer, $askResult): void {
84
-		$command = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
85
-
86
-		$this->encryptionManager->expects($this->once())->method('isEnabled')->willReturn(true);
87
-		$this->questionHelper->expects($this->once())->method('ask')->willReturn($askResult);
88
-
89
-		if ($answer === 'Y' || $answer === 'y') {
90
-			$this->encryptionManager->expects($this->once())
91
-				->method('getEncryptionModule')->willReturn($this->encryptionModule);
92
-			$this->encryptionModule->expects($this->once())
93
-				->method('encryptAll')->with($this->consoleInput, $this->consoleOutput);
94
-		} else {
95
-			$this->encryptionManager->expects($this->never())->method('getEncryptionModule');
96
-			$this->encryptionModule->expects($this->never())->method('encryptAll');
97
-		}
98
-
99
-		$this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput]);
100
-	}
101
-
102
-	public static function dataTestExecute(): array {
103
-		return [
104
-			['y', true], ['Y', true], ['n', false], ['N', false], ['', false]
105
-		];
106
-	}
107
-
108
-
109
-	public function testExecuteException(): void {
110
-		$this->expectException(\Exception::class);
111
-
112
-		$command = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
113
-		$this->encryptionManager->expects($this->once())->method('isEnabled')->willReturn(false);
114
-		$this->encryptionManager->expects($this->never())->method('getEncryptionModule');
115
-		$this->encryptionModule->expects($this->never())->method('encryptAll');
116
-		$this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput]);
117
-	}
21
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\IConfig */
22
+    protected $config;
23
+
24
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IManager */
25
+    protected $encryptionManager;
26
+
27
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\App\IAppManager */
28
+    protected $appManager;
29
+
30
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Input\InputInterface */
31
+    protected $consoleInput;
32
+
33
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Output\OutputInterface */
34
+    protected $consoleOutput;
35
+
36
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Helper\QuestionHelper */
37
+    protected $questionHelper;
38
+
39
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IEncryptionModule */
40
+    protected $encryptionModule;
41
+
42
+    /** @var EncryptAll */
43
+    protected $command;
44
+
45
+    protected function setUp(): void {
46
+        parent::setUp();
47
+
48
+        $this->config = $this->getMockBuilder(IConfig::class)
49
+            ->disableOriginalConstructor()
50
+            ->getMock();
51
+        $this->encryptionManager = $this->getMockBuilder(IManager::class)
52
+            ->disableOriginalConstructor()
53
+            ->getMock();
54
+        $this->appManager = $this->getMockBuilder(IAppManager::class)
55
+            ->disableOriginalConstructor()
56
+            ->getMock();
57
+        $this->encryptionModule = $this->getMockBuilder(IEncryptionModule::class)
58
+            ->disableOriginalConstructor()
59
+            ->getMock();
60
+        $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)
61
+            ->disableOriginalConstructor()
62
+            ->getMock();
63
+        $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
64
+        $this->consoleInput->expects($this->any())
65
+            ->method('isInteractive')
66
+            ->willReturn(true);
67
+        $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
68
+    }
69
+
70
+    public function testEncryptAll(): void {
71
+        // trash bin needs to be disabled in order to avoid adding dummy files to the users
72
+        // trash bin which gets deleted during the encryption process
73
+        $this->appManager->expects($this->once())->method('disableApp')->with('files_trashbin');
74
+
75
+        $instance = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
76
+        $this->invokePrivate($instance, 'forceMaintenanceAndTrashbin');
77
+        $this->invokePrivate($instance, 'resetMaintenanceAndTrashbin');
78
+    }
79
+
80
+    /**
81
+     * @dataProvider dataTestExecute
82
+     */
83
+    public function testExecute($answer, $askResult): void {
84
+        $command = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
85
+
86
+        $this->encryptionManager->expects($this->once())->method('isEnabled')->willReturn(true);
87
+        $this->questionHelper->expects($this->once())->method('ask')->willReturn($askResult);
88
+
89
+        if ($answer === 'Y' || $answer === 'y') {
90
+            $this->encryptionManager->expects($this->once())
91
+                ->method('getEncryptionModule')->willReturn($this->encryptionModule);
92
+            $this->encryptionModule->expects($this->once())
93
+                ->method('encryptAll')->with($this->consoleInput, $this->consoleOutput);
94
+        } else {
95
+            $this->encryptionManager->expects($this->never())->method('getEncryptionModule');
96
+            $this->encryptionModule->expects($this->never())->method('encryptAll');
97
+        }
98
+
99
+        $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput]);
100
+    }
101
+
102
+    public static function dataTestExecute(): array {
103
+        return [
104
+            ['y', true], ['Y', true], ['n', false], ['N', false], ['', false]
105
+        ];
106
+    }
107
+
108
+
109
+    public function testExecuteException(): void {
110
+        $this->expectException(\Exception::class);
111
+
112
+        $command = new EncryptAll($this->encryptionManager, $this->appManager, $this->config, $this->questionHelper);
113
+        $this->encryptionManager->expects($this->once())->method('isEnabled')->willReturn(false);
114
+        $this->encryptionManager->expects($this->never())->method('getEncryptionModule');
115
+        $this->encryptionModule->expects($this->never())->method('encryptAll');
116
+        $this->invokePrivate($command, 'execute', [$this->consoleInput, $this->consoleOutput]);
117
+    }
118 118
 }
Please login to merge, or discard this patch.
tests/Core/Command/Encryption/DecryptAllTest.php 2 patches
Indentation   +197 added lines, -197 removed lines patch added patch discarded remove patch
@@ -17,201 +17,201 @@
 block discarded – undo
17 17
 use Test\TestCase;
18 18
 
19 19
 class DecryptAllTest extends TestCase {
20
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\IConfig */
21
-	protected $config;
22
-
23
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IManager */
24
-	protected $encryptionManager;
25
-
26
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\App\IAppManager */
27
-	protected $appManager;
28
-
29
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Input\InputInterface */
30
-	protected $consoleInput;
31
-
32
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Output\OutputInterface */
33
-	protected $consoleOutput;
34
-
35
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Helper\QuestionHelper */
36
-	protected $questionHelper;
37
-
38
-	/** @var \PHPUnit\Framework\MockObject\MockObject | \OC\Encryption\DecryptAll */
39
-	protected $decryptAll;
40
-
41
-	protected function setUp(): void {
42
-		parent::setUp();
43
-
44
-		$this->config = $this->getMockBuilder(IConfig::class)
45
-			->disableOriginalConstructor()
46
-			->getMock();
47
-		$this->encryptionManager = $this->getMockBuilder(IManager::class)
48
-			->disableOriginalConstructor()
49
-			->getMock();
50
-		$this->appManager = $this->getMockBuilder(IAppManager::class)
51
-			->disableOriginalConstructor()
52
-			->getMock();
53
-		$this->questionHelper = $this->getMockBuilder(QuestionHelper::class)
54
-			->disableOriginalConstructor()
55
-			->getMock();
56
-		$this->decryptAll = $this->getMockBuilder(\OC\Encryption\DecryptAll::class)
57
-			->disableOriginalConstructor()->getMock();
58
-		$this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
59
-		$this->consoleInput->expects($this->any())
60
-			->method('isInteractive')
61
-			->willReturn(true);
62
-		$this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
63
-
64
-		$this->config->expects($this->any())
65
-			->method('getSystemValue')
66
-			->with('maintenance', false)
67
-			->willReturn(false);
68
-		$this->appManager->expects($this->any())
69
-			->method('isEnabledForUser')
70
-			->with('files_trashbin')->willReturn(true);
71
-	}
72
-
73
-	public function testMaintenanceAndTrashbin(): void {
74
-		// on construct we enable single-user-mode and disable the trash bin
75
-		// on destruct we disable single-user-mode again and enable the trash bin
76
-		$calls = [
77
-			['maintenance', true],
78
-			['maintenance', false],
79
-		];
80
-		$this->config->expects($this->exactly(2))
81
-			->method('setSystemValue')
82
-			->willReturnCallback(function () use (&$calls) {
83
-				$expected = array_shift($calls);
84
-				$this->assertEquals($expected, func_get_args());
85
-			});
86
-		$this->appManager->expects($this->once())
87
-			->method('disableApp')
88
-			->with('files_trashbin');
89
-		$this->appManager->expects($this->once())
90
-			->method('enableApp')
91
-			->with('files_trashbin');
92
-
93
-		$instance = new DecryptAll(
94
-			$this->encryptionManager,
95
-			$this->appManager,
96
-			$this->config,
97
-			$this->decryptAll,
98
-			$this->questionHelper
99
-		);
100
-		$this->invokePrivate($instance, 'forceMaintenanceAndTrashbin');
101
-
102
-		$this->assertTrue(
103
-			$this->invokePrivate($instance, 'wasTrashbinEnabled')
104
-		);
105
-
106
-		$this->assertFalse(
107
-			$this->invokePrivate($instance, 'wasMaintenanceModeEnabled')
108
-		);
109
-		$this->invokePrivate($instance, 'resetMaintenanceAndTrashbin');
110
-	}
111
-
112
-	/**
113
-	 * @dataProvider dataTestExecute
114
-	 */
115
-	public function testExecute($encryptionEnabled, $continue): void {
116
-		$instance = new DecryptAll(
117
-			$this->encryptionManager,
118
-			$this->appManager,
119
-			$this->config,
120
-			$this->decryptAll,
121
-			$this->questionHelper
122
-		);
123
-
124
-		$this->encryptionManager->expects($this->once())
125
-			->method('isEnabled')
126
-			->willReturn($encryptionEnabled);
127
-
128
-		$this->consoleInput->expects($this->any())
129
-			->method('getArgument')
130
-			->with('user')
131
-			->willReturn('user1');
132
-
133
-		if ($encryptionEnabled) {
134
-			$calls = [
135
-				['core', 'encryption_enabled', 'no'],
136
-				['core', 'encryption_enabled', 'yes'],
137
-			];
138
-			$this->config->expects($this->exactly(2))
139
-				->method('setAppValue')
140
-				->willReturnCallback(function () use (&$calls) {
141
-					$expected = array_shift($calls);
142
-					$this->assertEquals($expected, func_get_args());
143
-				});
144
-			$this->questionHelper->expects($this->once())
145
-				->method('ask')
146
-				->willReturn($continue);
147
-			if ($continue) {
148
-				$this->decryptAll->expects($this->once())
149
-					->method('decryptAll')
150
-					->with($this->consoleInput, $this->consoleOutput, 'user1');
151
-			} else {
152
-				$this->decryptAll->expects($this->never())->method('decryptAll');
153
-			}
154
-		} else {
155
-			$this->config->expects($this->never())->method('setAppValue');
156
-			$this->decryptAll->expects($this->never())->method('decryptAll');
157
-			$this->questionHelper->expects($this->never())->method('ask');
158
-		}
159
-
160
-		$this->invokePrivate($instance, 'execute', [$this->consoleInput, $this->consoleOutput]);
161
-	}
162
-
163
-	public static function dataTestExecute(): array {
164
-		return [
165
-			[true, true],
166
-			[true, false],
167
-			[false, true],
168
-			[false, false]
169
-		];
170
-	}
171
-
172
-
173
-	public function testExecuteFailure(): void {
174
-		$this->expectException(\Exception::class);
175
-
176
-		$instance = new DecryptAll(
177
-			$this->encryptionManager,
178
-			$this->appManager,
179
-			$this->config,
180
-			$this->decryptAll,
181
-			$this->questionHelper
182
-		);
183
-
184
-		// make sure that we enable encryption again after a exception was thrown
185
-		$calls = [
186
-			['core', 'encryption_enabled', 'no'],
187
-			['core', 'encryption_enabled', 'yes'],
188
-		];
189
-		$this->config->expects($this->exactly(2))
190
-			->method('setAppValue')
191
-			->willReturnCallback(function () use (&$calls) {
192
-				$expected = array_shift($calls);
193
-				$this->assertEquals($expected, func_get_args());
194
-			});
195
-		$this->encryptionManager->expects($this->once())
196
-			->method('isEnabled')
197
-			->willReturn(true);
198
-
199
-		$this->consoleInput->expects($this->any())
200
-			->method('getArgument')
201
-			->with('user')
202
-			->willReturn('user1');
203
-
204
-		$this->questionHelper->expects($this->once())
205
-			->method('ask')
206
-			->willReturn(true);
207
-
208
-		$this->decryptAll->expects($this->once())
209
-			->method('decryptAll')
210
-			->with($this->consoleInput, $this->consoleOutput, 'user1')
211
-			->willReturnCallback(function () {
212
-				throw new \Exception();
213
-			});
214
-
215
-		$this->invokePrivate($instance, 'execute', [$this->consoleInput, $this->consoleOutput]);
216
-	}
20
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\IConfig */
21
+    protected $config;
22
+
23
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\Encryption\IManager */
24
+    protected $encryptionManager;
25
+
26
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OCP\App\IAppManager */
27
+    protected $appManager;
28
+
29
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Input\InputInterface */
30
+    protected $consoleInput;
31
+
32
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Output\OutputInterface */
33
+    protected $consoleOutput;
34
+
35
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \Symfony\Component\Console\Helper\QuestionHelper */
36
+    protected $questionHelper;
37
+
38
+    /** @var \PHPUnit\Framework\MockObject\MockObject | \OC\Encryption\DecryptAll */
39
+    protected $decryptAll;
40
+
41
+    protected function setUp(): void {
42
+        parent::setUp();
43
+
44
+        $this->config = $this->getMockBuilder(IConfig::class)
45
+            ->disableOriginalConstructor()
46
+            ->getMock();
47
+        $this->encryptionManager = $this->getMockBuilder(IManager::class)
48
+            ->disableOriginalConstructor()
49
+            ->getMock();
50
+        $this->appManager = $this->getMockBuilder(IAppManager::class)
51
+            ->disableOriginalConstructor()
52
+            ->getMock();
53
+        $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)
54
+            ->disableOriginalConstructor()
55
+            ->getMock();
56
+        $this->decryptAll = $this->getMockBuilder(\OC\Encryption\DecryptAll::class)
57
+            ->disableOriginalConstructor()->getMock();
58
+        $this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
59
+        $this->consoleInput->expects($this->any())
60
+            ->method('isInteractive')
61
+            ->willReturn(true);
62
+        $this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
63
+
64
+        $this->config->expects($this->any())
65
+            ->method('getSystemValue')
66
+            ->with('maintenance', false)
67
+            ->willReturn(false);
68
+        $this->appManager->expects($this->any())
69
+            ->method('isEnabledForUser')
70
+            ->with('files_trashbin')->willReturn(true);
71
+    }
72
+
73
+    public function testMaintenanceAndTrashbin(): void {
74
+        // on construct we enable single-user-mode and disable the trash bin
75
+        // on destruct we disable single-user-mode again and enable the trash bin
76
+        $calls = [
77
+            ['maintenance', true],
78
+            ['maintenance', false],
79
+        ];
80
+        $this->config->expects($this->exactly(2))
81
+            ->method('setSystemValue')
82
+            ->willReturnCallback(function () use (&$calls) {
83
+                $expected = array_shift($calls);
84
+                $this->assertEquals($expected, func_get_args());
85
+            });
86
+        $this->appManager->expects($this->once())
87
+            ->method('disableApp')
88
+            ->with('files_trashbin');
89
+        $this->appManager->expects($this->once())
90
+            ->method('enableApp')
91
+            ->with('files_trashbin');
92
+
93
+        $instance = new DecryptAll(
94
+            $this->encryptionManager,
95
+            $this->appManager,
96
+            $this->config,
97
+            $this->decryptAll,
98
+            $this->questionHelper
99
+        );
100
+        $this->invokePrivate($instance, 'forceMaintenanceAndTrashbin');
101
+
102
+        $this->assertTrue(
103
+            $this->invokePrivate($instance, 'wasTrashbinEnabled')
104
+        );
105
+
106
+        $this->assertFalse(
107
+            $this->invokePrivate($instance, 'wasMaintenanceModeEnabled')
108
+        );
109
+        $this->invokePrivate($instance, 'resetMaintenanceAndTrashbin');
110
+    }
111
+
112
+    /**
113
+     * @dataProvider dataTestExecute
114
+     */
115
+    public function testExecute($encryptionEnabled, $continue): void {
116
+        $instance = new DecryptAll(
117
+            $this->encryptionManager,
118
+            $this->appManager,
119
+            $this->config,
120
+            $this->decryptAll,
121
+            $this->questionHelper
122
+        );
123
+
124
+        $this->encryptionManager->expects($this->once())
125
+            ->method('isEnabled')
126
+            ->willReturn($encryptionEnabled);
127
+
128
+        $this->consoleInput->expects($this->any())
129
+            ->method('getArgument')
130
+            ->with('user')
131
+            ->willReturn('user1');
132
+
133
+        if ($encryptionEnabled) {
134
+            $calls = [
135
+                ['core', 'encryption_enabled', 'no'],
136
+                ['core', 'encryption_enabled', 'yes'],
137
+            ];
138
+            $this->config->expects($this->exactly(2))
139
+                ->method('setAppValue')
140
+                ->willReturnCallback(function () use (&$calls) {
141
+                    $expected = array_shift($calls);
142
+                    $this->assertEquals($expected, func_get_args());
143
+                });
144
+            $this->questionHelper->expects($this->once())
145
+                ->method('ask')
146
+                ->willReturn($continue);
147
+            if ($continue) {
148
+                $this->decryptAll->expects($this->once())
149
+                    ->method('decryptAll')
150
+                    ->with($this->consoleInput, $this->consoleOutput, 'user1');
151
+            } else {
152
+                $this->decryptAll->expects($this->never())->method('decryptAll');
153
+            }
154
+        } else {
155
+            $this->config->expects($this->never())->method('setAppValue');
156
+            $this->decryptAll->expects($this->never())->method('decryptAll');
157
+            $this->questionHelper->expects($this->never())->method('ask');
158
+        }
159
+
160
+        $this->invokePrivate($instance, 'execute', [$this->consoleInput, $this->consoleOutput]);
161
+    }
162
+
163
+    public static function dataTestExecute(): array {
164
+        return [
165
+            [true, true],
166
+            [true, false],
167
+            [false, true],
168
+            [false, false]
169
+        ];
170
+    }
171
+
172
+
173
+    public function testExecuteFailure(): void {
174
+        $this->expectException(\Exception::class);
175
+
176
+        $instance = new DecryptAll(
177
+            $this->encryptionManager,
178
+            $this->appManager,
179
+            $this->config,
180
+            $this->decryptAll,
181
+            $this->questionHelper
182
+        );
183
+
184
+        // make sure that we enable encryption again after a exception was thrown
185
+        $calls = [
186
+            ['core', 'encryption_enabled', 'no'],
187
+            ['core', 'encryption_enabled', 'yes'],
188
+        ];
189
+        $this->config->expects($this->exactly(2))
190
+            ->method('setAppValue')
191
+            ->willReturnCallback(function () use (&$calls) {
192
+                $expected = array_shift($calls);
193
+                $this->assertEquals($expected, func_get_args());
194
+            });
195
+        $this->encryptionManager->expects($this->once())
196
+            ->method('isEnabled')
197
+            ->willReturn(true);
198
+
199
+        $this->consoleInput->expects($this->any())
200
+            ->method('getArgument')
201
+            ->with('user')
202
+            ->willReturn('user1');
203
+
204
+        $this->questionHelper->expects($this->once())
205
+            ->method('ask')
206
+            ->willReturn(true);
207
+
208
+        $this->decryptAll->expects($this->once())
209
+            ->method('decryptAll')
210
+            ->with($this->consoleInput, $this->consoleOutput, 'user1')
211
+            ->willReturnCallback(function () {
212
+                throw new \Exception();
213
+            });
214
+
215
+        $this->invokePrivate($instance, 'execute', [$this->consoleInput, $this->consoleOutput]);
216
+    }
217 217
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
 		];
80 80
 		$this->config->expects($this->exactly(2))
81 81
 			->method('setSystemValue')
82
-			->willReturnCallback(function () use (&$calls) {
82
+			->willReturnCallback(function() use (&$calls) {
83 83
 				$expected = array_shift($calls);
84 84
 				$this->assertEquals($expected, func_get_args());
85 85
 			});
@@ -137,7 +137,7 @@  discard block
 block discarded – undo
137 137
 			];
138 138
 			$this->config->expects($this->exactly(2))
139 139
 				->method('setAppValue')
140
-				->willReturnCallback(function () use (&$calls) {
140
+				->willReturnCallback(function() use (&$calls) {
141 141
 					$expected = array_shift($calls);
142 142
 					$this->assertEquals($expected, func_get_args());
143 143
 				});
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 		];
189 189
 		$this->config->expects($this->exactly(2))
190 190
 			->method('setAppValue')
191
-			->willReturnCallback(function () use (&$calls) {
191
+			->willReturnCallback(function() use (&$calls) {
192 192
 				$expected = array_shift($calls);
193 193
 				$this->assertEquals($expected, func_get_args());
194 194
 			});
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 		$this->decryptAll->expects($this->once())
209 209
 			->method('decryptAll')
210 210
 			->with($this->consoleInput, $this->consoleOutput, 'user1')
211
-			->willReturnCallback(function () {
211
+			->willReturnCallback(function() {
212 212
 				throw new \Exception();
213 213
 			});
214 214
 
Please login to merge, or discard this patch.
tests/Core/Command/Encryption/ChangeKeyStorageRootTest.php 1 patch
Indentation   +339 added lines, -339 removed lines patch added patch discarded remove patch
@@ -20,343 +20,343 @@
 block discarded – undo
20 20
 use Test\TestCase;
21 21
 
22 22
 class ChangeKeyStorageRootTest extends TestCase {
23
-	/** @var ChangeKeyStorageRoot */
24
-	protected $changeKeyStorageRoot;
25
-
26
-	/** @var View | \PHPUnit\Framework\MockObject\MockObject */
27
-	protected $view;
28
-
29
-	/** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */
30
-	protected $userManager;
31
-
32
-	/** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */
33
-	protected $config;
34
-
35
-	/** @var Util | \PHPUnit\Framework\MockObject\MockObject */
36
-	protected $util;
37
-
38
-	/** @var QuestionHelper | \PHPUnit\Framework\MockObject\MockObject */
39
-	protected $questionHelper;
40
-
41
-	/** @var InputInterface | \PHPUnit\Framework\MockObject\MockObject */
42
-	protected $inputInterface;
43
-
44
-	/** @var OutputInterface | \PHPUnit\Framework\MockObject\MockObject */
45
-	protected $outputInterface;
46
-
47
-	/** @var \OCP\UserInterface |  \PHPUnit\Framework\MockObject\MockObject */
48
-	protected $userInterface;
49
-
50
-	protected function setUp(): void {
51
-		parent::setUp();
52
-
53
-		$this->view = $this->getMockBuilder(View::class)->getMock();
54
-		$this->userManager = $this->getMockBuilder(IUserManager::class)->getMock();
55
-		$this->config = $this->getMockBuilder(IConfig::class)->getMock();
56
-		$this->util = $this->getMockBuilder('OC\Encryption\Util')->disableOriginalConstructor()->getMock();
57
-		$this->questionHelper = $this->getMockBuilder(QuestionHelper::class)->getMock();
58
-		$this->inputInterface = $this->getMockBuilder(InputInterface::class)->getMock();
59
-		$this->outputInterface = $this->getMockBuilder(OutputInterface::class)->getMock();
60
-		$this->userInterface = $this->getMockBuilder(UserInterface::class)->getMock();
61
-
62
-		/* We need format method to return a string */
63
-		$outputFormatter = $this->createMock(OutputFormatterInterface::class);
64
-		$outputFormatter->method('isDecorated')->willReturn(false);
65
-		$outputFormatter->method('format')->willReturnArgument(0);
66
-
67
-		$this->outputInterface->expects($this->any())->method('getFormatter')
68
-			->willReturn($outputFormatter);
69
-
70
-		$this->changeKeyStorageRoot = new ChangeKeyStorageRoot(
71
-			$this->view,
72
-			$this->userManager,
73
-			$this->config,
74
-			$this->util,
75
-			$this->questionHelper
76
-		);
77
-	}
78
-
79
-	/**
80
-	 * @dataProvider dataTestExecute
81
-	 */
82
-	public function testExecute($newRoot, $answer, $successMoveKey): void {
83
-		$changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
84
-			->setConstructorArgs(
85
-				[
86
-					$this->view,
87
-					$this->userManager,
88
-					$this->config,
89
-					$this->util,
90
-					$this->questionHelper
91
-				]
92
-			)->onlyMethods(['moveAllKeys'])->getMock();
93
-
94
-		$this->util->expects($this->once())->method('getKeyStorageRoot')
95
-			->willReturn('');
96
-		$this->inputInterface->expects($this->once())->method('getArgument')
97
-			->with('newRoot')->willReturn($newRoot);
98
-
99
-		if ($answer === true || $newRoot !== null) {
100
-			$changeKeyStorageRoot->expects($this->once())->method('moveAllKeys')
101
-				->willReturn($successMoveKey);
102
-		} else {
103
-			$changeKeyStorageRoot->expects($this->never())->method('moveAllKeys');
104
-		}
105
-
106
-		if ($successMoveKey === true) {
107
-			$this->util->expects($this->once())->method('setKeyStorageRoot');
108
-		} else {
109
-			$this->util->expects($this->never())->method('setKeyStorageRoot');
110
-		}
111
-
112
-		if ($newRoot === null) {
113
-			$this->questionHelper->expects($this->once())->method('ask')->willReturn($answer);
114
-		} else {
115
-			$this->questionHelper->expects($this->never())->method('ask');
116
-		}
117
-
118
-		$this->invokePrivate(
119
-			$changeKeyStorageRoot,
120
-			'execute',
121
-			[$this->inputInterface, $this->outputInterface]
122
-		);
123
-	}
124
-
125
-	public static function dataTestExecute(): array {
126
-		return [
127
-			[null, true, true],
128
-			[null, true, false],
129
-			[null, false, null],
130
-			['/newRoot', null, true],
131
-			['/newRoot', null, false]
132
-		];
133
-	}
134
-
135
-	public function testMoveAllKeys(): void {
136
-		/** @var \OC\Core\Command\Encryption\ChangeKeyStorageRoot $changeKeyStorageRoot */
137
-		$changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
138
-			->setConstructorArgs(
139
-				[
140
-					$this->view,
141
-					$this->userManager,
142
-					$this->config,
143
-					$this->util,
144
-					$this->questionHelper
145
-				]
146
-			)->onlyMethods(['prepareNewRoot', 'moveSystemKeys', 'moveUserKeys'])->getMock();
147
-
148
-		$changeKeyStorageRoot->expects($this->once())->method('prepareNewRoot')->with('newRoot');
149
-		$changeKeyStorageRoot->expects($this->once())->method('moveSystemKeys')->with('oldRoot', 'newRoot');
150
-		$changeKeyStorageRoot->expects($this->once())->method('moveUserKeys')->with('oldRoot', 'newRoot', $this->outputInterface);
151
-
152
-		$this->invokePrivate($changeKeyStorageRoot, 'moveAllKeys', ['oldRoot', 'newRoot', $this->outputInterface]);
153
-	}
154
-
155
-	public function testPrepareNewRoot(): void {
156
-		$this->view->expects($this->once())->method('is_dir')->with('newRoot')
157
-			->willReturn(true);
158
-
159
-		$this->view->expects($this->once())->method('file_put_contents')
160
-			->with('newRoot/' . \OC\Encryption\Keys\Storage::KEY_STORAGE_MARKER,
161
-				'Nextcloud will detect this folder as key storage root only if this file exists')->willReturn(true);
162
-
163
-		$this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']);
164
-	}
165
-
166
-	/**
167
-	 * @dataProvider dataTestPrepareNewRootException
168
-	 *
169
-	 * @param bool $dirExists
170
-	 * @param bool $couldCreateFile
171
-	 */
172
-	public function testPrepareNewRootException($dirExists, $couldCreateFile): void {
173
-		$this->expectException(\Exception::class);
174
-
175
-		$this->view->expects($this->once())->method('is_dir')->with('newRoot')
176
-			->willReturn($dirExists);
177
-		$this->view->expects($this->any())->method('file_put_contents')->willReturn($couldCreateFile);
178
-
179
-		$this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']);
180
-	}
181
-
182
-	public static function dataTestPrepareNewRootException(): array {
183
-		return [
184
-			[true, false],
185
-			[true, null],
186
-			[false, true]
187
-		];
188
-	}
189
-
190
-	/**
191
-	 * @dataProvider dataTestMoveSystemKeys
192
-	 *
193
-	 * @param bool $dirExists
194
-	 * @param bool $targetExists
195
-	 * @param bool $executeRename
196
-	 */
197
-	public function testMoveSystemKeys($dirExists, $targetExists, $executeRename): void {
198
-		$changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
199
-			->setConstructorArgs(
200
-				[
201
-					$this->view,
202
-					$this->userManager,
203
-					$this->config,
204
-					$this->util,
205
-					$this->questionHelper
206
-				]
207
-			)->onlyMethods(['targetExists'])->getMock();
208
-
209
-		$this->view->expects($this->once())->method('is_dir')
210
-			->with('oldRoot/files_encryption')->willReturn($dirExists);
211
-		$changeKeyStorageRoot->expects($this->any())->method('targetExists')
212
-			->with('newRoot/files_encryption')->willReturn($targetExists);
213
-
214
-		if ($executeRename) {
215
-			$this->view->expects($this->once())->method('rename')
216
-				->with('oldRoot/files_encryption', 'newRoot/files_encryption');
217
-		} else {
218
-			$this->view->expects($this->never())->method('rename');
219
-		}
220
-
221
-		$this->invokePrivate($changeKeyStorageRoot, 'moveSystemKeys', ['oldRoot', 'newRoot']);
222
-	}
223
-
224
-	public static function dataTestMoveSystemKeys(): array {
225
-		return [
226
-			[true, false, true],
227
-			[false, true, false],
228
-			[true, true, false],
229
-			[false, false, false]
230
-		];
231
-	}
232
-
233
-
234
-	public function testMoveUserKeys(): void {
235
-		$changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
236
-			->setConstructorArgs(
237
-				[
238
-					$this->view,
239
-					$this->userManager,
240
-					$this->config,
241
-					$this->util,
242
-					$this->questionHelper
243
-				]
244
-			)->onlyMethods(['setupUserFS', 'moveUserEncryptionFolder'])->getMock();
245
-
246
-		$this->userManager->expects($this->once())->method('getBackends')
247
-			->willReturn([$this->userInterface]);
248
-		$this->userInterface->expects($this->once())->method('getUsers')
249
-			->willReturn(['user1', 'user2']);
250
-		$changeKeyStorageRoot->expects($this->exactly(2))->method('setupUserFS');
251
-		$changeKeyStorageRoot->expects($this->exactly(2))->method('moveUserEncryptionFolder');
252
-
253
-		$this->invokePrivate($changeKeyStorageRoot, 'moveUserKeys', ['oldRoot', 'newRoot', $this->outputInterface]);
254
-	}
255
-
256
-	/**
257
-	 * @dataProvider dataTestMoveUserEncryptionFolder
258
-	 *
259
-	 * @param bool $userExists
260
-	 * @param bool $isDir
261
-	 * @param bool $targetExists
262
-	 * @param bool $shouldRename
263
-	 */
264
-	public function testMoveUserEncryptionFolder($userExists, $isDir, $targetExists, $shouldRename): void {
265
-		$changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
266
-			->setConstructorArgs(
267
-				[
268
-					$this->view,
269
-					$this->userManager,
270
-					$this->config,
271
-					$this->util,
272
-					$this->questionHelper
273
-				]
274
-			)->onlyMethods(['targetExists', 'prepareParentFolder'])->getMock();
275
-
276
-		$this->userManager->expects($this->once())->method('userExists')
277
-			->willReturn($userExists);
278
-		$this->view->expects($this->any())->method('is_dir')
279
-			->willReturn($isDir);
280
-		$changeKeyStorageRoot->expects($this->any())->method('targetExists')
281
-			->willReturn($targetExists);
282
-
283
-		if ($shouldRename) {
284
-			$changeKeyStorageRoot->expects($this->once())->method('prepareParentFolder')
285
-				->with('newRoot/user1');
286
-			$this->view->expects($this->once())->method('rename')
287
-				->with('oldRoot/user1/files_encryption', 'newRoot/user1/files_encryption');
288
-		} else {
289
-			$changeKeyStorageRoot->expects($this->never())->method('prepareParentFolder');
290
-			$this->view->expects($this->never())->method('rename');
291
-		}
292
-
293
-		$this->invokePrivate($changeKeyStorageRoot, 'moveUserEncryptionFolder', ['user1', 'oldRoot', 'newRoot']);
294
-	}
295
-
296
-	public static function dataTestMoveUserEncryptionFolder(): array {
297
-		return [
298
-			[true, true, false, true],
299
-			[true, false, true, false],
300
-			[false, true, true, false],
301
-			[false, false, true, false],
302
-			[false, true, false, false],
303
-			[false, true, true, false],
304
-			[false, false, false, false]
305
-		];
306
-	}
307
-
308
-
309
-	/**
310
-	 * @dataProvider dataTestPrepareParentFolder
311
-	 */
312
-	public function testPrepareParentFolder($path, $pathExists): void {
313
-		$this->view->expects($this->any())->method('file_exists')
314
-			->willReturnCallback(
315
-				function ($fileExistsPath) use ($path, $pathExists) {
316
-					if ($path === $fileExistsPath) {
317
-						return $pathExists;
318
-					}
319
-					return false;
320
-				}
321
-			);
322
-
323
-		if ($pathExists === false) {
324
-			$subDirs = explode('/', ltrim($path, '/'));
325
-			$this->view->expects($this->exactly(count($subDirs)))->method('mkdir');
326
-		} else {
327
-			$this->view->expects($this->never())->method('mkdir');
328
-		}
329
-
330
-		$this->invokePrivate(
331
-			$this->changeKeyStorageRoot,
332
-			'prepareParentFolder',
333
-			[$path]
334
-		);
335
-	}
336
-
337
-	public static function dataTestPrepareParentFolder(): array {
338
-		return [
339
-			['/user/folder/sub_folder/keystorage', true],
340
-			['/user/folder/sub_folder/keystorage', false]
341
-		];
342
-	}
343
-
344
-	public function testTargetExists(): void {
345
-		$this->view->expects($this->once())->method('file_exists')->with('path')
346
-			->willReturn(false);
347
-
348
-		$this->assertFalse(
349
-			$this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path'])
350
-		);
351
-	}
352
-
353
-
354
-	public function testTargetExistsException(): void {
355
-		$this->expectException(\Exception::class);
356
-
357
-		$this->view->expects($this->once())->method('file_exists')->with('path')
358
-			->willReturn(true);
359
-
360
-		$this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']);
361
-	}
23
+    /** @var ChangeKeyStorageRoot */
24
+    protected $changeKeyStorageRoot;
25
+
26
+    /** @var View | \PHPUnit\Framework\MockObject\MockObject */
27
+    protected $view;
28
+
29
+    /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */
30
+    protected $userManager;
31
+
32
+    /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */
33
+    protected $config;
34
+
35
+    /** @var Util | \PHPUnit\Framework\MockObject\MockObject */
36
+    protected $util;
37
+
38
+    /** @var QuestionHelper | \PHPUnit\Framework\MockObject\MockObject */
39
+    protected $questionHelper;
40
+
41
+    /** @var InputInterface | \PHPUnit\Framework\MockObject\MockObject */
42
+    protected $inputInterface;
43
+
44
+    /** @var OutputInterface | \PHPUnit\Framework\MockObject\MockObject */
45
+    protected $outputInterface;
46
+
47
+    /** @var \OCP\UserInterface |  \PHPUnit\Framework\MockObject\MockObject */
48
+    protected $userInterface;
49
+
50
+    protected function setUp(): void {
51
+        parent::setUp();
52
+
53
+        $this->view = $this->getMockBuilder(View::class)->getMock();
54
+        $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock();
55
+        $this->config = $this->getMockBuilder(IConfig::class)->getMock();
56
+        $this->util = $this->getMockBuilder('OC\Encryption\Util')->disableOriginalConstructor()->getMock();
57
+        $this->questionHelper = $this->getMockBuilder(QuestionHelper::class)->getMock();
58
+        $this->inputInterface = $this->getMockBuilder(InputInterface::class)->getMock();
59
+        $this->outputInterface = $this->getMockBuilder(OutputInterface::class)->getMock();
60
+        $this->userInterface = $this->getMockBuilder(UserInterface::class)->getMock();
61
+
62
+        /* We need format method to return a string */
63
+        $outputFormatter = $this->createMock(OutputFormatterInterface::class);
64
+        $outputFormatter->method('isDecorated')->willReturn(false);
65
+        $outputFormatter->method('format')->willReturnArgument(0);
66
+
67
+        $this->outputInterface->expects($this->any())->method('getFormatter')
68
+            ->willReturn($outputFormatter);
69
+
70
+        $this->changeKeyStorageRoot = new ChangeKeyStorageRoot(
71
+            $this->view,
72
+            $this->userManager,
73
+            $this->config,
74
+            $this->util,
75
+            $this->questionHelper
76
+        );
77
+    }
78
+
79
+    /**
80
+     * @dataProvider dataTestExecute
81
+     */
82
+    public function testExecute($newRoot, $answer, $successMoveKey): void {
83
+        $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
84
+            ->setConstructorArgs(
85
+                [
86
+                    $this->view,
87
+                    $this->userManager,
88
+                    $this->config,
89
+                    $this->util,
90
+                    $this->questionHelper
91
+                ]
92
+            )->onlyMethods(['moveAllKeys'])->getMock();
93
+
94
+        $this->util->expects($this->once())->method('getKeyStorageRoot')
95
+            ->willReturn('');
96
+        $this->inputInterface->expects($this->once())->method('getArgument')
97
+            ->with('newRoot')->willReturn($newRoot);
98
+
99
+        if ($answer === true || $newRoot !== null) {
100
+            $changeKeyStorageRoot->expects($this->once())->method('moveAllKeys')
101
+                ->willReturn($successMoveKey);
102
+        } else {
103
+            $changeKeyStorageRoot->expects($this->never())->method('moveAllKeys');
104
+        }
105
+
106
+        if ($successMoveKey === true) {
107
+            $this->util->expects($this->once())->method('setKeyStorageRoot');
108
+        } else {
109
+            $this->util->expects($this->never())->method('setKeyStorageRoot');
110
+        }
111
+
112
+        if ($newRoot === null) {
113
+            $this->questionHelper->expects($this->once())->method('ask')->willReturn($answer);
114
+        } else {
115
+            $this->questionHelper->expects($this->never())->method('ask');
116
+        }
117
+
118
+        $this->invokePrivate(
119
+            $changeKeyStorageRoot,
120
+            'execute',
121
+            [$this->inputInterface, $this->outputInterface]
122
+        );
123
+    }
124
+
125
+    public static function dataTestExecute(): array {
126
+        return [
127
+            [null, true, true],
128
+            [null, true, false],
129
+            [null, false, null],
130
+            ['/newRoot', null, true],
131
+            ['/newRoot', null, false]
132
+        ];
133
+    }
134
+
135
+    public function testMoveAllKeys(): void {
136
+        /** @var \OC\Core\Command\Encryption\ChangeKeyStorageRoot $changeKeyStorageRoot */
137
+        $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
138
+            ->setConstructorArgs(
139
+                [
140
+                    $this->view,
141
+                    $this->userManager,
142
+                    $this->config,
143
+                    $this->util,
144
+                    $this->questionHelper
145
+                ]
146
+            )->onlyMethods(['prepareNewRoot', 'moveSystemKeys', 'moveUserKeys'])->getMock();
147
+
148
+        $changeKeyStorageRoot->expects($this->once())->method('prepareNewRoot')->with('newRoot');
149
+        $changeKeyStorageRoot->expects($this->once())->method('moveSystemKeys')->with('oldRoot', 'newRoot');
150
+        $changeKeyStorageRoot->expects($this->once())->method('moveUserKeys')->with('oldRoot', 'newRoot', $this->outputInterface);
151
+
152
+        $this->invokePrivate($changeKeyStorageRoot, 'moveAllKeys', ['oldRoot', 'newRoot', $this->outputInterface]);
153
+    }
154
+
155
+    public function testPrepareNewRoot(): void {
156
+        $this->view->expects($this->once())->method('is_dir')->with('newRoot')
157
+            ->willReturn(true);
158
+
159
+        $this->view->expects($this->once())->method('file_put_contents')
160
+            ->with('newRoot/' . \OC\Encryption\Keys\Storage::KEY_STORAGE_MARKER,
161
+                'Nextcloud will detect this folder as key storage root only if this file exists')->willReturn(true);
162
+
163
+        $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']);
164
+    }
165
+
166
+    /**
167
+     * @dataProvider dataTestPrepareNewRootException
168
+     *
169
+     * @param bool $dirExists
170
+     * @param bool $couldCreateFile
171
+     */
172
+    public function testPrepareNewRootException($dirExists, $couldCreateFile): void {
173
+        $this->expectException(\Exception::class);
174
+
175
+        $this->view->expects($this->once())->method('is_dir')->with('newRoot')
176
+            ->willReturn($dirExists);
177
+        $this->view->expects($this->any())->method('file_put_contents')->willReturn($couldCreateFile);
178
+
179
+        $this->invokePrivate($this->changeKeyStorageRoot, 'prepareNewRoot', ['newRoot']);
180
+    }
181
+
182
+    public static function dataTestPrepareNewRootException(): array {
183
+        return [
184
+            [true, false],
185
+            [true, null],
186
+            [false, true]
187
+        ];
188
+    }
189
+
190
+    /**
191
+     * @dataProvider dataTestMoveSystemKeys
192
+     *
193
+     * @param bool $dirExists
194
+     * @param bool $targetExists
195
+     * @param bool $executeRename
196
+     */
197
+    public function testMoveSystemKeys($dirExists, $targetExists, $executeRename): void {
198
+        $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
199
+            ->setConstructorArgs(
200
+                [
201
+                    $this->view,
202
+                    $this->userManager,
203
+                    $this->config,
204
+                    $this->util,
205
+                    $this->questionHelper
206
+                ]
207
+            )->onlyMethods(['targetExists'])->getMock();
208
+
209
+        $this->view->expects($this->once())->method('is_dir')
210
+            ->with('oldRoot/files_encryption')->willReturn($dirExists);
211
+        $changeKeyStorageRoot->expects($this->any())->method('targetExists')
212
+            ->with('newRoot/files_encryption')->willReturn($targetExists);
213
+
214
+        if ($executeRename) {
215
+            $this->view->expects($this->once())->method('rename')
216
+                ->with('oldRoot/files_encryption', 'newRoot/files_encryption');
217
+        } else {
218
+            $this->view->expects($this->never())->method('rename');
219
+        }
220
+
221
+        $this->invokePrivate($changeKeyStorageRoot, 'moveSystemKeys', ['oldRoot', 'newRoot']);
222
+    }
223
+
224
+    public static function dataTestMoveSystemKeys(): array {
225
+        return [
226
+            [true, false, true],
227
+            [false, true, false],
228
+            [true, true, false],
229
+            [false, false, false]
230
+        ];
231
+    }
232
+
233
+
234
+    public function testMoveUserKeys(): void {
235
+        $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
236
+            ->setConstructorArgs(
237
+                [
238
+                    $this->view,
239
+                    $this->userManager,
240
+                    $this->config,
241
+                    $this->util,
242
+                    $this->questionHelper
243
+                ]
244
+            )->onlyMethods(['setupUserFS', 'moveUserEncryptionFolder'])->getMock();
245
+
246
+        $this->userManager->expects($this->once())->method('getBackends')
247
+            ->willReturn([$this->userInterface]);
248
+        $this->userInterface->expects($this->once())->method('getUsers')
249
+            ->willReturn(['user1', 'user2']);
250
+        $changeKeyStorageRoot->expects($this->exactly(2))->method('setupUserFS');
251
+        $changeKeyStorageRoot->expects($this->exactly(2))->method('moveUserEncryptionFolder');
252
+
253
+        $this->invokePrivate($changeKeyStorageRoot, 'moveUserKeys', ['oldRoot', 'newRoot', $this->outputInterface]);
254
+    }
255
+
256
+    /**
257
+     * @dataProvider dataTestMoveUserEncryptionFolder
258
+     *
259
+     * @param bool $userExists
260
+     * @param bool $isDir
261
+     * @param bool $targetExists
262
+     * @param bool $shouldRename
263
+     */
264
+    public function testMoveUserEncryptionFolder($userExists, $isDir, $targetExists, $shouldRename): void {
265
+        $changeKeyStorageRoot = $this->getMockBuilder('OC\Core\Command\Encryption\ChangeKeyStorageRoot')
266
+            ->setConstructorArgs(
267
+                [
268
+                    $this->view,
269
+                    $this->userManager,
270
+                    $this->config,
271
+                    $this->util,
272
+                    $this->questionHelper
273
+                ]
274
+            )->onlyMethods(['targetExists', 'prepareParentFolder'])->getMock();
275
+
276
+        $this->userManager->expects($this->once())->method('userExists')
277
+            ->willReturn($userExists);
278
+        $this->view->expects($this->any())->method('is_dir')
279
+            ->willReturn($isDir);
280
+        $changeKeyStorageRoot->expects($this->any())->method('targetExists')
281
+            ->willReturn($targetExists);
282
+
283
+        if ($shouldRename) {
284
+            $changeKeyStorageRoot->expects($this->once())->method('prepareParentFolder')
285
+                ->with('newRoot/user1');
286
+            $this->view->expects($this->once())->method('rename')
287
+                ->with('oldRoot/user1/files_encryption', 'newRoot/user1/files_encryption');
288
+        } else {
289
+            $changeKeyStorageRoot->expects($this->never())->method('prepareParentFolder');
290
+            $this->view->expects($this->never())->method('rename');
291
+        }
292
+
293
+        $this->invokePrivate($changeKeyStorageRoot, 'moveUserEncryptionFolder', ['user1', 'oldRoot', 'newRoot']);
294
+    }
295
+
296
+    public static function dataTestMoveUserEncryptionFolder(): array {
297
+        return [
298
+            [true, true, false, true],
299
+            [true, false, true, false],
300
+            [false, true, true, false],
301
+            [false, false, true, false],
302
+            [false, true, false, false],
303
+            [false, true, true, false],
304
+            [false, false, false, false]
305
+        ];
306
+    }
307
+
308
+
309
+    /**
310
+     * @dataProvider dataTestPrepareParentFolder
311
+     */
312
+    public function testPrepareParentFolder($path, $pathExists): void {
313
+        $this->view->expects($this->any())->method('file_exists')
314
+            ->willReturnCallback(
315
+                function ($fileExistsPath) use ($path, $pathExists) {
316
+                    if ($path === $fileExistsPath) {
317
+                        return $pathExists;
318
+                    }
319
+                    return false;
320
+                }
321
+            );
322
+
323
+        if ($pathExists === false) {
324
+            $subDirs = explode('/', ltrim($path, '/'));
325
+            $this->view->expects($this->exactly(count($subDirs)))->method('mkdir');
326
+        } else {
327
+            $this->view->expects($this->never())->method('mkdir');
328
+        }
329
+
330
+        $this->invokePrivate(
331
+            $this->changeKeyStorageRoot,
332
+            'prepareParentFolder',
333
+            [$path]
334
+        );
335
+    }
336
+
337
+    public static function dataTestPrepareParentFolder(): array {
338
+        return [
339
+            ['/user/folder/sub_folder/keystorage', true],
340
+            ['/user/folder/sub_folder/keystorage', false]
341
+        ];
342
+    }
343
+
344
+    public function testTargetExists(): void {
345
+        $this->view->expects($this->once())->method('file_exists')->with('path')
346
+            ->willReturn(false);
347
+
348
+        $this->assertFalse(
349
+            $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path'])
350
+        );
351
+    }
352
+
353
+
354
+    public function testTargetExistsException(): void {
355
+        $this->expectException(\Exception::class);
356
+
357
+        $this->view->expects($this->once())->method('file_exists')->with('path')
358
+            ->willReturn(true);
359
+
360
+        $this->invokePrivate($this->changeKeyStorageRoot, 'targetExists', ['path']);
361
+    }
362 362
 }
Please login to merge, or discard this patch.