ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
UninstallLanguageTest.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use ILIAS\UI\Component\Input\Factory as InputFactory;
27use PHPUnit\Framework\Attributes\DataProvider;
28
34{
36
38 {
39 [, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld(['de' => []]);
40
41 return $this->createActivity($lng_objects, $obj_language_factory);
42 }
43
44 protected function validPerformParameters(): array
45 {
46 return ['language_keys' => 'de'];
47 }
48
50 {
51 $rbac = $this->createStub(\ilRbacSystem::class);
52 $rbac->method('checkAccessOfUser')->willReturn(true);
53
54 $lng_objects = static fn(): array => [
55 ['obj_id' => 1, 'title' => 'de'],
56 ['obj_id' => 2, 'title' => 'de'],
57 ];
58 $obj_language_factory = static function (int $id): never {
59 throw new \LogicException('must never be called for an ambiguous title');
60 };
61
62 $result = $this->createActivity($lng_objects, $obj_language_factory, $rbac)
63 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, ['language_keys' => 'de']);
64
65 $this->assertTrue($result->isError());
66 $this->assertInstanceOf(\RuntimeException::class, $result->error());
67 }
68
74 private function buildFakeLanguageWorld(array $language_objects): array
75 {
76 $lng_objects_list = [];
77 $fakes_by_obj_id = [];
78 $obj_id = 1;
79
80 foreach ($language_objects as $language_key => $flags) {
81 $lng_objects_list[] = ['obj_id' => $obj_id, 'title' => $language_key];
82 $fakes_by_obj_id[$obj_id] = new FakeLanguageObject(
83 is_system_language: $flags['system'] ?? false,
84 is_user_language: $flags['user'] ?? false,
85 is_installed: $flags['installed'] ?? true,
86 uninstall_return_value: $flags['uninstall_return'] ?? 'uninstalled',
87 unwritten_overlay_modules: $flags['unwritten_overlay_modules'] ?? [],
88 );
89 $obj_id++;
90 }
91
92 $lng_objects = static fn(): array => $lng_objects_list;
93 $obj_language_factory = static fn(int $id): FakeLanguageObject => $fakes_by_obj_id[$id];
94
95 return [$fakes_by_obj_id, $lng_objects, $obj_language_factory];
96 }
97
99 {
100 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
101 'de' => [],
102 ]);
103
104 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
105 'language_keys' => 'de',
106 ]);
107
108 $this->assertSame(['de'], $result['uninstalled_language_keys']);
109 $this->assertSame([], $result['system_language_keys']);
110 $this->assertSame([], $result['user_language_keys']);
111 $this->assertSame([], $result['not_installed_language_keys']);
112 $this->assertSame([], $result['overlay_write_failed_language_keys']);
113 $this->assertSame(1, $fakes[1]->uninstallCallCount());
114 }
115
117 {
118 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
119 'de' => ['system' => true],
120 ]);
121
122 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
123 'language_keys' => 'de',
124 ]);
125
126 $this->assertSame([], $result['uninstalled_language_keys']);
127 $this->assertSame(['de'], $result['system_language_keys']);
128 $this->assertSame([], $result['user_language_keys']);
129 $this->assertSame([], $result['not_installed_language_keys']);
130 $this->assertSame(0, $fakes[1]->uninstallCallCount());
131 }
132
134 {
135 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
136 'de' => ['user' => true],
137 ]);
138
139 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
140 'language_keys' => 'de',
141 ]);
142
143 $this->assertSame([], $result['uninstalled_language_keys']);
144 $this->assertSame([], $result['system_language_keys']);
145 $this->assertSame(['de'], $result['user_language_keys']);
146 $this->assertSame([], $result['not_installed_language_keys']);
147 $this->assertSame(0, $fakes[1]->uninstallCallCount());
148 }
149
152 {
153 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
154 'de' => ['system' => true, 'user' => true],
155 ]);
156
157 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
158 'language_keys' => 'de',
159 ]);
160
161 $this->assertSame(['de'], $result['system_language_keys']);
162 $this->assertSame([], $result['user_language_keys']);
163 }
164
166 {
167 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
168 'de' => ['installed' => false],
169 ]);
170
171 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
172 'language_keys' => 'de',
173 ]);
174
175 $this->assertSame([], $result['uninstalled_language_keys']);
176 $this->assertSame([], $result['system_language_keys']);
177 $this->assertSame([], $result['user_language_keys']);
178 $this->assertSame(['de'], $result['not_installed_language_keys']);
179 $this->assertSame(0, $fakes[1]->uninstallCallCount());
180 }
181
184 {
185 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
186 'de' => ['uninstall_return' => ''],
187 ]);
188
189 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
190 'language_keys' => 'de',
191 ]);
192
193 $this->assertSame([], $result['uninstalled_language_keys']);
194 $this->assertSame([], $result['system_language_keys']);
195 $this->assertSame([], $result['user_language_keys']);
196 $this->assertSame(['de'], $result['not_installed_language_keys']);
197 // uninstall() must still have been attempted
198 $this->assertSame(1, $fakes[1]->uninstallCallCount());
199 }
200
203 {
204 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
205 'de' => ['unwritten_overlay_modules' => ['pilot']],
206 'fr' => [],
207 ]);
208
209 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform(['language_keys' => 'de,fr']);
210
211 $this->assertSame(['de', 'fr'], $result['uninstalled_language_keys']);
212 $this->assertSame(['de'], $result['overlay_write_failed_language_keys']);
213 $this->assertSame(1, $fakes[1]->uninstallCallCount());
214 }
215
218 {
219 [, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
220 'de' => ['uninstall_return' => '', 'unwritten_overlay_modules' => ['pilot']],
221 ]);
222
223 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform(['language_keys' => 'de']);
224
225 $this->assertSame(['de'], $result['not_installed_language_keys']);
226 $this->assertSame([], $result['overlay_write_failed_language_keys']);
227 }
228
231 {
232 $lng_objects = static fn(): array => [];
233 $factory_calls = [];
234 $obj_language_factory = static function (int $id) use (&$factory_calls): FakeLanguageObject {
235 $factory_calls[] = $id;
236 throw new \LogicException('must never be called for an unknown language key');
237 };
238
239 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
240 'language_keys' => 'xx',
241 ]);
242
243 $this->assertSame([], $result['uninstalled_language_keys']);
244 $this->assertSame([], $result['system_language_keys']);
245 $this->assertSame([], $result['user_language_keys']);
246 $this->assertSame(['xx'], $result['not_installed_language_keys']);
247 $this->assertSame([], $factory_calls);
248 }
249
254 {
255 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
256 'de' => [],
257 'en' => ['system' => true],
258 'fr' => ['user' => true],
259 'it' => ['installed' => false],
260 ]);
261
262 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
263 'language_keys' => ['de', 'en', 'fr', 'it', 'xx'],
264 ]);
265
266 $this->assertSame(['de'], $result['uninstalled_language_keys']);
267 $this->assertSame(['en'], $result['system_language_keys']);
268 $this->assertSame(['fr'], $result['user_language_keys']);
269 $this->assertSame(['it', 'xx'], $result['not_installed_language_keys']);
270
271 $this->assertSame(1, $fakes[1]->uninstallCallCount(), 'de must be uninstalled');
272 $this->assertSame(0, $fakes[2]->uninstallCallCount(), 'system language must never be uninstalled');
273 $this->assertSame(0, $fakes[3]->uninstallCallCount(), 'in-use language must never be uninstalled');
274 $this->assertSame(0, $fakes[4]->uninstallCallCount(), 'not-installed language must never be uninstalled');
275 }
276
278 {
279 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
280 'de' => [],
281 ]);
282
283 $result = $this->createActivity($lng_objects, $obj_language_factory)->perform([
284 'language_keys' => [' de, de ', 'de'],
285 ]);
286
287 $this->assertSame(['de'], $result['uninstalled_language_keys']);
288 $this->assertSame(1, $fakes[1]->uninstallCallCount());
289 }
290
291 public static function invalidLanguageKeysProvider(): array
292 {
293 return [
294 'missing language_keys key' => [[]],
295 'empty (only whitespace/commas)' => [['language_keys' => ' , ']],
296 'nested array value' => [['language_keys' => ['de', ['fr']]]],
297 'three letters' => [['language_keys' => 'deu']],
298 'one letter' => [['language_keys' => 'd']],
299 'uppercase' => [['language_keys' => 'DE']],
300 'contains a digit' => [['language_keys' => 'de1']],
301 'contains a hyphen' => [['language_keys' => 'de-at']],
302 ];
303 }
304
305 #[DataProvider('invalidLanguageKeysProvider')]
307 {
308 $this->expectException(InvalidInputException::class);
309
310 $this->createActivity(static fn(): array => [], static fn(int $id) => null)->perform($parameters);
311 }
312
314 public function testNonArrayParametersAreRejected(): void
315 {
316 $this->expectException(InvalidInputException::class);
317
318 $this->createActivity(static fn(): array => [], static fn(int $id) => null)->perform('not-an-array');
319 }
320
322 {
323 $text = $this->createMock(Text::class);
324 $text->expects($this->once())->method('withRequired')->with(true)->willReturnSelf();
325 $text->expects($this->once())
326 ->method('withDedicatedName')
327 ->with('language_keys')
328 ->willReturnSelf();
329
330 $field = $this->createMock(\ILIAS\UI\Component\Input\Field\Factory::class);
331 $field->expects($this->once())->method('text')->with(
332 'Language keys',
333 'Comma-separated list of language keys, e.g. de, fr, it.'
334 )->willReturn($text);
335 // no mode parameter: the select field must never be built
336 $field->expects($this->never())->method('select');
337
338 $group = $this->createMock(\ILIAS\UI\Component\Input\Field\Section::class);
339 $field->expects($this->once())
340 ->method('section')
341 ->with(['language_keys' => $text], $this->anything())
342 ->willReturn($group);
343
344 $activity = $this->createActivity(
345 static fn(): array => [],
346 static fn(int $id) => null
347 );
348
349 $this->assertSame($group, $activity->getInputDescription($field));
350 }
351
353 {
354 $rbac = $this->createMock(\ilRbacSystem::class);
355 $rbac->expects($this->once())
356 ->method('checkAccessOfUser')
357 ->with(6, 'write', $this->anything())
358 ->willReturn(false);
359
360 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
361 'de' => [],
362 ]);
363 $result = $this->createActivity(
364 $lng_objects,
365 $obj_language_factory,
366 $rbac
367 )->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, ['language_keys' => 'de']);
368
369 $this->assertTrue($result->isError());
370 $this->assertSame(0, $fakes[1]->uninstallCallCount());
371 }
372
374 {
375 $rbac = $this->createStub(\ilRbacSystem::class);
376 $rbac->method('checkAccessOfUser')->willReturn(true);
377
378 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
379 'de' => [],
380 ]);
381
382 $result = $this->createActivity(
383 $lng_objects,
384 $obj_language_factory,
385 $rbac
386 )->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, ['language_keys' => 'de']);
387
388 $this->assertFalse($result->isError());
389 $this->assertSame(['de'], $result->value()['uninstalled_language_keys']);
390 $this->assertSame(1, $fakes[1]->uninstallCallCount());
391 }
392
395 {
396 $rbac = $this->createStub(\ilRbacSystem::class);
397 $rbac->method('checkAccessOfUser')->willReturn(true);
398
399 [$fakes, $lng_objects, $obj_language_factory] = $this->buildFakeLanguageWorld([
400 'de' => [],
401 'fr' => [],
402 ]);
403
404 $result = $this->createActivity($lng_objects, $obj_language_factory, $rbac)
405 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, ['language_keys' => ['de', 'fr']]);
406
407 $this->assertFalse($result->isError());
408 $this->assertSame(['de', 'fr'], $result->value()['uninstalled_language_keys']);
409 $this->assertSame(1, $fakes[1]->uninstallCallCount());
410 $this->assertSame(1, $fakes[2]->uninstallCallCount());
411 }
412}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
Cross-checks the declared output field names against the keys perform() returns, using a real Descrip...
Stand-in for \ilObjLanguage, which needs the global $DIC; injected via UninstallLanguage's $obj_langu...
UninstallLanguage works on language objects behind a mocked RepositoryProvider, answering from small ...
testSystemLanguageTakesPriorityOverUserLanguage()
isSystemLanguage() takes priority over "in use" when both flags are set.
testNoOverlayWriteFailureIsReportedForALanguageUninstallRejected()
A language the guards of uninstall() rejected has no overlay state to report.
testMixedBulkRequestPartitionsEachKeyIntoTheCorrectBucket()
Languages in every state at once land in their own bucket; only the uninstalled one calls uninstall()...
testMaybePerformAsAcceptsAnArrayOfLanguageKeysAndUninstallsEachOne()
ilObjLanguageFolderGUI sends 'language_keys' as array of strings; the real grind() pipeline must join...
testLanguageWhereUninstallItselfRejectsIsReportedAsNotInstalled()
uninstall() returning '' is the authority: reported as not_installed_language_keys,...
testUnknownLanguageKeyIsReportedAsNotInstalledWithoutTouchingTheObjectFactory()
A key without a "lng" object is not installed, and the object factory is never invoked for it.
testOverlayWriteFailureIsReportedAlongsideTheSuccessfulUninstall()
A module whose PO/MO overlay could not be removed is reported in addition to the successful uninstall...
testNonArrayParametersAreRejected()
Pins InvalidInputException, not just its parent \InvalidArgumentException.
Definition: UI.php:27
This is how a factory for inputs looks like.
Definition: Factory.php:27
This describes text inputs.
Definition: Text.php:29
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
createActivity(\Closure $lng_objects, \Closure $obj_language_factory, ?\ilRbacSystem $rbac=null, int $language_folder_ref_id=0, ?RepositoryProvider $repository=null,)
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
$text
Definition: xapiexit.php:21