Files
myep/tests/Command/BpnXmlAnonymizeCommandTest.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);
}
}