403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/client-portal-laravel/current/scripts/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/client-portal-laravel/current/scripts/coverage-gaps.php
#!/usr/bin/env php
<?php

/**
 * Coverage Gaps Script
 *
 * Shows files without 100% line coverage and their uncovered line numbers.
 *
 * Usage:
 *   php scripts/coverage-gaps.php app/Models
 *   php scripts/coverage-gaps.php app/Services/Notifications
 *   php scripts/coverage-gaps.php --clover=path/to/coverage.xml app/Models
 *   php scripts/coverage-gaps.php --generate app/Models
 */

// Parse args manually (PHP getopt stops at first non-option)
$positional = [];
$cloverFile = null;
$generate = false;
$showHelp = false;

foreach (array_slice($argv, 1) as $arg) {
    if (str_starts_with($arg, '--clover=')) {
        $cloverFile = substr($arg, 9);
    } elseif ($arg === '--generate') {
        $generate = true;
    } elseif ($arg === '--help') {
        $showHelp = true;
    } elseif (! str_starts_with($arg, '-')) {
        $positional[] = $arg;
    }
}

if ($showHelp || empty($positional)) {
    fwrite(STDERR, <<<'USAGE'
Usage: php scripts/coverage-gaps.php [options] <directory>

Options:
  --clover=FILE   Use existing Clover XML coverage file
  --generate      Run tests first to generate fresh coverage
  --help          Show this help

If neither --clover nor --generate is given, the script looks for the
most recent coverage XML in tests/.me/

Examples:
  php scripts/coverage-gaps.php app/Models
  php scripts/coverage-gaps.php --generate app/Services
  php scripts/coverage-gaps.php --clover=tests/.me/coverage.xml app/Models

USAGE);
    exit(1);
}

$targetDir = rtrim($positional[0], '/');
$projectRoot = dirname(__DIR__);
if (! is_file("$projectRoot/artisan") && is_file(getcwd().'/artisan')) {
    $projectRoot = getcwd();
}
$absoluteTarget = realpath("$projectRoot/$targetDir");

if (! $absoluteTarget || ! is_dir($absoluteTarget)) {
    fwrite(STDERR, "Error: Directory '$targetDir' not found.\n");
    exit(1);
}

// Determine coverage XML path
$cloverPath = null;

if ($cloverFile !== null) {
    $cloverPath = $cloverFile;
    if (! str_starts_with($cloverPath, '/')) {
        $cloverPath = "$projectRoot/$cloverPath";
    }
} elseif ($generate) {
    $cloverPath = "$projectRoot/tests/.coverage/.gaps/coverage.xml";
    @mkdir(dirname($cloverPath), 0755, true);
    fwrite(STDERR, "Generating coverage report...\n");
    $cmd = sprintf(
        'cd %s && php artisan test --parallel --coverage-clover=%s 2>&1',
        escapeshellarg($projectRoot),
        escapeshellarg($cloverPath)
    );
    passthru($cmd, $exitCode);
    if ($exitCode !== 0) {
        fwrite(STDERR, "Error: Test run failed.\n");
        exit(1);
    }
    fwrite(STDERR, "\n");
} else {
    // Find most recent clover XML
    $searchDirs = [
        "$projectRoot/tests/.me",
    ];
    $candidates = [];
    foreach ($searchDirs as $dir) {
        if (! is_dir($dir)) {
            continue;
        }
        $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
        foreach ($it as $file) {
            if ($file->getFilename() === 'coverage.xml') {
                $candidates[] = $file->getPathname();
            }
        }
    }
    if (! empty($candidates)) {
        usort($candidates, fn ($a, $b) => filemtime($b) - filemtime($a));
        $cloverPath = $candidates[0];
    }
}

if (! $cloverPath || ! file_exists($cloverPath)) {
    fwrite(STDERR, "Error: No coverage XML found. Run with --generate or --clover=FILE\n");
    exit(1);
}

$age = time() - filemtime($cloverPath);
$ageMin = round($age / 60);
if ($ageMin > 60) {
    $ageStr = round($ageMin / 60, 1).'h';
} else {
    $ageStr = $ageMin.'m';
}
fwrite(STDERR, "Using: $cloverPath ($ageStr old)\n\n");

// Parse Clover XML
$xml = simplexml_load_file($cloverPath);
if (! $xml) {
    fwrite(STDERR, "Error: Failed to parse coverage XML.\n");
    exit(1);
}

$results = [];
$perfectCount = 0;

// Process files from both <package><file> and top-level <file> nodes
$fileNodes = [];
foreach ($xml->project->package as $package) {
    foreach ($package->file as $file) {
        $fileNodes[] = $file;
    }
}
foreach ($xml->project->file as $file) {
    $fileNodes[] = $file;
}

foreach ($fileNodes as $file) {
    $filePath = (string) $file['name'];

    if (! str_starts_with($filePath, $absoluteTarget.'/')) {
        continue;
    }

    $uncoveredLines = [];
    foreach ($file->line as $line) {
        if ((string) $line['type'] === 'stmt' && (int) $line['count'] === 0) {
            $uncoveredLines[] = (int) $line['num'];
        }
    }

    $relativePath = ltrim(str_replace($projectRoot, '', $filePath), '/');

    if (empty($uncoveredLines)) {
        $perfectCount++;

        continue;
    }

    sort($uncoveredLines);
    $results[$relativePath] = formatLineRanges($uncoveredLines);
}

if (empty($results) && $perfectCount === 0) {
    fwrite(STDERR, "No coverage data found for '$targetDir'.\n");
    fwrite(STDERR, "This may mean the directory has no executable lines, or tests don't cover it.\n");
    exit(1);
}

// Sort by file path
ksort($results);

// Output
foreach ($results as $file => $lines) {
    echo "$file $lines\n";
}

$totalFiles = count($results) + $perfectCount;
fwrite(STDERR, "\n{$perfectCount}/{$totalFiles} files at 100% coverage");
if (! empty($results)) {
    fwrite(STDERR, ', '.count($results).' with gaps');
}
fwrite(STDERR, "\n");

exit(empty($results) ? 0 : 1);

/**
 * Collapse consecutive line numbers into ranges.
 * [1,2,3,5,7,8,9] => "1-3, 5, 7-9"
 */
function formatLineRanges(array $lines): string
{
    if (empty($lines)) {
        return '';
    }

    $ranges = [];
    $start = $lines[0];
    $end = $lines[0];

    for ($i = 1; $i < count($lines); $i++) {
        if ($lines[$i] === $end + 1) {
            $end = $lines[$i];
        } else {
            $ranges[] = $start === $end ? (string) $start : "$start-$end";
            $start = $lines[$i];
            $end = $lines[$i];
        }
    }
    $ranges[] = $start === $end ? (string) $start : "$start-$end";

    return implode(', ', $ranges);
}

Youez - 2016 - github.com/yon3zu
LinuXploit