Skip to content

Commit 12aa3f8

Browse files
author
Konrad Michalik
authored
Merge pull request #82 from move-elevator/support-empty-xliff
feat: enhance MismatchValidator to track empty files
2 parents 4cd989b + cde4039 commit 12aa3f8

2 files changed

Lines changed: 120 additions & 10 deletions

File tree

src/Validator/MismatchValidator.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,17 @@ class MismatchValidator extends AbstractValidator implements ValidatorInterface
3838
public function processFile(ParserInterface $file): array
3939
{
4040
$keys = $file->extractKeys();
41+
$fileKey = !empty($this->currentFilePath) ? $this->currentFilePath : $file->getFileName();
4142

4243
if (!$keys) {
43-
$this->logger?->error('The source file '.$file->getFileName().' is not valid.');
44+
// Track empty files with an empty array to detect missing translations
45+
$this->keyArray[$fileKey] = [];
4446

4547
return [];
4648
}
49+
4750
foreach ($keys as $key) {
4851
$value = $file->getContentByKey($key);
49-
$fileKey = !empty($this->currentFilePath) ? $this->currentFilePath : $file->getFileName();
5052
$this->keyArray[$fileKey][$key] = $value ?? null;
5153
}
5254

@@ -170,7 +172,7 @@ public function renderDetailedOutput(OutputInterface $output, array $issues): vo
170172
$files = $details['files'] ?? [];
171173
$currentFile = basename($issue->getFile());
172174

173-
if (!in_array($key, $allKeys)) {
175+
if (!in_array($key, $allKeys, true)) {
174176
$allKeys[] = $key;
175177
}
176178

tests/src/Validator/MismatchValidatorTest.php

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,23 @@ public function testProcessFile(): void
5757
);
5858
}
5959

60-
public function testProcessFileWithInvalidFile(): void
60+
public function testProcessFileWithEmptyFile(): void
6161
{
6262
$parser = $this->createMock(ParserInterface::class);
63-
$parser->method('extractKeys')->willReturn(null);
64-
$parser->method('getFileName')->willReturn('invalid.xlf');
63+
$parser->method('extractKeys')->willReturn([]);
64+
$parser->method('getFileName')->willReturn('empty.xlf');
6565

6666
$logger = $this->createMock(LoggerInterface::class);
67-
$logger->expects($this->once())
68-
->method('error')
69-
->with($this->stringContains('The source file invalid.xlf is not valid.'));
70-
7167
$validator = new MismatchValidator($logger);
7268
$result = $validator->processFile($parser);
7369

70+
// Empty files should now be tracked with an empty array
71+
$reflection = new ReflectionClass($validator);
72+
$keyArrayProperty = $reflection->getProperty('keyArray');
73+
$keyArray = $keyArrayProperty->getValue($validator);
74+
75+
$this->assertArrayHasKey('empty.xlf', $keyArray);
76+
$this->assertSame([], $keyArray['empty.xlf']);
7477
$this->assertEmpty($result);
7578
}
7679

@@ -316,4 +319,109 @@ public function testGetShortName(): void
316319

