Skip to content

Deal with merging coverage files, generated with different base paths #115

Open
@ipeevski

Description

@ipeevski

There are a number of use cases, when test coverage can be generated in different places (with different base paths).

Here are some ways to run tests, where each might result in a different path:
a. Run tests locally
b. Run inside docker
c. Run on a remote machine
d. Run inside CI pipeline runners
e. Run distributed across different machines

Our use case in particular was combinging unit tests running locally and acceptance tests running inside a docker container, accessed via selenium.

Right now those test coverages cannot be merged, since it requires the base paths to be the same.
I'm proposing a proof of concept of an utility to align base paths, so phpcov can be used to merge those properly.
(This can be added to phpcov or the parent CodeCoverage package).

Here is a script that would map all the paths in a given .cov file from one path to another:

<?php
// Relies on SebastianBergmann\CodeCoverage being available via composer
include 'vendor/autoload.php';

use SebastianBergmann\CodeCoverage\CodeCoverage;
use SebastianBergmann\CodeCoverage\Driver\PcovDriver;
use SebastianBergmann\CodeCoverage\ProcessedCodeCoverageData;
use SebastianBergmann\CodeCoverage\Report\PHP as PHPReport;

// The following three parameters are specifying what to be processed.
// If it's implemented as a function, those would be the input parameters.

// The file name to be processed
$filename = 'unit.cov';
// Replace the remote path
$from = '/app/';
// With the local path (where phpcov is running from)
$to = '/home/user/project/';

// Get the existing .cov file as a CodeCoverage class
$codeCoverage = include $filename;

$data = new ProcessedCodeCoverageData();

// Process line coverage
$lines = $codeCoverage->getData()->lineCoverage();
$newLines = [];
foreach ($lines as $file => $lineData) {
    $file = str_replace($from, $to, $file);
    $newLines[$file] = $lineData;
}
$data->setLineCoverage($newLines);

// Process function coverage
$functions = $codeCoverage->getData()->functionCoverage();
$newFunctions = [];
foreach ($functions as $file => $functionData) {
    $file = str_replace($from, $to, $file);
    $newFunctions[$file] = $functionData;
}
$data->setFunctionCoverage($newFunctions);

// Process filters
$filter = $codeCoverage->filter();
$files = $filter->files();
foreach ($files as $file) {
    $filter->excludeFile($file);
    $file = str_replace($from, $to, $file);
    $filter->includeFile($file);
}

// Create the new CodeCoverage class
$replacedCodeCoverage = new CodeCoverage(new PcovDriver($filter), $filter);
$replacedCodeCoverage->setTests($codeCoverage->getTests());
$replacedCodeCoverage->setData($data);
$replacedCodeCoverage->getReport();

// Save the new .cov file with paths replaced
(new PHPReport)->process($replacedCodeCoverage, $filename);

Note: Because there are some sorts being applied when fetching the files, the order inside the .cov file will differ if it's run with the the to/from being the same. If it's run a second time though, they are an exact match.

Note: I might have missed other parts that need to be populated in the new CodeCoverage class, but this worked for me.

Feel free to use the code included here anyway you see fit.
If you want me to create a patch, please let me know what would be your preferred place for this (static method in a class in CodeCoverage or phpcov?).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions