14declare(strict_types=1);
26use PHPUnit\Framework\Attributes\DataProvider;
27use PHPUnit\Framework\MockObject\MockObject;
43 $rbac = $this->createMock(\ilRbacSystem::class);
44 $rbac->expects($this->once())
45 ->method(
'checkAccessOfUser')
46 ->with(6,
'write', 42)
49 $activity = $this->
createActivity(rbac_system: $rbac, language_folder_ref_id: 42);
51 $this->assertTrue($activity->isAllowedToPerform(6, [
'language_key' =>
'de',
'enabled' =>
true]));
56 $rbac = $this->createStub(\ilRbacSystem::class);
57 $rbac->method(
'checkAccessOfUser')->willReturn(
false);
61 $this->assertFalse($activity->isAllowedToPerform(6, [
'language_key' =>
'de',
'enabled' =>
true]));
67 $repository = $this->createMock(RepositoryProvider::class);
68 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
69 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
71 $rbac = $this->createStub(\ilRbacSystem::class);
72 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
76 $this->assertTrue($activity->isAllowedToPerform(6, [
'language_key' =>
'de',
'enabled' =>
true]));
83 'stored off, request on -> changed, write on' => [
false,
true,
true,
true],
84 'stored off, request off -> unchanged, no write' => [
false,
false,
false,
null],
85 'stored on, request on -> unchanged, no write' => [
true,
true,
false,
null],
86 'stored on, request off -> changed, write off' => [
true,
false,
true,
false],
90 #[DataProvider('performChangedDecisionProvider')]
93 bool $requested_enabled,
94 bool $expected_changed,
95 ?
bool $expected_written_value
98 $repository->expects($this->once())->method(
'isPageTranslationEnabled')
100 ->willReturn($stored_value);
102 if ($expected_written_value ===
null) {
103 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
105 $repository->expects($this->once())
106 ->method(
'setPageTranslationEnabled')
107 ->with(
'de', $expected_written_value);
111 ->perform([
'language_key' =>
'de',
'enabled' => $requested_enabled]);
114 [
'language_key' =>
'de',
'enabled' => $requested_enabled,
'changed' => $expected_changed],
122 $repository = $this->createMock(RepositoryProvider::class);
123 $repository->expects($this->once())
124 ->method(
'isPageTranslationEnabled')->with(
'fr')->willReturn(
false);
132 $repository = $this->createMock(RepositoryProvider::class);
133 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
false);
134 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
true);
137 ->perform([
'language_key' =>
' de ',
'enabled' =>
true]);
139 $this->assertSame(
'de', $result[
'language_key']);
145 'non-array parameters' => [
'not-an-array'],
146 'empty array' => [[]],
147 'missing language_key' => [[
'enabled' =>
true]],
148 'non-string language_key' => [[
'language_key' => 42,
'enabled' =>
true]],
149 'empty string language_key' => [[
'language_key' =>
'',
'enabled' =>
true]],
150 'whitespace-only language_key' => [[
'language_key' =>
' ',
'enabled' =>
true]],
151 'missing enabled' => [[
'language_key' =>
'de']],
152 'non-bool enabled: string "1"' => [[
'language_key' =>
'de',
'enabled' =>
'1']],
153 'non-bool enabled: string "true"' => [[
'language_key' =>
'de',
'enabled' =>
'true']],
154 'non-bool enabled: string ""' => [[
'language_key' =>
'de',
'enabled' =>
'']],
155 'non-bool enabled: int 1' => [[
'language_key' =>
'de',
'enabled' => 1]],
156 'non-bool enabled: int 0' => [[
'language_key' =>
'de',
'enabled' => 0]],
157 'non-bool enabled: float 1.0' => [[
'language_key' =>
'de',
'enabled' => 1.0]],
158 'non-bool enabled: null' => [[
'language_key' =>
'de',
'enabled' =>
null]],
159 'non-bool enabled: array' => [[
'language_key' =>
'de',
'enabled' => [
true]]],
163 #[DataProvider('invalidPerformParametersProvider')]
166 $repository = $this->createMock(RepositoryProvider::class);
167 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
168 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
170 $this->expectException(InvalidInputException::class);
177 $rbac = $this->createStub(\ilRbacSystem::class);
178 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
180 $repository = $this->createMock(RepositoryProvider::class);
181 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
false);
182 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
true);
185 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de',
'enabled' =>
true]);
187 $this->assertFalse($result->isError());
189 [
'language_key' =>
'de',
'enabled' =>
true,
'changed' =>
true],
197 $rbac = $this->createMock(\ilRbacSystem::class);
198 $rbac->expects($this->once())
199 ->method(
'checkAccessOfUser')
200 ->with(6,
'write', $this->anything())
203 $repository = $this->createMock(RepositoryProvider::class);
204 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
205 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
208 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de',
'enabled' =>
true]);
210 $this->assertTrue($result->isError());
211 $this->assertInstanceOf(\DomainException::class, $result->error());
212 $this->assertSame(403, $result->error()->getCode());
218 $rbac = $this->createStub(\ilRbacSystem::class);
219 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
221 $repository = $this->createMock(RepositoryProvider::class);
222 $repository->method(
'isPageTranslationEnabled')->willReturn(
false);
223 $repository->method(
'setPageTranslationEnabled')->willThrowException(
new \RuntimeException(
'database write failed'));
226 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de',
'enabled' =>
true]);
228 $this->assertTrue($result->isError());
229 $error = $result->error();
230 $this->assertSame(500,
$error->getCode());
231 $this->assertSame(
'database write failed',
$error->getPrevious()?->
getMessage());
237 $rbac = $this->createMock(\ilRbacSystem::class);
238 $rbac->expects($this->never())->method(
'checkAccessOfUser');
240 $result = $this->
createActivity(rbac_system: $rbac)->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, []);
242 $this->assertTrue($result->isError());
243 $this->assertInstanceOf(InvalidInputException::class, $result->error());
244 $this->assertNotSame(
'', $result->error()->getMessage());
250 'missing language_key' => [[
'enabled' =>
true]],
254 #[DataProvider('invalidRawParametersRejectedByGrindWithStringErrorProvider')]
256 array $raw_parameters
259 $rbac->expects($this->never())->method(
'checkAccessOfUser');
261 $repository = $this->createMock(RepositoryProvider::class);
262 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
263 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
266 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, $raw_parameters);
268 $this->assertTrue($result->isError());
269 $this->assertInstanceOf(InvalidInputException::class, $result->error());
270 $this->assertNotSame(
'', $result->error()->getMessage());
277 'non-string language_key' => [[
'language_key' => 42,
'enabled' =>
true]],
279 'non-bool enabled: array' => [[
'language_key' =>
'de',
'enabled' => [
true]]],
280 'non-bool enabled: float 1.0' => [[
'language_key' =>
'de',
'enabled' => 1.0]],
284 #[DataProvider('invalidRawParametersProvider')]
286 array $raw_parameters
289 $rbac->expects($this->never())->method(
'checkAccessOfUser');
291 $repository = $this->createMock(RepositoryProvider::class);
292 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
293 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
296 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, $raw_parameters);
298 $this->assertTrue($result->isError());
299 $this->assertInstanceOf(InvalidInputException::class, $result->error());
300 $this->assertSame(400, $result->error()->getCode());
306 $rbac = $this->createMock(\ilRbacSystem::class);
307 $rbac->expects($this->once())->method(
'checkAccessOfUser')->willReturn(
true);
309 $repository = $this->createMock(RepositoryProvider::class);
310 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
true);
311 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
false);
314 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de']);
316 $this->assertFalse($result->isError());
318 [
'language_key' =>
'de',
'enabled' =>
false,
'changed' =>
true],
326 $rbac = $this->createMock(\ilRbacSystem::class);
327 $rbac->expects($this->once())->method(
'checkAccessOfUser')->willReturn(
true);
329 $repository = $this->createMock(RepositoryProvider::class);
330 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
331 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
334 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
' ',
'enabled' =>
true]);
336 $this->assertTrue($result->isError());
337 $this->assertInstanceOf(InvalidInputException::class, $result->error());
338 $this->assertSame(400, $result->error()->getCode());
344 'string "1"' => [
'1'],
345 'string "true"' => [
'true'],
353 'string "0"' => [
'0'],
354 'string "false"' => [
'false'],
362 #[DataProvider('tolerantlyAcceptedTruthyEnabledValuesProvider')]
365 $rbac = $this->createStub(\ilRbacSystem::class);
366 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
368 $repository = $this->createMock(RepositoryProvider::class);
369 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
false);
370 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
true);
373 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de',
'enabled' => $value]);
375 $this->assertFalse($result->isError());
377 [
'language_key' =>
'de',
'enabled' =>
true,
'changed' =>
true],
383 #[DataProvider('tolerantlyAcceptedFalsyEnabledValuesProvider')]
386 $rbac = $this->createStub(\ilRbacSystem::class);
387 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
389 $repository = $this->createMock(RepositoryProvider::class);
390 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
true);
391 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
false);
394 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'de',
'enabled' => $value]);
396 $this->assertFalse($result->isError());
398 [
'language_key' =>
'de',
'enabled' =>
false,
'changed' =>
true],
406 $repository = $this->createMock(RepositoryProvider::class);
407 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
408 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
410 $this->expectException(InvalidInputException::class);
413 ->perform([
'language_key' =>
'xx',
'enabled' =>
true]);
419 $repository = $this->createMock(RepositoryProvider::class);
420 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
421 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
423 $dangerous_key =
'<script>alert(1)</script>&"quoted"';
427 ->perform([
'language_key' => $dangerous_key,
'enabled' =>
true]);
428 $this->fail(
'Expected an InvalidInputException to be thrown.');
430 $this->assertStringContainsString($dangerous_key,
$e->getMessage());
431 $this->assertStringNotContainsString(
'<script>',
$e->getMessage());
432 $this->assertStringNotContainsString(
'"',
$e->getMessage());
439 $rbac = $this->createMock(\ilRbacSystem::class);
440 $rbac->expects($this->once())->method(
'checkAccessOfUser')->willReturn(
true);
442 $repository = $this->createMock(RepositoryProvider::class);
443 $repository->expects($this->never())->method(
'isPageTranslationEnabled');
444 $repository->expects($this->never())->method(
'setPageTranslationEnabled');
447 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
'xx',
'enabled' =>
true]);
449 $this->assertTrue($result->isError());
450 $this->assertInstanceOf(InvalidInputException::class, $result->error());
451 $this->assertSame(400, $result->error()->getCode());
457 $rbac = $this->createStub(\ilRbacSystem::class);
458 $rbac->method(
'checkAccessOfUser')->willReturn(
true);
460 $repository = $this->createMock(RepositoryProvider::class);
461 $repository->expects($this->once())->method(
'isPageTranslationEnabled')->with(
'de')->willReturn(
false);
462 $repository->expects($this->once())->method(
'setPageTranslationEnabled')->with(
'de',
true);
465 ->maybePerformAs($this->createRealFieldsUiFactory()->input(), 6, [
'language_key' =>
' de ',
'enabled' =>
true]);
467 $this->assertFalse($result->isError());
468 $this->assertSame(
'de', $result->value()[
'language_key']);
473 $text = $this->createMock(Text::class);
474 $text->expects($this->once())->method(
'withRequired')->with(
true)->willReturnSelf();
475 $text->expects($this->once())->method(
'withDedicatedName')->with(
'language_key')->willReturnSelf();
477 $checkbox = $this->createMock(Checkbox::class);
478 $checkbox->expects($this->once())
479 ->method(
'withDedicatedName')
484 $field->expects($this->once())
488 'Language key the page translation setting applies to, e.g. de, fr, it.'
491 $field->expects($this->once())
495 'Whether page translation should be enabled for this language.'
497 ->willReturn($checkbox);
500 $field->expects($this->once())
502 ->with([
'language_key' =>
$text,
'enabled' => $checkbox], $this->anything())
503 ->willReturn($group);
507 $this->assertSame($group, $activity->getInputDescription($field));
515 $description = $activity->getOutputDescription(
new DescriptionFactory());
518 foreach ($description->getFields() as $field) {
519 $field_names[] = $field->getName();
522 $this->assertSame([
'language_key',
'enabled',
'changed'], $field_names);
528 int $language_folder_ref_id = 0,
529 array $installed_languages = [
'de',
'fr'],
532 $repository->method(
'getInstalledLanguages')->willReturn($installed_languages);
535 $this->rbacOf($rbac_system ?? $this->createMock(\ilRbacSystem::class)),
536 $this->languageFolder($language_folder_ref_id),
Every legacy and repository access of the runtime language activities.
Contract tests shared by every Activity test case; subclasses only supply createDefaultActivity().
Unlike SetLanguageDetectionEnabled it is parameterised by a language_key, and perform() itself valida...
testMaybePerformAsToleratesCommonPrimitiveTruthyEnabledRepresentations(mixed $value)
Unlike perform(), maybePerformAs() accepts common primitive representations of "true".
testMaybePerformAsTrimsLanguageKeyBeforeBuildingTheSettingKey()
A language_key with surrounding whitespace resolves to the same setting key as via perform().
static invalidRawParametersRejectedByGrindWithStringErrorProvider()
testInputDescriptionBuildsAGroupWithARequiredLanguageKeyTextFieldAndAnEnabledCheckbox()
testMaybePerformAsToleratesCommonPrimitiveFalsyEnabledRepresentations(mixed $value)
Same for "false".
testPerformWritesOnlyWhenTheRequestedValueDiffersFromTheStoredOne(bool $stored_value, bool $requested_enabled, bool $expected_changed, ?bool $expected_written_value)
static invalidPerformParametersProvider()
static tolerantlyAcceptedFalsyEnabledValuesProvider()
testMaybePerformAsRejectsWhitespaceOnlyLanguageKeyAfterThePermissionCheck()
A whitespace-only language_key passes grind()'s required-check, so perform() rejects it after the per...
testPerformRejectsInvalidOrIncompleteParametersWithoutTouchingSettings(mixed $parameters)
testMaybePerformAsWithMissingRawParametersKeysIsAResultErrorAndNeverChecksPermission()
A missing 'language_key' fails the required Text field in grind(), before rbac is touched.
testMaybePerformAsRejectsInvalidRawParametersAsResultErrorWithoutTouchingSettingsOrRbac(array $raw_parameters)
createActivity(?\ilRbacSystem $rbac_system=null,(RepositoryProvider &MockObject)|null $repository=null, int $language_folder_ref_id=0, array $installed_languages=['de', 'fr'],)
testMaybePerformAsWithMissingEnabledKeyDefaultsToFalseAndStillPerformsTheWrite()
A missing 'enabled' defaults to false like an unchecked HTML checkbox, and still reaches perform().
testPerformReadsTheCorrectPerLanguageSettingKeyWithDefaultZero()
Pins the key "lang_translate_<language_key>" and the default '0'.
static tolerantlyAcceptedTruthyEnabledValuesProvider()
testPerformRejectsUnknownLanguageKeyWithoutTouchingSettings()
An unknown language_key is rejected by perform() itself, for direct callers too.
testPerformRejectsUnknownLanguageKeyMessageContainsTheRawUnescapedKey()
The message embeds the key raw: escaping is RendersActivityErrors' job.
testIsAllowedToPerformNeverTouchesSettings()
isAllowedToPerform() is a pure permission check: no Setting access.
testPerformTrimsLanguageKeyForBothTheSettingKeyAndTheReturnedValue()
perform() re-implements its own trim() of language_key.
static invalidRawParametersProvider()
testMaybePerformAsWithGrantedPermissionPerformsAndReturnsOkResult()
testIsAllowedToPerformDelegatesToRbacSystemWithWriteAndTheConfiguredRefId()
testOutputDescriptionDescribesTheThreeDocumentedFieldsInOrder()
Real DescriptionFactory: a mocked with([...]) would accept the fields in any order.
static performChangedDecisionProvider()
Only a difference between the stored and the requested value is written.
testDefectFromWithinPerformIsMaskedAsA500ResultError()
A Throwable from perform() becomes a Result\Error.
testIsAllowedToPerformReturnsFalseWhenRbacDenies()
testMaybePerformAsRejectsRawParametersAtGrindLevelWithStringErrorWithoutTouchingSettingsOrRbac(array $raw_parameters)
testMaybePerformAsWithDeniedPermissionReturnsErrorAndNeverTouchesSettings()
A denied "write" yields a Result\Error and leaves the Setting untouched.
testMaybePerformAsRejectsUnknownLanguageKeyAfterPermissionCheckAndNeverTouchesSettings()
Same rejection end-to-end: it passes grind() and the permission check, perform() rejects it.
class ilRbacSystem system function like checkAccess, addActiveRole ... Supporting system functions ar...
This describes text inputs.
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.