317320
$this->assertSame('MismatchValidator', $validator->getShortName());
318321
}
322+
323+
public function testPostProcessDetectsEmptyFileWithMissingKeys(): void
324+
{
325+
$parser1 = $this->createMock(ParserInterface::class);
326+
$parser1->method('extractKeys')->willReturn(['key1', 'key2']);
327+
$parser1->method('getFileName')->willReturn('source.xlf');
328+
329+
$parser2 = $this->createMock(ParserInterface::class);
330+
$parser2->method('extractKeys')->willReturn([]);
331+
$parser2->method('getFileName')->willReturn('empty.xlf');
332+
333+
$logger = $this->createMock(LoggerInterface::class);
334+
$validator = new MismatchValidator($logger);
335+
336+
$validator->processFile($parser1);
337+
$validator->processFile($parser2);
338+
339+
$validator->postProcess();
340+
341+
// Accessing protected property for testing purposes
342+
$reflection = new ReflectionClass($validator);
343+
$issuesProperty = $reflection->getProperty('issues');
344+
$issues = $issuesProperty->getValue($validator);
345+
346+
// Should detect both keys as missing in the empty file
347+
$this->assertCount(2, $issues);
348+
349+
$issueArrays = array_map(fn ($issue) => $issue->toArray(), $issues);
350+
351+
// Check that both key1 and key2 are reported as mismatches
352+
$keys = array_map(fn ($issue) => $issue['issues']['key'], $issueArrays);
353+
$this->assertContains('key1', $keys);
354+
$this->assertContains('key2', $keys);
355+
356+
// Verify that the empty file is included in the details
357+
foreach ($issueArrays as $issueArray) {
358+
$files = $issueArray['issues']['files'];
359+
$this->assertCount(2, $files);
360+
361+
$fileNames = array_map(fn ($file) => $file['file'], $files);
362+
$this->assertContains('source.xlf', $fileNames);
363+
$this->assertContains('empty.xlf', $fileNames);
364+
365+
// Empty file should have null value for all keys
366+
foreach ($files as $file) {
367+
if ('empty.xlf' === $file['file']) {
368+
$this->assertNull($file['value']);
369+
}
370+
}
371+
}
372+
}
373+
374+
public function testPostProcessWithMixedScenario(): void
375+
{
376+
// Source file with 6 keys
377+
$parser1 = $this->createMock(ParserInterface::class);
378+
$parser1->method('extractKeys')->willReturn(['key1', 'key2', 'key3', 'key4', 'key5', 'key6']);
379+
$parser1->method('getFileName')->willReturn('source.xlf');
380+
381+
// Partial translation file with 3 keys
382+
$parser2 = $this->createMock(ParserInterface::class);
383+
$parser2->method('extractKeys')->willReturn(['key1', 'key2', 'key3']);
384+
$parser2->method('getFileName')->willReturn('partial.xlf');
385+
386+
// Empty translation file
387+
$parser3 = $this->createMock(ParserInterface::class);
388+
$parser3->method('extractKeys')->willReturn([]);
389+
$parser3->method('getFileName')->willReturn('empty.xlf');
390+
391+
$logger = $this->createMock(LoggerInterface::class);
392+
$validator = new MismatchValidator($logger);
393+
394+
$validator->processFile($parser1);
395+
$validator->processFile($parser2);
396+
$validator->processFile($parser3);
397+
398+
$validator->postProcess();
399+
400+
// Accessing protected property for testing purposes
401+
$reflection = new ReflectionClass($validator);
402+
$issuesProperty = $reflection->getProperty('issues');
403+
$issues = $issuesProperty->getValue($validator);
404+
405+
// Should detect all 6 keys as mismatches since:
406+
// - key1, key2, key3 are missing from empty.xlf
407+
// - key4, key5, key6 are missing from both partial.xlf and empty.xlf
408+
$this->assertCount(6, $issues);
409+
410+
$issueArrays = array_map(fn ($issue) => $issue->toArray(), $issues);
411+
$keys = array_map(fn ($issue) => $issue['issues']['key'], $issueArrays);
412+
413+
// All keys should be reported as missing somewhere
414+
$this->assertContains('key1', $keys);
415+
$this->assertContains('key2', $keys);
416+
$this->assertContains('key3', $keys);
417+
$this->assertContains('key4', $keys);
418+
$this->assertContains('key5', $keys);
419+
$this->assertContains('key6', $keys);
420+
421+
// Verify that all three files are tracked in each issue
422+
foreach ($issueArrays as $issueArray) {
423+
$files = $issueArray['issues']['files'];
424+
$this->assertCount(3, $files);
425+
}
426+
}
319427
}

0 commit comments

Comments
 (0)