Skip to content

Instantly share code, notes, and snippets.

@mfn
Last active March 11, 2021 15:33
Show Gist options
  • Select an option

  • Save mfn/e865d539010d1ed78bc1b16cfe15b2cc to your computer and use it in GitHub Desktop.

Select an option

Save mfn/e865d539010d1ed78bc1b16cfe15b2cc to your computer and use it in GitHub Desktop.

Revisions

  1. mfn renamed this gist Mar 11, 2021. 1 changed file with 0 additions and 0 deletions.
  2. mfn created this gist Mar 11, 2021.
    88 changes: 88 additions & 0 deletions phpunix_xml_class_to_file.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    #!/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));
    }
    }