Completed
Push — master ( 5d14f8...2337bd )
by Robin
27:19 queued 16s
created
apps/theming/tests/UtilTest.php 2 patches
Indentation   +204 added lines, -204 removed lines patch added patch discarded remove patch
@@ -22,208 +22,208 @@
 block discarded – undo
22 22
 
23 23
 class UtilTest extends TestCase {
24 24
 
25
-	protected Util $util;
26
-	protected IConfig&MockObject $config;
27
-	protected IAppData&MockObject $appData;
28
-	protected IAppManager $appManager;
29
-	protected ImageManager&MockObject $imageManager;
30
-
31
-	protected function setUp(): void {
32
-		parent::setUp();
33
-		$this->config = $this->createMock(IConfig::class);
34
-		$this->appData = $this->createMock(IAppData::class);
35
-		$this->appManager = Server::get(IAppManager::class);
36
-		$this->imageManager = $this->createMock(ImageManager::class);
37
-		$this->util = new Util($this->createMock(ServerVersion::class), $this->config, $this->appManager, $this->appData, $this->imageManager);
38
-	}
39
-
40
-	public static function dataColorContrast(): array {
41
-		return [
42
-			['#ffffff', '#FFFFFF', 1],
43
-			['#000000', '#000000', 1],
44
-			['#ffffff', '#000000', 21],
45
-			['#000000', '#FFFFFF', 21],
46
-			['#9E9E9E', '#353535', 4.578],
47
-			['#353535', '#9E9E9E', 4.578],
48
-		];
49
-	}
50
-
51
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataColorContrast')]
52
-	public function testColorContrast(string $color1, string $color2, int|float $contrast): void {
53
-		$this->assertEqualsWithDelta($contrast, $this->util->colorContrast($color1, $color2), .001);
54
-	}
55
-
56
-	public static function dataInvertTextColor(): array {
57
-		return [
58
-			['#ffffff', true],
59
-			['#000000', false],
60
-			['#00679e', false],
61
-			['#ffff00', true],
62
-		];
63
-	}
64
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataInvertTextColor')]
65
-	public function testInvertTextColor(string $color, bool $expected): void {
66
-		$invert = $this->util->invertTextColor($color);
67
-		$this->assertEquals($expected, $invert);
68
-	}
69
-
70
-	public function testCalculateLuminanceLight(): void {
71
-		$luminance = $this->util->calculateLuminance('#ffffff');
72
-		$this->assertEquals(1, $luminance);
73
-	}
74
-
75
-	public function testCalculateLuminanceDark(): void {
76
-		$luminance = $this->util->calculateLuminance('#000000');
77
-		$this->assertEquals(0, $luminance);
78
-	}
79
-
80
-	public function testCalculateLuminanceLightShorthand(): void {
81
-		$luminance = $this->util->calculateLuminance('#fff');
82
-		$this->assertEquals(1, $luminance);
83
-	}
84
-
85
-	public function testCalculateLuminanceDarkShorthand(): void {
86
-		$luminance = $this->util->calculateLuminance('#000');
87
-		$this->assertEquals(0, $luminance);
88
-	}
89
-
90
-	public function testInvertTextColorInvalid(): void {
91
-		$this->expectException(\Exception::class);
92
-		$this->util->invertTextColor('aaabbbcccddd123');
93
-	}
94
-
95
-	public function testInvertTextColorEmpty(): void {
96
-		$this->expectException(\Exception::class);
97
-		$this->util->invertTextColor('');
98
-	}
99
-
100
-	public function testElementColorDefaultBlack(): void {
101
-		$elementColor = $this->util->elementColor('#000000');
102
-		$this->assertEquals('#4d4d4d', $elementColor);
103
-	}
104
-
105
-	public function testElementColorDefaultWhite(): void {
106
-		$elementColor = $this->util->elementColor('#ffffff');
107
-		$this->assertEquals('#b3b3b3', $elementColor);
108
-	}
109
-
110
-	public function testElementColorBlackOnDarkBackground(): void {
111
-		$elementColor = $this->util->elementColor('#000000', false);
112
-		$this->assertEquals('#4d4d4d', $elementColor);
113
-	}
114
-
115
-	public function testElementColorBlackOnBrightBackground(): void {
116
-		$elementColor = $this->util->elementColor('#000000', true);
117
-		$this->assertEquals('#000000', $elementColor);
118
-	}
119
-
120
-	public function testElementColorWhiteOnBrightBackground(): void {
121
-		$elementColor = $this->util->elementColor('#ffffff', true);
122
-		$this->assertEquals('#b3b3b3', $elementColor);
123
-	}
124
-
125
-	public function testElementColorWhiteOnDarkBackground(): void {
126
-		$elementColor = $this->util->elementColor('#ffffff', false);
127
-		$this->assertEquals('#ffffff', $elementColor);
128
-	}
129
-
130
-	public function testGenerateRadioButtonWhite(): void {
131
-		$button = $this->util->generateRadioButton('#ffffff');
132
-		$expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiNmZmZmZmYiLz48L3N2Zz4=';
133
-		$this->assertEquals($expected, $button);
134
-	}
135
-
136
-	public function testGenerateRadioButtonBlack(): void {
137
-		$button = $this->util->generateRadioButton('#000000');
138
-		$expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiMwMDAwMDAiLz48L3N2Zz4=';
139
-		$this->assertEquals($expected, $button);
140
-	}
141
-
142
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetAppIcon')]
143
-	public function testGetAppIcon(string $app, string $expected): void {
144
-		$this->appData->expects($this->any())
145
-			->method('getFolder')
146
-			->with('global/images')
147
-			->willThrowException(new NotFoundException());
148
-		$icon = $this->util->getAppIcon($app);
149
-		$this->assertEquals($expected, $icon);
150
-	}
151
-
152
-	public static function dataGetAppIcon(): array {
153
-		return [
154
-			['user_ldap', Server::get(IAppManager::class)->getAppPath('user_ldap') . '/img/app.svg'],
155
-			['noapplikethis', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
156
-			['comments', Server::get(IAppManager::class)->getAppPath('comments') . '/img/comments.svg'],
157
-		];
158
-	}
159
-
160
-	public function testGetAppIconThemed(): void {
161
-		$file = $this->createMock(ISimpleFile::class);
162
-		$folder = $this->createMock(ISimpleFolder::class);
163
-		$folder->expects($this->once())
164
-			->method('getFile')
165
-			->with('logo')
166
-			->willReturn($file);
167
-		$this->appData->expects($this->once())
168
-			->method('getFolder')
169
-			->with('global/images')
170
-			->willReturn($folder);
171
-		$icon = $this->util->getAppIcon('noapplikethis');
172
-		$this->assertEquals($file, $icon);
173
-	}
174
-
175
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetAppImage')]
176
-	public function testGetAppImage(string $app, string $image, string|bool $expected): void {
177
-		$this->assertEquals($expected, $this->util->getAppImage($app, $image));
178
-	}
179
-
180
-	public static function dataGetAppImage(): array {
181
-		return [
182
-			['core', 'logo/logo.svg', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
183
-			['files', 'folder', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
184
-			['files', 'folder.svg', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
185
-			['noapplikethis', 'foobar.svg', false],
186
-		];
187
-	}
188
-
189
-	public function testColorizeSvg(): void {
190
-		$input = '#0082c9 #0082C9 #000000 #FFFFFF';
191
-		$expected = '#AAAAAA #AAAAAA #000000 #FFFFFF';
192
-		$result = $this->util->colorizeSvg($input, '#AAAAAA');
193
-		$this->assertEquals($expected, $result);
194
-	}
195
-
196
-	public function testIsAlreadyThemedFalse(): void {
197
-		$this->config->expects($this->once())
198
-			->method('getSystemValue')
199
-			->with('theme', '')
200
-			->willReturn('');
201
-		$actual = $this->util->isAlreadyThemed();
202
-		$this->assertFalse($actual);
203
-	}
204
-
205
-	public function testIsAlreadyThemedTrue(): void {
206
-		$this->config->expects($this->once())
207
-			->method('getSystemValue')
208
-			->with('theme', '')
209
-			->willReturn('example');
210
-		$actual = $this->util->isAlreadyThemed();
211
-		$this->assertTrue($actual);
212
-	}
213
-
214
-	public static function dataIsBackgroundThemed(): array {
215
-		return [
216
-			['', false],
217
-			['png', true],
218
-			['backgroundColor', false],
219
-		];
220
-	}
221
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataIsBackgroundThemed')]
222
-	public function testIsBackgroundThemed(string $backgroundMime, bool $expected): void {
223
-		$this->config->expects($this->once())
224
-			->method('getAppValue')
225
-			->with('theming', 'backgroundMime', '')
226
-			->willReturn($backgroundMime);
227
-		$this->assertEquals($expected, $this->util->isBackgroundThemed());
228
-	}
25
+    protected Util $util;
26
+    protected IConfig&MockObject $config;
27
+    protected IAppData&MockObject $appData;
28
+    protected IAppManager $appManager;
29
+    protected ImageManager&MockObject $imageManager;
30
+
31
+    protected function setUp(): void {
32
+        parent::setUp();
33
+        $this->config = $this->createMock(IConfig::class);
34
+        $this->appData = $this->createMock(IAppData::class);
35
+        $this->appManager = Server::get(IAppManager::class);
36
+        $this->imageManager = $this->createMock(ImageManager::class);
37
+        $this->util = new Util($this->createMock(ServerVersion::class), $this->config, $this->appManager, $this->appData, $this->imageManager);
38
+    }
39
+
40
+    public static function dataColorContrast(): array {
41
+        return [
42
+            ['#ffffff', '#FFFFFF', 1],
43
+            ['#000000', '#000000', 1],
44
+            ['#ffffff', '#000000', 21],
45
+            ['#000000', '#FFFFFF', 21],
46
+            ['#9E9E9E', '#353535', 4.578],
47
+            ['#353535', '#9E9E9E', 4.578],
48
+        ];
49
+    }
50
+
51
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataColorContrast')]
52
+    public function testColorContrast(string $color1, string $color2, int|float $contrast): void {
53
+        $this->assertEqualsWithDelta($contrast, $this->util->colorContrast($color1, $color2), .001);
54
+    }
55
+
56
+    public static function dataInvertTextColor(): array {
57
+        return [
58
+            ['#ffffff', true],
59
+            ['#000000', false],
60
+            ['#00679e', false],
61
+            ['#ffff00', true],
62
+        ];
63
+    }
64
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataInvertTextColor')]
65
+    public function testInvertTextColor(string $color, bool $expected): void {
66
+        $invert = $this->util->invertTextColor($color);
67
+        $this->assertEquals($expected, $invert);
68
+    }
69
+
70
+    public function testCalculateLuminanceLight(): void {
71
+        $luminance = $this->util->calculateLuminance('#ffffff');
72
+        $this->assertEquals(1, $luminance);
73
+    }
74
+
75
+    public function testCalculateLuminanceDark(): void {
76
+        $luminance = $this->util->calculateLuminance('#000000');
77
+        $this->assertEquals(0, $luminance);
78
+    }
79
+
80
+    public function testCalculateLuminanceLightShorthand(): void {
81
+        $luminance = $this->util->calculateLuminance('#fff');
82
+        $this->assertEquals(1, $luminance);
83
+    }
84
+
85
+    public function testCalculateLuminanceDarkShorthand(): void {
86
+        $luminance = $this->util->calculateLuminance('#000');
87
+        $this->assertEquals(0, $luminance);
88
+    }
89
+
90
+    public function testInvertTextColorInvalid(): void {
91
+        $this->expectException(\Exception::class);
92
+        $this->util->invertTextColor('aaabbbcccddd123');
93
+    }
94
+
95
+    public function testInvertTextColorEmpty(): void {
96
+        $this->expectException(\Exception::class);
97
+        $this->util->invertTextColor('');
98
+    }
99
+
100
+    public function testElementColorDefaultBlack(): void {
101
+        $elementColor = $this->util->elementColor('#000000');
102
+        $this->assertEquals('#4d4d4d', $elementColor);
103
+    }
104
+
105
+    public function testElementColorDefaultWhite(): void {
106
+        $elementColor = $this->util->elementColor('#ffffff');
107
+        $this->assertEquals('#b3b3b3', $elementColor);
108
+    }
109
+
110
+    public function testElementColorBlackOnDarkBackground(): void {
111
+        $elementColor = $this->util->elementColor('#000000', false);
112
+        $this->assertEquals('#4d4d4d', $elementColor);
113
+    }
114
+
115
+    public function testElementColorBlackOnBrightBackground(): void {
116
+        $elementColor = $this->util->elementColor('#000000', true);
117
+        $this->assertEquals('#000000', $elementColor);
118
+    }
119
+
120
+    public function testElementColorWhiteOnBrightBackground(): void {
121
+        $elementColor = $this->util->elementColor('#ffffff', true);
122
+        $this->assertEquals('#b3b3b3', $elementColor);
123
+    }
124
+
125
+    public function testElementColorWhiteOnDarkBackground(): void {
126
+        $elementColor = $this->util->elementColor('#ffffff', false);
127
+        $this->assertEquals('#ffffff', $elementColor);
128
+    }
129
+
130
+    public function testGenerateRadioButtonWhite(): void {
131
+        $button = $this->util->generateRadioButton('#ffffff');
132
+        $expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiNmZmZmZmYiLz48L3N2Zz4=';
133
+        $this->assertEquals($expected, $button);
134
+    }
135
+
136
+    public function testGenerateRadioButtonBlack(): void {
137
+        $button = $this->util->generateRadioButton('#000000');
138
+        $expected = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTYiIHdpZHRoPSIxNiI+PHBhdGggZD0iTTggMWE3IDcgMCAwIDAtNyA3IDcgNyAwIDAgMCA3IDcgNyA3IDAgMCAwIDctNyA3IDcgMCAwIDAtNy03em0wIDFhNiA2IDAgMCAxIDYgNiA2IDYgMCAwIDEtNiA2IDYgNiAwIDAgMS02LTYgNiA2IDAgMCAxIDYtNnptMCAyYTQgNCAwIDEgMCAwIDggNCA0IDAgMCAwIDAtOHoiIGZpbGw9IiMwMDAwMDAiLz48L3N2Zz4=';
139
+        $this->assertEquals($expected, $button);
140
+    }
141
+
142
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetAppIcon')]
143
+    public function testGetAppIcon(string $app, string $expected): void {
144
+        $this->appData->expects($this->any())
145
+            ->method('getFolder')
146
+            ->with('global/images')
147
+            ->willThrowException(new NotFoundException());
148
+        $icon = $this->util->getAppIcon($app);
149
+        $this->assertEquals($expected, $icon);
150
+    }
151
+
152
+    public static function dataGetAppIcon(): array {
153
+        return [
154
+            ['user_ldap', Server::get(IAppManager::class)->getAppPath('user_ldap') . '/img/app.svg'],
155
+            ['noapplikethis', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
156
+            ['comments', Server::get(IAppManager::class)->getAppPath('comments') . '/img/comments.svg'],
157
+        ];
158
+    }
159
+
160
+    public function testGetAppIconThemed(): void {
161
+        $file = $this->createMock(ISimpleFile::class);
162
+        $folder = $this->createMock(ISimpleFolder::class);
163
+        $folder->expects($this->once())
164
+            ->method('getFile')
165
+            ->with('logo')
166
+            ->willReturn($file);
167
+        $this->appData->expects($this->once())
168
+            ->method('getFolder')
169
+            ->with('global/images')
170
+            ->willReturn($folder);
171
+        $icon = $this->util->getAppIcon('noapplikethis');
172
+        $this->assertEquals($file, $icon);
173
+    }
174
+
175
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetAppImage')]
176
+    public function testGetAppImage(string $app, string $image, string|bool $expected): void {
177
+        $this->assertEquals($expected, $this->util->getAppImage($app, $image));
178
+    }
179
+
180
+    public static function dataGetAppImage(): array {
181
+        return [
182
+            ['core', 'logo/logo.svg', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
183
+            ['files', 'folder', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
184
+            ['files', 'folder.svg', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
185
+            ['noapplikethis', 'foobar.svg', false],
186
+        ];
187
+    }
188
+
189
+    public function testColorizeSvg(): void {
190
+        $input = '#0082c9 #0082C9 #000000 #FFFFFF';
191
+        $expected = '#AAAAAA #AAAAAA #000000 #FFFFFF';
192
+        $result = $this->util->colorizeSvg($input, '#AAAAAA');
193
+        $this->assertEquals($expected, $result);
194
+    }
195
+
196
+    public function testIsAlreadyThemedFalse(): void {
197
+        $this->config->expects($this->once())
198
+            ->method('getSystemValue')
199
+            ->with('theme', '')
200
+            ->willReturn('');
201
+        $actual = $this->util->isAlreadyThemed();
202
+        $this->assertFalse($actual);
203
+    }
204
+
205
+    public function testIsAlreadyThemedTrue(): void {
206
+        $this->config->expects($this->once())
207
+            ->method('getSystemValue')
208
+            ->with('theme', '')
209
+            ->willReturn('example');
210
+        $actual = $this->util->isAlreadyThemed();
211
+        $this->assertTrue($actual);
212
+    }
213
+
214
+    public static function dataIsBackgroundThemed(): array {
215
+        return [
216
+            ['', false],
217
+            ['png', true],
218
+            ['backgroundColor', false],
219
+        ];
220
+    }
221
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataIsBackgroundThemed')]
222
+    public function testIsBackgroundThemed(string $backgroundMime, bool $expected): void {
223
+        $this->config->expects($this->once())
224
+            ->method('getAppValue')
225
+            ->with('theming', 'backgroundMime', '')
226
+            ->willReturn($backgroundMime);
227
+        $this->assertEquals($expected, $this->util->isBackgroundThemed());
228
+    }
229 229
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
 	}
50 50
 
51 51
 	#[\PHPUnit\Framework\Attributes\DataProvider('dataColorContrast')]
52
-	public function testColorContrast(string $color1, string $color2, int|float $contrast): void {
52
+	public function testColorContrast(string $color1, string $color2, int | float $contrast): void {
53 53
 		$this->assertEqualsWithDelta($contrast, $this->util->colorContrast($color1, $color2), .001);
54 54
 	}
55 55
 
@@ -151,9 +151,9 @@  discard block
 block discarded – undo
151 151
 
152 152
 	public static function dataGetAppIcon(): array {
153 153
 		return [
154
-			['user_ldap', Server::get(IAppManager::class)->getAppPath('user_ldap') . '/img/app.svg'],
155
-			['noapplikethis', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
156
-			['comments', Server::get(IAppManager::class)->getAppPath('comments') . '/img/comments.svg'],
154
+			['user_ldap', Server::get(IAppManager::class)->getAppPath('user_ldap').'/img/app.svg'],
155
+			['noapplikethis', \OC::$SERVERROOT.'/core/img/logo/logo.svg'],
156
+			['comments', Server::get(IAppManager::class)->getAppPath('comments').'/img/comments.svg'],
157 157
 		];
158 158
 	}
159 159
 
@@ -173,15 +173,15 @@  discard block
 block discarded – undo
173 173
 	}
174 174
 
175 175
 	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetAppImage')]
176
-	public function testGetAppImage(string $app, string $image, string|bool $expected): void {
176
+	public function testGetAppImage(string $app, string $image, string | bool $expected): void {
177 177
 		$this->assertEquals($expected, $this->util->getAppImage($app, $image));
178 178
 	}
179 179
 
180 180
 	public static function dataGetAppImage(): array {
181 181
 		return [
182
-			['core', 'logo/logo.svg', \OC::$SERVERROOT . '/core/img/logo/logo.svg'],
183
-			['files', 'folder', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
184
-			['files', 'folder.svg', \OC::$SERVERROOT . '/apps/files/img/folder.svg'],
182
+			['core', 'logo/logo.svg', \OC::$SERVERROOT.'/core/img/logo/logo.svg'],
183
+			['files', 'folder', \OC::$SERVERROOT.'/apps/files/img/folder.svg'],
184
+			['files', 'folder.svg', \OC::$SERVERROOT.'/apps/files/img/folder.svg'],
185 185
 			['noapplikethis', 'foobar.svg', false],
186 186
 		];
187 187
 	}
Please login to merge, or discard this patch.
apps/theming/tests/Controller/UserThemeControllerTest.php 1 patch
Indentation   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -29,96 +29,96 @@
 block discarded – undo
29 29
 use Test\TestCase;
30 30
 
31 31
 class UserThemeControllerTest extends TestCase {
32
-	private IRequest&MockObject $request;
33
-	private IConfig&MockObject $config;
34
-	private IUserSession&MockObject $userSession;
35
-	private ThemesService&MockObject $themesService;
36
-	private ThemingDefaults&MockObject $themingDefaults;
37
-	private BackgroundService&MockObject $backgroundService;
38
-	private UserThemeController $userThemeController;
39
-
40
-
41
-	/** @var ITheme[] */
42
-	private array $themes;
43
-
44
-	protected function setUp(): void {
45
-		$this->request = $this->createMock(IRequest::class);
46
-		$this->config = $this->createMock(IConfig::class);
47
-		$this->userSession = $this->createMock(IUserSession::class);
48
-		$this->themesService = $this->createMock(ThemesService::class);
49
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
50
-		$this->backgroundService = $this->createMock(BackgroundService::class);
51
-
52
-		$this->themes = [
53
-			'default' => $this->createMock(DefaultTheme::class),
54
-			'light' => $this->createMock(LightTheme::class),
55
-			'dark' => $this->createMock(DarkTheme::class),
56
-			'light-highcontrast' => $this->createMock(HighContrastTheme::class),
57
-			'dark-highcontrast' => $this->createMock(DarkHighContrastTheme::class),
58
-			'opendyslexic' => $this->createMock(DyslexiaFont::class),
59
-		];
60
-
61
-		$user = $this->createMock(IUser::class);
62
-		$this->userSession->expects($this->any())
63
-			->method('getUser')
64
-			->willReturn($user);
65
-		$user->expects($this->any())
66
-			->method('getUID')
67
-			->willReturn('user');
68
-
69
-		$this->userThemeController = new UserThemeController(
70
-			Application::APP_ID,
71
-			$this->request,
72
-			$this->config,
73
-			$this->userSession,
74
-			$this->themesService,
75
-			$this->themingDefaults,
76
-			$this->backgroundService,
77
-		);
78
-
79
-		parent::setUp();
80
-	}
81
-
82
-	public static function dataTestThemes(): array {
83
-		return [
84
-			['default'],
85
-			['light'],
86
-			['dark'],
87
-			['light-highcontrast'],
88
-			['dark-highcontrast'],
89
-			['opendyslexic'],
90
-			['', OCSBadRequestException::class],
91
-			['badTheme', OCSBadRequestException::class],
92
-		];
93
-	}
94
-
95
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestThemes')]
96
-	public function testEnableTheme(string $themeId, ?string $exception = null): void {
97
-		$this->themesService
98
-			->expects($this->any())
99
-			->method('getThemes')
100
-			->willReturn($this->themes);
101
-
102
-		if ($exception) {
103
-			$this->expectException($exception);
104
-		}
105
-
106
-		$expected = new DataResponse();
107
-		$this->assertEquals($expected, $this->userThemeController->enableTheme($themeId));
108
-	}
109
-
110
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestThemes')]
111
-	public function testDisableTheme(string $themeId, ?string $exception = null): void {
112
-		$this->themesService
113
-			->expects($this->any())
114
-			->method('getThemes')
115
-			->willReturn($this->themes);
116
-
117
-		if ($exception) {
118
-			$this->expectException($exception);
119
-		}
120
-
121
-		$expected = new DataResponse();
122
-		$this->assertEquals($expected, $this->userThemeController->disableTheme($themeId));
123
-	}
32
+    private IRequest&MockObject $request;
33
+    private IConfig&MockObject $config;
34
+    private IUserSession&MockObject $userSession;
35
+    private ThemesService&MockObject $themesService;
36
+    private ThemingDefaults&MockObject $themingDefaults;
37
+    private BackgroundService&MockObject $backgroundService;
38
+    private UserThemeController $userThemeController;
39
+
40
+
41
+    /** @var ITheme[] */
42
+    private array $themes;
43
+
44
+    protected function setUp(): void {
45
+        $this->request = $this->createMock(IRequest::class);
46
+        $this->config = $this->createMock(IConfig::class);
47
+        $this->userSession = $this->createMock(IUserSession::class);
48
+        $this->themesService = $this->createMock(ThemesService::class);
49
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
50
+        $this->backgroundService = $this->createMock(BackgroundService::class);
51
+
52
+        $this->themes = [
53
+            'default' => $this->createMock(DefaultTheme::class),
54
+            'light' => $this->createMock(LightTheme::class),
55
+            'dark' => $this->createMock(DarkTheme::class),
56
+            'light-highcontrast' => $this->createMock(HighContrastTheme::class),
57
+            'dark-highcontrast' => $this->createMock(DarkHighContrastTheme::class),
58
+            'opendyslexic' => $this->createMock(DyslexiaFont::class),
59
+        ];
60
+
61
+        $user = $this->createMock(IUser::class);
62
+        $this->userSession->expects($this->any())
63
+            ->method('getUser')
64
+            ->willReturn($user);
65
+        $user->expects($this->any())
66
+            ->method('getUID')
67
+            ->willReturn('user');
68
+
69
+        $this->userThemeController = new UserThemeController(
70
+            Application::APP_ID,
71
+            $this->request,
72
+            $this->config,
73
+            $this->userSession,
74
+            $this->themesService,
75
+            $this->themingDefaults,
76
+            $this->backgroundService,
77
+        );
78
+
79
+        parent::setUp();
80
+    }
81
+
82
+    public static function dataTestThemes(): array {
83
+        return [
84
+            ['default'],
85
+            ['light'],
86
+            ['dark'],
87
+            ['light-highcontrast'],
88
+            ['dark-highcontrast'],
89
+            ['opendyslexic'],
90
+            ['', OCSBadRequestException::class],
91
+            ['badTheme', OCSBadRequestException::class],
92
+        ];
93
+    }
94
+
95
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestThemes')]
96
+    public function testEnableTheme(string $themeId, ?string $exception = null): void {
97
+        $this->themesService
98
+            ->expects($this->any())
99
+            ->method('getThemes')
100
+            ->willReturn($this->themes);
101
+
102
+        if ($exception) {
103
+            $this->expectException($exception);
104
+        }
105
+
106
+        $expected = new DataResponse();
107
+        $this->assertEquals($expected, $this->userThemeController->enableTheme($themeId));
108
+    }
109
+
110
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestThemes')]
111
+    public function testDisableTheme(string $themeId, ?string $exception = null): void {
112
+        $this->themesService
113
+            ->expects($this->any())
114
+            ->method('getThemes')
115
+            ->willReturn($this->themes);
116
+
117
+        if ($exception) {
118
+            $this->expectException($exception);
119
+        }
120
+
121
+        $expected = new DataResponse();
122
+        $this->assertEquals($expected, $this->userThemeController->disableTheme($themeId));
123
+    }
124 124
 }
Please login to merge, or discard this patch.
apps/theming/tests/Controller/ThemingControllerTest.php 2 patches
Indentation   +722 added lines, -722 removed lines patch added patch discarded remove patch
@@ -35,726 +35,726 @@
 block discarded – undo
35 35
 
36 36
 class ThemingControllerTest extends TestCase {
37 37
 
38
-	private IRequest&MockObject $request;
39
-	private IConfig&MockObject $config;
40
-	private IAppConfig&MockObject $appConfig;
41
-	private ThemingDefaults&MockObject $themingDefaults;
42
-	private IL10N&MockObject $l10n;
43
-	private IAppManager&MockObject $appManager;
44
-	private ImageManager&MockObject $imageManager;
45
-	private IURLGenerator&MockObject $urlGenerator;
46
-	private ThemesService&MockObject $themesService;
47
-	private INavigationManager&MockObject $navigationManager;
48
-
49
-	private ThemingController $themingController;
50
-
51
-	protected function setUp(): void {
52
-		$this->request = $this->createMock(IRequest::class);
53
-		$this->config = $this->createMock(IConfig::class);
54
-		$this->appConfig = $this->createMock(IAppConfig::class);
55
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
56
-		$this->l10n = $this->createMock(L10N::class);
57
-		$this->appManager = $this->createMock(IAppManager::class);
58
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
59
-		$this->imageManager = $this->createMock(ImageManager::class);
60
-		$this->themesService = $this->createMock(ThemesService::class);
61
-		$this->navigationManager = $this->createMock(INavigationManager::class);
62
-
63
-		$timeFactory = $this->createMock(ITimeFactory::class);
64
-		$timeFactory->expects($this->any())
65
-			->method('getTime')
66
-			->willReturn(123);
67
-
68
-		$this->overwriteService(ITimeFactory::class, $timeFactory);
69
-
70
-		$this->themingController = new ThemingController(
71
-			'theming',
72
-			$this->request,
73
-			$this->config,
74
-			$this->appConfig,
75
-			$this->themingDefaults,
76
-			$this->l10n,
77
-			$this->urlGenerator,
78
-			$this->appManager,
79
-			$this->imageManager,
80
-			$this->themesService,
81
-			$this->navigationManager,
82
-		);
83
-
84
-		parent::setUp();
85
-	}
86
-
87
-	public static function dataUpdateStylesheetSuccess(): array {
88
-		return [
89
-			['name', str_repeat('a', 250), 'Saved'],
90
-			['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
91
-			['slogan', str_repeat('a', 500), 'Saved'],
92
-			['color', '#0082c9', 'Saved'],
93
-			['color', '#0082C9', 'Saved'],
94
-			['color', '#0082C9', 'Saved'],
95
-			['imprintUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
96
-			['privacyUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
97
-		];
98
-	}
99
-
100
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetSuccess')]
101
-	public function testUpdateStylesheetSuccess(string $setting, string $value, string $message): void {
102
-		$this->themingDefaults
103
-			->expects($this->once())
104
-			->method('set')
105
-			->with($setting, $value);
106
-		$this->l10n
107
-			->expects($this->once())
108
-			->method('t')
109
-			->willReturnCallback(function ($str) {
110
-				return $str;
111
-			});
112
-
113
-		$expected = new DataResponse(
114
-			[
115
-				'data'
116
-					=> [
117
-						'message' => $message,
118
-					],
119
-				'status' => 'success',
120
-			]
121
-		);
122
-		$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
123
-	}
124
-
125
-	public static function dataUpdateStylesheetError(): array {
126
-		$urls = [
127
-			'url' => 'web address',
128
-			'imprintUrl' => 'legal notice address',
129
-			'privacyUrl' => 'privacy policy address',
130
-		];
131
-
132
-		$urlTests = [];
133
-		foreach ($urls as $urlKey => $urlName) {
134
-			// Check length limit
135
-			$urlTests[] = [$urlKey, 'http://example.com/' . str_repeat('a', 501), "The given {$urlName} is too long"];
136
-			// Check potential evil javascript
137
-			$urlTests[] = [$urlKey, 'javascript:alert(1)', "The given {$urlName} is not a valid URL"];
138
-			// Check XSS
139
-			$urlTests[] = [$urlKey, 'https://example.com/"><script/src="alert(\'1\')"><a/href/="', "The given {$urlName} is not a valid URL"];
140
-		}
141
-
142
-		return [
143
-			['name', str_repeat('a', 251), 'The given name is too long'],
144
-			['slogan', str_repeat('a', 501), 'The given slogan is too long'],
145
-			['primary_color', '0082C9', 'The given color is invalid'],
146
-			['primary_color', '#0082Z9', 'The given color is invalid'],
147
-			['primary_color', 'Nextcloud', 'The given color is invalid'],
148
-			['background_color', '0082C9', 'The given color is invalid'],
149
-			['background_color', '#0082Z9', 'The given color is invalid'],
150
-			['background_color', 'Nextcloud', 'The given color is invalid'],
151
-
152
-			...$urlTests,
153
-		];
154
-	}
155
-
156
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetError')]
157
-	public function testUpdateStylesheetError(string $setting, string $value, string $message): void {
158
-		$this->themingDefaults
159
-			->expects($this->never())
160
-			->method('set')
161
-			->with($setting, $value);
162
-		$this->l10n
163
-			->expects($this->any())
164
-			->method('t')
165
-			->willReturnCallback(function ($str) {
166
-				return $str;
167
-			});
168
-
169
-		$expected = new DataResponse(
170
-			[
171
-				'data'
172
-					=> [
173
-						'message' => $message,
174
-					],
175
-				'status' => 'error',
176
-			],
177
-			Http::STATUS_BAD_REQUEST
178
-		);
179
-		$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
180
-	}
181
-
182
-	public function testUpdateLogoNoData(): void {
183
-		$this->request
184
-			->expects($this->once())
185
-			->method('getParam')
186
-			->with('key')
187
-			->willReturn('logo');
188
-		$this->request
189
-			->expects($this->once())
190
-			->method('getUploadedFile')
191
-			->with('image')
192
-			->willReturn(null);
193
-		$this->l10n
194
-			->expects($this->any())
195
-			->method('t')
196
-			->willReturnCallback(function ($str) {
197
-				return $str;
198
-			});
199
-
200
-		$expected = new DataResponse(
201
-			[
202
-				'data'
203
-					=> [
204
-						'message' => 'No file uploaded',
205
-					],
206
-				'status' => 'failure',
207
-			],
208
-			Http::STATUS_UNPROCESSABLE_ENTITY
209
-		);
210
-
211
-		$this->assertEquals($expected, $this->themingController->uploadImage());
212
-	}
213
-
214
-	public function testUploadInvalidUploadKey(): void {
215
-		$this->request
216
-			->expects($this->once())
217
-			->method('getParam')
218
-			->with('key')
219
-			->willReturn('invalid');
220
-		$this->request
221
-			->expects($this->never())
222
-			->method('getUploadedFile');
223
-		$this->l10n
224
-			->expects($this->any())
225
-			->method('t')
226
-			->willReturnCallback(function ($str) {
227
-				return $str;
228
-			});
229
-
230
-		$expected = new DataResponse(
231
-			[
232
-				'data'
233
-					=> [
234
-						'message' => 'Invalid key',
235
-					],
236
-				'status' => 'failure',
237
-			],
238
-			Http::STATUS_BAD_REQUEST
239
-		);
240
-
241
-		$this->assertEquals($expected, $this->themingController->uploadImage());
242
-	}
243
-
244
-	/**
245
-	 * Checks that trying to upload an SVG favicon without imagemagick
246
-	 * results in an unsupported media type response.
247
-	 */
248
-	public function testUploadSVGFaviconWithoutImagemagick(): void {
249
-		$this->imageManager
250
-			->method('shouldReplaceIcons')
251
-			->willReturn(false);
252
-
253
-		$this->request
254
-			->expects($this->once())
255
-			->method('getParam')
256
-			->with('key')
257
-			->willReturn('favicon');
258
-		$this->request
259
-			->expects($this->once())
260
-			->method('getUploadedFile')
261
-			->with('image')
262
-			->willReturn([
263
-				'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg',
264
-				'type' => 'image/svg',
265
-				'name' => 'testimagelarge.svg',
266
-				'error' => 0,
267
-			]);
268
-		$this->l10n
269
-			->expects($this->any())
270
-			->method('t')
271
-			->willReturnCallback(function ($str) {
272
-				return $str;
273
-			});
274
-
275
-		$this->imageManager->expects($this->once())
276
-			->method('updateImage')
277
-			->willThrowException(new \Exception('Unsupported image type'));
278
-
279
-		$expected = new DataResponse(
280
-			[
281
-				'data'
282
-					=> [
283
-						'message' => 'Unsupported image type',
284
-					],
285
-				'status' => 'failure'
286
-			],
287
-			Http::STATUS_UNPROCESSABLE_ENTITY
288
-		);
289
-
290
-		$this->assertEquals($expected, $this->themingController->uploadImage());
291
-	}
292
-
293
-	public function testUpdateLogoInvalidMimeType(): void {
294
-		$this->request
295
-			->expects($this->once())
296
-			->method('getParam')
297
-			->with('key')
298
-			->willReturn('logo');
299
-		$this->request
300
-			->expects($this->once())
301
-			->method('getUploadedFile')
302
-			->with('image')
303
-			->willReturn([
304
-				'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt',
305
-				'type' => 'application/pdf',
306
-				'name' => 'logo.pdf',
307
-				'error' => 0,
308
-			]);
309
-		$this->l10n
310
-			->expects($this->any())
311
-			->method('t')
312
-			->willReturnCallback(function ($str) {
313
-				return $str;
314
-			});
315
-
316
-		$this->imageManager->expects($this->once())
317
-			->method('updateImage')
318
-			->willThrowException(new \Exception('Unsupported image type'));
319
-
320
-		$expected = new DataResponse(
321
-			[
322
-				'data'
323
-					=> [
324
-						'message' => 'Unsupported image type',
325
-					],
326
-				'status' => 'failure'
327
-			],
328
-			Http::STATUS_UNPROCESSABLE_ENTITY
329
-		);
330
-
331
-		$this->assertEquals($expected, $this->themingController->uploadImage());
332
-	}
333
-
334
-	public static function dataUpdateImages(): array {
335
-		return [
336
-			['image/jpeg', false],
337
-			['image/jpeg', true],
338
-			['image/gif'],
339
-			['image/png'],
340
-			['image/svg+xml'],
341
-			['image/svg']
342
-		];
343
-	}
344
-
345
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImages')]
346
-	public function testUpdateLogoNormalLogoUpload(string $mimeType, bool $folderExists = true): void {
347
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
348
-		$destination = Server::get(ITempManager::class)->getTemporaryFolder();
349
-
350
-		touch($tmpLogo);
351
-		copy(__DIR__ . '/../../../../tests/data/testimage.png', $tmpLogo);
352
-		$this->request
353
-			->expects($this->once())
354
-			->method('getParam')
355
-			->with('key')
356
-			->willReturn('logo');
357
-		$this->request
358
-			->expects($this->once())
359
-			->method('getUploadedFile')
360
-			->with('image')
361
-			->willReturn([
362
-				'tmp_name' => $tmpLogo,
363
-				'type' => $mimeType,
364
-				'name' => 'logo.svg',
365
-				'error' => 0,
366
-			]);
367
-		$this->l10n
368
-			->expects($this->any())
369
-			->method('t')
370
-			->willReturnCallback(function ($str) {
371
-				return $str;
372
-			});
373
-
374
-		$this->imageManager->expects($this->once())
375
-			->method('getImageUrl')
376
-			->with('logo')
377
-			->willReturn('imageUrl');
378
-
379
-		$this->imageManager->expects($this->once())
380
-			->method('updateImage');
381
-
382
-		$expected = new DataResponse(
383
-			[
384
-				'data'
385
-					=> [
386
-						'name' => 'logo.svg',
387
-						'message' => 'Saved',
388
-						'url' => 'imageUrl',
389
-					],
390
-				'status' => 'success'
391
-			]
392
-		);
393
-
394
-		$this->assertEquals($expected, $this->themingController->uploadImage());
395
-	}
396
-
397
-	public function testUpdateLogoLoginScreenUpload(): void {
398
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . 'logo.png';
399
-
400
-		touch($tmpLogo);
401
-		copy(__DIR__ . '/../../../../tests/data/desktopapp.png', $tmpLogo);
402
-		$this->request
403
-			->expects($this->once())
404
-			->method('getParam')
405
-			->with('key')
406
-			->willReturn('background');
407
-		$this->request
408
-			->expects($this->once())
409
-			->method('getUploadedFile')
410
-			->with('image')
411
-			->willReturn([
412
-				'tmp_name' => $tmpLogo,
413
-				'type' => 'image/svg+xml',
414
-				'name' => 'logo.svg',
415
-				'error' => 0,
416
-			]);
417
-		$this->l10n
418
-			->expects($this->any())
419
-			->method('t')
420
-			->willReturnCallback(function ($str) {
421
-				return $str;
422
-			});
423
-
424
-		$this->imageManager->expects($this->once())
425
-			->method('updateImage');
426
-
427
-		$this->imageManager->expects($this->once())
428
-			->method('getImageUrl')
429
-			->with('background')
430
-			->willReturn('imageUrl');
431
-		$expected = new DataResponse(
432
-			[
433
-				'data'
434
-					=> [
435
-						'name' => 'logo.svg',
436
-						'message' => 'Saved',
437
-						'url' => 'imageUrl',
438
-					],
439
-				'status' => 'success'
440
-			]
441
-		);
442
-		$this->assertEquals($expected, $this->themingController->uploadImage());
443
-	}
444
-
445
-	public function testUpdateLogoLoginScreenUploadWithInvalidImage(): void {
446
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
447
-
448
-		touch($tmpLogo);
449
-		file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
450
-		$this->request
451
-			->expects($this->once())
452
-			->method('getParam')
453
-			->with('key')
454
-			->willReturn('logo');
455
-		$this->request
456
-			->expects($this->once())
457
-			->method('getUploadedFile')
458
-			->with('image')
459
-			->willReturn([
460
-				'tmp_name' => $tmpLogo,
461
-				'type' => 'foobar',
462
-				'name' => 'logo.svg',
463
-				'error' => 0,
464
-			]);
465
-		$this->l10n
466
-			->expects($this->any())
467
-			->method('t')
468
-			->willReturnCallback(function ($str) {
469
-				return $str;
470
-			});
471
-
472
-		$this->imageManager->expects($this->once())
473
-			->method('updateImage')
474
-			->willThrowException(new \Exception('Unsupported image type'));
475
-
476
-		$expected = new DataResponse(
477
-			[
478
-				'data'
479
-					=> [
480
-						'message' => 'Unsupported image type',
481
-					],
482
-				'status' => 'failure'
483
-			],
484
-			Http::STATUS_UNPROCESSABLE_ENTITY
485
-		);
486
-		$this->assertEquals($expected, $this->themingController->uploadImage());
487
-	}
488
-
489
-	public static function dataPhpUploadErrors(): array {
490
-		return [
491
-			[UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'],
492
-			[UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'],
493
-			[UPLOAD_ERR_PARTIAL, 'The file was only partially uploaded'],
494
-			[UPLOAD_ERR_NO_FILE, 'No file was uploaded'],
495
-			[UPLOAD_ERR_NO_TMP_DIR, 'Missing a temporary folder'],
496
-			[UPLOAD_ERR_CANT_WRITE, 'Could not write file to disk'],
497
-			[UPLOAD_ERR_EXTENSION, 'A PHP extension stopped the file upload'],
498
-		];
499
-	}
500
-
501
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
502
-	public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload(int $error, string $expectedErrorMessage): void {
503
-		$this->request
504
-			->expects($this->once())
505
-			->method('getParam')
506
-			->with('key')
507
-			->willReturn('background');
508
-		$this->request
509
-			->expects($this->once())
510
-			->method('getUploadedFile')
511
-			->with('image')
512
-			->willReturn([
513
-				'tmp_name' => '',
514
-				'type' => 'image/svg+xml',
515
-				'name' => 'logo.svg',
516
-				'error' => $error,
517
-			]);
518
-		$this->l10n
519
-			->expects($this->any())
520
-			->method('t')
521
-			->willReturnCallback(function ($str) {
522
-				return $str;
523
-			});
524
-
525
-		$expected = new DataResponse(
526
-			[
527
-				'data'
528
-					=> [
529
-						'message' => $expectedErrorMessage,
530
-					],
531
-				'status' => 'failure'
532
-			],
533
-			Http::STATUS_UNPROCESSABLE_ENTITY
534
-		);
535
-		$this->assertEquals($expected, $this->themingController->uploadImage());
536
-	}
537
-
538
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
539
-	public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage): void {
540
-		$this->request
541
-			->expects($this->once())
542
-			->method('getParam')
543
-			->with('key')
544
-			->willReturn('background');
545
-		$this->request
546
-			->expects($this->once())
547
-			->method('getUploadedFile')
548
-			->with('image')
549
-			->willReturn([
550
-				'tmp_name' => '',
551
-				'type' => 'text/svg',
552
-				'name' => 'logo.svg',
553
-				'error' => $error,
554
-			]);
555
-		$this->l10n
556
-			->expects($this->any())
557
-			->method('t')
558
-			->willReturnCallback(function ($str) {
559
-				return $str;
560
-			});
561
-
562
-		$expected = new DataResponse(
563
-			[
564
-				'data'
565
-					=> [
566
-						'message' => $expectedErrorMessage
567
-					],
568
-				'status' => 'failure'
569
-			],
570
-			Http::STATUS_UNPROCESSABLE_ENTITY
571
-		);
572
-		$this->assertEquals($expected, $this->themingController->uploadImage());
573
-	}
574
-
575
-	public function testUndo(): void {
576
-		$this->l10n
577
-			->expects($this->once())
578
-			->method('t')
579
-			->with('Saved')
580
-			->willReturn('Saved');
581
-		$this->themingDefaults
582
-			->expects($this->once())
583
-			->method('undo')
584
-			->with('MySetting')
585
-			->willReturn('MyValue');
586
-
587
-		$expected = new DataResponse(
588
-			[
589
-				'data'
590
-					=> [
591
-						'value' => 'MyValue',
592
-						'message' => 'Saved'
593
-					],
594
-				'status' => 'success'
595
-			]
596
-		);
597
-		$this->assertEquals($expected, $this->themingController->undo('MySetting'));
598
-	}
599
-
600
-	public static function dataUndoDelete(): array {
601
-		return [
602
-			[ 'backgroundMime', 'background' ],
603
-			[ 'logoMime', 'logo' ]
604
-		];
605
-	}
606
-
607
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUndoDelete')]
608
-	public function testUndoDelete(string $value, string $filename): void {
609
-		$this->l10n
610
-			->expects($this->once())
611
-			->method('t')
612
-			->with('Saved')
613
-			->willReturn('Saved');
614
-		$this->themingDefaults
615
-			->expects($this->once())
616
-			->method('undo')
617
-			->with($value)
618
-			->willReturn($value);
619
-
620
-		$expected = new DataResponse(
621
-			[
622
-				'data'
623
-					=> [
624
-						'value' => $value,
625
-						'message' => 'Saved',
626
-					],
627
-				'status' => 'success'
628
-			]
629
-		);
630
-		$this->assertEquals($expected, $this->themingController->undo($value));
631
-	}
632
-
633
-
634
-
635
-	public function testGetLogoNotExistent(): void {
636
-		$this->imageManager->method('getImage')
637
-			->with($this->equalTo('logo'))
638
-			->willThrowException(new NotFoundException());
639
-
640
-		$expected = new NotFoundResponse();
641
-		$this->assertEquals($expected, $this->themingController->getImage('logo'));
642
-	}
643
-
644
-	public function testGetLogo(): void {
645
-		$file = $this->createMock(ISimpleFile::class);
646
-		$file->method('getName')->willReturn('logo.svg');
647
-		$file->method('getMTime')->willReturn(42);
648
-		$this->imageManager->expects($this->once())
649
-			->method('getImage')
650
-			->willReturn($file);
651
-		$this->config
652
-			->expects($this->any())
653
-			->method('getAppValue')
654
-			->with('theming', 'logoMime', '')
655
-			->willReturn('text/svg');
656
-
657
-		@$expected = new FileDisplayResponse($file);
658
-		$expected->cacheFor(3600);
659
-		$expected->addHeader('Content-Type', 'text/svg');
660
-		$expected->addHeader('Content-Disposition', 'attachment; filename="logo"');
661
-		$csp = new ContentSecurityPolicy();
662
-		$csp->allowInlineStyle();
663
-		$expected->setContentSecurityPolicy($csp);
664
-		@$this->assertEquals($expected, $this->themingController->getImage('logo'));
665
-	}
666
-
667
-
668
-	public function testGetLoginBackgroundNotExistent(): void {
669
-		$this->imageManager->method('getImage')
670
-			->with($this->equalTo('background'))
671
-			->willThrowException(new NotFoundException());
672
-		$expected = new NotFoundResponse();
673
-		$this->assertEquals($expected, $this->themingController->getImage('background'));
674
-	}
675
-
676
-	public function testGetLoginBackground(): void {
677
-		$file = $this->createMock(ISimpleFile::class);
678
-		$file->method('getName')->willReturn('background.png');
679
-		$file->method('getMTime')->willReturn(42);
680
-		$this->imageManager->expects($this->once())
681
-			->method('getImage')
682
-			->willReturn($file);
683
-
684
-		$this->config
685
-			->expects($this->any())
686
-			->method('getAppValue')
687
-			->with('theming', 'backgroundMime', '')
688
-			->willReturn('image/png');
689
-
690
-		@$expected = new FileDisplayResponse($file);
691
-		$expected->cacheFor(3600);
692
-		$expected->addHeader('Content-Type', 'image/png');
693
-		$expected->addHeader('Content-Disposition', 'attachment; filename="background"');
694
-		$csp = new ContentSecurityPolicy();
695
-		$csp->allowInlineStyle();
696
-		$expected->setContentSecurityPolicy($csp);
697
-		@$this->assertEquals($expected, $this->themingController->getImage('background'));
698
-	}
699
-
700
-	public static function dataGetManifest(): array {
701
-		return [
702
-			[true],
703
-			[false],
704
-		];
705
-	}
706
-
707
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetManifest')]
708
-	public function testGetManifest(bool $standalone): void {
709
-		$this->config
710
-			->expects($this->once())
711
-			->method('getAppValue')
712
-			->with('theming', 'cachebuster', '0')
713
-			->willReturn('0');
714
-		$this->themingDefaults
715
-			->expects($this->any())
716
-			->method('getName')
717
-			->willReturn('Nextcloud');
718
-		$this->urlGenerator
719
-			->expects($this->once())
720
-			->method('getBaseUrl')
721
-			->willReturn('localhost');
722
-		$this->urlGenerator
723
-			->expects($this->exactly(2))
724
-			->method('linkToRoute')
725
-			->willReturnMap([
726
-				['theming.Icon.getTouchIcon', ['app' => 'core'], 'touchicon'],
727
-				['theming.Icon.getFavicon', ['app' => 'core'], 'favicon'],
728
-			]);
729
-		$this->config
730
-			->expects($this->exactly(2))
731
-			->method('getSystemValueBool')
732
-			->with('theming.standalone_window.enabled', true)
733
-			->willReturn($standalone);
734
-		$response = new JSONResponse([
735
-			'name' => 'Nextcloud',
736
-			'start_url' => 'localhost',
737
-			'icons'
738
-				=> [
739
-					[
740
-						'src' => 'touchicon?v=0',
741
-						'type' => 'image/png',
742
-						'sizes' => '512x512'
743
-					],
744
-					[
745
-						'src' => 'favicon?v=0',
746
-						'type' => 'image/svg+xml',
747
-						'sizes' => '16x16'
748
-					]
749
-				],
750
-			'display_override' => [$standalone ? 'minimal-ui' : ''],
751
-			'display' => $standalone ? 'standalone' : 'browser',
752
-			'short_name' => 'Nextcloud',
753
-			'theme_color' => null,
754
-			'background_color' => null,
755
-			'description' => null
756
-		]);
757
-		$response->cacheFor(3600);
758
-		$this->assertEquals($response, $this->themingController->getManifest('core'));
759
-	}
38
+    private IRequest&MockObject $request;
39
+    private IConfig&MockObject $config;
40
+    private IAppConfig&MockObject $appConfig;
41
+    private ThemingDefaults&MockObject $themingDefaults;
42
+    private IL10N&MockObject $l10n;
43
+    private IAppManager&MockObject $appManager;
44
+    private ImageManager&MockObject $imageManager;
45
+    private IURLGenerator&MockObject $urlGenerator;
46
+    private ThemesService&MockObject $themesService;
47
+    private INavigationManager&MockObject $navigationManager;
48
+
49
+    private ThemingController $themingController;
50
+
51
+    protected function setUp(): void {
52
+        $this->request = $this->createMock(IRequest::class);
53
+        $this->config = $this->createMock(IConfig::class);
54
+        $this->appConfig = $this->createMock(IAppConfig::class);
55
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
56
+        $this->l10n = $this->createMock(L10N::class);
57
+        $this->appManager = $this->createMock(IAppManager::class);
58
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
59
+        $this->imageManager = $this->createMock(ImageManager::class);
60
+        $this->themesService = $this->createMock(ThemesService::class);
61
+        $this->navigationManager = $this->createMock(INavigationManager::class);
62
+
63
+        $timeFactory = $this->createMock(ITimeFactory::class);
64
+        $timeFactory->expects($this->any())
65
+            ->method('getTime')
66
+            ->willReturn(123);
67
+
68
+        $this->overwriteService(ITimeFactory::class, $timeFactory);
69
+
70
+        $this->themingController = new ThemingController(
71
+            'theming',
72
+            $this->request,
73
+            $this->config,
74
+            $this->appConfig,
75
+            $this->themingDefaults,
76
+            $this->l10n,
77
+            $this->urlGenerator,
78
+            $this->appManager,
79
+            $this->imageManager,
80
+            $this->themesService,
81
+            $this->navigationManager,
82
+        );
83
+
84
+        parent::setUp();
85
+    }
86
+
87
+    public static function dataUpdateStylesheetSuccess(): array {
88
+        return [
89
+            ['name', str_repeat('a', 250), 'Saved'],
90
+            ['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
91
+            ['slogan', str_repeat('a', 500), 'Saved'],
92
+            ['color', '#0082c9', 'Saved'],
93
+            ['color', '#0082C9', 'Saved'],
94
+            ['color', '#0082C9', 'Saved'],
95
+            ['imprintUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
96
+            ['privacyUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
97
+        ];
98
+    }
99
+
100
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetSuccess')]
101
+    public function testUpdateStylesheetSuccess(string $setting, string $value, string $message): void {
102
+        $this->themingDefaults
103
+            ->expects($this->once())
104
+            ->method('set')
105
+            ->with($setting, $value);
106
+        $this->l10n
107
+            ->expects($this->once())
108
+            ->method('t')
109
+            ->willReturnCallback(function ($str) {
110
+                return $str;
111
+            });
112
+
113
+        $expected = new DataResponse(
114
+            [
115
+                'data'
116
+                    => [
117
+                        'message' => $message,
118
+                    ],
119
+                'status' => 'success',
120
+            ]
121
+        );
122
+        $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
123
+    }
124
+
125
+    public static function dataUpdateStylesheetError(): array {
126
+        $urls = [
127
+            'url' => 'web address',
128
+            'imprintUrl' => 'legal notice address',
129
+            'privacyUrl' => 'privacy policy address',
130
+        ];
131
+
132
+        $urlTests = [];
133
+        foreach ($urls as $urlKey => $urlName) {
134
+            // Check length limit
135
+            $urlTests[] = [$urlKey, 'http://example.com/' . str_repeat('a', 501), "The given {$urlName} is too long"];
136
+            // Check potential evil javascript
137
+            $urlTests[] = [$urlKey, 'javascript:alert(1)', "The given {$urlName} is not a valid URL"];
138
+            // Check XSS
139
+            $urlTests[] = [$urlKey, 'https://example.com/"><script/src="alert(\'1\')"><a/href/="', "The given {$urlName} is not a valid URL"];
140
+        }
141
+
142
+        return [
143
+            ['name', str_repeat('a', 251), 'The given name is too long'],
144
+            ['slogan', str_repeat('a', 501), 'The given slogan is too long'],
145
+            ['primary_color', '0082C9', 'The given color is invalid'],
146
+            ['primary_color', '#0082Z9', 'The given color is invalid'],
147
+            ['primary_color', 'Nextcloud', 'The given color is invalid'],
148
+            ['background_color', '0082C9', 'The given color is invalid'],
149
+            ['background_color', '#0082Z9', 'The given color is invalid'],
150
+            ['background_color', 'Nextcloud', 'The given color is invalid'],
151
+
152
+            ...$urlTests,
153
+        ];
154
+    }
155
+
156
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetError')]
157
+    public function testUpdateStylesheetError(string $setting, string $value, string $message): void {
158
+        $this->themingDefaults
159
+            ->expects($this->never())
160
+            ->method('set')
161
+            ->with($setting, $value);
162
+        $this->l10n
163
+            ->expects($this->any())
164
+            ->method('t')
165
+            ->willReturnCallback(function ($str) {
166
+                return $str;
167
+            });
168
+
169
+        $expected = new DataResponse(
170
+            [
171
+                'data'
172
+                    => [
173
+                        'message' => $message,
174
+                    ],
175
+                'status' => 'error',
176
+            ],
177
+            Http::STATUS_BAD_REQUEST
178
+        );
179
+        $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
180
+    }
181
+
182
+    public function testUpdateLogoNoData(): void {
183
+        $this->request
184
+            ->expects($this->once())
185
+            ->method('getParam')
186
+            ->with('key')
187
+            ->willReturn('logo');
188
+        $this->request
189
+            ->expects($this->once())
190
+            ->method('getUploadedFile')
191
+            ->with('image')
192
+            ->willReturn(null);
193
+        $this->l10n
194
+            ->expects($this->any())
195
+            ->method('t')
196
+            ->willReturnCallback(function ($str) {
197
+                return $str;
198
+            });
199
+
200
+        $expected = new DataResponse(
201
+            [
202
+                'data'
203
+                    => [
204
+                        'message' => 'No file uploaded',
205
+                    ],
206
+                'status' => 'failure',
207
+            ],
208
+            Http::STATUS_UNPROCESSABLE_ENTITY
209
+        );
210
+
211
+        $this->assertEquals($expected, $this->themingController->uploadImage());
212
+    }
213
+
214
+    public function testUploadInvalidUploadKey(): void {
215
+        $this->request
216
+            ->expects($this->once())
217
+            ->method('getParam')
218
+            ->with('key')
219
+            ->willReturn('invalid');
220
+        $this->request
221
+            ->expects($this->never())
222
+            ->method('getUploadedFile');
223
+        $this->l10n
224
+            ->expects($this->any())
225
+            ->method('t')
226
+            ->willReturnCallback(function ($str) {
227
+                return $str;
228
+            });
229
+
230
+        $expected = new DataResponse(
231
+            [
232
+                'data'
233
+                    => [
234
+                        'message' => 'Invalid key',
235
+                    ],
236
+                'status' => 'failure',
237
+            ],
238
+            Http::STATUS_BAD_REQUEST
239
+        );
240
+
241
+        $this->assertEquals($expected, $this->themingController->uploadImage());
242
+    }
243
+
244
+    /**
245
+     * Checks that trying to upload an SVG favicon without imagemagick
246
+     * results in an unsupported media type response.
247
+     */
248
+    public function testUploadSVGFaviconWithoutImagemagick(): void {
249
+        $this->imageManager
250
+            ->method('shouldReplaceIcons')
251
+            ->willReturn(false);
252
+
253
+        $this->request
254
+            ->expects($this->once())
255
+            ->method('getParam')
256
+            ->with('key')
257
+            ->willReturn('favicon');
258
+        $this->request
259
+            ->expects($this->once())
260
+            ->method('getUploadedFile')
261
+            ->with('image')
262
+            ->willReturn([
263
+                'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg',
264
+                'type' => 'image/svg',
265
+                'name' => 'testimagelarge.svg',
266
+                'error' => 0,
267
+            ]);
268
+        $this->l10n
269
+            ->expects($this->any())
270
+            ->method('t')
271
+            ->willReturnCallback(function ($str) {
272
+                return $str;
273
+            });
274
+
275
+        $this->imageManager->expects($this->once())
276
+            ->method('updateImage')
277
+            ->willThrowException(new \Exception('Unsupported image type'));
278
+
279
+        $expected = new DataResponse(
280
+            [
281
+                'data'
282
+                    => [
283
+                        'message' => 'Unsupported image type',
284
+                    ],
285
+                'status' => 'failure'
286
+            ],
287
+            Http::STATUS_UNPROCESSABLE_ENTITY
288
+        );
289
+
290
+        $this->assertEquals($expected, $this->themingController->uploadImage());
291
+    }
292
+
293
+    public function testUpdateLogoInvalidMimeType(): void {
294
+        $this->request
295
+            ->expects($this->once())
296
+            ->method('getParam')
297
+            ->with('key')
298
+            ->willReturn('logo');
299
+        $this->request
300
+            ->expects($this->once())
301
+            ->method('getUploadedFile')
302
+            ->with('image')
303
+            ->willReturn([
304
+                'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt',
305
+                'type' => 'application/pdf',
306
+                'name' => 'logo.pdf',
307
+                'error' => 0,
308
+            ]);
309
+        $this->l10n
310
+            ->expects($this->any())
311
+            ->method('t')
312
+            ->willReturnCallback(function ($str) {
313
+                return $str;
314
+            });
315
+
316
+        $this->imageManager->expects($this->once())
317
+            ->method('updateImage')
318
+            ->willThrowException(new \Exception('Unsupported image type'));
319
+
320
+        $expected = new DataResponse(
321
+            [
322
+                'data'
323
+                    => [
324
+                        'message' => 'Unsupported image type',
325
+                    ],
326
+                'status' => 'failure'
327
+            ],
328
+            Http::STATUS_UNPROCESSABLE_ENTITY
329
+        );
330
+
331
+        $this->assertEquals($expected, $this->themingController->uploadImage());
332
+    }
333
+
334
+    public static function dataUpdateImages(): array {
335
+        return [
336
+            ['image/jpeg', false],
337
+            ['image/jpeg', true],
338
+            ['image/gif'],
339
+            ['image/png'],
340
+            ['image/svg+xml'],
341
+            ['image/svg']
342
+        ];
343
+    }
344
+
345
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImages')]
346
+    public function testUpdateLogoNormalLogoUpload(string $mimeType, bool $folderExists = true): void {
347
+        $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
348
+        $destination = Server::get(ITempManager::class)->getTemporaryFolder();
349
+
350
+        touch($tmpLogo);
351
+        copy(__DIR__ . '/../../../../tests/data/testimage.png', $tmpLogo);
352
+        $this->request
353
+            ->expects($this->once())
354
+            ->method('getParam')
355
+            ->with('key')
356
+            ->willReturn('logo');
357
+        $this->request
358
+            ->expects($this->once())
359
+            ->method('getUploadedFile')
360
+            ->with('image')
361
+            ->willReturn([
362
+                'tmp_name' => $tmpLogo,
363
+                'type' => $mimeType,
364
+                'name' => 'logo.svg',
365
+                'error' => 0,
366
+            ]);
367
+        $this->l10n
368
+            ->expects($this->any())
369
+            ->method('t')
370
+            ->willReturnCallback(function ($str) {
371
+                return $str;
372
+            });
373
+
374
+        $this->imageManager->expects($this->once())
375
+            ->method('getImageUrl')
376
+            ->with('logo')
377
+            ->willReturn('imageUrl');
378
+
379
+        $this->imageManager->expects($this->once())
380
+            ->method('updateImage');
381
+
382
+        $expected = new DataResponse(
383
+            [
384
+                'data'
385
+                    => [
386
+                        'name' => 'logo.svg',
387
+                        'message' => 'Saved',
388
+                        'url' => 'imageUrl',
389
+                    ],
390
+                'status' => 'success'
391
+            ]
392
+        );
393
+
394
+        $this->assertEquals($expected, $this->themingController->uploadImage());
395
+    }
396
+
397
+    public function testUpdateLogoLoginScreenUpload(): void {
398
+        $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . 'logo.png';
399
+
400
+        touch($tmpLogo);
401
+        copy(__DIR__ . '/../../../../tests/data/desktopapp.png', $tmpLogo);
402
+        $this->request
403
+            ->expects($this->once())
404
+            ->method('getParam')
405
+            ->with('key')
406
+            ->willReturn('background');
407
+        $this->request
408
+            ->expects($this->once())
409
+            ->method('getUploadedFile')
410
+            ->with('image')
411
+            ->willReturn([
412
+                'tmp_name' => $tmpLogo,
413
+                'type' => 'image/svg+xml',
414
+                'name' => 'logo.svg',
415
+                'error' => 0,
416
+            ]);
417
+        $this->l10n
418
+            ->expects($this->any())
419
+            ->method('t')
420
+            ->willReturnCallback(function ($str) {
421
+                return $str;
422
+            });
423
+
424
+        $this->imageManager->expects($this->once())
425
+            ->method('updateImage');
426
+
427
+        $this->imageManager->expects($this->once())
428
+            ->method('getImageUrl')
429
+            ->with('background')
430
+            ->willReturn('imageUrl');
431
+        $expected = new DataResponse(
432
+            [
433
+                'data'
434
+                    => [
435
+                        'name' => 'logo.svg',
436
+                        'message' => 'Saved',
437
+                        'url' => 'imageUrl',
438
+                    ],
439
+                'status' => 'success'
440
+            ]
441
+        );
442
+        $this->assertEquals($expected, $this->themingController->uploadImage());
443
+    }
444
+
445
+    public function testUpdateLogoLoginScreenUploadWithInvalidImage(): void {
446
+        $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
447
+
448
+        touch($tmpLogo);
449
+        file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
450
+        $this->request
451
+            ->expects($this->once())
452
+            ->method('getParam')
453
+            ->with('key')
454
+            ->willReturn('logo');
455
+        $this->request
456
+            ->expects($this->once())
457
+            ->method('getUploadedFile')
458
+            ->with('image')
459
+            ->willReturn([
460
+                'tmp_name' => $tmpLogo,
461
+                'type' => 'foobar',
462
+                'name' => 'logo.svg',
463
+                'error' => 0,
464
+            ]);
465
+        $this->l10n
466
+            ->expects($this->any())
467
+            ->method('t')
468
+            ->willReturnCallback(function ($str) {
469
+                return $str;
470
+            });
471
+
472
+        $this->imageManager->expects($this->once())
473
+            ->method('updateImage')
474
+            ->willThrowException(new \Exception('Unsupported image type'));
475
+
476
+        $expected = new DataResponse(
477
+            [
478
+                'data'
479
+                    => [
480
+                        'message' => 'Unsupported image type',
481
+                    ],
482
+                'status' => 'failure'
483
+            ],
484
+            Http::STATUS_UNPROCESSABLE_ENTITY
485
+        );
486
+        $this->assertEquals($expected, $this->themingController->uploadImage());
487
+    }
488
+
489
+    public static function dataPhpUploadErrors(): array {
490
+        return [
491
+            [UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'],
492
+            [UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'],
493
+            [UPLOAD_ERR_PARTIAL, 'The file was only partially uploaded'],
494
+            [UPLOAD_ERR_NO_FILE, 'No file was uploaded'],
495
+            [UPLOAD_ERR_NO_TMP_DIR, 'Missing a temporary folder'],
496
+            [UPLOAD_ERR_CANT_WRITE, 'Could not write file to disk'],
497
+            [UPLOAD_ERR_EXTENSION, 'A PHP extension stopped the file upload'],
498
+        ];
499
+    }
500
+
501
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
502
+    public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload(int $error, string $expectedErrorMessage): void {
503
+        $this->request
504
+            ->expects($this->once())
505
+            ->method('getParam')
506
+            ->with('key')
507
+            ->willReturn('background');
508
+        $this->request
509
+            ->expects($this->once())
510
+            ->method('getUploadedFile')
511
+            ->with('image')
512
+            ->willReturn([
513
+                'tmp_name' => '',
514
+                'type' => 'image/svg+xml',
515
+                'name' => 'logo.svg',
516
+                'error' => $error,
517
+            ]);
518
+        $this->l10n
519
+            ->expects($this->any())
520
+            ->method('t')
521
+            ->willReturnCallback(function ($str) {
522
+                return $str;
523
+            });
524
+
525
+        $expected = new DataResponse(
526
+            [
527
+                'data'
528
+                    => [
529
+                        'message' => $expectedErrorMessage,
530
+                    ],
531
+                'status' => 'failure'
532
+            ],
533
+            Http::STATUS_UNPROCESSABLE_ENTITY
534
+        );
535
+        $this->assertEquals($expected, $this->themingController->uploadImage());
536
+    }
537
+
538
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
539
+    public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage): void {
540
+        $this->request
541
+            ->expects($this->once())
542
+            ->method('getParam')
543
+            ->with('key')
544
+            ->willReturn('background');
545
+        $this->request
546
+            ->expects($this->once())
547
+            ->method('getUploadedFile')
548
+            ->with('image')
549
+            ->willReturn([
550
+                'tmp_name' => '',
551
+                'type' => 'text/svg',
552
+                'name' => 'logo.svg',
553
+                'error' => $error,
554
+            ]);
555
+        $this->l10n
556
+            ->expects($this->any())
557
+            ->method('t')
558
+            ->willReturnCallback(function ($str) {
559
+                return $str;
560
+            });
561
+
562
+        $expected = new DataResponse(
563
+            [
564
+                'data'
565
+                    => [
566
+                        'message' => $expectedErrorMessage
567
+                    ],
568
+                'status' => 'failure'
569
+            ],
570
+            Http::STATUS_UNPROCESSABLE_ENTITY
571
+        );
572
+        $this->assertEquals($expected, $this->themingController->uploadImage());
573
+    }
574
+
575
+    public function testUndo(): void {
576
+        $this->l10n
577
+            ->expects($this->once())
578
+            ->method('t')
579
+            ->with('Saved')
580
+            ->willReturn('Saved');
581
+        $this->themingDefaults
582
+            ->expects($this->once())
583
+            ->method('undo')
584
+            ->with('MySetting')
585
+            ->willReturn('MyValue');
586
+
587
+        $expected = new DataResponse(
588
+            [
589
+                'data'
590
+                    => [
591
+                        'value' => 'MyValue',
592
+                        'message' => 'Saved'
593
+                    ],
594
+                'status' => 'success'
595
+            ]
596
+        );
597
+        $this->assertEquals($expected, $this->themingController->undo('MySetting'));
598
+    }
599
+
600
+    public static function dataUndoDelete(): array {
601
+        return [
602
+            [ 'backgroundMime', 'background' ],
603
+            [ 'logoMime', 'logo' ]
604
+        ];
605
+    }
606
+
607
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUndoDelete')]
608
+    public function testUndoDelete(string $value, string $filename): void {
609
+        $this->l10n
610
+            ->expects($this->once())
611
+            ->method('t')
612
+            ->with('Saved')
613
+            ->willReturn('Saved');
614
+        $this->themingDefaults
615
+            ->expects($this->once())
616
+            ->method('undo')
617
+            ->with($value)
618
+            ->willReturn($value);
619
+
620
+        $expected = new DataResponse(
621
+            [
622
+                'data'
623
+                    => [
624
+                        'value' => $value,
625
+                        'message' => 'Saved',
626
+                    ],
627
+                'status' => 'success'
628
+            ]
629
+        );
630
+        $this->assertEquals($expected, $this->themingController->undo($value));
631
+    }
632
+
633
+
634
+
635
+    public function testGetLogoNotExistent(): void {
636
+        $this->imageManager->method('getImage')
637
+            ->with($this->equalTo('logo'))
638
+            ->willThrowException(new NotFoundException());
639
+
640
+        $expected = new NotFoundResponse();
641
+        $this->assertEquals($expected, $this->themingController->getImage('logo'));
642
+    }
643
+
644
+    public function testGetLogo(): void {
645
+        $file = $this->createMock(ISimpleFile::class);
646
+        $file->method('getName')->willReturn('logo.svg');
647
+        $file->method('getMTime')->willReturn(42);
648
+        $this->imageManager->expects($this->once())
649
+            ->method('getImage')
650
+            ->willReturn($file);
651
+        $this->config
652
+            ->expects($this->any())
653
+            ->method('getAppValue')
654
+            ->with('theming', 'logoMime', '')
655
+            ->willReturn('text/svg');
656
+
657
+        @$expected = new FileDisplayResponse($file);
658
+        $expected->cacheFor(3600);
659
+        $expected->addHeader('Content-Type', 'text/svg');
660
+        $expected->addHeader('Content-Disposition', 'attachment; filename="logo"');
661
+        $csp = new ContentSecurityPolicy();
662
+        $csp->allowInlineStyle();
663
+        $expected->setContentSecurityPolicy($csp);
664
+        @$this->assertEquals($expected, $this->themingController->getImage('logo'));
665
+    }
666
+
667
+
668
+    public function testGetLoginBackgroundNotExistent(): void {
669
+        $this->imageManager->method('getImage')
670
+            ->with($this->equalTo('background'))
671
+            ->willThrowException(new NotFoundException());
672
+        $expected = new NotFoundResponse();
673
+        $this->assertEquals($expected, $this->themingController->getImage('background'));
674
+    }
675
+
676
+    public function testGetLoginBackground(): void {
677
+        $file = $this->createMock(ISimpleFile::class);
678
+        $file->method('getName')->willReturn('background.png');
679
+        $file->method('getMTime')->willReturn(42);
680
+        $this->imageManager->expects($this->once())
681
+            ->method('getImage')
682
+            ->willReturn($file);
683
+
684
+        $this->config
685
+            ->expects($this->any())
686
+            ->method('getAppValue')
687
+            ->with('theming', 'backgroundMime', '')
688
+            ->willReturn('image/png');
689
+
690
+        @$expected = new FileDisplayResponse($file);
691
+        $expected->cacheFor(3600);
692
+        $expected->addHeader('Content-Type', 'image/png');
693
+        $expected->addHeader('Content-Disposition', 'attachment; filename="background"');
694
+        $csp = new ContentSecurityPolicy();
695
+        $csp->allowInlineStyle();
696
+        $expected->setContentSecurityPolicy($csp);
697
+        @$this->assertEquals($expected, $this->themingController->getImage('background'));
698
+    }
699
+
700
+    public static function dataGetManifest(): array {
701
+        return [
702
+            [true],
703
+            [false],
704
+        ];
705
+    }
706
+
707
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetManifest')]
708
+    public function testGetManifest(bool $standalone): void {
709
+        $this->config
710
+            ->expects($this->once())
711
+            ->method('getAppValue')
712
+            ->with('theming', 'cachebuster', '0')
713
+            ->willReturn('0');
714
+        $this->themingDefaults
715
+            ->expects($this->any())
716
+            ->method('getName')
717
+            ->willReturn('Nextcloud');
718
+        $this->urlGenerator
719
+            ->expects($this->once())
720
+            ->method('getBaseUrl')
721
+            ->willReturn('localhost');
722
+        $this->urlGenerator
723
+            ->expects($this->exactly(2))
724
+            ->method('linkToRoute')
725
+            ->willReturnMap([
726
+                ['theming.Icon.getTouchIcon', ['app' => 'core'], 'touchicon'],
727
+                ['theming.Icon.getFavicon', ['app' => 'core'], 'favicon'],
728
+            ]);
729
+        $this->config
730
+            ->expects($this->exactly(2))
731
+            ->method('getSystemValueBool')
732
+            ->with('theming.standalone_window.enabled', true)
733
+            ->willReturn($standalone);
734
+        $response = new JSONResponse([
735
+            'name' => 'Nextcloud',
736
+            'start_url' => 'localhost',
737
+            'icons'
738
+                => [
739
+                    [
740
+                        'src' => 'touchicon?v=0',
741
+                        'type' => 'image/png',
742
+                        'sizes' => '512x512'
743
+                    ],
744
+                    [
745
+                        'src' => 'favicon?v=0',
746
+                        'type' => 'image/svg+xml',
747
+                        'sizes' => '16x16'
748
+                    ]
749
+                ],
750
+            'display_override' => [$standalone ? 'minimal-ui' : ''],
751
+            'display' => $standalone ? 'standalone' : 'browser',
752
+            'short_name' => 'Nextcloud',
753
+            'theme_color' => null,
754
+            'background_color' => null,
755
+            'description' => null
756
+        ]);
757
+        $response->cacheFor(3600);
758
+        $this->assertEquals($response, $this->themingController->getManifest('core'));
759
+    }
760 760
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -87,13 +87,13 @@  discard block
 block discarded – undo
87 87
 	public static function dataUpdateStylesheetSuccess(): array {
88 88
 		return [
89 89
 			['name', str_repeat('a', 250), 'Saved'],
90
-			['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
90
+			['url', 'https://nextcloud.com/'.str_repeat('a', 478), 'Saved'],
91 91
 			['slogan', str_repeat('a', 500), 'Saved'],
92 92
 			['color', '#0082c9', 'Saved'],
93 93
 			['color', '#0082C9', 'Saved'],
94 94
 			['color', '#0082C9', 'Saved'],
95
-			['imprintUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
96
-			['privacyUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
95
+			['imprintUrl', 'https://nextcloud.com/'.str_repeat('a', 478), 'Saved'],
96
+			['privacyUrl', 'https://nextcloud.com/'.str_repeat('a', 478), 'Saved'],
97 97
 		];
98 98
 	}
99 99
 
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
 		$this->l10n
107 107
 			->expects($this->once())
108 108
 			->method('t')
109
-			->willReturnCallback(function ($str) {
109
+			->willReturnCallback(function($str) {
110 110
 				return $str;
111 111
 			});
112 112
 
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
 		$urlTests = [];
133 133
 		foreach ($urls as $urlKey => $urlName) {
134 134
 			// Check length limit
135
-			$urlTests[] = [$urlKey, 'http://example.com/' . str_repeat('a', 501), "The given {$urlName} is too long"];
135
+			$urlTests[] = [$urlKey, 'http://example.com/'.str_repeat('a', 501), "The given {$urlName} is too long"];
136 136
 			// Check potential evil javascript
137 137
 			$urlTests[] = [$urlKey, 'javascript:alert(1)', "The given {$urlName} is not a valid URL"];
138 138
 			// Check XSS
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 		$this->l10n
163 163
 			->expects($this->any())
164 164
 			->method('t')
165
-			->willReturnCallback(function ($str) {
165
+			->willReturnCallback(function($str) {
166 166
 				return $str;
167 167
 			});
168 168
 
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
 		$this->l10n
194 194
 			->expects($this->any())
195 195
 			->method('t')
196
-			->willReturnCallback(function ($str) {
196
+			->willReturnCallback(function($str) {
197 197
 				return $str;
198 198
 			});
199 199
 
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
 		$this->l10n
224 224
 			->expects($this->any())
225 225
 			->method('t')
226
-			->willReturnCallback(function ($str) {
226
+			->willReturnCallback(function($str) {
227 227
 				return $str;
228 228
 			});
229 229
 
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
 			->method('getUploadedFile')
261 261
 			->with('image')
262 262
 			->willReturn([
263
-				'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg',
263
+				'tmp_name' => __DIR__.'/../../../../tests/data/testimagelarge.svg',
264 264
 				'type' => 'image/svg',
265 265
 				'name' => 'testimagelarge.svg',
266 266
 				'error' => 0,
@@ -268,7 +268,7 @@  discard block
 block discarded – undo
268 268
 		$this->l10n
269 269
 			->expects($this->any())
270 270
 			->method('t')
271
-			->willReturnCallback(function ($str) {
271
+			->willReturnCallback(function($str) {
272 272
 				return $str;
273 273
 			});
274 274
 
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
 			->method('getUploadedFile')
302 302
 			->with('image')
303 303
 			->willReturn([
304
-				'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt',
304
+				'tmp_name' => __DIR__.'/../../../../tests/data/lorem.txt',
305 305
 				'type' => 'application/pdf',
306 306
 				'name' => 'logo.pdf',
307 307
 				'error' => 0,
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 		$this->l10n
310 310
 			->expects($this->any())
311 311
 			->method('t')
312
-			->willReturnCallback(function ($str) {
312
+			->willReturnCallback(function($str) {
313 313
 				return $str;
314 314
 			});
315 315
 
@@ -344,11 +344,11 @@  discard block
 block discarded – undo
344 344
 
345 345
 	#[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImages')]
346 346
 	public function testUpdateLogoNormalLogoUpload(string $mimeType, bool $folderExists = true): void {
347
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
347
+		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder().'/logo.svg';
348 348
 		$destination = Server::get(ITempManager::class)->getTemporaryFolder();
349 349
 
350 350
 		touch($tmpLogo);
351
-		copy(__DIR__ . '/../../../../tests/data/testimage.png', $tmpLogo);
351
+		copy(__DIR__.'/../../../../tests/data/testimage.png', $tmpLogo);
352 352
 		$this->request
353 353
 			->expects($this->once())
354 354
 			->method('getParam')
@@ -367,7 +367,7 @@  discard block
 block discarded – undo
367 367
 		$this->l10n
368 368
 			->expects($this->any())
369 369
 			->method('t')
370
-			->willReturnCallback(function ($str) {
370
+			->willReturnCallback(function($str) {
371 371
 				return $str;
372 372
 			});
373 373
 
@@ -395,10 +395,10 @@  discard block
 block discarded – undo
395 395
 	}
396 396
 
397 397
 	public function testUpdateLogoLoginScreenUpload(): void {
398
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . 'logo.png';
398
+		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder().'logo.png';
399 399
 
400 400
 		touch($tmpLogo);
401
-		copy(__DIR__ . '/../../../../tests/data/desktopapp.png', $tmpLogo);
401
+		copy(__DIR__.'/../../../../tests/data/desktopapp.png', $tmpLogo);
402 402
 		$this->request
403 403
 			->expects($this->once())
404 404
 			->method('getParam')
@@ -417,7 +417,7 @@  discard block
 block discarded – undo
417 417
 		$this->l10n
418 418
 			->expects($this->any())
419 419
 			->method('t')
420
-			->willReturnCallback(function ($str) {
420
+			->willReturnCallback(function($str) {
421 421
 				return $str;
422 422
 			});
423 423
 
@@ -443,10 +443,10 @@  discard block
 block discarded – undo
443 443
 	}
444 444
 
445 445
 	public function testUpdateLogoLoginScreenUploadWithInvalidImage(): void {
446
-		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
446
+		$tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder().'/logo.svg';
447 447
 
448 448
 		touch($tmpLogo);
449
-		file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
449
+		file_put_contents($tmpLogo, file_get_contents(__DIR__.'/../../../../tests/data/data.zip'));
450 450
 		$this->request
451 451
 			->expects($this->once())
452 452
 			->method('getParam')
@@ -465,7 +465,7 @@  discard block
 block discarded – undo
465 465
 		$this->l10n
466 466
 			->expects($this->any())
467 467
 			->method('t')
468
-			->willReturnCallback(function ($str) {
468
+			->willReturnCallback(function($str) {
469 469
 				return $str;
470 470
 			});
471 471
 
@@ -518,7 +518,7 @@  discard block
 block discarded – undo
518 518
 		$this->l10n
519 519
 			->expects($this->any())
520 520
 			->method('t')
521
-			->willReturnCallback(function ($str) {
521
+			->willReturnCallback(function($str) {
522 522
 				return $str;
523 523
 			});
524 524
 
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
 		$this->l10n
556 556
 			->expects($this->any())
557 557
 			->method('t')
558
-			->willReturnCallback(function ($str) {
558
+			->willReturnCallback(function($str) {
559 559
 				return $str;
560 560
 			});
561 561
 
@@ -599,8 +599,8 @@  discard block
 block discarded – undo
599 599
 
600 600
 	public static function dataUndoDelete(): array {
601 601
 		return [
602
-			[ 'backgroundMime', 'background' ],
603
-			[ 'logoMime', 'logo' ]
602
+			['backgroundMime', 'background'],
603
+			['logoMime', 'logo']
604 604
 		];
605 605
 	}
606 606
 
Please login to merge, or discard this patch.
apps/theming/tests/Controller/IconControllerTest.php 1 patch
Indentation   +158 added lines, -158 removed lines patch added patch discarded remove patch
@@ -24,162 +24,162 @@
 block discarded – undo
24 24
 use Test\TestCase;
25 25
 
26 26
 class IconControllerTest extends TestCase {
27
-	private IRequest&MockObject $request;
28
-	private ThemingDefaults&MockObject $themingDefaults;
29
-	private ITimeFactory&MockObject $timeFactory;
30
-	private IconBuilder&MockObject $iconBuilder;
31
-	private FileAccessHelper&MockObject $fileAccessHelper;
32
-	private IAppManager&MockObject $appManager;
33
-	private ImageManager&MockObject $imageManager;
34
-	private IconController $iconController;
35
-
36
-	protected function setUp(): void {
37
-		$this->request = $this->createMock(IRequest::class);
38
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
39
-		$this->iconBuilder = $this->createMock(IconBuilder::class);
40
-		$this->imageManager = $this->createMock(ImageManager::class);
41
-		$this->fileAccessHelper = $this->createMock(FileAccessHelper::class);
42
-		$this->appManager = $this->createMock(IAppManager::class);
43
-
44
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
45
-		$this->timeFactory->expects($this->any())
46
-			->method('getTime')
47
-			->willReturn(123);
48
-
49
-		$this->overwriteService(ITimeFactory::class, $this->timeFactory);
50
-
51
-		$this->iconController = new IconController(
52
-			'theming',
53
-			$this->request,
54
-			$this->themingDefaults,
55
-			$this->iconBuilder,
56
-			$this->imageManager,
57
-			$this->fileAccessHelper,
58
-			$this->appManager,
59
-		);
60
-
61
-		parent::setUp();
62
-	}
63
-
64
-	private function iconFileMock($filename, $data) {
65
-		$icon = $this->getMockBuilder('OCP\Files\File')->getMock();
66
-		$icon->expects($this->any())->method('getContent')->willReturn($data);
67
-		$icon->expects($this->any())->method('getMimeType')->willReturn('image type');
68
-		$icon->expects($this->any())->method('getEtag')->willReturn('my etag');
69
-		$icon->expects($this->any())->method('getName')->willReturn('my name');
70
-		$icon->expects($this->any())->method('getMTime')->willReturn(42);
71
-		$icon->method('getName')->willReturn($filename);
72
-		return new SimpleFile($icon);
73
-	}
74
-
75
-	public function testGetThemedIcon(): void {
76
-		$file = $this->iconFileMock('icon-core-filetypes_folder.svg', 'filecontent');
77
-		$this->imageManager->expects($this->once())
78
-			->method('getCachedImage')
79
-			->with('icon-core-filetypes_folder.svg')
80
-			->willReturn($file);
81
-		$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']);
82
-		$expected->cacheFor(86400, false, true);
83
-		$this->assertEquals($expected, $this->iconController->getThemedIcon('core', 'filetypes/folder.svg'));
84
-	}
85
-
86
-	public function testGetFaviconDefault(): void {
87
-		if (!extension_loaded('imagick')) {
88
-			$this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
89
-		}
90
-		$checkImagick = new \Imagick();
91
-		if (count($checkImagick->queryFormats('SVG')) < 1) {
92
-			$this->markTestSkipped('No SVG provider present.');
93
-		}
94
-		$file = $this->iconFileMock('filename', 'filecontent');
95
-		$this->imageManager->expects($this->once())
96
-			->method('getImage', false)
97
-			->with('favicon')
98
-			->willThrowException(new NotFoundException());
99
-		$this->imageManager->expects($this->any())
100
-			->method('shouldReplaceIcons')
101
-			->willReturn(true);
102
-		$this->imageManager->expects($this->once())
103
-			->method('getCachedImage')
104
-			->willThrowException(new NotFoundException());
105
-		$this->iconBuilder->expects($this->once())
106
-			->method('getFavicon')
107
-			->with('core')
108
-			->willReturn('filecontent');
109
-		$this->imageManager->expects($this->once())
110
-			->method('setCachedImage')
111
-			->willReturn($file);
112
-
113
-		$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
114
-		$expected->cacheFor(86400);
115
-		$this->assertEquals($expected, $this->iconController->getFavicon());
116
-	}
117
-
118
-	public function testGetFaviconFail(): void {
119
-		$this->imageManager->expects($this->once())
120
-			->method('getImage')
121
-			->with('favicon', false)
122
-			->willThrowException(new NotFoundException());
123
-		$this->imageManager->expects($this->any())
124
-			->method('shouldReplaceIcons')
125
-			->willReturn(false);
126
-		$fallbackLogo = \OC::$SERVERROOT . '/core/img/favicon.png';
127
-		$this->fileAccessHelper->expects($this->once())
128
-			->method('file_get_contents')
129
-			->with($fallbackLogo)
130
-			->willReturn(file_get_contents($fallbackLogo));
131
-		$expected = new DataDisplayResponse(file_get_contents($fallbackLogo), Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
132
-		$expected->cacheFor(86400);
133
-		$this->assertEquals($expected, $this->iconController->getFavicon());
134
-	}
135
-
136
-	public function testGetTouchIconDefault(): void {
137
-		if (!extension_loaded('imagick')) {
138
-			$this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
139
-		}
140
-		$checkImagick = new \Imagick();
141
-		if (count($checkImagick->queryFormats('SVG')) < 1) {
142
-			$this->markTestSkipped('No SVG provider present.');
143
-		}
144
-
145
-		$this->imageManager->expects($this->once())
146
-			->method('getImage')
147
-			->willThrowException(new NotFoundException());
148
-		$this->imageManager->expects($this->any())
149
-			->method('shouldReplaceIcons')
150
-			->willReturn(true);
151
-		$this->iconBuilder->expects($this->once())
152
-			->method('getTouchIcon')
153
-			->with('core')
154
-			->willReturn('filecontent');
155
-		$file = $this->iconFileMock('filename', 'filecontent');
156
-		$this->imageManager->expects($this->once())
157
-			->method('getCachedImage')
158
-			->willThrowException(new NotFoundException());
159
-		$this->imageManager->expects($this->once())
160
-			->method('setCachedImage')
161
-			->willReturn($file);
162
-
163
-		$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/png']);
164
-		$expected->cacheFor(86400);
165
-		$this->assertEquals($expected, $this->iconController->getTouchIcon());
166
-	}
167
-
168
-	public function testGetTouchIconFail(): void {
169
-		$this->imageManager->expects($this->once())
170
-			->method('getImage')
171
-			->with('favicon')
172
-			->willThrowException(new NotFoundException());
173
-		$this->imageManager->expects($this->any())
174
-			->method('shouldReplaceIcons')
175
-			->willReturn(false);
176
-		$fallbackLogo = \OC::$SERVERROOT . '/core/img/favicon-touch.png';
177
-		$this->fileAccessHelper->expects($this->once())
178
-			->method('file_get_contents')
179
-			->with($fallbackLogo)
180
-			->willReturn(file_get_contents($fallbackLogo));
181
-		$expected = new DataDisplayResponse(file_get_contents($fallbackLogo), Http::STATUS_OK, ['Content-Type' => 'image/png']);
182
-		$expected->cacheFor(86400);
183
-		$this->assertEquals($expected, $this->iconController->getTouchIcon());
184
-	}
27
+    private IRequest&MockObject $request;
28
+    private ThemingDefaults&MockObject $themingDefaults;
29
+    private ITimeFactory&MockObject $timeFactory;
30
+    private IconBuilder&MockObject $iconBuilder;
31
+    private FileAccessHelper&MockObject $fileAccessHelper;
32
+    private IAppManager&MockObject $appManager;
33
+    private ImageManager&MockObject $imageManager;
34
+    private IconController $iconController;
35
+
36
+    protected function setUp(): void {
37
+        $this->request = $this->createMock(IRequest::class);
38
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
39
+        $this->iconBuilder = $this->createMock(IconBuilder::class);
40
+        $this->imageManager = $this->createMock(ImageManager::class);
41
+        $this->fileAccessHelper = $this->createMock(FileAccessHelper::class);
42
+        $this->appManager = $this->createMock(IAppManager::class);
43
+
44
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
45
+        $this->timeFactory->expects($this->any())
46
+            ->method('getTime')
47
+            ->willReturn(123);
48
+
49
+        $this->overwriteService(ITimeFactory::class, $this->timeFactory);
50
+
51
+        $this->iconController = new IconController(
52
+            'theming',
53
+            $this->request,
54
+            $this->themingDefaults,
55
+            $this->iconBuilder,
56
+            $this->imageManager,
57
+            $this->fileAccessHelper,
58
+            $this->appManager,
59
+        );
60
+
61
+        parent::setUp();
62
+    }
63
+
64
+    private function iconFileMock($filename, $data) {
65
+        $icon = $this->getMockBuilder('OCP\Files\File')->getMock();
66
+        $icon->expects($this->any())->method('getContent')->willReturn($data);
67
+        $icon->expects($this->any())->method('getMimeType')->willReturn('image type');
68
+        $icon->expects($this->any())->method('getEtag')->willReturn('my etag');
69
+        $icon->expects($this->any())->method('getName')->willReturn('my name');
70
+        $icon->expects($this->any())->method('getMTime')->willReturn(42);
71
+        $icon->method('getName')->willReturn($filename);
72
+        return new SimpleFile($icon);
73
+    }
74
+
75
+    public function testGetThemedIcon(): void {
76
+        $file = $this->iconFileMock('icon-core-filetypes_folder.svg', 'filecontent');
77
+        $this->imageManager->expects($this->once())
78
+            ->method('getCachedImage')
79
+            ->with('icon-core-filetypes_folder.svg')
80
+            ->willReturn($file);
81
+        $expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']);
82
+        $expected->cacheFor(86400, false, true);
83
+        $this->assertEquals($expected, $this->iconController->getThemedIcon('core', 'filetypes/folder.svg'));
84
+    }
85
+
86
+    public function testGetFaviconDefault(): void {
87
+        if (!extension_loaded('imagick')) {
88
+            $this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
89
+        }
90
+        $checkImagick = new \Imagick();
91
+        if (count($checkImagick->queryFormats('SVG')) < 1) {
92
+            $this->markTestSkipped('No SVG provider present.');
93
+        }
94
+        $file = $this->iconFileMock('filename', 'filecontent');
95
+        $this->imageManager->expects($this->once())
96
+            ->method('getImage', false)
97
+            ->with('favicon')
98
+            ->willThrowException(new NotFoundException());
99
+        $this->imageManager->expects($this->any())
100
+            ->method('shouldReplaceIcons')
101
+            ->willReturn(true);
102
+        $this->imageManager->expects($this->once())
103
+            ->method('getCachedImage')
104
+            ->willThrowException(new NotFoundException());
105
+        $this->iconBuilder->expects($this->once())
106
+            ->method('getFavicon')
107
+            ->with('core')
108
+            ->willReturn('filecontent');
109
+        $this->imageManager->expects($this->once())
110
+            ->method('setCachedImage')
111
+            ->willReturn($file);
112
+
113
+        $expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
114
+        $expected->cacheFor(86400);
115
+        $this->assertEquals($expected, $this->iconController->getFavicon());
116
+    }
117
+
118
+    public function testGetFaviconFail(): void {
119
+        $this->imageManager->expects($this->once())
120
+            ->method('getImage')
121
+            ->with('favicon', false)
122
+            ->willThrowException(new NotFoundException());
123
+        $this->imageManager->expects($this->any())
124
+            ->method('shouldReplaceIcons')
125
+            ->willReturn(false);
126
+        $fallbackLogo = \OC::$SERVERROOT . '/core/img/favicon.png';
127
+        $this->fileAccessHelper->expects($this->once())
128
+            ->method('file_get_contents')
129
+            ->with($fallbackLogo)
130
+            ->willReturn(file_get_contents($fallbackLogo));
131
+        $expected = new DataDisplayResponse(file_get_contents($fallbackLogo), Http::STATUS_OK, ['Content-Type' => 'image/x-icon']);
132
+        $expected->cacheFor(86400);
133
+        $this->assertEquals($expected, $this->iconController->getFavicon());
134
+    }
135
+
136
+    public function testGetTouchIconDefault(): void {
137
+        if (!extension_loaded('imagick')) {
138
+            $this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
139
+        }
140
+        $checkImagick = new \Imagick();
141
+        if (count($checkImagick->queryFormats('SVG')) < 1) {
142
+            $this->markTestSkipped('No SVG provider present.');
143
+        }
144
+
145
+        $this->imageManager->expects($this->once())
146
+            ->method('getImage')
147
+            ->willThrowException(new NotFoundException());
148
+        $this->imageManager->expects($this->any())
149
+            ->method('shouldReplaceIcons')
150
+            ->willReturn(true);
151
+        $this->iconBuilder->expects($this->once())
152
+            ->method('getTouchIcon')
153
+            ->with('core')
154
+            ->willReturn('filecontent');
155
+        $file = $this->iconFileMock('filename', 'filecontent');
156
+        $this->imageManager->expects($this->once())
157
+            ->method('getCachedImage')
158
+            ->willThrowException(new NotFoundException());
159
+        $this->imageManager->expects($this->once())
160
+            ->method('setCachedImage')
161
+            ->willReturn($file);
162
+
163
+        $expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/png']);
164
+        $expected->cacheFor(86400);
165
+        $this->assertEquals($expected, $this->iconController->getTouchIcon());
166
+    }
167
+
168
+    public function testGetTouchIconFail(): void {
169
+        $this->imageManager->expects($this->once())
170
+            ->method('getImage')
171
+            ->with('favicon')
172
+            ->willThrowException(new NotFoundException());
173
+        $this->imageManager->expects($this->any())
174
+            ->method('shouldReplaceIcons')
175
+            ->willReturn(false);
176
+        $fallbackLogo = \OC::$SERVERROOT . '/core/img/favicon-touch.png';
177
+        $this->fileAccessHelper->expects($this->once())
178
+            ->method('file_get_contents')
179
+            ->with($fallbackLogo)
180
+            ->willReturn(file_get_contents($fallbackLogo));
181
+        $expected = new DataDisplayResponse(file_get_contents($fallbackLogo), Http::STATUS_OK, ['Content-Type' => 'image/png']);
182
+        $expected->cacheFor(86400);
183
+        $this->assertEquals($expected, $this->iconController->getTouchIcon());
184
+    }
185 185
 }
Please login to merge, or discard this patch.
apps/theming/tests/Settings/PersonalTest.php 1 patch
Indentation   +200 added lines, -200 removed lines patch added patch discarded remove patch
@@ -33,204 +33,204 @@
 block discarded – undo
33 33
 use Test\TestCase;
34 34
 
35 35
 class PersonalTest extends TestCase {
36
-	private IConfig&MockObject $config;
37
-	private ThemesService&MockObject $themesService;
38
-	private IInitialState&MockObject $initialStateService;
39
-	private ThemingDefaults&MockObject $themingDefaults;
40
-	private INavigationManager&MockObject $navigationManager;
41
-	private Personal $admin;
42
-
43
-	/** @var ITheme[] */
44
-	private array $themes;
45
-
46
-	protected function setUp(): void {
47
-		parent::setUp();
48
-		$this->config = $this->createMock(IConfig::class);
49
-		$this->themesService = $this->createMock(ThemesService::class);
50
-		$this->initialStateService = $this->createMock(IInitialState::class);
51
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
52
-		$this->navigationManager = $this->createMock(INavigationManager::class);
53
-
54
-		$this->initThemes();
55
-
56
-		$this->themesService
57
-			->expects($this->any())
58
-			->method('getThemes')
59
-			->willReturn($this->themes);
60
-
61
-		$this->admin = new Personal(
62
-			Application::APP_ID,
63
-			'admin',
64
-			$this->config,
65
-			$this->themesService,
66
-			$this->initialStateService,
67
-			$this->themingDefaults,
68
-			$this->navigationManager,
69
-		);
70
-	}
71
-
72
-	public function dataTestGetForm(): array {
73
-		return [
74
-			['', [
75
-				$this->formatThemeForm('default'),
76
-				$this->formatThemeForm('light'),
77
-				$this->formatThemeForm('dark'),
78
-				$this->formatThemeForm('light-highcontrast'),
79
-				$this->formatThemeForm('dark-highcontrast'),
80
-				$this->formatThemeForm('opendyslexic'),
81
-			]],
82
-			['dark', [
83
-				$this->formatThemeForm('dark'),
84
-				$this->formatThemeForm('opendyslexic'),
85
-			]],
86
-		];
87
-	}
88
-
89
-	/**
90
-	 * @param string[] $enabledThemes
91
-	 */
92
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetForm')]
93
-	public function testGetForm(string $enforcedTheme, array $themesState): void {
94
-		$this->config->expects($this->once())
95
-			->method('getSystemValueString')
96
-			->with('enforce_theme', '')
97
-			->willReturn($enforcedTheme);
98
-
99
-		$this->config->expects($this->any())
100
-			->method('getUserValue')
101
-			->willReturnMap([
102
-				['admin', 'core', 'apporder', '[]', '[]'],
103
-				['admin', 'theming', 'background_image', BackgroundService::BACKGROUND_DEFAULT],
104
-			]);
105
-
106
-		$this->navigationManager->expects($this->once())
107
-			->method('getDefaultEntryIdForUser')
108
-			->willReturn('forced_id');
109
-
110
-		$this->initialStateService->expects($this->exactly(8))
111
-			->method('provideInitialState')
112
-			->willReturnMap([
113
-				['shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS],
114
-				['themingDefaults'],
115
-				['enableBlurFilter', ''],
116
-				['userBackgroundImage'],
117
-				['themes', $themesState],
118
-				['enforceTheme', $enforcedTheme],
119
-				['isUserThemingDisabled', false],
120
-				['navigationBar', ['userAppOrder' => [], 'enforcedDefaultApp' => 'forced_id']],
121
-			]);
122
-
123
-		$expected = new TemplateResponse('theming', 'settings-personal');
124
-		$this->assertEquals($expected, $this->admin->getForm());
125
-	}
126
-
127
-	public function testGetSection(): void {
128
-		$this->assertSame('theming', $this->admin->getSection());
129
-	}
130
-
131
-	public function testGetPriority(): void {
132
-		$this->assertSame(40, $this->admin->getPriority());
133
-	}
134
-
135
-	private function initThemes() {
136
-		$util = $this->createMock(Util::class);
137
-		$themingDefaults = $this->createMock(ThemingDefaults::class);
138
-		$userSession = $this->createMock(IUserSession::class);
139
-		$urlGenerator = $this->createMock(IURLGenerator::class);
140
-		$imageManager = $this->createMock(ImageManager::class);
141
-		$config = $this->createMock(IConfig::class);
142
-		$l10n = $this->createMock(IL10N::class);
143
-		$appManager = $this->createMock(IAppManager::class);
144
-
145
-		$themingDefaults->expects($this->any())
146
-			->method('getColorPrimary')
147
-			->willReturn('#0082c9');
148
-
149
-		$themingDefaults->expects($this->any())
150
-			->method('getDefaultColorPrimary')
151
-			->willReturn('#0082c9');
152
-
153
-		$this->themes = [
154
-			'default' => new DefaultTheme(
155
-				$util,
156
-				$themingDefaults,
157
-				$userSession,
158
-				$urlGenerator,
159
-				$imageManager,
160
-				$config,
161
-				$l10n,
162
-				$appManager,
163
-				null,
164
-			),
165
-			'light' => new LightTheme(
166
-				$util,
167
-				$themingDefaults,
168
-				$userSession,
169
-				$urlGenerator,
170
-				$imageManager,
171
-				$config,
172
-				$l10n,
173
-				$appManager,
174
-				null,
175
-			),
176
-			'dark' => new DarkTheme(
177
-				$util,
178
-				$themingDefaults,
179
-				$userSession,
180
-				$urlGenerator,
181
-				$imageManager,
182
-				$config,
183
-				$l10n,
184
-				$appManager,
185
-				null,
186
-			),
187
-			'light-highcontrast' => new HighContrastTheme(
188
-				$util,
189
-				$themingDefaults,
190
-				$userSession,
191
-				$urlGenerator,
192
-				$imageManager,
193
-				$config,
194
-				$l10n,
195
-				$appManager,
196
-				null,
197
-			),
198
-			'dark-highcontrast' => new DarkHighContrastTheme(
199
-				$util,
200
-				$themingDefaults,
201
-				$userSession,
202
-				$urlGenerator,
203
-				$imageManager,
204
-				$config,
205
-				$l10n,
206
-				$appManager,
207
-				null,
208
-			),
209
-			'opendyslexic' => new DyslexiaFont(
210
-				$util,
211
-				$themingDefaults,
212
-				$userSession,
213
-				$urlGenerator,
214
-				$imageManager,
215
-				$config,
216
-				$l10n,
217
-				$appManager,
218
-				null,
219
-			),
220
-		];
221
-	}
222
-
223
-	private function formatThemeForm(string $themeId): array {
224
-		$this->initThemes();
225
-
226
-		$theme = $this->themes[$themeId];
227
-		return [
228
-			'id' => $theme->getId(),
229
-			'type' => $theme->getType(),
230
-			'title' => $theme->getTitle(),
231
-			'enableLabel' => $theme->getEnableLabel(),
232
-			'description' => $theme->getDescription(),
233
-			'enabled' => false,
234
-		];
235
-	}
36
+    private IConfig&MockObject $config;
37
+    private ThemesService&MockObject $themesService;
38
+    private IInitialState&MockObject $initialStateService;
39
+    private ThemingDefaults&MockObject $themingDefaults;
40
+    private INavigationManager&MockObject $navigationManager;
41
+    private Personal $admin;
42
+
43
+    /** @var ITheme[] */
44
+    private array $themes;
45
+
46
+    protected function setUp(): void {
47
+        parent::setUp();
48
+        $this->config = $this->createMock(IConfig::class);
49
+        $this->themesService = $this->createMock(ThemesService::class);
50
+        $this->initialStateService = $this->createMock(IInitialState::class);
51
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
52
+        $this->navigationManager = $this->createMock(INavigationManager::class);
53
+
54
+        $this->initThemes();
55
+
56
+        $this->themesService
57
+            ->expects($this->any())
58
+            ->method('getThemes')
59
+            ->willReturn($this->themes);
60
+
61
+        $this->admin = new Personal(
62
+            Application::APP_ID,
63
+            'admin',
64
+            $this->config,
65
+            $this->themesService,
66
+            $this->initialStateService,
67
+            $this->themingDefaults,
68
+            $this->navigationManager,
69
+        );
70
+    }
71
+
72
+    public function dataTestGetForm(): array {
73
+        return [
74
+            ['', [
75
+                $this->formatThemeForm('default'),
76
+                $this->formatThemeForm('light'),
77
+                $this->formatThemeForm('dark'),
78
+                $this->formatThemeForm('light-highcontrast'),
79
+                $this->formatThemeForm('dark-highcontrast'),
80
+                $this->formatThemeForm('opendyslexic'),
81
+            ]],
82
+            ['dark', [
83
+                $this->formatThemeForm('dark'),
84
+                $this->formatThemeForm('opendyslexic'),
85
+            ]],
86
+        ];
87
+    }
88
+
89
+    /**
90
+     * @param string[] $enabledThemes
91
+     */
92
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetForm')]
93
+    public function testGetForm(string $enforcedTheme, array $themesState): void {
94
+        $this->config->expects($this->once())
95
+            ->method('getSystemValueString')
96
+            ->with('enforce_theme', '')
97
+            ->willReturn($enforcedTheme);
98
+
99
+        $this->config->expects($this->any())
100
+            ->method('getUserValue')
101
+            ->willReturnMap([
102
+                ['admin', 'core', 'apporder', '[]', '[]'],
103
+                ['admin', 'theming', 'background_image', BackgroundService::BACKGROUND_DEFAULT],
104
+            ]);
105
+
106
+        $this->navigationManager->expects($this->once())
107
+            ->method('getDefaultEntryIdForUser')
108
+            ->willReturn('forced_id');
109
+
110
+        $this->initialStateService->expects($this->exactly(8))
111
+            ->method('provideInitialState')
112
+            ->willReturnMap([
113
+                ['shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS],
114
+                ['themingDefaults'],
115
+                ['enableBlurFilter', ''],
116
+                ['userBackgroundImage'],
117
+                ['themes', $themesState],
118
+                ['enforceTheme', $enforcedTheme],
119
+                ['isUserThemingDisabled', false],
120
+                ['navigationBar', ['userAppOrder' => [], 'enforcedDefaultApp' => 'forced_id']],
121
+            ]);
122
+
123
+        $expected = new TemplateResponse('theming', 'settings-personal');
124
+        $this->assertEquals($expected, $this->admin->getForm());
125
+    }
126
+
127
+    public function testGetSection(): void {
128
+        $this->assertSame('theming', $this->admin->getSection());
129
+    }
130
+
131
+    public function testGetPriority(): void {
132
+        $this->assertSame(40, $this->admin->getPriority());
133
+    }
134
+
135
+    private function initThemes() {
136
+        $util = $this->createMock(Util::class);
137
+        $themingDefaults = $this->createMock(ThemingDefaults::class);
138
+        $userSession = $this->createMock(IUserSession::class);
139
+        $urlGenerator = $this->createMock(IURLGenerator::class);
140
+        $imageManager = $this->createMock(ImageManager::class);
141
+        $config = $this->createMock(IConfig::class);
142
+        $l10n = $this->createMock(IL10N::class);
143
+        $appManager = $this->createMock(IAppManager::class);
144
+
145
+        $themingDefaults->expects($this->any())
146
+            ->method('getColorPrimary')
147
+            ->willReturn('#0082c9');
148
+
149
+        $themingDefaults->expects($this->any())
150
+            ->method('getDefaultColorPrimary')
151
+            ->willReturn('#0082c9');
152
+
153
+        $this->themes = [
154
+            'default' => new DefaultTheme(
155
+                $util,
156
+                $themingDefaults,
157
+                $userSession,
158
+                $urlGenerator,
159
+                $imageManager,
160
+                $config,
161
+                $l10n,
162
+                $appManager,
163
+                null,
164
+            ),
165
+            'light' => new LightTheme(
166
+                $util,
167
+                $themingDefaults,
168
+                $userSession,
169
+                $urlGenerator,
170
+                $imageManager,
171
+                $config,
172
+                $l10n,
173
+                $appManager,
174
+                null,
175
+            ),
176
+            'dark' => new DarkTheme(
177
+                $util,
178
+                $themingDefaults,
179
+                $userSession,
180
+                $urlGenerator,
181
+                $imageManager,
182
+                $config,
183
+                $l10n,
184
+                $appManager,
185
+                null,
186
+            ),
187
+            'light-highcontrast' => new HighContrastTheme(
188
+                $util,
189
+                $themingDefaults,
190
+                $userSession,
191
+                $urlGenerator,
192
+                $imageManager,
193
+                $config,
194
+                $l10n,
195
+                $appManager,
196
+                null,
197
+            ),
198
+            'dark-highcontrast' => new DarkHighContrastTheme(
199
+                $util,
200
+                $themingDefaults,
201
+                $userSession,
202
+                $urlGenerator,
203
+                $imageManager,
204
+                $config,
205
+                $l10n,
206
+                $appManager,
207
+                null,
208
+            ),
209
+            'opendyslexic' => new DyslexiaFont(
210
+                $util,
211
+                $themingDefaults,
212
+                $userSession,
213
+                $urlGenerator,
214
+                $imageManager,
215
+                $config,
216
+                $l10n,
217
+                $appManager,
218
+                null,
219
+            ),
220
+        ];
221
+    }
222
+
223
+    private function formatThemeForm(string $themeId): array {
224
+        $this->initThemes();
225
+
226
+        $theme = $this->themes[$themeId];
227
+        return [
228
+            'id' => $theme->getId(),
229
+            'type' => $theme->getType(),
230
+            'title' => $theme->getTitle(),
231
+            'enableLabel' => $theme->getEnableLabel(),
232
+            'description' => $theme->getDescription(),
233
+            'enabled' => false,
234
+        ];
235
+    }
236 236
 }
Please login to merge, or discard this patch.
apps/theming/tests/ImageManagerTest.php 1 patch
Indentation   +358 added lines, -358 removed lines patch added patch discarded remove patch
@@ -22,362 +22,362 @@
 block discarded – undo
22 22
 use Test\TestCase;
23 23
 
24 24
 class ImageManagerTest extends TestCase {
25
-	protected IConfig&MockObject $config;
26
-	protected IAppData&MockObject $appData;
27
-	private IURLGenerator&MockObject $urlGenerator;
28
-	private ICacheFactory&MockObject $cacheFactory;
29
-	private LoggerInterface&MockObject $logger;
30
-	private ITempManager&MockObject $tempManager;
31
-	private ISimpleFolder&MockObject $rootFolder;
32
-	protected ImageManager $imageManager;
33
-
34
-	protected function setUp(): void {
35
-		parent::setUp();
36
-		$this->config = $this->createMock(IConfig::class);
37
-		$this->appData = $this->createMock(IAppData::class);
38
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
39
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
40
-		$this->logger = $this->createMock(LoggerInterface::class);
41
-		$this->tempManager = $this->createMock(ITempManager::class);
42
-		$this->rootFolder = $this->createMock(ISimpleFolder::class);
43
-		$backgroundService = $this->createMock(BackgroundService::class);
44
-		$this->imageManager = new ImageManager(
45
-			$this->config,
46
-			$this->appData,
47
-			$this->urlGenerator,
48
-			$this->cacheFactory,
49
-			$this->logger,
50
-			$this->tempManager,
51
-			$backgroundService,
52
-		);
53
-		$this->appData
54
-			->expects($this->any())
55
-			->method('getFolder')
56
-			->with('global')
57
-			->willReturn($this->rootFolder);
58
-	}
59
-
60
-	private function checkImagick() {
61
-		if (!extension_loaded('imagick')) {
62
-			$this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
63
-		}
64
-		$checkImagick = new \Imagick();
65
-		if (empty($checkImagick->queryFormats('SVG'))) {
66
-			$this->markTestSkipped('No SVG provider present.');
67
-		}
68
-		if (empty($checkImagick->queryFormats('PNG'))) {
69
-			$this->markTestSkipped('No PNG provider present.');
70
-		}
71
-	}
72
-
73
-	public function mockGetImage($key, $file) {
74
-		/** @var MockObject $folder */
75
-		$folder = $this->createMock(ISimpleFolder::class);
76
-		if ($file === null) {
77
-			$folder->expects($this->once())
78
-				->method('getFile')
79
-				->with('logo')
80
-				->willThrowException(new NotFoundException());
81
-		} else {
82
-			$file->expects($this->once())
83
-				->method('getContent')
84
-				->willReturn(file_get_contents(__DIR__ . '/../../../tests/data/testimage.png'));
85
-			$folder->expects($this->exactly(2))
86
-				->method('fileExists')
87
-				->willReturnMap([
88
-					['logo', true],
89
-					['logo.png', false],
90
-				]);
91
-			$folder->expects($this->once())
92
-				->method('getFile')
93
-				->with('logo')
94
-				->willReturn($file);
95
-			$newFile = $this->createMock(ISimpleFile::class);
96
-			$folder->expects($this->once())
97
-				->method('newFile')
98
-				->with('logo.png')
99
-				->willReturn($newFile);
100
-			$newFile->expects($this->once())
101
-				->method('putContent');
102
-			$this->rootFolder->expects($this->once())
103
-				->method('getFolder')
104
-				->with('images')
105
-				->willReturn($folder);
106
-		}
107
-	}
108
-
109
-	public function testGetImageUrl(): void {
110
-		$this->checkImagick();
111
-		$this->config->expects($this->exactly(2))
112
-			->method('getAppValue')
113
-			->willReturnMap([
114
-				['theming', 'cachebuster', '0', '0'],
115
-				['theming', 'logoMime', '', '0'],
116
-			]);
117
-		$this->urlGenerator->expects($this->once())
118
-			->method('linkToRoute')
119
-			->willReturn('url-to-image');
120
-		$this->assertEquals('url-to-image?v=0', $this->imageManager->getImageUrl('logo', false));
121
-	}
122
-
123
-	public function testGetImageUrlDefault(): void {
124
-		$this->config->expects($this->exactly(2))
125
-			->method('getAppValue')
126
-			->willReturnMap([
127
-				['theming', 'cachebuster', '0', '0'],
128
-				['theming', 'logoMime', '', ''],
129
-			]);
130
-		$this->urlGenerator->expects($this->once())
131
-			->method('imagePath')
132
-			->with('core', 'logo/logo.png')
133
-			->willReturn('logo/logo.png');
134
-		$this->assertEquals('logo/logo.png?v=0', $this->imageManager->getImageUrl('logo'));
135
-	}
136
-
137
-	public function testGetImageUrlAbsolute(): void {
138
-		$this->checkImagick();
139
-		$this->config->expects($this->exactly(2))
140
-			->method('getAppValue')
141
-			->willReturnMap([
142
-				['theming', 'cachebuster', '0', '0'],
143
-				['theming', 'logoMime', '', ''],
144
-			]);
145
-		$this->urlGenerator->expects($this->any())
146
-			->method('getAbsoluteUrl')
147
-			->willReturn('url-to-image-absolute?v=0');
148
-		$this->assertEquals('url-to-image-absolute?v=0', $this->imageManager->getImageUrlAbsolute('logo', false));
149
-	}
150
-
151
-	public function testGetImage(): void {
152
-		$this->checkImagick();
153
-		$this->config->expects($this->once())
154
-			->method('getAppValue')->with('theming', 'logoMime', false)
155
-			->willReturn('png');
156
-		$file = $this->createMock(ISimpleFile::class);
157
-		$this->mockGetImage('logo', $file);
158
-		$this->assertEquals($file, $this->imageManager->getImage('logo', false));
159
-	}
160
-
161
-
162
-	public function testGetImageUnset(): void {
163
-		$this->expectException(NotFoundException::class);
164
-
165
-		$this->config->expects($this->once())
166
-			->method('getAppValue')->with('theming', 'logoMime', false)
167
-			->willReturn(false);
168
-		$this->imageManager->getImage('logo');
169
-	}
170
-
171
-	public function testGetCacheFolder(): void {
172
-		$folder = $this->createMock(ISimpleFolder::class);
173
-		$this->config->expects($this->once())
174
-			->method('getAppValue')
175
-			->with('theming', 'cachebuster', '0')
176
-			->willReturn('0');
177
-		$this->rootFolder->expects($this->once())
178
-			->method('getFolder')
179
-			->with('0')
180
-			->willReturn($folder);
181
-		$this->assertEquals($folder, $this->imageManager->getCacheFolder());
182
-	}
183
-	public function testGetCacheFolderCreate(): void {
184
-		$folder = $this->createMock(ISimpleFolder::class);
185
-		$this->config->expects($this->exactly(2))
186
-			->method('getAppValue')
187
-			->with('theming', 'cachebuster', '0')
188
-			->willReturn('0');
189
-		$this->rootFolder->expects($this->exactly(2))
190
-			->method('getFolder')
191
-			->with('0')
192
-			->willReturnOnConsecutiveCalls(
193
-				$this->throwException(new NotFoundException()),
194
-				$folder,
195
-			);
196
-		$this->rootFolder->expects($this->once())
197
-			->method('newFolder')
198
-			->with('0')
199
-			->willReturn($folder);
200
-		$this->rootFolder->expects($this->once())
201
-			->method('getDirectoryListing')
202
-			->willReturn([]);
203
-		$this->assertEquals($folder, $this->imageManager->getCacheFolder());
204
-	}
205
-
206
-	public function testGetCachedImage(): void {
207
-		$expected = $this->createMock(ISimpleFile::class);
208
-		$folder = $this->setupCacheFolder();
209
-		$folder->expects($this->once())
210
-			->method('getFile')
211
-			->with('filename')
212
-			->willReturn($expected);
213
-		$this->assertEquals($expected, $this->imageManager->getCachedImage('filename'));
214
-	}
215
-
216
-
217
-	public function testGetCachedImageNotFound(): void {
218
-		$this->expectException(NotFoundException::class);
219
-
220
-		$folder = $this->setupCacheFolder();
221
-		$folder->expects($this->once())
222
-			->method('getFile')
223
-			->with('filename')
224
-			->willThrowException(new NotFoundException());
225
-		$image = $this->imageManager->getCachedImage('filename');
226
-	}
227
-
228
-	public function testSetCachedImage(): void {
229
-		$folder = $this->setupCacheFolder();
230
-		$file = $this->createMock(ISimpleFile::class);
231
-		$folder->expects($this->once())
232
-			->method('fileExists')
233
-			->with('filename')
234
-			->willReturn(true);
235
-		$folder->expects($this->once())
236
-			->method('getFile')
237
-			->with('filename')
238
-			->willReturn($file);
239
-		$file->expects($this->once())
240
-			->method('putContent')
241
-			->with('filecontent');
242
-		$this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent'));
243
-	}
244
-
245
-	public function testSetCachedImageCreate(): void {
246
-		$folder = $this->setupCacheFolder();
247
-		$file = $this->createMock(ISimpleFile::class);
248
-		$folder->expects($this->once())
249
-			->method('fileExists')
250
-			->with('filename')
251
-			->willReturn(false);
252
-		$folder->expects($this->once())
253
-			->method('newFile')
254
-			->with('filename')
255
-			->willReturn($file);
256
-		$file->expects($this->once())
257
-			->method('putContent')
258
-			->with('filecontent');
259
-		$this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent'));
260
-	}
261
-
262
-	private function setupCacheFolder() {
263
-		$folder = $this->createMock(ISimpleFolder::class);
264
-		$this->config->expects($this->once())
265
-			->method('getAppValue')
266
-			->with('theming', 'cachebuster', '0')
267
-			->willReturn('0');
268
-		$this->rootFolder->expects($this->once())
269
-			->method('getFolder')
270
-			->with('0')
271
-			->willReturn($folder);
272
-		return $folder;
273
-	}
274
-
275
-	public function testCleanup(): void {
276
-		$folders = [
277
-			$this->createMock(ISimpleFolder::class),
278
-			$this->createMock(ISimpleFolder::class),
279
-			$this->createMock(ISimpleFolder::class)
280
-		];
281
-		foreach ($folders as $index => $folder) {
282
-			$folder->expects($this->any())
283
-				->method('getName')
284
-				->willReturn("$index");
285
-		}
286
-		$folders[0]->expects($this->once())->method('delete');
287
-		$folders[1]->expects($this->once())->method('delete');
288
-		$folders[2]->expects($this->never())->method('delete');
289
-		$this->config->expects($this->once())
290
-			->method('getAppValue')
291
-			->with('theming', 'cachebuster', '0')
292
-			->willReturn('2');
293
-		$this->rootFolder->expects($this->once())
294
-			->method('getDirectoryListing')
295
-			->willReturn($folders);
296
-		$this->rootFolder->expects($this->once())
297
-			->method('getFolder')
298
-			->with('2')
299
-			->willReturn($folders[2]);
300
-		$this->imageManager->cleanup();
301
-	}
302
-
303
-
304
-	public static function dataUpdateImage(): array {
305
-		return [
306
-			['background', __DIR__ . '/../../../tests/data/testimage.png', true, false],
307
-			['background', __DIR__ . '/../../../tests/data/testimage.png', false, false],
308
-			['background', __DIR__ . '/../../../tests/data/testimage.jpg', true, false],
309
-			['background', __DIR__ . '/../../../tests/data/testimage.webp', true, false],
310
-			['background', __DIR__ . '/../../../tests/data/testimage-large.jpg', true, true],
311
-			['background', __DIR__ . '/../../../tests/data/testimage-wide.png', true, true],
312
-			['logo', __DIR__ . '/../../../tests/data/testimagelarge.svg', true, false],
313
-		];
314
-	}
315
-
316
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImage')]
317
-	public function testUpdateImage(string $key, string $tmpFile, bool $folderExists, bool $shouldConvert): void {
318
-		$file = $this->createMock(ISimpleFile::class);
319
-		$folder = $this->createMock(ISimpleFolder::class);
320
-		$oldFile = $this->createMock(ISimpleFile::class);
321
-		$folder->expects($this->any())
322
-			->method('getFile')
323
-			->willReturn($oldFile);
324
-
325
-		if ($folderExists) {
326
-			$this->rootFolder
327
-				->expects($this->any())
328
-				->method('getFolder')
329
-				->with('images')
330
-				->willReturn($folder);
331
-		} else {
332
-			$this->rootFolder
333
-				->expects($this->any())
334
-				->method('getFolder')
335
-				->with('images')
336
-				->willThrowException(new NotFoundException());
337
-			$this->rootFolder
338
-				->expects($this->any())
339
-				->method('newFolder')
340
-				->with('images')
341
-				->willReturn($folder);
342
-		}
343
-
344
-		$folder->expects($this->once())
345
-			->method('newFile')
346
-			->with($key)
347
-			->willReturn($file);
348
-
349
-		if ($shouldConvert) {
350
-			$this->tempManager->expects($this->once())
351
-				->method('getTemporaryFile')
352
-				->willReturn('/tmp/randomtempfile-theming');
353
-		}
354
-
355
-		$this->imageManager->updateImage($key, $tmpFile);
356
-	}
357
-
358
-	public function testUnsupportedImageType(): void {
359
-		$this->expectException(\Exception::class);
360
-		$this->expectExceptionMessage('Unsupported image type: text/plain');
361
-
362
-		$file = $this->createMock(ISimpleFile::class);
363
-		$folder = $this->createMock(ISimpleFolder::class);
364
-		$oldFile = $this->createMock(ISimpleFile::class);
365
-
366
-		$folder->expects($this->any())
367
-			->method('getFile')
368
-			->willReturn($oldFile);
369
-
370
-		$this->rootFolder
371
-			->expects($this->any())
372
-			->method('getFolder')
373
-			->with('images')
374
-			->willReturn($folder);
375
-
376
-		$folder->expects($this->once())
377
-			->method('newFile')
378
-			->with('favicon')
379
-			->willReturn($file);
380
-
381
-		$this->imageManager->updateImage('favicon', __DIR__ . '/../../../tests/data/lorem.txt');
382
-	}
25
+    protected IConfig&MockObject $config;
26
+    protected IAppData&MockObject $appData;
27
+    private IURLGenerator&MockObject $urlGenerator;
28
+    private ICacheFactory&MockObject $cacheFactory;
29
+    private LoggerInterface&MockObject $logger;
30
+    private ITempManager&MockObject $tempManager;
31
+    private ISimpleFolder&MockObject $rootFolder;
32
+    protected ImageManager $imageManager;
33
+
34
+    protected function setUp(): void {
35
+        parent::setUp();
36
+        $this->config = $this->createMock(IConfig::class);
37
+        $this->appData = $this->createMock(IAppData::class);
38
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
39
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
40
+        $this->logger = $this->createMock(LoggerInterface::class);
41
+        $this->tempManager = $this->createMock(ITempManager::class);
42
+        $this->rootFolder = $this->createMock(ISimpleFolder::class);
43
+        $backgroundService = $this->createMock(BackgroundService::class);
44
+        $this->imageManager = new ImageManager(
45
+            $this->config,
46
+            $this->appData,
47
+            $this->urlGenerator,
48
+            $this->cacheFactory,
49
+            $this->logger,
50
+            $this->tempManager,
51
+            $backgroundService,
52
+        );
53
+        $this->appData
54
+            ->expects($this->any())
55
+            ->method('getFolder')
56
+            ->with('global')
57
+            ->willReturn($this->rootFolder);
58
+    }
59
+
60
+    private function checkImagick() {
61
+        if (!extension_loaded('imagick')) {
62
+            $this->markTestSkipped('Imagemagick is required for dynamic icon generation.');
63
+        }
64
+        $checkImagick = new \Imagick();
65
+        if (empty($checkImagick->queryFormats('SVG'))) {
66
+            $this->markTestSkipped('No SVG provider present.');
67
+        }
68
+        if (empty($checkImagick->queryFormats('PNG'))) {
69
+            $this->markTestSkipped('No PNG provider present.');
70
+        }
71
+    }
72
+
73
+    public function mockGetImage($key, $file) {
74
+        /** @var MockObject $folder */
75
+        $folder = $this->createMock(ISimpleFolder::class);
76
+        if ($file === null) {
77
+            $folder->expects($this->once())
78
+                ->method('getFile')
79
+                ->with('logo')
80
+                ->willThrowException(new NotFoundException());
81
+        } else {
82
+            $file->expects($this->once())
83
+                ->method('getContent')
84
+                ->willReturn(file_get_contents(__DIR__ . '/../../../tests/data/testimage.png'));
85
+            $folder->expects($this->exactly(2))
86
+                ->method('fileExists')
87
+                ->willReturnMap([
88
+                    ['logo', true],
89
+                    ['logo.png', false],
90
+                ]);
91
+            $folder->expects($this->once())
92
+                ->method('getFile')
93
+                ->with('logo')
94
+                ->willReturn($file);
95
+            $newFile = $this->createMock(ISimpleFile::class);
96
+            $folder->expects($this->once())
97
+                ->method('newFile')
98
+                ->with('logo.png')
99
+                ->willReturn($newFile);
100
+            $newFile->expects($this->once())
101
+                ->method('putContent');
102
+            $this->rootFolder->expects($this->once())
103
+                ->method('getFolder')
104
+                ->with('images')
105
+                ->willReturn($folder);
106
+        }
107
+    }
108
+
109
+    public function testGetImageUrl(): void {
110
+        $this->checkImagick();
111
+        $this->config->expects($this->exactly(2))
112
+            ->method('getAppValue')
113
+            ->willReturnMap([
114
+                ['theming', 'cachebuster', '0', '0'],
115
+                ['theming', 'logoMime', '', '0'],
116
+            ]);
117
+        $this->urlGenerator->expects($this->once())
118
+            ->method('linkToRoute')
119
+            ->willReturn('url-to-image');
120
+        $this->assertEquals('url-to-image?v=0', $this->imageManager->getImageUrl('logo', false));
121
+    }
122
+
123
+    public function testGetImageUrlDefault(): void {
124
+        $this->config->expects($this->exactly(2))
125
+            ->method('getAppValue')
126
+            ->willReturnMap([
127
+                ['theming', 'cachebuster', '0', '0'],
128
+                ['theming', 'logoMime', '', ''],
129
+            ]);
130
+        $this->urlGenerator->expects($this->once())
131
+            ->method('imagePath')
132
+            ->with('core', 'logo/logo.png')
133
+            ->willReturn('logo/logo.png');
134
+        $this->assertEquals('logo/logo.png?v=0', $this->imageManager->getImageUrl('logo'));
135
+    }
136
+
137
+    public function testGetImageUrlAbsolute(): void {
138
+        $this->checkImagick();
139
+        $this->config->expects($this->exactly(2))
140
+            ->method('getAppValue')
141
+            ->willReturnMap([
142
+                ['theming', 'cachebuster', '0', '0'],
143
+                ['theming', 'logoMime', '', ''],
144
+            ]);
145
+        $this->urlGenerator->expects($this->any())
146
+            ->method('getAbsoluteUrl')
147
+            ->willReturn('url-to-image-absolute?v=0');
148
+        $this->assertEquals('url-to-image-absolute?v=0', $this->imageManager->getImageUrlAbsolute('logo', false));
149
+    }
150
+
151
+    public function testGetImage(): void {
152
+        $this->checkImagick();
153
+        $this->config->expects($this->once())
154
+            ->method('getAppValue')->with('theming', 'logoMime', false)
155
+            ->willReturn('png');
156
+        $file = $this->createMock(ISimpleFile::class);
157
+        $this->mockGetImage('logo', $file);
158
+        $this->assertEquals($file, $this->imageManager->getImage('logo', false));
159
+    }
160
+
161
+
162
+    public function testGetImageUnset(): void {
163
+        $this->expectException(NotFoundException::class);
164
+
165
+        $this->config->expects($this->once())
166
+            ->method('getAppValue')->with('theming', 'logoMime', false)
167
+            ->willReturn(false);
168
+        $this->imageManager->getImage('logo');
169
+    }
170
+
171
+    public function testGetCacheFolder(): void {
172
+        $folder = $this->createMock(ISimpleFolder::class);
173
+        $this->config->expects($this->once())
174
+            ->method('getAppValue')
175
+            ->with('theming', 'cachebuster', '0')
176
+            ->willReturn('0');
177
+        $this->rootFolder->expects($this->once())
178
+            ->method('getFolder')
179
+            ->with('0')
180
+            ->willReturn($folder);
181
+        $this->assertEquals($folder, $this->imageManager->getCacheFolder());
182
+    }
183
+    public function testGetCacheFolderCreate(): void {
184
+        $folder = $this->createMock(ISimpleFolder::class);
185
+        $this->config->expects($this->exactly(2))
186
+            ->method('getAppValue')
187
+            ->with('theming', 'cachebuster', '0')
188
+            ->willReturn('0');
189
+        $this->rootFolder->expects($this->exactly(2))
190
+            ->method('getFolder')
191
+            ->with('0')
192
+            ->willReturnOnConsecutiveCalls(
193
+                $this->throwException(new NotFoundException()),
194
+                $folder,
195
+            );
196
+        $this->rootFolder->expects($this->once())
197
+            ->method('newFolder')
198
+            ->with('0')
199
+            ->willReturn($folder);
200
+        $this->rootFolder->expects($this->once())
201
+            ->method('getDirectoryListing')
202
+            ->willReturn([]);
203
+        $this->assertEquals($folder, $this->imageManager->getCacheFolder());
204
+    }
205
+
206
+    public function testGetCachedImage(): void {
207
+        $expected = $this->createMock(ISimpleFile::class);
208
+        $folder = $this->setupCacheFolder();
209
+        $folder->expects($this->once())
210
+            ->method('getFile')
211
+            ->with('filename')
212
+            ->willReturn($expected);
213
+        $this->assertEquals($expected, $this->imageManager->getCachedImage('filename'));
214
+    }
215
+
216
+
217
+    public function testGetCachedImageNotFound(): void {
218
+        $this->expectException(NotFoundException::class);
219
+
220
+        $folder = $this->setupCacheFolder();
221
+        $folder->expects($this->once())
222
+            ->method('getFile')
223
+            ->with('filename')
224
+            ->willThrowException(new NotFoundException());
225
+        $image = $this->imageManager->getCachedImage('filename');
226
+    }
227
+
228
+    public function testSetCachedImage(): void {
229
+        $folder = $this->setupCacheFolder();
230
+        $file = $this->createMock(ISimpleFile::class);
231
+        $folder->expects($this->once())
232
+            ->method('fileExists')
233
+            ->with('filename')
234
+            ->willReturn(true);
235
+        $folder->expects($this->once())
236
+            ->method('getFile')
237
+            ->with('filename')
238
+            ->willReturn($file);
239
+        $file->expects($this->once())
240
+            ->method('putContent')
241
+            ->with('filecontent');
242
+        $this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent'));
243
+    }
244
+
245
+    public function testSetCachedImageCreate(): void {
246
+        $folder = $this->setupCacheFolder();
247
+        $file = $this->createMock(ISimpleFile::class);
248
+        $folder->expects($this->once())
249
+            ->method('fileExists')
250
+            ->with('filename')
251
+            ->willReturn(false);
252
+        $folder->expects($this->once())
253
+            ->method('newFile')
254
+            ->with('filename')
255
+            ->willReturn($file);
256
+        $file->expects($this->once())
257
+            ->method('putContent')
258
+            ->with('filecontent');
259
+        $this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent'));
260
+    }
261
+
262
+    private function setupCacheFolder() {
263
+        $folder = $this->createMock(ISimpleFolder::class);
264
+        $this->config->expects($this->once())
265
+            ->method('getAppValue')
266
+            ->with('theming', 'cachebuster', '0')
267
+            ->willReturn('0');
268
+        $this->rootFolder->expects($this->once())
269
+            ->method('getFolder')
270
+            ->with('0')
271
+            ->willReturn($folder);
272
+        return $folder;
273
+    }
274
+
275
+    public function testCleanup(): void {
276
+        $folders = [
277
+            $this->createMock(ISimpleFolder::class),
278
+            $this->createMock(ISimpleFolder::class),
279
+            $this->createMock(ISimpleFolder::class)
280
+        ];
281
+        foreach ($folders as $index => $folder) {
282
+            $folder->expects($this->any())
283
+                ->method('getName')
284
+                ->willReturn("$index");
285
+        }
286
+        $folders[0]->expects($this->once())->method('delete');
287
+        $folders[1]->expects($this->once())->method('delete');
288
+        $folders[2]->expects($this->never())->method('delete');
289
+        $this->config->expects($this->once())
290
+            ->method('getAppValue')
291
+            ->with('theming', 'cachebuster', '0')
292
+            ->willReturn('2');
293
+        $this->rootFolder->expects($this->once())
294
+            ->method('getDirectoryListing')
295
+            ->willReturn($folders);
296
+        $this->rootFolder->expects($this->once())
297
+            ->method('getFolder')
298
+            ->with('2')
299
+            ->willReturn($folders[2]);
300
+        $this->imageManager->cleanup();
301
+    }
302
+
303
+
304
+    public static function dataUpdateImage(): array {
305
+        return [
306
+            ['background', __DIR__ . '/../../../tests/data/testimage.png', true, false],
307
+            ['background', __DIR__ . '/../../../tests/data/testimage.png', false, false],
308
+            ['background', __DIR__ . '/../../../tests/data/testimage.jpg', true, false],
309
+            ['background', __DIR__ . '/../../../tests/data/testimage.webp', true, false],
310
+            ['background', __DIR__ . '/../../../tests/data/testimage-large.jpg', true, true],
311
+            ['background', __DIR__ . '/../../../tests/data/testimage-wide.png', true, true],
312
+            ['logo', __DIR__ . '/../../../tests/data/testimagelarge.svg', true, false],
313
+        ];
314
+    }
315
+
316
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImage')]
317
+    public function testUpdateImage(string $key, string $tmpFile, bool $folderExists, bool $shouldConvert): void {
318
+        $file = $this->createMock(ISimpleFile::class);
319
+        $folder = $this->createMock(ISimpleFolder::class);
320
+        $oldFile = $this->createMock(ISimpleFile::class);
321
+        $folder->expects($this->any())
322
+            ->method('getFile')
323
+            ->willReturn($oldFile);
324
+
325
+        if ($folderExists) {
326
+            $this->rootFolder
327
+                ->expects($this->any())
328
+                ->method('getFolder')
329
+                ->with('images')
330
+                ->willReturn($folder);
331
+        } else {
332
+            $this->rootFolder
333
+                ->expects($this->any())
334
+                ->method('getFolder')
335
+                ->with('images')
336
+                ->willThrowException(new NotFoundException());
337
+            $this->rootFolder
338
+                ->expects($this->any())
339
+                ->method('newFolder')
340
+                ->with('images')
341
+                ->willReturn($folder);
342
+        }
343
+
344
+        $folder->expects($this->once())
345
+            ->method('newFile')
346
+            ->with($key)
347
+            ->willReturn($file);
348
+
349
+        if ($shouldConvert) {
350
+            $this->tempManager->expects($this->once())
351
+                ->method('getTemporaryFile')
352
+                ->willReturn('/tmp/randomtempfile-theming');
353
+        }
354
+
355
+        $this->imageManager->updateImage($key, $tmpFile);
356
+    }
357
+
358
+    public function testUnsupportedImageType(): void {
359
+        $this->expectException(\Exception::class);
360
+        $this->expectExceptionMessage('Unsupported image type: text/plain');
361
+
362
+        $file = $this->createMock(ISimpleFile::class);
363
+        $folder = $this->createMock(ISimpleFolder::class);
364
+        $oldFile = $this->createMock(ISimpleFile::class);
365
+
366
+        $folder->expects($this->any())
367
+            ->method('getFile')
368
+            ->willReturn($oldFile);
369
+
370
+        $this->rootFolder
371
+            ->expects($this->any())
372
+            ->method('getFolder')
373
+            ->with('images')
374
+            ->willReturn($folder);
375
+
376
+        $folder->expects($this->once())
377
+            ->method('newFile')
378
+            ->with('favicon')
379
+            ->willReturn($file);
380
+
381
+        $this->imageManager->updateImage('favicon', __DIR__ . '/../../../tests/data/lorem.txt');
382
+    }
383 383
 }
Please login to merge, or discard this patch.
apps/theming/tests/Service/ThemesServiceTest.php 1 patch
Indentation   +336 added lines, -336 removed lines patch added patch discarded remove patch
@@ -30,340 +30,340 @@
 block discarded – undo
30 30
 use Test\TestCase;
31 31
 
32 32
 class ThemesServiceTest extends TestCase {
33
-	private IUserSession&MockObject $userSession;
34
-	private IConfig&MockObject $config;
35
-	private LoggerInterface&MockObject $logger;
36
-
37
-	private ThemingDefaults&MockObject $themingDefaults;
38
-	private ThemesService $themesService;
39
-
40
-	/** @var ITheme[] */
41
-	private array $themes;
42
-
43
-	protected function setUp(): void {
44
-		$this->userSession = $this->createMock(IUserSession::class);
45
-		$this->config = $this->createMock(IConfig::class);
46
-		$this->logger = $this->createMock(LoggerInterface::class);
47
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
48
-
49
-		$this->themingDefaults->expects($this->any())
50
-			->method('getColorPrimary')
51
-			->willReturn('#0082c9');
52
-
53
-		$this->themingDefaults->expects($this->any())
54
-			->method('getDefaultColorPrimary')
55
-			->willReturn('#0082c9');
56
-
57
-		$this->initThemes();
58
-
59
-		$this->themesService = new ThemesService(
60
-			$this->userSession,
61
-			$this->config,
62
-			$this->logger,
63
-			...array_values($this->themes)
64
-		);
65
-
66
-		parent::setUp();
67
-	}
68
-
69
-	public function testGetThemes(): void {
70
-		$expected = [
71
-			'default',
72
-			'light',
73
-			'dark',
74
-			'light-highcontrast',
75
-			'dark-highcontrast',
76
-			'opendyslexic',
77
-		];
78
-		$this->assertEquals($expected, array_keys($this->themesService->getThemes()));
79
-	}
80
-
81
-	public function testGetThemesEnforced(): void {
82
-		$this->config->expects($this->once())
83
-			->method('getSystemValueString')
84
-			->with('enforce_theme', '')
85
-			->willReturn('dark');
86
-		$this->logger->expects($this->never())
87
-			->method('error');
88
-
89
-		$expected = [
90
-			'default',
91
-			'dark',
92
-		];
93
-
94
-		$this->assertEquals($expected, array_keys($this->themesService->getThemes()));
95
-	}
96
-
97
-	public function testGetThemesEnforcedInvalid(): void {
98
-		$this->config->expects($this->once())
99
-			->method('getSystemValueString')
100
-			->with('enforce_theme', '')
101
-			->willReturn('invalid');
102
-		$this->logger->expects($this->once())
103
-			->method('error')
104
-			->with('Enforced theme not found', ['theme' => 'invalid']);
105
-
106
-		$expected = [
107
-			'default',
108
-			'light',
109
-			'dark',
110
-			'light-highcontrast',
111
-			'dark-highcontrast',
112
-			'opendyslexic',
113
-		];
114
-
115
-		$this->assertEquals($expected, array_keys($this->themesService->getThemes()));
116
-	}
117
-
118
-	public static function dataTestEnableTheme(): array {
119
-		return [
120
-			['default', ['default'], ['default']],
121
-			['dark', ['default'], ['dark']],
122
-			['dark', ['dark'], ['dark']],
123
-			['opendyslexic', ['dark'], ['dark', 'opendyslexic']],
124
-			['dark', ['light-highcontrast', 'opendyslexic'], ['opendyslexic', 'dark']],
125
-		];
126
-	}
127
-
128
-	/**
129
-	 *
130
-	 * @param string[] $enabledThemes
131
-	 * @param string[] $expectedEnabled
132
-	 */
133
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestEnableTheme')]
134
-	public function testEnableTheme(string $toEnable, array $enabledThemes, array $expectedEnabled): void {
135
-		$user = $this->createMock(IUser::class);
136
-		$this->userSession->expects($this->any())
137
-			->method('getUser')
138
-			->willReturn($user);
139
-		$user->expects($this->any())
140
-			->method('getUID')
141
-			->willReturn('user');
142
-
143
-		$this->config->expects($this->once())
144
-			->method('getUserValue')
145
-			->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
146
-			->willReturn(json_encode($enabledThemes));
147
-
148
-		$this->assertEquals($expectedEnabled, $this->themesService->enableTheme($this->themes[$toEnable]));
149
-	}
150
-
151
-
152
-	public static function dataTestDisableTheme(): array {
153
-		return [
154
-			['dark', ['default'], ['default']],
155
-			['dark', ['dark'], []],
156
-			['opendyslexic', ['dark', 'opendyslexic'], ['dark'], ],
157
-			['light-highcontrast', ['opendyslexic'], ['opendyslexic']],
158
-		];
159
-	}
160
-
161
-	/**
162
-	 *
163
-	 * @param string[] $enabledThemes
164
-	 * @param string[] $expectedEnabled
165
-	 */
166
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestDisableTheme')]
167
-	public function testDisableTheme(string $toDisable, array $enabledThemes, array $expectedEnabled): void {
168
-		$user = $this->createMock(IUser::class);
169
-		$this->userSession->expects($this->any())
170
-			->method('getUser')
171
-			->willReturn($user);
172
-		$user->expects($this->any())
173
-			->method('getUID')
174
-			->willReturn('user');
175
-
176
-		$this->config->expects($this->once())
177
-			->method('getUserValue')
178
-			->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
179
-			->willReturn(json_encode($enabledThemes));
180
-
181
-
182
-		$this->assertEquals($expectedEnabled, $this->themesService->disableTheme($this->themes[$toDisable]));
183
-	}
184
-
185
-
186
-	public static function dataTestIsEnabled(): array {
187
-		return [
188
-			['dark', [], false],
189
-			['dark', ['dark'], true],
190
-			['opendyslexic', ['dark', 'opendyslexic'], true],
191
-			['light-highcontrast', ['opendyslexic'], false],
192
-		];
193
-	}
194
-
195
-	/**
196
-	 * @param string[] $enabledThemes
197
-	 */
198
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsEnabled')]
199
-	public function testIsEnabled(string $themeId, array $enabledThemes, bool $expected): void {
200
-		$user = $this->createMock(IUser::class);
201
-		$this->userSession->expects($this->any())
202
-			->method('getUser')
203
-			->willReturn($user);
204
-		$user->expects($this->any())
205
-			->method('getUID')
206
-			->willReturn('user');
207
-
208
-		$this->config->expects($this->once())
209
-			->method('getUserValue')
210
-			->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
211
-			->willReturn(json_encode($enabledThemes));
212
-
213
-
214
-		$this->assertEquals($expected, $this->themesService->isEnabled($this->themes[$themeId]));
215
-	}
216
-
217
-	public function testGetEnabledThemes(): void {
218
-		$user = $this->createMock(IUser::class);
219
-		$this->userSession->expects($this->any())
220
-			->method('getUser')
221
-			->willReturn($user);
222
-		$user->expects($this->any())
223
-			->method('getUID')
224
-			->willReturn('user');
225
-
226
-
227
-		$this->config->expects($this->once())
228
-			->method('getUserValue')
229
-			->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
230
-			->willReturn(json_encode(['default']));
231
-		$this->config->expects($this->once())
232
-			->method('getSystemValueString')
233
-			->with('enforce_theme', '')
234
-			->willReturn('');
235
-
236
-		$this->assertEquals(['default'], $this->themesService->getEnabledThemes());
237
-	}
238
-
239
-	public function testGetEnabledThemesEnforced(): void {
240
-		$user = $this->createMock(IUser::class);
241
-		$this->userSession->expects($this->any())
242
-			->method('getUser')
243
-			->willReturn($user);
244
-		$user->expects($this->any())
245
-			->method('getUID')
246
-			->willReturn('user');
247
-
248
-
249
-		$this->config->expects($this->once())
250
-			->method('getUserValue')
251
-			->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
252
-			->willReturn(json_encode([]));
253
-		$this->config->expects($this->once())
254
-			->method('getSystemValueString')
255
-			->with('enforce_theme', '')
256
-			->willReturn('light');
257
-
258
-		$this->assertEquals(['light'], $this->themesService->getEnabledThemes());
259
-	}
260
-
261
-
262
-	public static function dataTestSetEnabledThemes(): array {
263
-		return [
264
-			[[], []],
265
-			[['light'], ['light']],
266
-			[['dark'], ['dark']],
267
-			[['dark', 'dark', 'opendyslexic'], ['dark', 'opendyslexic']],
268
-		];
269
-	}
270
-
271
-	/**
272
-	 *
273
-	 * @param string[] $enabledThemes
274
-	 * @param string[] $expected
275
-	 */
276
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSetEnabledThemes')]
277
-	public function testSetEnabledThemes(array $enabledThemes, array $expected): void {
278
-		$user = $this->createMock(IUser::class);
279
-		$this->userSession->expects($this->any())
280
-			->method('getUser')
281
-			->willReturn($user);
282
-		$user->expects($this->any())
283
-			->method('getUID')
284
-			->willReturn('user');
285
-
286
-		$this->config->expects($this->once())
287
-			->method('setUserValue')
288
-			->with('user', Application::APP_ID, 'enabled-themes', json_encode($expected));
289
-
290
-		$this->invokePrivate($this->themesService, 'setEnabledThemes', [$enabledThemes]);
291
-	}
292
-
293
-	private function initThemes() {
294
-		$util = $this->createMock(Util::class);
295
-		$urlGenerator = $this->createMock(IURLGenerator::class);
296
-		$imageManager = $this->createMock(ImageManager::class);
297
-		$l10n = $this->createMock(IL10N::class);
298
-		$appManager = $this->createMock(IAppManager::class);
299
-
300
-		$this->themes = [
301
-			'default' => new DefaultTheme(
302
-				$util,
303
-				$this->themingDefaults,
304
-				$this->userSession,
305
-				$urlGenerator,
306
-				$imageManager,
307
-				$this->config,
308
-				$l10n,
309
-				$appManager,
310
-				null,
311
-			),
312
-			'light' => new LightTheme(
313
-				$util,
314
-				$this->themingDefaults,
315
-				$this->userSession,
316
-				$urlGenerator,
317
-				$imageManager,
318
-				$this->config,
319
-				$l10n,
320
-				$appManager,
321
-				null,
322
-			),
323
-			'dark' => new DarkTheme(
324
-				$util,
325
-				$this->themingDefaults,
326
-				$this->userSession,
327
-				$urlGenerator,
328
-				$imageManager,
329
-				$this->config,
330
-				$l10n,
331
-				$appManager,
332
-				null,
333
-			),
334
-			'light-highcontrast' => new HighContrastTheme(
335
-				$util,
336
-				$this->themingDefaults,
337
-				$this->userSession,
338
-				$urlGenerator,
339
-				$imageManager,
340
-				$this->config,
341
-				$l10n,
342
-				$appManager,
343
-				null,
344
-			),
345
-			'dark-highcontrast' => new DarkHighContrastTheme(
346
-				$util,
347
-				$this->themingDefaults,
348
-				$this->userSession,
349
-				$urlGenerator,
350
-				$imageManager,
351
-				$this->config,
352
-				$l10n,
353
-				$appManager,
354
-				null,
355
-			),
356
-			'opendyslexic' => new DyslexiaFont(
357
-				$util,
358
-				$this->themingDefaults,
359
-				$this->userSession,
360
-				$urlGenerator,
361
-				$imageManager,
362
-				$this->config,
363
-				$l10n,
364
-				$appManager,
365
-				null,
366
-			),
367
-		];
368
-	}
33
+    private IUserSession&MockObject $userSession;
34
+    private IConfig&MockObject $config;
35
+    private LoggerInterface&MockObject $logger;
36
+
37
+    private ThemingDefaults&MockObject $themingDefaults;
38
+    private ThemesService $themesService;
39
+
40
+    /** @var ITheme[] */
41
+    private array $themes;
42
+
43
+    protected function setUp(): void {
44
+        $this->userSession = $this->createMock(IUserSession::class);
45
+        $this->config = $this->createMock(IConfig::class);
46
+        $this->logger = $this->createMock(LoggerInterface::class);
47
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
48
+
49
+        $this->themingDefaults->expects($this->any())
50
+            ->method('getColorPrimary')
51
+            ->willReturn('#0082c9');
52
+
53
+        $this->themingDefaults->expects($this->any())
54
+            ->method('getDefaultColorPrimary')
55
+            ->willReturn('#0082c9');
56
+
57
+        $this->initThemes();
58
+
59
+        $this->themesService = new ThemesService(
60
+            $this->userSession,
61
+            $this->config,
62
+            $this->logger,
63
+            ...array_values($this->themes)
64
+        );
65
+
66
+        parent::setUp();
67
+    }
68
+
69
+    public function testGetThemes(): void {
70
+        $expected = [
71
+            'default',
72
+            'light',
73
+            'dark',
74
+            'light-highcontrast',
75
+            'dark-highcontrast',
76
+            'opendyslexic',
77
+        ];
78
+        $this->assertEquals($expected, array_keys($this->themesService->getThemes()));
79
+    }
80
+
81
+    public function testGetThemesEnforced(): void {
82
+        $this->config->expects($this->once())
83
+            ->method('getSystemValueString')
84
+            ->with('enforce_theme', '')
85
+            ->willReturn('dark');
86
+        $this->logger->expects($this->never())
87
+            ->method('error');
88
+
89
+        $expected = [
90
+            'default',
91
+            'dark',
92
+        ];
93
+
94
+        $this->assertEquals($expected, array_keys($this->themesService->getThemes()));
95
+    }
96
+
97
+    public function testGetThemesEnforcedInvalid(): void {
98
+        $this->config->expects($this->once())
99
+            ->method('getSystemValueString')
100
+            ->with('enforce_theme', '')
101
+            ->willReturn('invalid');
102
+        $this->logger->expects($this->once())
103
+            ->method('error')
104
+            ->with('Enforced theme not found', ['theme' => 'invalid']);
105
+
106
+        $expected = [
107
+            'default',
108
+            'light',
109
+            'dark',
110
+            'light-highcontrast',
111
+            'dark-highcontrast',
112
+            'opendyslexic',
113
+        ];
114
+
115
+        $this->assertEquals($expected, array_keys($this->themesService->getThemes()));
116
+    }
117
+
118
+    public static function dataTestEnableTheme(): array {
119
+        return [
120
+            ['default', ['default'], ['default']],
121
+            ['dark', ['default'], ['dark']],
122
+            ['dark', ['dark'], ['dark']],
123
+            ['opendyslexic', ['dark'], ['dark', 'opendyslexic']],
124
+            ['dark', ['light-highcontrast', 'opendyslexic'], ['opendyslexic', 'dark']],
125
+        ];
126
+    }
127
+
128
+    /**
129
+     *
130
+     * @param string[] $enabledThemes
131
+     * @param string[] $expectedEnabled
132
+     */
133
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestEnableTheme')]
134
+    public function testEnableTheme(string $toEnable, array $enabledThemes, array $expectedEnabled): void {
135
+        $user = $this->createMock(IUser::class);
136
+        $this->userSession->expects($this->any())
137
+            ->method('getUser')
138
+            ->willReturn($user);
139
+        $user->expects($this->any())
140
+            ->method('getUID')
141
+            ->willReturn('user');
142
+
143
+        $this->config->expects($this->once())
144
+            ->method('getUserValue')
145
+            ->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
146
+            ->willReturn(json_encode($enabledThemes));
147
+
148
+        $this->assertEquals($expectedEnabled, $this->themesService->enableTheme($this->themes[$toEnable]));
149
+    }
150
+
151
+
152
+    public static function dataTestDisableTheme(): array {
153
+        return [
154
+            ['dark', ['default'], ['default']],
155
+            ['dark', ['dark'], []],
156
+            ['opendyslexic', ['dark', 'opendyslexic'], ['dark'], ],
157
+            ['light-highcontrast', ['opendyslexic'], ['opendyslexic']],
158
+        ];
159
+    }
160
+
161
+    /**
162
+     *
163
+     * @param string[] $enabledThemes
164
+     * @param string[] $expectedEnabled
165
+     */
166
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestDisableTheme')]
167
+    public function testDisableTheme(string $toDisable, array $enabledThemes, array $expectedEnabled): void {
168
+        $user = $this->createMock(IUser::class);
169
+        $this->userSession->expects($this->any())
170
+            ->method('getUser')
171
+            ->willReturn($user);
172
+        $user->expects($this->any())
173
+            ->method('getUID')
174
+            ->willReturn('user');
175
+
176
+        $this->config->expects($this->once())
177
+            ->method('getUserValue')
178
+            ->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
179
+            ->willReturn(json_encode($enabledThemes));
180
+
181
+
182
+        $this->assertEquals($expectedEnabled, $this->themesService->disableTheme($this->themes[$toDisable]));
183
+    }
184
+
185
+
186
+    public static function dataTestIsEnabled(): array {
187
+        return [
188
+            ['dark', [], false],
189
+            ['dark', ['dark'], true],
190
+            ['opendyslexic', ['dark', 'opendyslexic'], true],
191
+            ['light-highcontrast', ['opendyslexic'], false],
192
+        ];
193
+    }
194
+
195
+    /**
196
+     * @param string[] $enabledThemes
197
+     */
198
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestIsEnabled')]
199
+    public function testIsEnabled(string $themeId, array $enabledThemes, bool $expected): void {
200
+        $user = $this->createMock(IUser::class);
201
+        $this->userSession->expects($this->any())
202
+            ->method('getUser')
203
+            ->willReturn($user);
204
+        $user->expects($this->any())
205
+            ->method('getUID')
206
+            ->willReturn('user');
207
+
208
+        $this->config->expects($this->once())
209
+            ->method('getUserValue')
210
+            ->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
211
+            ->willReturn(json_encode($enabledThemes));
212
+
213
+
214
+        $this->assertEquals($expected, $this->themesService->isEnabled($this->themes[$themeId]));
215
+    }
216
+
217
+    public function testGetEnabledThemes(): void {
218
+        $user = $this->createMock(IUser::class);
219
+        $this->userSession->expects($this->any())
220
+            ->method('getUser')
221
+            ->willReturn($user);
222
+        $user->expects($this->any())
223
+            ->method('getUID')
224
+            ->willReturn('user');
225
+
226
+
227
+        $this->config->expects($this->once())
228
+            ->method('getUserValue')
229
+            ->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
230
+            ->willReturn(json_encode(['default']));
231
+        $this->config->expects($this->once())
232
+            ->method('getSystemValueString')
233
+            ->with('enforce_theme', '')
234
+            ->willReturn('');
235
+
236
+        $this->assertEquals(['default'], $this->themesService->getEnabledThemes());
237
+    }
238
+
239
+    public function testGetEnabledThemesEnforced(): void {
240
+        $user = $this->createMock(IUser::class);
241
+        $this->userSession->expects($this->any())
242
+            ->method('getUser')
243
+            ->willReturn($user);
244
+        $user->expects($this->any())
245
+            ->method('getUID')
246
+            ->willReturn('user');
247
+
248
+
249
+        $this->config->expects($this->once())
250
+            ->method('getUserValue')
251
+            ->with('user', Application::APP_ID, 'enabled-themes', '["default"]')
252
+            ->willReturn(json_encode([]));
253
+        $this->config->expects($this->once())
254
+            ->method('getSystemValueString')
255
+            ->with('enforce_theme', '')
256
+            ->willReturn('light');
257
+
258
+        $this->assertEquals(['light'], $this->themesService->getEnabledThemes());
259
+    }
260
+
261
+
262
+    public static function dataTestSetEnabledThemes(): array {
263
+        return [
264
+            [[], []],
265
+            [['light'], ['light']],
266
+            [['dark'], ['dark']],
267
+            [['dark', 'dark', 'opendyslexic'], ['dark', 'opendyslexic']],
268
+        ];
269
+    }
270
+
271
+    /**
272
+     *
273
+     * @param string[] $enabledThemes
274
+     * @param string[] $expected
275
+     */
276
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSetEnabledThemes')]
277
+    public function testSetEnabledThemes(array $enabledThemes, array $expected): void {
278
+        $user = $this->createMock(IUser::class);
279
+        $this->userSession->expects($this->any())
280
+            ->method('getUser')
281
+            ->willReturn($user);
282
+        $user->expects($this->any())
283
+            ->method('getUID')
284
+            ->willReturn('user');
285
+
286
+        $this->config->expects($this->once())
287
+            ->method('setUserValue')
288
+            ->with('user', Application::APP_ID, 'enabled-themes', json_encode($expected));
289
+
290
+        $this->invokePrivate($this->themesService, 'setEnabledThemes', [$enabledThemes]);
291
+    }
292
+
293
+    private function initThemes() {
294
+        $util = $this->createMock(Util::class);
295
+        $urlGenerator = $this->createMock(IURLGenerator::class);
296
+        $imageManager = $this->createMock(ImageManager::class);
297
+        $l10n = $this->createMock(IL10N::class);
298
+        $appManager = $this->createMock(IAppManager::class);
299
+
300
+        $this->themes = [
301
+            'default' => new DefaultTheme(
302
+                $util,
303
+                $this->themingDefaults,
304
+                $this->userSession,
305
+                $urlGenerator,
306
+                $imageManager,
307
+                $this->config,
308
+                $l10n,
309
+                $appManager,
310
+                null,
311
+            ),
312
+            'light' => new LightTheme(
313
+                $util,
314
+                $this->themingDefaults,
315
+                $this->userSession,
316
+                $urlGenerator,
317
+                $imageManager,
318
+                $this->config,
319
+                $l10n,
320
+                $appManager,
321
+                null,
322
+            ),
323
+            'dark' => new DarkTheme(
324
+                $util,
325
+                $this->themingDefaults,
326
+                $this->userSession,
327
+                $urlGenerator,
328
+                $imageManager,
329
+                $this->config,
330
+                $l10n,
331
+                $appManager,
332
+                null,
333
+            ),
334
+            'light-highcontrast' => new HighContrastTheme(
335
+                $util,
336
+                $this->themingDefaults,
337
+                $this->userSession,
338
+                $urlGenerator,
339
+                $imageManager,
340
+                $this->config,
341
+                $l10n,
342
+                $appManager,
343
+                null,
344
+            ),
345
+            'dark-highcontrast' => new DarkHighContrastTheme(
346
+                $util,
347
+                $this->themingDefaults,
348
+                $this->userSession,
349
+                $urlGenerator,
350
+                $imageManager,
351
+                $this->config,
352
+                $l10n,
353
+                $appManager,
354
+                null,
355
+            ),
356
+            'opendyslexic' => new DyslexiaFont(
357
+                $util,
358
+                $this->themingDefaults,
359
+                $this->userSession,
360
+                $urlGenerator,
361
+                $imageManager,
362
+                $this->config,
363
+                $l10n,
364
+                $appManager,
365
+                null,
366
+            ),
367
+        ];
368
+    }
369 369
 }
Please login to merge, or discard this patch.
apps/theming/tests/ThemingDefaultsTest.php 2 patches
Indentation   +785 added lines, -785 removed lines patch added patch discarded remove patch
@@ -26,789 +26,789 @@
 block discarded – undo
26 26
 use Test\TestCase;
27 27
 
28 28
 class ThemingDefaultsTest extends TestCase {
29
-	private IAppConfig&MockObject $appConfig;
30
-	private IConfig&MockObject $config;
31
-	private \OC_Defaults $defaults;
32
-	private IL10N|MockObject $l10n;
33
-	private IUserSession&MockObject $userSession;
34
-	private IURLGenerator&MockObject $urlGenerator;
35
-	private ICacheFactory&MockObject $cacheFactory;
36
-	private Util&MockObject $util;
37
-	private ICache&MockObject $cache;
38
-	private IAppManager&MockObject $appManager;
39
-	private ImageManager&MockObject $imageManager;
40
-	private INavigationManager&MockObject $navigationManager;
41
-	private BackgroundService&MockObject $backgroundService;
42
-	private ThemingDefaults $template;
43
-
44
-	protected function setUp(): void {
45
-		parent::setUp();
46
-		$this->appConfig = $this->createMock(IAppConfig::class);
47
-		$this->config = $this->createMock(IConfig::class);
48
-		$this->l10n = $this->createMock(IL10N::class);
49
-		$this->userSession = $this->createMock(IUserSession::class);
50
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
51
-		$this->cacheFactory = $this->createMock(ICacheFactory::class);
52
-		$this->cache = $this->createMock(ICache::class);
53
-		$this->util = $this->createMock(Util::class);
54
-		$this->imageManager = $this->createMock(ImageManager::class);
55
-		$this->appManager = $this->createMock(IAppManager::class);
56
-		$this->navigationManager = $this->createMock(INavigationManager::class);
57
-		$this->backgroundService = $this->createMock(BackgroundService::class);
58
-		$this->defaults = new \OC_Defaults();
59
-		$this->urlGenerator
60
-			->expects($this->any())
61
-			->method('getBaseUrl')
62
-			->willReturn('');
63
-		$this->template = new ThemingDefaults(
64
-			$this->config,
65
-			$this->appConfig,
66
-			$this->l10n,
67
-			$this->userSession,
68
-			$this->urlGenerator,
69
-			$this->cacheFactory,
70
-			$this->util,
71
-			$this->imageManager,
72
-			$this->appManager,
73
-			$this->navigationManager,
74
-			$this->backgroundService,
75
-		);
76
-	}
77
-
78
-	public function testGetNameWithDefault(): void {
79
-		$this->config
80
-			->expects($this->once())
81
-			->method('getAppValue')
82
-			->with('theming', 'name', 'Nextcloud')
83
-			->willReturn('Nextcloud');
84
-
85
-		$this->assertEquals('Nextcloud', $this->template->getName());
86
-	}
87
-
88
-	public function testGetNameWithCustom(): void {
89
-		$this->config
90
-			->expects($this->once())
91
-			->method('getAppValue')
92
-			->with('theming', 'name', 'Nextcloud')
93
-			->willReturn('MyCustomCloud');
94
-
95
-		$this->assertEquals('MyCustomCloud', $this->template->getName());
96
-	}
97
-
98
-	public function testGetHTMLNameWithDefault(): void {
99
-		$this->config
100
-			->expects($this->once())
101
-			->method('getAppValue')
102
-			->with('theming', 'name', 'Nextcloud')
103
-			->willReturn('Nextcloud');
104
-
105
-		$this->assertEquals('Nextcloud', $this->template->getHTMLName());
106
-	}
107
-
108
-	public function testGetHTMLNameWithCustom(): void {
109
-		$this->config
110
-			->expects($this->once())
111
-			->method('getAppValue')
112
-			->with('theming', 'name', 'Nextcloud')
113
-			->willReturn('MyCustomCloud');
114
-
115
-		$this->assertEquals('MyCustomCloud', $this->template->getHTMLName());
116
-	}
117
-
118
-	public function testGetTitleWithDefault(): void {
119
-		$this->config
120
-			->expects($this->once())
121
-			->method('getAppValue')
122
-			->with('theming', 'name', 'Nextcloud')
123
-			->willReturn('Nextcloud');
124
-
125
-		$this->assertEquals('Nextcloud', $this->template->getTitle());
126
-	}
127
-
128
-	public function testGetTitleWithCustom(): void {
129
-		$this->config
130
-			->expects($this->once())
131
-			->method('getAppValue')
132
-			->with('theming', 'name', 'Nextcloud')
133
-			->willReturn('MyCustomCloud');
134
-
135
-		$this->assertEquals('MyCustomCloud', $this->template->getTitle());
136
-	}
137
-
138
-
139
-	public function testGetEntityWithDefault(): void {
140
-		$this->config
141
-			->expects($this->once())
142
-			->method('getAppValue')
143
-			->with('theming', 'name', 'Nextcloud')
144
-			->willReturn('Nextcloud');
145
-
146
-		$this->assertEquals('Nextcloud', $this->template->getEntity());
147
-	}
148
-
149
-	public function testGetEntityWithCustom(): void {
150
-		$this->config
151
-			->expects($this->once())
152
-			->method('getAppValue')
153
-			->with('theming', 'name', 'Nextcloud')
154
-			->willReturn('MyCustomCloud');
155
-
156
-		$this->assertEquals('MyCustomCloud', $this->template->getEntity());
157
-	}
158
-
159
-	public function testGetBaseUrlWithDefault(): void {
160
-		$this->config
161
-			->expects($this->once())
162
-			->method('getAppValue')
163
-			->with('theming', 'url', $this->defaults->getBaseUrl())
164
-			->willReturn($this->defaults->getBaseUrl());
165
-
166
-		$this->assertEquals($this->defaults->getBaseUrl(), $this->template->getBaseUrl());
167
-	}
168
-
169
-	public function testGetBaseUrlWithCustom(): void {
170
-		$this->config
171
-			->expects($this->once())
172
-			->method('getAppValue')
173
-			->with('theming', 'url', $this->defaults->getBaseUrl())
174
-			->willReturn('https://example.com/');
175
-
176
-		$this->assertEquals('https://example.com/', $this->template->getBaseUrl());
177
-	}
178
-
179
-	public static function legalUrlProvider(): array {
180
-		return [
181
-			[''],
182
-			['https://example.com/legal.html'],
183
-		];
184
-	}
185
-
186
-	#[\PHPUnit\Framework\Attributes\DataProvider('legalUrlProvider')]
187
-	public function testGetImprintURL(string $imprintUrl): void {
188
-		$this->config
189
-			->expects($this->once())
190
-			->method('getAppValue')
191
-			->with('theming', 'imprintUrl', '')
192
-			->willReturn($imprintUrl);
193
-
194
-		$this->assertEquals($imprintUrl, $this->template->getImprintUrl());
195
-	}
196
-
197
-	#[\PHPUnit\Framework\Attributes\DataProvider('legalUrlProvider')]
198
-	public function testGetPrivacyURL(string $privacyUrl): void {
199
-		$this->config
200
-			->expects($this->once())
201
-			->method('getAppValue')
202
-			->with('theming', 'privacyUrl', '')
203
-			->willReturn($privacyUrl);
204
-
205
-		$this->assertEquals($privacyUrl, $this->template->getPrivacyUrl());
206
-	}
207
-
208
-	public function testGetSloganWithDefault(): void {
209
-		$this->config
210
-			->expects($this->once())
211
-			->method('getAppValue')
212
-			->with('theming', 'slogan', $this->defaults->getSlogan())
213
-			->willReturn($this->defaults->getSlogan());
214
-
215
-		$this->assertEquals($this->defaults->getSlogan(), $this->template->getSlogan());
216
-	}
217
-
218
-	public function testGetSloganWithCustom(): void {
219
-		$this->config
220
-			->expects($this->once())
221
-			->method('getAppValue')
222
-			->with('theming', 'slogan', $this->defaults->getSlogan())
223
-			->willReturn('My custom Slogan');
224
-
225
-		$this->assertEquals('My custom Slogan', $this->template->getSlogan());
226
-	}
227
-
228
-	public function testGetShortFooter(): void {
229
-		$this->config
230
-			->expects($this->exactly(5))
231
-			->method('getAppValue')
232
-			->willReturnMap([
233
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
234
-				['theming', 'name', 'Nextcloud', 'Name'],
235
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
236
-				['theming', 'imprintUrl', '', ''],
237
-				['theming', 'privacyUrl', '', ''],
238
-			]);
239
-
240
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
241
-	}
242
-
243
-	public function testGetShortFooterEmptyUrl(): void {
244
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
245
-		$this->config
246
-			->expects($this->exactly(5))
247
-			->method('getAppValue')
248
-			->willReturnMap([
249
-				['theming', 'url', $this->defaults->getBaseUrl(), ''],
250
-				['theming', 'name', 'Nextcloud', 'Name'],
251
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
252
-				['theming', 'imprintUrl', '', ''],
253
-				['theming', 'privacyUrl', '', ''],
254
-			]);
255
-
256
-		$this->assertEquals('<span class="entity-name">Name</span> – Slogan', $this->template->getShortFooter());
257
-	}
258
-
259
-	public function testGetShortFooterEmptySlogan(): void {
260
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
261
-		$this->config
262
-			->expects($this->exactly(5))
263
-			->method('getAppValue')
264
-			->willReturnMap([
265
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
266
-				['theming', 'name', 'Nextcloud', 'Name'],
267
-				['theming', 'slogan', $this->defaults->getSlogan(), ''],
268
-				['theming', 'imprintUrl', '', ''],
269
-				['theming', 'privacyUrl', '', ''],
270
-			]);
271
-
272
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a>', $this->template->getShortFooter());
273
-	}
274
-
275
-	public function testGetShortFooterImprint(): void {
276
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
277
-		$this->config
278
-			->expects($this->exactly(5))
279
-			->method('getAppValue')
280
-			->willReturnMap([
281
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
282
-				['theming', 'name', 'Nextcloud', 'Name'],
283
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
284
-				['theming', 'imprintUrl', '', 'https://example.com/imprint'],
285
-				['theming', 'privacyUrl', '', ''],
286
-			]);
287
-
288
-		$this->l10n
289
-			->expects($this->any())
290
-			->method('t')
291
-			->willReturnArgument(0);
292
-
293
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/imprint" class="legal" target="_blank" rel="noreferrer noopener">Legal notice</a></span>', $this->template->getShortFooter());
294
-	}
295
-
296
-	public function testGetShortFooterPrivacy(): void {
297
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
298
-		$this->config
299
-			->expects($this->exactly(5))
300
-			->method('getAppValue')
301
-			->willReturnMap([
302
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
303
-				['theming', 'name', 'Nextcloud', 'Name'],
304
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
305
-				['theming', 'imprintUrl', '', ''],
306
-				['theming', 'privacyUrl', '', 'https://example.com/privacy'],
307
-			]);
308
-
309
-		$this->l10n
310
-			->expects($this->any())
311
-			->method('t')
312
-			->willReturnArgument(0);
313
-
314
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/privacy" class="legal" target="_blank" rel="noreferrer noopener">Privacy policy</a></span>', $this->template->getShortFooter());
315
-	}
316
-
317
-	public function testGetShortFooterAllLegalLinks(): void {
318
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
319
-		$this->config
320
-			->expects($this->exactly(5))
321
-			->method('getAppValue')
322
-			->willReturnMap([
323
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
324
-				['theming', 'name', 'Nextcloud', 'Name'],
325
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
326
-				['theming', 'imprintUrl', '', 'https://example.com/imprint'],
327
-				['theming', 'privacyUrl', '', 'https://example.com/privacy'],
328
-			]);
329
-
330
-		$this->l10n
331
-			->expects($this->any())
332
-			->method('t')
333
-			->willReturnArgument(0);
334
-
335
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/imprint" class="legal" target="_blank" rel="noreferrer noopener">Legal notice</a> · <a href="https://example.com/privacy" class="legal" target="_blank" rel="noreferrer noopener">Privacy policy</a></span>', $this->template->getShortFooter());
336
-	}
337
-
338
-	public static function invalidLegalUrlProvider(): array {
339
-		return [
340
-			['example.com/legal'],  # missing scheme
341
-			['https:///legal'],     # missing host
342
-		];
343
-	}
344
-
345
-	#[\PHPUnit\Framework\Attributes\DataProvider('invalidLegalUrlProvider')]
346
-	public function testGetShortFooterInvalidImprint(string $invalidImprintUrl): void {
347
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
348
-		$this->config
349
-			->expects($this->exactly(5))
350
-			->method('getAppValue')
351
-			->willReturnMap([
352
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
353
-				['theming', 'name', 'Nextcloud', 'Name'],
354
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
355
-				['theming', 'imprintUrl', '', $invalidImprintUrl],
356
-				['theming', 'privacyUrl', '', ''],
357
-			]);
358
-
359
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
360
-	}
361
-
362
-	#[\PHPUnit\Framework\Attributes\DataProvider('invalidLegalUrlProvider')]
363
-	public function testGetShortFooterInvalidPrivacy(string $invalidPrivacyUrl): void {
364
-		$this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
365
-		$this->config
366
-			->expects($this->exactly(5))
367
-			->method('getAppValue')
368
-			->willReturnMap([
369
-				['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
370
-				['theming', 'name', 'Nextcloud', 'Name'],
371
-				['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
372
-				['theming', 'imprintUrl', '', ''],
373
-				['theming', 'privacyUrl', '', $invalidPrivacyUrl],
374
-			]);
375
-
376
-		$this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
377
-	}
378
-
379
-	public function testGetColorPrimaryWithDefault(): void {
380
-		$this->appConfig
381
-			->expects(self::once())
382
-			->method('getValueBool')
383
-			->with('theming', 'disable-user-theming')
384
-			->willReturn(false);
385
-		$this->appConfig
386
-			->expects(self::once())
387
-			->method('getValueString')
388
-			->with('theming', 'primary_color', '')
389
-			->willReturn($this->defaults->getColorPrimary());
390
-
391
-		$this->assertEquals($this->defaults->getColorPrimary(), $this->template->getColorPrimary());
392
-	}
393
-
394
-	public function testGetColorPrimaryWithCustom(): void {
395
-		$this->appConfig
396
-			->expects(self::once())
397
-			->method('getValueBool')
398
-			->with('theming', 'disable-user-theming')
399
-			->willReturn(false);
400
-		$this->appConfig
401
-			->expects(self::once())
402
-			->method('getValueString')
403
-			->with('theming', 'primary_color', '')
404
-			->willReturn('#fff');
405
-
406
-		$this->assertEquals('#fff', $this->template->getColorPrimary());
407
-	}
408
-
409
-	public static function dataGetColorPrimary(): array {
410
-		return [
411
-			'with fallback default' => [
412
-				'disableTheming' => false,
413
-				'primaryColor' => '',
414
-				'userPrimaryColor' => '',
415
-				'expected' => BackgroundService::DEFAULT_COLOR,
416
-			],
417
-			'with custom admin primary' => [
418
-				'disableTheming' => false,
419
-				'primaryColor' => '#aaa',
420
-				'userPrimaryColor' => '',
421
-				'expected' => '#aaa',
422
-			],
423
-			'with custom invalid admin primary' => [
424
-				'disableTheming' => false,
425
-				'primaryColor' => 'invalid',
426
-				'userPrimaryColor' => '',
427
-				'expected' => BackgroundService::DEFAULT_COLOR,
428
-			],
429
-			'with custom invalid user primary' => [
430
-				'disableTheming' => false,
431
-				'primaryColor' => '',
432
-				'userPrimaryColor' => 'invalid-name',
433
-				'expected' => BackgroundService::DEFAULT_COLOR,
434
-			],
435
-			'with custom user primary' => [
436
-				'disableTheming' => false,
437
-				'primaryColor' => '',
438
-				'userPrimaryColor' => '#bbb',
439
-				'expected' => '#bbb',
440
-			],
441
-			'with disabled user theming primary' => [
442
-				'disableTheming' => true,
443
-				'primaryColor' => '#aaa',
444
-				'userPrimaryColor' => '#bbb',
445
-				'expected' => '#aaa',
446
-			],
447
-		];
448
-	}
449
-
450
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetColorPrimary')]
451
-	public function testGetColorPrimary(bool $disableTheming, string $primaryColor, string $userPrimaryColor, string $expected): void {
452
-		$user = $this->createMock(IUser::class);
453
-		$this->userSession->expects($this->any())
454
-			->method('getUser')
455
-			->willReturn($user);
456
-		$user->expects($this->any())
457
-			->method('getUID')
458
-			->willReturn('user');
459
-		$this->appConfig
460
-			->expects(self::any())
461
-			->method('getValueBool')
462
-			->with('theming', 'disable-user-theming')
463
-			->willReturn($disableTheming);
464
-		$this->appConfig
465
-			->expects(self::any())
466
-			->method('getValueString')
467
-			->with('theming', 'primary_color', '')
468
-			->willReturn($primaryColor);
469
-		$this->config
470
-			->expects($this->any())
471
-			->method('getUserValue')
472
-			->with('user', 'theming', 'primary_color', '')
473
-			->willReturn($userPrimaryColor);
474
-
475
-		$this->assertEquals($expected, $this->template->getColorPrimary());
476
-	}
477
-
478
-	public function testSet(): void {
479
-		$expectedCalls = [
480
-			['theming', 'MySetting', 'MyValue'],
481
-			['theming', 'cachebuster', 16],
482
-		];
483
-		$i = 0;
484
-		$this->config
485
-			->expects($this->exactly(2))
486
-			->method('setAppValue')
487
-			->willReturnCallback(function () use ($expectedCalls, &$i): void {
488
-				$this->assertEquals($expectedCalls[$i], func_get_args());
489
-				$i++;
490
-			});
491
-		$this->config
492
-			->expects($this->once())
493
-			->method('getAppValue')
494
-			->with('theming', 'cachebuster', '0')
495
-			->willReturn('15');
496
-		$this->cacheFactory
497
-			->expects($this->exactly(2))
498
-			->method('createDistributed')
499
-			->willReturnMap([
500
-				['theming-', $this->cache],
501
-				['imagePath', $this->cache],
502
-			]);
503
-		$this->cache
504
-			->expects($this->any())
505
-			->method('clear')
506
-			->with('');
507
-		$this->template->set('MySetting', 'MyValue');
508
-	}
509
-
510
-	public function testUndoName(): void {
511
-		$this->config
512
-			->expects($this->once())
513
-			->method('deleteAppValue')
514
-			->with('theming', 'name');
515
-		$this->config
516
-			->expects($this->exactly(2))
517
-			->method('getAppValue')
518
-			->willReturnMap([
519
-				['theming', 'cachebuster', '0', '15'],
520
-				['theming', 'name', 'Nextcloud', 'Nextcloud'],
521
-			]);
522
-		$this->config
523
-			->expects($this->once())
524
-			->method('setAppValue')
525
-			->with('theming', 'cachebuster', 16);
526
-
527
-		$this->assertSame('Nextcloud', $this->template->undo('name'));
528
-	}
529
-
530
-	public function testUndoBaseUrl(): void {
531
-		$this->config
532
-			->expects($this->once())
533
-			->method('deleteAppValue')
534
-			->with('theming', 'url');
535
-		$this->config
536
-			->expects($this->exactly(2))
537
-			->method('getAppValue')
538
-			->willReturnMap([
539
-				['theming', 'cachebuster', '0', '15'],
540
-				['theming', 'url', $this->defaults->getBaseUrl(), $this->defaults->getBaseUrl()],
541
-			]);
542
-		$this->config
543
-			->expects($this->once())
544
-			->method('setAppValue')
545
-			->with('theming', 'cachebuster', 16);
546
-
547
-		$this->assertSame($this->defaults->getBaseUrl(), $this->template->undo('url'));
548
-	}
549
-
550
-	public function testUndoSlogan(): void {
551
-		$this->config
552
-			->expects($this->once())
553
-			->method('deleteAppValue')
554
-			->with('theming', 'slogan');
555
-		$this->config
556
-			->expects($this->exactly(2))
557
-			->method('getAppValue')
558
-			->willReturnMap([
559
-				['theming', 'cachebuster', '0', '15'],
560
-				['theming', 'slogan', $this->defaults->getSlogan(), $this->defaults->getSlogan()],
561
-			]);
562
-		$this->config
563
-			->expects($this->once())
564
-			->method('setAppValue')
565
-			->with('theming', 'cachebuster', 16);
566
-
567
-		$this->assertSame($this->defaults->getSlogan(), $this->template->undo('slogan'));
568
-	}
569
-
570
-	public function testUndoPrimaryColor(): void {
571
-		$this->config
572
-			->expects($this->once())
573
-			->method('deleteAppValue')
574
-			->with('theming', 'primary_color');
575
-		$this->config
576
-			->expects($this->once())
577
-			->method('getAppValue')
578
-			->with('theming', 'cachebuster', '0')
579
-			->willReturn('15');
580
-		$this->config
581
-			->expects($this->once())
582
-			->method('setAppValue')
583
-			->with('theming', 'cachebuster', 16);
584
-
585
-		$this->assertSame($this->defaults->getColorPrimary(), $this->template->undo('primary_color'));
586
-	}
587
-
588
-	public function testUndoDefaultAction(): void {
589
-		$this->config
590
-			->expects($this->once())
591
-			->method('deleteAppValue')
592
-			->with('theming', 'defaultitem');
593
-		$this->config
594
-			->expects($this->once())
595
-			->method('getAppValue')
596
-			->with('theming', 'cachebuster', '0')
597
-			->willReturn('15');
598
-		$this->config
599
-			->expects($this->once())
600
-			->method('setAppValue')
601
-			->with('theming', 'cachebuster', 16);
602
-
603
-		$this->assertSame('', $this->template->undo('defaultitem'));
604
-	}
605
-
606
-	public function testGetBackground(): void {
607
-		$this->imageManager
608
-			->expects($this->once())
609
-			->method('getImageUrl')
610
-			->with('background')
611
-			->willReturn('custom-background?v=0');
612
-		$this->assertEquals('custom-background?v=0', $this->template->getBackground());
613
-	}
614
-
615
-	private function getLogoHelper($withName, $useSvg) {
616
-		$this->imageManager->expects($this->any())
617
-			->method('getImage')
618
-			->with('logo')
619
-			->willThrowException(new NotFoundException());
620
-		$this->config
621
-			->expects($this->exactly(2))
622
-			->method('getAppValue')
623
-			->willReturnMap([
624
-				['theming', 'logoMime', '', ''],
625
-				['theming', 'cachebuster', '0', '0'],
626
-			]);
627
-		$this->urlGenerator->expects($this->once())
628
-			->method('imagePath')
629
-			->with('core', $withName)
630
-			->willReturn('core-logo');
631
-		$this->assertEquals('core-logo?v=0', $this->template->getLogo($useSvg));
632
-	}
633
-
634
-	public function testGetLogoDefaultWithSvg(): void {
635
-		$this->getLogoHelper('logo/logo.svg', true);
636
-	}
637
-
638
-	public function testGetLogoDefaultWithoutSvg(): void {
639
-		$this->getLogoHelper('logo/logo.png', false);
640
-	}
641
-
642
-	public function testGetLogoCustom(): void {
643
-		$this->config
644
-			->expects($this->exactly(2))
645
-			->method('getAppValue')
646
-			->willReturnMap([
647
-				['theming', 'logoMime', '', 'image/svg+xml'],
648
-				['theming', 'cachebuster', '0', '0'],
649
-			]);
650
-		$this->urlGenerator->expects($this->once())
651
-			->method('linkToRoute')
652
-			->with('theming.Theming.getImage')
653
-			->willReturn('custom-logo?v=0');
654
-		$this->assertEquals('custom-logo' . '?v=0', $this->template->getLogo());
655
-	}
656
-
657
-	public function testGetScssVariablesCached(): void {
658
-		$this->config->expects($this->any())->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('1');
659
-		$this->cacheFactory->expects($this->once())
660
-			->method('createDistributed')
661
-			->with('theming-1-')
662
-			->willReturn($this->cache);
663
-		$this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(['foo' => 'bar']);
664
-		$this->assertEquals(['foo' => 'bar'], $this->template->getScssVariables());
665
-	}
666
-
667
-	public function testGetScssVariables(): void {
668
-		$this->config
669
-			->expects($this->any())
670
-			->method('getAppValue')
671
-			->willReturnMap([
672
-				['theming', 'cachebuster', '0', '0'],
673
-				['theming', 'logoMime', '', 'jpeg'],
674
-				['theming', 'backgroundMime', '', 'jpeg'],
675
-				['theming', 'logoheaderMime', '', 'jpeg'],
676
-				['theming', 'faviconMime', '', 'jpeg'],
677
-			]);
678
-
679
-		$this->appConfig
680
-			->expects(self::atLeastOnce())
681
-			->method('getValueString')
682
-			->willReturnMap([
683
-				['theming', 'primary_color', '', false, $this->defaults->getColorPrimary()],
684
-				['theming', 'primary_color', $this->defaults->getColorPrimary(), false, $this->defaults->getColorPrimary()],
685
-			]);
686
-
687
-		$this->util->expects($this->any())->method('invertTextColor')->with($this->defaults->getColorPrimary())->willReturn(false);
688
-		$this->util->expects($this->any())->method('elementColor')->with($this->defaults->getColorPrimary())->willReturn('#aaaaaa');
689
-		$this->cacheFactory->expects($this->once())
690
-			->method('createDistributed')
691
-			->with('theming-0-')
692
-			->willReturn($this->cache);
693
-		$this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(null);
694
-		$this->imageManager->expects($this->exactly(4))
695
-			->method('getImageUrl')
696
-			->willReturnMap([
697
-				['logo', 'custom-logo?v=0'],
698
-				['logoheader', 'custom-logoheader?v=0'],
699
-				['favicon', 'custom-favicon?v=0'],
700
-				['background', 'custom-background?v=0'],
701
-			]);
702
-
703
-		$expected = [
704
-			'theming-cachebuster' => '\'0\'',
705
-			'theming-logo-mime' => '\'jpeg\'',
706
-			'theming-background-mime' => '\'jpeg\'',
707
-			'image-logo' => "url('custom-logo?v=0')",
708
-			'image-login-background' => "url('custom-background?v=0')",
709
-			'color-primary' => $this->defaults->getColorPrimary(),
710
-			'color-primary-text' => '#ffffff',
711
-			'image-login-plain' => 'false',
712
-			'color-primary-element' => '#aaaaaa',
713
-			'theming-logoheader-mime' => '\'jpeg\'',
714
-			'theming-favicon-mime' => '\'jpeg\'',
715
-			'image-logoheader' => "url('custom-logoheader?v=0')",
716
-			'image-favicon' => "url('custom-favicon?v=0')",
717
-			'has-legal-links' => 'false'
718
-		];
719
-		$this->assertEquals($expected, $this->template->getScssVariables());
720
-	}
721
-
722
-	public function testGetDefaultAndroidURL(): void {
723
-		$this->config
724
-			->expects($this->once())
725
-			->method('getAppValue')
726
-			->with('theming', 'AndroidClientUrl', 'https://play.google.com/store/apps/details?id=com.nextcloud.client')
727
-			->willReturn('https://play.google.com/store/apps/details?id=com.nextcloud.client');
728
-
729
-		$this->assertEquals('https://play.google.com/store/apps/details?id=com.nextcloud.client', $this->template->getAndroidClientUrl());
730
-	}
731
-
732
-	public function testGetCustomAndroidURL(): void {
733
-		$this->config
734
-			->expects($this->once())
735
-			->method('getAppValue')
736
-			->with('theming', 'AndroidClientUrl', 'https://play.google.com/store/apps/details?id=com.nextcloud.client')
737
-			->willReturn('https://play.google.com/store/apps/details?id=com.mycloud.client');
738
-
739
-		$this->assertEquals('https://play.google.com/store/apps/details?id=com.mycloud.client', $this->template->getAndroidClientUrl());
740
-	}
741
-
742
-	public function testGetDefaultiOSURL(): void {
743
-		$this->config
744
-			->expects($this->once())
745
-			->method('getAppValue')
746
-			->with('theming', 'iOSClientUrl', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8')
747
-			->willReturn('https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8');
748
-
749
-		$this->assertEquals('https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8', $this->template->getiOSClientUrl());
750
-	}
751
-
752
-	public function testGetCustomiOSURL(): void {
753
-		$this->config
754
-			->expects($this->once())
755
-			->method('getAppValue')
756
-			->with('theming', 'iOSClientUrl', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8')
757
-			->willReturn('https://geo.itunes.apple.com/us/app/nextcloud/id1234567890?mt=8');
758
-
759
-		$this->assertEquals('https://geo.itunes.apple.com/us/app/nextcloud/id1234567890?mt=8', $this->template->getiOSClientUrl());
760
-	}
761
-
762
-	public function testGetDefaultiTunesAppId(): void {
763
-		$this->config
764
-			->expects($this->once())
765
-			->method('getAppValue')
766
-			->with('theming', 'iTunesAppId', '1125420102')
767
-			->willReturn('1125420102');
768
-
769
-		$this->assertEquals('1125420102', $this->template->getiTunesAppId());
770
-	}
771
-
772
-	public function testGetCustomiTunesAppId(): void {
773
-		$this->config
774
-			->expects($this->once())
775
-			->method('getAppValue')
776
-			->with('theming', 'iTunesAppId', '1125420102')
777
-			->willReturn('1234567890');
778
-
779
-		$this->assertEquals('1234567890', $this->template->getiTunesAppId());
780
-	}
781
-
782
-	public static function dataReplaceImagePath(): array {
783
-		return [
784
-			['core', 'test.png', false],
785
-			['core', 'manifest.json'],
786
-			['core', 'favicon.ico'],
787
-			['core', 'favicon-touch.png']
788
-		];
789
-	}
790
-
791
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataReplaceImagePath')]
792
-	public function testReplaceImagePath(string $app, string $image, string|bool $result = 'themingRoute?v=1234abcd'): void {
793
-		$this->cache->expects($this->any())
794
-			->method('get')
795
-			->with('shouldReplaceIcons')
796
-			->willReturn(true);
797
-		$this->config
798
-			->expects($this->any())
799
-			->method('getAppValue')
800
-			->with('theming', 'cachebuster', '0')
801
-			->willReturn('0');
802
-		$this->urlGenerator
803
-			->expects($this->any())
804
-			->method('linkToRoute')
805
-			->willReturn('themingRoute');
806
-		if ($result) {
807
-			$this->util
808
-				->expects($this->once())
809
-				->method('getCacheBuster')
810
-				->willReturn('1234abcd');
811
-		}
812
-		$this->assertEquals($result, $this->template->replaceImagePath($app, $image));
813
-	}
29
+    private IAppConfig&MockObject $appConfig;
30
+    private IConfig&MockObject $config;
31
+    private \OC_Defaults $defaults;
32
+    private IL10N|MockObject $l10n;
33
+    private IUserSession&MockObject $userSession;
34
+    private IURLGenerator&MockObject $urlGenerator;
35
+    private ICacheFactory&MockObject $cacheFactory;
36
+    private Util&MockObject $util;
37
+    private ICache&MockObject $cache;
38
+    private IAppManager&MockObject $appManager;
39
+    private ImageManager&MockObject $imageManager;
40
+    private INavigationManager&MockObject $navigationManager;
41
+    private BackgroundService&MockObject $backgroundService;
42
+    private ThemingDefaults $template;
43
+
44
+    protected function setUp(): void {
45
+        parent::setUp();
46
+        $this->appConfig = $this->createMock(IAppConfig::class);
47
+        $this->config = $this->createMock(IConfig::class);
48
+        $this->l10n = $this->createMock(IL10N::class);
49
+        $this->userSession = $this->createMock(IUserSession::class);
50
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
51
+        $this->cacheFactory = $this->createMock(ICacheFactory::class);
52
+        $this->cache = $this->createMock(ICache::class);
53
+        $this->util = $this->createMock(Util::class);
54
+        $this->imageManager = $this->createMock(ImageManager::class);
55
+        $this->appManager = $this->createMock(IAppManager::class);
56
+        $this->navigationManager = $this->createMock(INavigationManager::class);
57
+        $this->backgroundService = $this->createMock(BackgroundService::class);
58
+        $this->defaults = new \OC_Defaults();
59
+        $this->urlGenerator
60
+            ->expects($this->any())
61
+            ->method('getBaseUrl')
62
+            ->willReturn('');
63
+        $this->template = new ThemingDefaults(
64
+            $this->config,
65
+            $this->appConfig,
66
+            $this->l10n,
67
+            $this->userSession,
68
+            $this->urlGenerator,
69
+            $this->cacheFactory,
70
+            $this->util,
71
+            $this->imageManager,
72
+            $this->appManager,
73
+            $this->navigationManager,
74
+            $this->backgroundService,
75
+        );
76
+    }
77
+
78
+    public function testGetNameWithDefault(): void {
79
+        $this->config
80
+            ->expects($this->once())
81
+            ->method('getAppValue')
82
+            ->with('theming', 'name', 'Nextcloud')
83
+            ->willReturn('Nextcloud');
84
+
85
+        $this->assertEquals('Nextcloud', $this->template->getName());
86
+    }
87
+
88
+    public function testGetNameWithCustom(): void {
89
+        $this->config
90
+            ->expects($this->once())
91
+            ->method('getAppValue')
92
+            ->with('theming', 'name', 'Nextcloud')
93
+            ->willReturn('MyCustomCloud');
94
+
95
+        $this->assertEquals('MyCustomCloud', $this->template->getName());
96
+    }
97
+
98
+    public function testGetHTMLNameWithDefault(): void {
99
+        $this->config
100
+            ->expects($this->once())
101
+            ->method('getAppValue')
102
+            ->with('theming', 'name', 'Nextcloud')
103
+            ->willReturn('Nextcloud');
104
+
105
+        $this->assertEquals('Nextcloud', $this->template->getHTMLName());
106
+    }
107
+
108
+    public function testGetHTMLNameWithCustom(): void {
109
+        $this->config
110
+            ->expects($this->once())
111
+            ->method('getAppValue')
112
+            ->with('theming', 'name', 'Nextcloud')
113
+            ->willReturn('MyCustomCloud');
114
+
115
+        $this->assertEquals('MyCustomCloud', $this->template->getHTMLName());
116
+    }
117
+
118
+    public function testGetTitleWithDefault(): void {
119
+        $this->config
120
+            ->expects($this->once())
121
+            ->method('getAppValue')
122
+            ->with('theming', 'name', 'Nextcloud')
123
+            ->willReturn('Nextcloud');
124
+
125
+        $this->assertEquals('Nextcloud', $this->template->getTitle());
126
+    }
127
+
128
+    public function testGetTitleWithCustom(): void {
129
+        $this->config
130
+            ->expects($this->once())
131
+            ->method('getAppValue')
132
+            ->with('theming', 'name', 'Nextcloud')
133
+            ->willReturn('MyCustomCloud');
134
+
135
+        $this->assertEquals('MyCustomCloud', $this->template->getTitle());
136
+    }
137
+
138
+
139
+    public function testGetEntityWithDefault(): void {
140
+        $this->config
141
+            ->expects($this->once())
142
+            ->method('getAppValue')
143
+            ->with('theming', 'name', 'Nextcloud')
144
+            ->willReturn('Nextcloud');
145
+
146
+        $this->assertEquals('Nextcloud', $this->template->getEntity());
147
+    }
148
+
149
+    public function testGetEntityWithCustom(): void {
150
+        $this->config
151
+            ->expects($this->once())
152
+            ->method('getAppValue')
153
+            ->with('theming', 'name', 'Nextcloud')
154
+            ->willReturn('MyCustomCloud');
155
+
156
+        $this->assertEquals('MyCustomCloud', $this->template->getEntity());
157
+    }
158
+
159
+    public function testGetBaseUrlWithDefault(): void {
160
+        $this->config
161
+            ->expects($this->once())
162
+            ->method('getAppValue')
163
+            ->with('theming', 'url', $this->defaults->getBaseUrl())
164
+            ->willReturn($this->defaults->getBaseUrl());
165
+
166
+        $this->assertEquals($this->defaults->getBaseUrl(), $this->template->getBaseUrl());
167
+    }
168
+
169
+    public function testGetBaseUrlWithCustom(): void {
170
+        $this->config
171
+            ->expects($this->once())
172
+            ->method('getAppValue')
173
+            ->with('theming', 'url', $this->defaults->getBaseUrl())
174
+            ->willReturn('https://example.com/');
175
+
176
+        $this->assertEquals('https://example.com/', $this->template->getBaseUrl());
177
+    }
178
+
179
+    public static function legalUrlProvider(): array {
180
+        return [
181
+            [''],
182
+            ['https://example.com/legal.html'],
183
+        ];
184
+    }
185
+
186
+    #[\PHPUnit\Framework\Attributes\DataProvider('legalUrlProvider')]
187
+    public function testGetImprintURL(string $imprintUrl): void {
188
+        $this->config
189
+            ->expects($this->once())
190
+            ->method('getAppValue')
191
+            ->with('theming', 'imprintUrl', '')
192
+            ->willReturn($imprintUrl);
193
+
194
+        $this->assertEquals($imprintUrl, $this->template->getImprintUrl());
195
+    }
196
+
197
+    #[\PHPUnit\Framework\Attributes\DataProvider('legalUrlProvider')]
198
+    public function testGetPrivacyURL(string $privacyUrl): void {
199
+        $this->config
200
+            ->expects($this->once())
201
+            ->method('getAppValue')
202
+            ->with('theming', 'privacyUrl', '')
203
+            ->willReturn($privacyUrl);
204
+
205
+        $this->assertEquals($privacyUrl, $this->template->getPrivacyUrl());
206
+    }
207
+
208
+    public function testGetSloganWithDefault(): void {
209
+        $this->config
210
+            ->expects($this->once())
211
+            ->method('getAppValue')
212
+            ->with('theming', 'slogan', $this->defaults->getSlogan())
213
+            ->willReturn($this->defaults->getSlogan());
214
+
215
+        $this->assertEquals($this->defaults->getSlogan(), $this->template->getSlogan());
216
+    }
217
+
218
+    public function testGetSloganWithCustom(): void {
219
+        $this->config
220
+            ->expects($this->once())
221
+            ->method('getAppValue')
222
+            ->with('theming', 'slogan', $this->defaults->getSlogan())
223
+            ->willReturn('My custom Slogan');
224
+
225
+        $this->assertEquals('My custom Slogan', $this->template->getSlogan());
226
+    }
227
+
228
+    public function testGetShortFooter(): void {
229
+        $this->config
230
+            ->expects($this->exactly(5))
231
+            ->method('getAppValue')
232
+            ->willReturnMap([
233
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
234
+                ['theming', 'name', 'Nextcloud', 'Name'],
235
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
236
+                ['theming', 'imprintUrl', '', ''],
237
+                ['theming', 'privacyUrl', '', ''],
238
+            ]);
239
+
240
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
241
+    }
242
+
243
+    public function testGetShortFooterEmptyUrl(): void {
244
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
245
+        $this->config
246
+            ->expects($this->exactly(5))
247
+            ->method('getAppValue')
248
+            ->willReturnMap([
249
+                ['theming', 'url', $this->defaults->getBaseUrl(), ''],
250
+                ['theming', 'name', 'Nextcloud', 'Name'],
251
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
252
+                ['theming', 'imprintUrl', '', ''],
253
+                ['theming', 'privacyUrl', '', ''],
254
+            ]);
255
+
256
+        $this->assertEquals('<span class="entity-name">Name</span> – Slogan', $this->template->getShortFooter());
257
+    }
258
+
259
+    public function testGetShortFooterEmptySlogan(): void {
260
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
261
+        $this->config
262
+            ->expects($this->exactly(5))
263
+            ->method('getAppValue')
264
+            ->willReturnMap([
265
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
266
+                ['theming', 'name', 'Nextcloud', 'Name'],
267
+                ['theming', 'slogan', $this->defaults->getSlogan(), ''],
268
+                ['theming', 'imprintUrl', '', ''],
269
+                ['theming', 'privacyUrl', '', ''],
270
+            ]);
271
+
272
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a>', $this->template->getShortFooter());
273
+    }
274
+
275
+    public function testGetShortFooterImprint(): void {
276
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
277
+        $this->config
278
+            ->expects($this->exactly(5))
279
+            ->method('getAppValue')
280
+            ->willReturnMap([
281
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
282
+                ['theming', 'name', 'Nextcloud', 'Name'],
283
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
284
+                ['theming', 'imprintUrl', '', 'https://example.com/imprint'],
285
+                ['theming', 'privacyUrl', '', ''],
286
+            ]);
287
+
288
+        $this->l10n
289
+            ->expects($this->any())
290
+            ->method('t')
291
+            ->willReturnArgument(0);
292
+
293
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/imprint" class="legal" target="_blank" rel="noreferrer noopener">Legal notice</a></span>', $this->template->getShortFooter());
294
+    }
295
+
296
+    public function testGetShortFooterPrivacy(): void {
297
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
298
+        $this->config
299
+            ->expects($this->exactly(5))
300
+            ->method('getAppValue')
301
+            ->willReturnMap([
302
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
303
+                ['theming', 'name', 'Nextcloud', 'Name'],
304
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
305
+                ['theming', 'imprintUrl', '', ''],
306
+                ['theming', 'privacyUrl', '', 'https://example.com/privacy'],
307
+            ]);
308
+
309
+        $this->l10n
310
+            ->expects($this->any())
311
+            ->method('t')
312
+            ->willReturnArgument(0);
313
+
314
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/privacy" class="legal" target="_blank" rel="noreferrer noopener">Privacy policy</a></span>', $this->template->getShortFooter());
315
+    }
316
+
317
+    public function testGetShortFooterAllLegalLinks(): void {
318
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
319
+        $this->config
320
+            ->expects($this->exactly(5))
321
+            ->method('getAppValue')
322
+            ->willReturnMap([
323
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
324
+                ['theming', 'name', 'Nextcloud', 'Name'],
325
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
326
+                ['theming', 'imprintUrl', '', 'https://example.com/imprint'],
327
+                ['theming', 'privacyUrl', '', 'https://example.com/privacy'],
328
+            ]);
329
+
330
+        $this->l10n
331
+            ->expects($this->any())
332
+            ->method('t')
333
+            ->willReturnArgument(0);
334
+
335
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan<br/><span class="footer__legal-links"><a href="https://example.com/imprint" class="legal" target="_blank" rel="noreferrer noopener">Legal notice</a> · <a href="https://example.com/privacy" class="legal" target="_blank" rel="noreferrer noopener">Privacy policy</a></span>', $this->template->getShortFooter());
336
+    }
337
+
338
+    public static function invalidLegalUrlProvider(): array {
339
+        return [
340
+            ['example.com/legal'],  # missing scheme
341
+            ['https:///legal'],     # missing host
342
+        ];
343
+    }
344
+
345
+    #[\PHPUnit\Framework\Attributes\DataProvider('invalidLegalUrlProvider')]
346
+    public function testGetShortFooterInvalidImprint(string $invalidImprintUrl): void {
347
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
348
+        $this->config
349
+            ->expects($this->exactly(5))
350
+            ->method('getAppValue')
351
+            ->willReturnMap([
352
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
353
+                ['theming', 'name', 'Nextcloud', 'Name'],
354
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
355
+                ['theming', 'imprintUrl', '', $invalidImprintUrl],
356
+                ['theming', 'privacyUrl', '', ''],
357
+            ]);
358
+
359
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
360
+    }
361
+
362
+    #[\PHPUnit\Framework\Attributes\DataProvider('invalidLegalUrlProvider')]
363
+    public function testGetShortFooterInvalidPrivacy(string $invalidPrivacyUrl): void {
364
+        $this->navigationManager->expects($this->once())->method('getAll')->with(INavigationManager::TYPE_GUEST)->willReturn([]);
365
+        $this->config
366
+            ->expects($this->exactly(5))
367
+            ->method('getAppValue')
368
+            ->willReturnMap([
369
+                ['theming', 'url', $this->defaults->getBaseUrl(), 'url'],
370
+                ['theming', 'name', 'Nextcloud', 'Name'],
371
+                ['theming', 'slogan', $this->defaults->getSlogan(), 'Slogan'],
372
+                ['theming', 'imprintUrl', '', ''],
373
+                ['theming', 'privacyUrl', '', $invalidPrivacyUrl],
374
+            ]);
375
+
376
+        $this->assertEquals('<a href="url" target="_blank" rel="noreferrer noopener" class="entity-name">Name</a> – Slogan', $this->template->getShortFooter());
377
+    }
378
+
379
+    public function testGetColorPrimaryWithDefault(): void {
380
+        $this->appConfig
381
+            ->expects(self::once())
382
+            ->method('getValueBool')
383
+            ->with('theming', 'disable-user-theming')
384
+            ->willReturn(false);
385
+        $this->appConfig
386
+            ->expects(self::once())
387
+            ->method('getValueString')
388
+            ->with('theming', 'primary_color', '')
389
+            ->willReturn($this->defaults->getColorPrimary());
390
+
391
+        $this->assertEquals($this->defaults->getColorPrimary(), $this->template->getColorPrimary());
392
+    }
393
+
394
+    public function testGetColorPrimaryWithCustom(): void {
395
+        $this->appConfig
396
+            ->expects(self::once())
397
+            ->method('getValueBool')
398
+            ->with('theming', 'disable-user-theming')
399
+            ->willReturn(false);
400
+        $this->appConfig
401
+            ->expects(self::once())
402
+            ->method('getValueString')
403
+            ->with('theming', 'primary_color', '')
404
+            ->willReturn('#fff');
405
+
406
+        $this->assertEquals('#fff', $this->template->getColorPrimary());
407
+    }
408
+
409
+    public static function dataGetColorPrimary(): array {
410
+        return [
411
+            'with fallback default' => [
412
+                'disableTheming' => false,
413
+                'primaryColor' => '',
414
+                'userPrimaryColor' => '',
415
+                'expected' => BackgroundService::DEFAULT_COLOR,
416
+            ],
417
+            'with custom admin primary' => [
418
+                'disableTheming' => false,
419
+                'primaryColor' => '#aaa',
420
+                'userPrimaryColor' => '',
421
+                'expected' => '#aaa',
422
+            ],
423
+            'with custom invalid admin primary' => [
424
+                'disableTheming' => false,
425
+                'primaryColor' => 'invalid',
426
+                'userPrimaryColor' => '',
427
+                'expected' => BackgroundService::DEFAULT_COLOR,
428
+            ],
429
+            'with custom invalid user primary' => [
430
+                'disableTheming' => false,
431
+                'primaryColor' => '',
432
+                'userPrimaryColor' => 'invalid-name',
433
+                'expected' => BackgroundService::DEFAULT_COLOR,
434
+            ],
435
+            'with custom user primary' => [
436
+                'disableTheming' => false,
437
+                'primaryColor' => '',
438
+                'userPrimaryColor' => '#bbb',
439
+                'expected' => '#bbb',
440
+            ],
441
+            'with disabled user theming primary' => [
442
+                'disableTheming' => true,
443
+                'primaryColor' => '#aaa',
444
+                'userPrimaryColor' => '#bbb',
445
+                'expected' => '#aaa',
446
+            ],
447
+        ];
448
+    }
449
+
450
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetColorPrimary')]
451
+    public function testGetColorPrimary(bool $disableTheming, string $primaryColor, string $userPrimaryColor, string $expected): void {
452
+        $user = $this->createMock(IUser::class);
453
+        $this->userSession->expects($this->any())
454
+            ->method('getUser')
455
+            ->willReturn($user);
456
+        $user->expects($this->any())
457
+            ->method('getUID')
458
+            ->willReturn('user');
459
+        $this->appConfig
460
+            ->expects(self::any())
461
+            ->method('getValueBool')
462
+            ->with('theming', 'disable-user-theming')
463
+            ->willReturn($disableTheming);
464
+        $this->appConfig
465
+            ->expects(self::any())
466
+            ->method('getValueString')
467
+            ->with('theming', 'primary_color', '')
468
+            ->willReturn($primaryColor);
469
+        $this->config
470
+            ->expects($this->any())
471
+            ->method('getUserValue')
472
+            ->with('user', 'theming', 'primary_color', '')
473
+            ->willReturn($userPrimaryColor);
474
+
475
+        $this->assertEquals($expected, $this->template->getColorPrimary());
476
+    }
477
+
478
+    public function testSet(): void {
479
+        $expectedCalls = [
480
+            ['theming', 'MySetting', 'MyValue'],
481
+            ['theming', 'cachebuster', 16],
482
+        ];
483
+        $i = 0;
484
+        $this->config
485
+            ->expects($this->exactly(2))
486
+            ->method('setAppValue')
487
+            ->willReturnCallback(function () use ($expectedCalls, &$i): void {
488
+                $this->assertEquals($expectedCalls[$i], func_get_args());
489
+                $i++;
490
+            });
491
+        $this->config
492
+            ->expects($this->once())
493
+            ->method('getAppValue')
494
+            ->with('theming', 'cachebuster', '0')
495
+            ->willReturn('15');
496
+        $this->cacheFactory
497
+            ->expects($this->exactly(2))
498
+            ->method('createDistributed')
499
+            ->willReturnMap([
500
+                ['theming-', $this->cache],
501
+                ['imagePath', $this->cache],
502
+            ]);
503
+        $this->cache
504
+            ->expects($this->any())
505
+            ->method('clear')
506
+            ->with('');
507
+        $this->template->set('MySetting', 'MyValue');
508
+    }
509
+
510
+    public function testUndoName(): void {
511
+        $this->config
512
+            ->expects($this->once())
513
+            ->method('deleteAppValue')
514
+            ->with('theming', 'name');
515
+        $this->config
516
+            ->expects($this->exactly(2))
517
+            ->method('getAppValue')
518
+            ->willReturnMap([
519
+                ['theming', 'cachebuster', '0', '15'],
520
+                ['theming', 'name', 'Nextcloud', 'Nextcloud'],
521
+            ]);
522
+        $this->config
523
+            ->expects($this->once())
524
+            ->method('setAppValue')
525
+            ->with('theming', 'cachebuster', 16);
526
+
527
+        $this->assertSame('Nextcloud', $this->template->undo('name'));
528
+    }
529
+
530
+    public function testUndoBaseUrl(): void {
531
+        $this->config
532
+            ->expects($this->once())
533
+            ->method('deleteAppValue')
534
+            ->with('theming', 'url');
535
+        $this->config
536
+            ->expects($this->exactly(2))
537
+            ->method('getAppValue')
538
+            ->willReturnMap([
539
+                ['theming', 'cachebuster', '0', '15'],
540
+                ['theming', 'url', $this->defaults->getBaseUrl(), $this->defaults->getBaseUrl()],
541
+            ]);
542
+        $this->config
543
+            ->expects($this->once())
544
+            ->method('setAppValue')
545
+            ->with('theming', 'cachebuster', 16);
546
+
547
+        $this->assertSame($this->defaults->getBaseUrl(), $this->template->undo('url'));
548
+    }
549
+
550
+    public function testUndoSlogan(): void {
551
+        $this->config
552
+            ->expects($this->once())
553
+            ->method('deleteAppValue')
554
+            ->with('theming', 'slogan');
555
+        $this->config
556
+            ->expects($this->exactly(2))
557
+            ->method('getAppValue')
558
+            ->willReturnMap([
559
+                ['theming', 'cachebuster', '0', '15'],
560
+                ['theming', 'slogan', $this->defaults->getSlogan(), $this->defaults->getSlogan()],
561
+            ]);
562
+        $this->config
563
+            ->expects($this->once())
564
+            ->method('setAppValue')
565
+            ->with('theming', 'cachebuster', 16);
566
+
567
+        $this->assertSame($this->defaults->getSlogan(), $this->template->undo('slogan'));
568
+    }
569
+
570
+    public function testUndoPrimaryColor(): void {
571
+        $this->config
572
+            ->expects($this->once())
573
+            ->method('deleteAppValue')
574
+            ->with('theming', 'primary_color');
575
+        $this->config
576
+            ->expects($this->once())
577
+            ->method('getAppValue')
578
+            ->with('theming', 'cachebuster', '0')
579
+            ->willReturn('15');
580
+        $this->config
581
+            ->expects($this->once())
582
+            ->method('setAppValue')
583
+            ->with('theming', 'cachebuster', 16);
584
+
585
+        $this->assertSame($this->defaults->getColorPrimary(), $this->template->undo('primary_color'));
586
+    }
587
+
588
+    public function testUndoDefaultAction(): void {
589
+        $this->config
590
+            ->expects($this->once())
591
+            ->method('deleteAppValue')
592
+            ->with('theming', 'defaultitem');
593
+        $this->config
594
+            ->expects($this->once())
595
+            ->method('getAppValue')
596
+            ->with('theming', 'cachebuster', '0')
597
+            ->willReturn('15');
598
+        $this->config
599
+            ->expects($this->once())
600
+            ->method('setAppValue')
601
+            ->with('theming', 'cachebuster', 16);
602
+
603
+        $this->assertSame('', $this->template->undo('defaultitem'));
604
+    }
605
+
606
+    public function testGetBackground(): void {
607
+        $this->imageManager
608
+            ->expects($this->once())
609
+            ->method('getImageUrl')
610
+            ->with('background')
611
+            ->willReturn('custom-background?v=0');
612
+        $this->assertEquals('custom-background?v=0', $this->template->getBackground());
613
+    }
614
+
615
+    private function getLogoHelper($withName, $useSvg) {
616
+        $this->imageManager->expects($this->any())
617
+            ->method('getImage')
618
+            ->with('logo')
619
+            ->willThrowException(new NotFoundException());
620
+        $this->config
621
+            ->expects($this->exactly(2))
622
+            ->method('getAppValue')
623
+            ->willReturnMap([
624
+                ['theming', 'logoMime', '', ''],
625
+                ['theming', 'cachebuster', '0', '0'],
626
+            ]);
627
+        $this->urlGenerator->expects($this->once())
628
+            ->method('imagePath')
629
+            ->with('core', $withName)
630
+            ->willReturn('core-logo');
631
+        $this->assertEquals('core-logo?v=0', $this->template->getLogo($useSvg));
632
+    }
633
+
634
+    public function testGetLogoDefaultWithSvg(): void {
635
+        $this->getLogoHelper('logo/logo.svg', true);
636
+    }
637
+
638
+    public function testGetLogoDefaultWithoutSvg(): void {
639
+        $this->getLogoHelper('logo/logo.png', false);
640
+    }
641
+
642
+    public function testGetLogoCustom(): void {
643
+        $this->config
644
+            ->expects($this->exactly(2))
645
+            ->method('getAppValue')
646
+            ->willReturnMap([
647
+                ['theming', 'logoMime', '', 'image/svg+xml'],
648
+                ['theming', 'cachebuster', '0', '0'],
649
+            ]);
650
+        $this->urlGenerator->expects($this->once())
651
+            ->method('linkToRoute')
652
+            ->with('theming.Theming.getImage')
653
+            ->willReturn('custom-logo?v=0');
654
+        $this->assertEquals('custom-logo' . '?v=0', $this->template->getLogo());
655
+    }
656
+
657
+    public function testGetScssVariablesCached(): void {
658
+        $this->config->expects($this->any())->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('1');
659
+        $this->cacheFactory->expects($this->once())
660
+            ->method('createDistributed')
661
+            ->with('theming-1-')
662
+            ->willReturn($this->cache);
663
+        $this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(['foo' => 'bar']);
664
+        $this->assertEquals(['foo' => 'bar'], $this->template->getScssVariables());
665
+    }
666
+
667
+    public function testGetScssVariables(): void {
668
+        $this->config
669
+            ->expects($this->any())
670
+            ->method('getAppValue')
671
+            ->willReturnMap([
672
+                ['theming', 'cachebuster', '0', '0'],
673
+                ['theming', 'logoMime', '', 'jpeg'],
674
+                ['theming', 'backgroundMime', '', 'jpeg'],
675
+                ['theming', 'logoheaderMime', '', 'jpeg'],
676
+                ['theming', 'faviconMime', '', 'jpeg'],
677
+            ]);
678
+
679
+        $this->appConfig
680
+            ->expects(self::atLeastOnce())
681
+            ->method('getValueString')
682
+            ->willReturnMap([
683
+                ['theming', 'primary_color', '', false, $this->defaults->getColorPrimary()],
684
+                ['theming', 'primary_color', $this->defaults->getColorPrimary(), false, $this->defaults->getColorPrimary()],
685
+            ]);
686
+
687
+        $this->util->expects($this->any())->method('invertTextColor')->with($this->defaults->getColorPrimary())->willReturn(false);
688
+        $this->util->expects($this->any())->method('elementColor')->with($this->defaults->getColorPrimary())->willReturn('#aaaaaa');
689
+        $this->cacheFactory->expects($this->once())
690
+            ->method('createDistributed')
691
+            ->with('theming-0-')
692
+            ->willReturn($this->cache);
693
+        $this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(null);
694
+        $this->imageManager->expects($this->exactly(4))
695
+            ->method('getImageUrl')
696
+            ->willReturnMap([
697
+                ['logo', 'custom-logo?v=0'],
698
+                ['logoheader', 'custom-logoheader?v=0'],
699
+                ['favicon', 'custom-favicon?v=0'],
700
+                ['background', 'custom-background?v=0'],
701
+            ]);
702
+
703
+        $expected = [
704
+            'theming-cachebuster' => '\'0\'',
705
+            'theming-logo-mime' => '\'jpeg\'',
706
+            'theming-background-mime' => '\'jpeg\'',
707
+            'image-logo' => "url('custom-logo?v=0')",
708
+            'image-login-background' => "url('custom-background?v=0')",
709
+            'color-primary' => $this->defaults->getColorPrimary(),
710
+            'color-primary-text' => '#ffffff',
711
+            'image-login-plain' => 'false',
712
+            'color-primary-element' => '#aaaaaa',
713
+            'theming-logoheader-mime' => '\'jpeg\'',
714
+            'theming-favicon-mime' => '\'jpeg\'',
715
+            'image-logoheader' => "url('custom-logoheader?v=0')",
716
+            'image-favicon' => "url('custom-favicon?v=0')",
717
+            'has-legal-links' => 'false'
718
+        ];
719
+        $this->assertEquals($expected, $this->template->getScssVariables());
720
+    }
721
+
722
+    public function testGetDefaultAndroidURL(): void {
723
+        $this->config
724
+            ->expects($this->once())
725
+            ->method('getAppValue')
726
+            ->with('theming', 'AndroidClientUrl', 'https://play.google.com/store/apps/details?id=com.nextcloud.client')
727
+            ->willReturn('https://play.google.com/store/apps/details?id=com.nextcloud.client');
728
+
729
+        $this->assertEquals('https://play.google.com/store/apps/details?id=com.nextcloud.client', $this->template->getAndroidClientUrl());
730
+    }
731
+
732
+    public function testGetCustomAndroidURL(): void {
733
+        $this->config
734
+            ->expects($this->once())
735
+            ->method('getAppValue')
736
+            ->with('theming', 'AndroidClientUrl', 'https://play.google.com/store/apps/details?id=com.nextcloud.client')
737
+            ->willReturn('https://play.google.com/store/apps/details?id=com.mycloud.client');
738
+
739
+        $this->assertEquals('https://play.google.com/store/apps/details?id=com.mycloud.client', $this->template->getAndroidClientUrl());
740
+    }
741
+
742
+    public function testGetDefaultiOSURL(): void {
743
+        $this->config
744
+            ->expects($this->once())
745
+            ->method('getAppValue')
746
+            ->with('theming', 'iOSClientUrl', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8')
747
+            ->willReturn('https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8');
748
+
749
+        $this->assertEquals('https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8', $this->template->getiOSClientUrl());
750
+    }
751
+
752
+    public function testGetCustomiOSURL(): void {
753
+        $this->config
754
+            ->expects($this->once())
755
+            ->method('getAppValue')
756
+            ->with('theming', 'iOSClientUrl', 'https://geo.itunes.apple.com/us/app/nextcloud/id1125420102?mt=8')
757
+            ->willReturn('https://geo.itunes.apple.com/us/app/nextcloud/id1234567890?mt=8');
758
+
759
+        $this->assertEquals('https://geo.itunes.apple.com/us/app/nextcloud/id1234567890?mt=8', $this->template->getiOSClientUrl());
760
+    }
761
+
762
+    public function testGetDefaultiTunesAppId(): void {
763
+        $this->config
764
+            ->expects($this->once())
765
+            ->method('getAppValue')
766
+            ->with('theming', 'iTunesAppId', '1125420102')
767
+            ->willReturn('1125420102');
768
+
769
+        $this->assertEquals('1125420102', $this->template->getiTunesAppId());
770
+    }
771
+
772
+    public function testGetCustomiTunesAppId(): void {
773
+        $this->config
774
+            ->expects($this->once())
775
+            ->method('getAppValue')
776
+            ->with('theming', 'iTunesAppId', '1125420102')
777
+            ->willReturn('1234567890');
778
+
779
+        $this->assertEquals('1234567890', $this->template->getiTunesAppId());
780
+    }
781
+
782
+    public static function dataReplaceImagePath(): array {
783
+        return [
784
+            ['core', 'test.png', false],
785
+            ['core', 'manifest.json'],
786
+            ['core', 'favicon.ico'],
787
+            ['core', 'favicon-touch.png']
788
+        ];
789
+    }
790
+
791
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataReplaceImagePath')]
792
+    public function testReplaceImagePath(string $app, string $image, string|bool $result = 'themingRoute?v=1234abcd'): void {
793
+        $this->cache->expects($this->any())
794
+            ->method('get')
795
+            ->with('shouldReplaceIcons')
796
+            ->willReturn(true);
797
+        $this->config
798
+            ->expects($this->any())
799
+            ->method('getAppValue')
800
+            ->with('theming', 'cachebuster', '0')
801
+            ->willReturn('0');
802
+        $this->urlGenerator
803
+            ->expects($this->any())
804
+            ->method('linkToRoute')
805
+            ->willReturn('themingRoute');
806
+        if ($result) {
807
+            $this->util
808
+                ->expects($this->once())
809
+                ->method('getCacheBuster')
810
+                ->willReturn('1234abcd');
811
+        }
812
+        $this->assertEquals($result, $this->template->replaceImagePath($app, $image));
813
+    }
814 814
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -29,7 +29,7 @@  discard block
 block discarded – undo
29 29
 	private IAppConfig&MockObject $appConfig;
30 30
 	private IConfig&MockObject $config;
31 31
 	private \OC_Defaults $defaults;
32
-	private IL10N|MockObject $l10n;
32
+	private IL10N | MockObject $l10n;
33 33
 	private IUserSession&MockObject $userSession;
34 34
 	private IURLGenerator&MockObject $urlGenerator;
35 35
 	private ICacheFactory&MockObject $cacheFactory;
@@ -337,8 +337,8 @@  discard block
 block discarded – undo
337 337
 
338 338
 	public static function invalidLegalUrlProvider(): array {
339 339
 		return [
340
-			['example.com/legal'],  # missing scheme
341
-			['https:///legal'],     # missing host
340
+			['example.com/legal'], # missing scheme
341
+			['https:///legal'], # missing host
342 342
 		];
343 343
 	}
344 344
 
@@ -484,7 +484,7 @@  discard block
 block discarded – undo
484 484
 		$this->config
485 485
 			->expects($this->exactly(2))
486 486
 			->method('setAppValue')
487
-			->willReturnCallback(function () use ($expectedCalls, &$i): void {
487
+			->willReturnCallback(function() use ($expectedCalls, &$i): void {
488 488
 				$this->assertEquals($expectedCalls[$i], func_get_args());
489 489
 				$i++;
490 490
 			});
@@ -651,7 +651,7 @@  discard block
 block discarded – undo
651 651
 			->method('linkToRoute')
652 652
 			->with('theming.Theming.getImage')
653 653
 			->willReturn('custom-logo?v=0');
654
-		$this->assertEquals('custom-logo' . '?v=0', $this->template->getLogo());
654
+		$this->assertEquals('custom-logo'.'?v=0', $this->template->getLogo());
655 655
 	}
656 656
 
657 657
 	public function testGetScssVariablesCached(): void {
@@ -789,7 +789,7 @@  discard block
 block discarded – undo
789 789
 	}
790 790
 
791 791
 	#[\PHPUnit\Framework\Attributes\DataProvider('dataReplaceImagePath')]
792
-	public function testReplaceImagePath(string $app, string $image, string|bool $result = 'themingRoute?v=1234abcd'): void {
792
+	public function testReplaceImagePath(string $app, string $image, string | bool $result = 'themingRoute?v=1234abcd'): void {
793 793
 		$this->cache->expects($this->any())
794 794
 			->method('get')
795 795
 			->with('shouldReplaceIcons')
Please login to merge, or discard this patch.
apps/theming/tests/ServicesTest.php 1 patch
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -28,43 +28,43 @@
 block discarded – undo
28 28
  * @package OCA\Theming\Tests
29 29
  */
30 30
 class ServicesTest extends TestCase {
31
-	protected App $app;
31
+    protected App $app;
32 32
 
33
-	protected IAppContainer $container;
33
+    protected IAppContainer $container;
34 34
 
35
-	protected function setUp(): void {
36
-		parent::setUp();
37
-		$this->app = new App('theming');
38
-		$this->container = $this->app->getContainer();
39
-	}
35
+    protected function setUp(): void {
36
+        parent::setUp();
37
+        $this->app = new App('theming');
38
+        $this->container = $this->app->getContainer();
39
+    }
40 40
 
41
-	public static function queryData(): array {
42
-		return [
43
-			[IL10N::class],
41
+    public static function queryData(): array {
42
+        return [
43
+            [IL10N::class],
44 44
 
45
-			// lib/
46
-			[Capabilities::class],
47
-			[Capabilities::class, ICapability::class],
48
-			[ThemingDefaults::class],
49
-			[ThemingDefaults::class, \OC_Defaults::class],
50
-			[Util::class],
45
+            // lib/
46
+            [Capabilities::class],
47
+            [Capabilities::class, ICapability::class],
48
+            [ThemingDefaults::class],
49
+            [ThemingDefaults::class, \OC_Defaults::class],
50
+            [Util::class],
51 51
 
52
-			// Controller
53
-			[ThemingController::class, ThemingController::class],
52
+            // Controller
53
+            [ThemingController::class, ThemingController::class],
54 54
 
55
-			// Settings
56
-			[Admin::class],
57
-			[Admin::class, ISettings::class],
58
-			[PersonalSection::class],
59
-			[PersonalSection::class, IIconSection::class],
60
-		];
61
-	}
55
+            // Settings
56
+            [Admin::class],
57
+            [Admin::class, ISettings::class],
58
+            [PersonalSection::class],
59
+            [PersonalSection::class, IIconSection::class],
60
+        ];
61
+    }
62 62
 
63
-	#[\PHPUnit\Framework\Attributes\DataProvider('queryData')]
64
-	public function testContainerQuery(string $service, ?string $expected = null): void {
65
-		if ($expected === null) {
66
-			$expected = $service;
67
-		}
68
-		$this->assertInstanceOf($expected, $this->container->query($service));
69
-	}
63
+    #[\PHPUnit\Framework\Attributes\DataProvider('queryData')]
64
+    public function testContainerQuery(string $service, ?string $expected = null): void {
65
+        if ($expected === null) {
66
+            $expected = $service;
67
+        }
68
+        $this->assertInstanceOf($expected, $this->container->query($service));
69
+    }
70 70
 }
Please login to merge, or discard this patch.