19declare(strict_types=1);
24use PHPUnit\Framework\TestCase;
45 protected function setUp(): void
48 $this->root = sys_get_temp_dir() .
'/ilias_overlay_revisions_' . bin2hex(random_bytes(6));
49 $this->client_data_dir = $this->root .
'/client';
50 mkdir($this->client_data_dir, 0775,
true);
53 $this->root .
'/rvs/rvs_de.po',
72 private function sync(array $entries): void
82 private function served(
string $key =
'greeting'): ?string
92 $revisions = array_values(array_filter(
105 return is_file($file) ? trim((
string) file_get_contents($file)) :
null;
111 foreach ([
'Servus',
'Moin',
'Grüß Gott',
'Servus',
'Tach'] as $value) {
112 $this->
sync([
'greeting' => $value]);
115 $this->assertNotNull($current);
116 $this->assertNotSame($previous, $current);
117 $this->assertSame($value, $this->
served(),
'visible in the process that wrote it');
118 $this->assertSame(
'Anders', $this->
served(
'other'),
'the shipped values stay served');
119 $expected = array_values(array_filter([$current, $previous]));
121 $this->assertSame($expected, $this->
revisions(),
'the current revision and the one served before it - nothing older');
122 $previous = $current;
128 $this->
sync([
'greeting' =>
'Servus']);
131 $inode = fileinode($current_file);
134 $this->
sync([
'greeting' =>
'Servus']);
136 $this->assertSame($current, $this->
current());
137 $this->assertSame([$current], $this->
revisions());
138 $this->assertSame($inode, fileinode($current_file),
'`current` was not written again');
143 $this->
sync([
'greeting' =>
'Servus']);
144 $first = (string) $this->
current();
145 $this->
sync([
'greeting' =>
'Moin']);
146 $second = (string) $this->
current();
148 $this->
sync([
'greeting' =>
'Servus']);
150 $this->assertSame($first, $this->
current());
151 $this->assertSame(
'Servus', $this->
served());
152 $expected = [$first, $second];
154 $this->assertSame($expected, $this->
revisions());
159 $this->
sync([
'greeting' =>
'Servus']);
160 $damaged = (string) $this->
current();
161 $this->
sync([
'greeting' =>
'Moin']);
162 $kept = (string) $this->
current();
169 file_put_contents($mo,
'garbage');
171 $this->
sync([
'greeting' =>
'Servus']);
173 $current = (string) $this->
current();
174 $this->assertNotSame($damaged, $current);
175 $this->assertSame(
'Servus', $this->
served());
177 [
'greeting' =>
'Servus'],
184 $expected = [$current, $kept];
186 $this->assertSame($expected, $this->
revisions(),
'the damaged one is gone, the previous one is kept');
191 $this->
sync([
'greeting' =>
'Servus']);
192 $this->
sync([
'greeting' =>
'Moin']);
194 $this->assertFileExists($overlay_po);
196 $this->
sync([
'greeting' =>
'Hallo',
'other' =>
'Anders']);
198 $this->assertFileDoesNotExist($overlay_po);
199 $this->assertNull($this->
current(),
'nothing is named any more, so nothing of the old revisions is served');
200 $this->assertSame(
'Hallo', $this->
served());
203 $this->
sync([
'greeting' =>
'Hallo',
'other' =>
'Anders']);
205 $this->assertSame([], $this->
revisions());
210 $this->
sync([
'greeting' =>
'Servus']);
213 $this->assertCount(1, $this->
revisions(),
'precondition: what a crash or an old version leaves behind');
215 $this->
sync([
'greeting' =>
'Hallo',
'other' =>
'Anders']);
217 $this->assertSame([], $this->
revisions());
218 $this->assertSame(
'Hallo', $this->
served());
trait RestoresProcessState
Whatever a test does to the process (locale, LANGUAGE/LC_*, LOCPATH, the static state of the runtime ...
static isOverlayRevision(string $name)
static overlayRevisionDirectory(string $overlay_directory, string $revision)
One compiled revision of the overlay in $overlay_directory: r-<hash>/, bound with bindtextdomain() as...
static overlayMoFile(string $revision_directory, string $module, string $lang_key)
The compiled overlay of $module for $lang_key in $revision_directory: r-<hash>/messages/LC_MESSAGES/<...
static overlayDirectory(string $client_data_dir, string $module, string $lang_key)
The overlay of $module for $lang_key lives in <client data dir>/lang/<module>/<lang>/: the ....
static overlayLockFile(string $overlay_directory)
The lock file serializing the writes of the overlay in $overlay_directory.
static overlayCurrentFile(string $overlay_directory)
The file naming the revision (see overlayRevisionDirectory()) of the overlay in $overlay_directory th...
The revisions of an overlay (<client data dir>/lang/<module>/<lang>/r-<hash>/, named by current) as M...
LanguageFileDirectoryManager $manager
testRevisionsWithoutAnOverlayAreRemovedByTheNextSyncOfShippedValues()
testADamagedRevisionIsNeverReusedAndNeverChangedInPlace()
testSyncingTheSameContentAgainWritesNothingNew()
testEveryNewRevisionIsServedAtOnceAndOnlyTheCurrentAndThePreviousOneStay()
served(string $key='greeting')
testAnOverlayThatBecameEmptyServesTheShippedValuesAgainAndTheNextSyncRemovesItsRevisions()
testGoingBackToTheContentOfTheKeptPreviousRevisionReusesIt()
static sync(LanguageFileDirectoryManager $language_file_directory_manager, string $ilias_absolute_path, string $lang_key, string $module, array $entries, ?string $client_data_dir, bool $refresh_original_from_shipped=false, ?bool $expected_overlay_exists=null, ?array $remarks=null, array $local_change_dates=[])
Brings the overlay of $module/$lang_key in line with $entries, the complete final content of the modu...
TranslationRepository over the build (ShippedTranslationsBuild) with the overlay of local changes (Mi...
Fixture helpers for PO/MO migrated modules, built with the component's own gettext adapter (Translati...
static directory(string $prefix, string $path, bool $local=false)
static catalog(string $module, array $entries)
static readMo(string $file)
static writePo(string $file, TranslationCatalog $catalog)
static removeDirectory(string $directory)
static build(LanguageFileDirectoryManager $manager, string $ilias_absolute_path)
Builds the shipped .po files of $manager below $ilias_absolute_path into the artifact directory of re...
static resetRuntime(?string $artifact_directory=null)
Forgets the static state of the runtime read path and points build and runtime at $artifact_directory...