194 lines
7.7 KiB
PHP
194 lines
7.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Command;
|
|
|
|
use App\Command\BpnXmlAnonymizeCommand;
|
|
use App\Service\BpnXmlAnonymizer;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\Console\Command\Command;
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
|
|
|
class BpnXmlAnonymizeCommandTest extends TestCase
|
|
{
|
|
/** @var array<int, string> */
|
|
private array $tempDirectories = [];
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
foreach ($this->tempDirectories as $directory) {
|
|
$this->removeDirectory($directory);
|
|
}
|
|
|
|
$this->tempDirectories = [];
|
|
}
|
|
|
|
public function testSingleFileStillAnonymizesPairedResponseFile(): void
|
|
{
|
|
$inputDir = $this->createTempDirectory();
|
|
$outputDir = $this->createTempDirectory();
|
|
$inputFile = $inputDir.'/travel_request.xml';
|
|
$pairedInputFile = $inputDir.'/travel_response.xml';
|
|
$targetFile = $outputDir.'/travel_request.xml';
|
|
$pairedTargetFile = $outputDir.'/travel_response.xml';
|
|
|
|
file_put_contents($inputFile, '<xml>travel-request</xml>');
|
|
file_put_contents($pairedInputFile, '<xml>travel-response</xml>');
|
|
|
|
$calls = [];
|
|
$lastIdentityCount = 0;
|
|
$anonymizer = $this->createMock(BpnXmlAnonymizer::class);
|
|
$anonymizer->expects(self::once())
|
|
->method('resetState')
|
|
->willReturnCallback(static function () use (&$calls, &$lastIdentityCount): void {
|
|
$calls[] = ['resetState'];
|
|
$lastIdentityCount = 0;
|
|
});
|
|
$anonymizer->expects(self::exactly(2))
|
|
->method('anonymize')
|
|
->willReturnCallback(function (string $xml, bool $resetState) use (&$calls, &$lastIdentityCount): string {
|
|
$calls[] = ['anonymize', trim($xml), $resetState];
|
|
$lastIdentityCount = true === $resetState ? 1 : 2;
|
|
|
|
return sprintf('ANON:%s', trim($xml));
|
|
});
|
|
$anonymizer->method('getLastIdentityCount')
|
|
->willReturnCallback(function () use (&$lastIdentityCount): int {
|
|
return $lastIdentityCount;
|
|
});
|
|
|
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand($anonymizer));
|
|
$tester->execute([
|
|
'infile' => $inputFile,
|
|
'outfile' => $targetFile,
|
|
]);
|
|
|
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
self::assertSame('ANON:<xml>travel-request</xml>', trim((string) file_get_contents($targetFile)));
|
|
self::assertSame('ANON:<xml>travel-response</xml>', trim((string) file_get_contents($pairedTargetFile)));
|
|
self::assertSame([
|
|
['resetState'],
|
|
['anonymize', '<xml>travel-request</xml>', true],
|
|
['anonymize', '<xml>travel-response</xml>', false],
|
|
], $calls);
|
|
self::assertStringContainsString('Paired file anonymized', $tester->getDisplay());
|
|
}
|
|
|
|
public function testDirectoryInputAnonymizesAllPairsIntoOutputDirectory(): void
|
|
{
|
|
$inputDir = $this->createTempDirectory();
|
|
$outputDir = $this->createTempDirectory().'/anonymized';
|
|
|
|
file_put_contents($inputDir.'/alpha_request.xml', '<xml>alpha-request</xml>');
|
|
file_put_contents($inputDir.'/alpha_response.xml', '<xml>alpha-response</xml>');
|
|
file_put_contents($inputDir.'/beta_request.xml', '<xml>beta-request</xml>');
|
|
file_put_contents($inputDir.'/beta_response.xml', '<xml>beta-response</xml>');
|
|
|
|
$calls = [];
|
|
$lastIdentityCount = 0;
|
|
$anonymizer = $this->createMock(BpnXmlAnonymizer::class);
|
|
$anonymizer->expects(self::exactly(2))
|
|
->method('resetState')
|
|
->willReturnCallback(static function () use (&$calls, &$lastIdentityCount): void {
|
|
$calls[] = ['resetState'];
|
|
$lastIdentityCount = 0;
|
|
});
|
|
$anonymizer->expects(self::exactly(4))
|
|
->method('anonymize')
|
|
->willReturnCallback(function (string $xml, bool $resetState) use (&$calls, &$lastIdentityCount): string {
|
|
$content = trim($xml);
|
|
$calls[] = ['anonymize', $content, $resetState];
|
|
|
|
if (str_contains($content, 'request')) {
|
|
$lastIdentityCount = true === $resetState ? 1 : 0;
|
|
} else {
|
|
$lastIdentityCount = 2;
|
|
}
|
|
|
|
return sprintf('ANON:%s', $content);
|
|
});
|
|
$anonymizer->method('getLastIdentityCount')
|
|
->willReturnCallback(function () use (&$lastIdentityCount): int {
|
|
return $lastIdentityCount;
|
|
});
|
|
|
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand($anonymizer));
|
|
$tester->execute([
|
|
'infile' => $inputDir,
|
|
'outfile' => $outputDir,
|
|
]);
|
|
|
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
self::assertSame('ANON:<xml>alpha-request</xml>', trim((string) file_get_contents($outputDir.'/alpha_request.xml')));
|
|
self::assertSame('ANON:<xml>alpha-response</xml>', trim((string) file_get_contents($outputDir.'/alpha_response.xml')));
|
|
self::assertSame('ANON:<xml>beta-request</xml>', trim((string) file_get_contents($outputDir.'/beta_request.xml')));
|
|
self::assertSame('ANON:<xml>beta-response</xml>', trim((string) file_get_contents($outputDir.'/beta_response.xml')));
|
|
self::assertSame([
|
|
['resetState'],
|
|
['anonymize', '<xml>alpha-request</xml>', true],
|
|
['anonymize', '<xml>alpha-response</xml>', false],
|
|
['resetState'],
|
|
['anonymize', '<xml>beta-request</xml>', true],
|
|
['anonymize', '<xml>beta-response</xml>', false],
|
|
], $calls);
|
|
self::assertStringContainsString('Processed 4 XML files', $tester->getDisplay());
|
|
self::assertStringContainsString('Anonymized 4 persons', $tester->getDisplay());
|
|
}
|
|
|
|
public function testSingleFileWithoutSupportedPersonNodesWarnsInsteadOfClaimingSuccess(): void
|
|
{
|
|
$inputDir = $this->createTempDirectory();
|
|
$inputFile = $inputDir.'/meta.xml';
|
|
$targetFile = $inputDir.'/meta-out.xml';
|
|
|
|
file_put_contents($inputFile, '<?xml version="1.0" encoding="UTF-8"?><root><meta>hello</meta></root>');
|
|
|
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand(new BpnXmlAnonymizer()));
|
|
$tester->execute([
|
|
'infile' => $inputFile,
|
|
'outfile' => $targetFile,
|
|
]);
|
|
|
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
|
self::assertStringContainsString('No anonymizable person data found', $tester->getDisplay());
|
|
self::assertStringNotContainsString('Anonymized 0 persons', $tester->getDisplay());
|
|
self::assertFileExists($targetFile);
|
|
}
|
|
|
|
private function createTempDirectory(): string
|
|
{
|
|
$directory = sys_get_temp_dir().'/bpn-xml-anonymize-'.bin2hex(random_bytes(6));
|
|
if (false === mkdir($directory, 0777, true) && false === is_dir($directory)) {
|
|
self::fail(sprintf('Unable to create temporary directory: %s', $directory));
|
|
}
|
|
|
|
$this->tempDirectories[] = $directory;
|
|
|
|
return $directory;
|
|
}
|
|
|
|
private function removeDirectory(string $directory): void
|
|
{
|
|
if (false === is_dir($directory)) {
|
|
return;
|
|
}
|
|
|
|
$items = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
|
|
\RecursiveIteratorIterator::CHILD_FIRST,
|
|
);
|
|
|
|
foreach ($items as $item) {
|
|
if ($item->isDir()) {
|
|
rmdir($item->getPathname());
|
|
continue;
|
|
}
|
|
|
|
unlink($item->getPathname());
|
|
}
|
|
|
|
rmdir($directory);
|
|
}
|
|
}
|