Skip to content

Instantly share code, notes, and snippets.

@mfn
Last active March 11, 2021 15:33
Show Gist options
  • Save mfn/e865d539010d1ed78bc1b16cfe15b2cc to your computer and use it in GitHub Desktop.
Save mfn/e865d539010d1ed78bc1b16cfe15b2cc to your computer and use it in GitHub Desktop.
Take the output of https://gist.github.com/mfn/256636242cbe8a51252ce28181a6b074 and rewrite an existing phpunit.xml to use only these test classes (mapped to files)
#!/usr/bin/env php
<?php declare(strict_types = 1);
$command = array_shift($argv);
if (3 !== count($argv)) {
echo <<<USAGE
Usage: $command path/to/composer.json path/to/phpunit.xml path/to/slice.xml > new_phpunit.xml
Based on your composer PSR-4 autoload configuration, the classes referenced
in slice.xml will be converted to test files and replace any <testsuites> in
your phpunit.xml with a list of all the files.
USAGE;
exit(1);
}
$composerJson = json_decode(file_get_contents($argv[0]), true, 512, JSON_THROW_ON_ERROR);
$psr4Autoloaders = array_merge(
$composerJson['autoload-dev']['psr-4'] ?? [],
$composerJson['autoload']['psr-4'] ?? [],
);
if (!$psr4Autoloaders) {
throw new RuntimeException('No PSR-4 autoloaders found in composer.json!');
}
$mapper = new MapClassToFile($psr4Autoloaders);
$classes = [];
$slicedXml = simplexml_load_file($argv[2]);
foreach ($slicedXml->testCaseClass as $class) {
$classes[$class['name']->__toString()] = true;
}
unset($slicedXml);
$phpunitXml = simplexml_load_file($argv[1]);
// Remove all existing suites
unset($phpunitXml->testsuites->testsuite);
$testsuite = $phpunitXml->testsuites->addChild('testsuite');
$testsuite->addAttribute('name', $argv[2]);
foreach (array_keys($classes) as $class) {
$file = $mapper->map($class);
$testsuite->addChild('file', $file);
}
echo $phpunitXml->asXML();
class MapClassToFile
{
private array $psr4Autoloaders;
public function __construct(array $psr4Autoloaders)
{
$this->psr4Autoloaders = $psr4Autoloaders;
}
public function map(string $class): string
{
foreach ($this->psr4Autoloaders as $namespacePrefix => $directory) {
if ($this->startsWith($class, $namespacePrefix)) {
$file = substr($class, strlen($namespacePrefix));
$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
return "$directory$file.php";
}
}
$msg = "Did not find a matching namespace for class $class in PSR-4 autoloaders found in composer.json: ";
$msg .= json_encode($this->psr4Autoloaders);
throw new RuntimeException($msg);
}
/**
* Starts the $haystack string with the prefix $needle?
*/
private function startsWith(string $haystack, string $needle): bool
{
return 0 === strncmp($haystack, $needle, strlen($needle));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment