mirror of
https://github.com/pestphp/pest.git
synced 2026-04-24 07:57:29 +02:00
wip
This commit is contained in:
@ -142,6 +142,16 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
*/
|
||||
private int $executedCount = 0;
|
||||
|
||||
/**
|
||||
* Cached assertion count per test id for the current replay run. Keyed
|
||||
* by `ClassName::methodName`; populated when `getCachedResult()` hits
|
||||
* cache and drained by `Testable::__runTest()` on the short-circuit
|
||||
* path so the emitted count matches the recorded run.
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private array $cachedAssertionsByTestId = [];
|
||||
|
||||
/**
|
||||
* Captured at replay setup so the end-of-run summary can report the
|
||||
* scope of the changes that drove the run.
|
||||
@ -268,6 +278,11 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
|
||||
if ($result !== null) {
|
||||
$this->replayedCount++;
|
||||
// Cache the assertion count alongside the status so `Testable`
|
||||
// can emit the exact `addToAssertionCount()` at replay time
|
||||
// without hitting the graph twice per test.
|
||||
$assertions = $this->replayGraph->getAssertions($this->branch, $testId);
|
||||
$this->cachedAssertionsByTestId[$testId] = $assertions ?? 0;
|
||||
} else {
|
||||
// Graph knows the test file but has no stored result for this
|
||||
// specific test id (new test, or first time seeing this method).
|
||||
@ -278,6 +293,17 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exact assertion count captured for the given test during its last
|
||||
* recorded run. Returns `0` if unknown (new test, or old graph entry
|
||||
* pre-dating assertion-count tracking). `Testable::__runTest` reads
|
||||
* this to feed `addToAssertionCount()` instead of defaulting to 1.
|
||||
*/
|
||||
public function getCachedAssertions(string $testId): int
|
||||
{
|
||||
return $this->cachedAssertionsByTestId[$testId] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -1101,7 +1127,14 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
|
||||
}
|
||||
|
||||
foreach ($results as $testId => $result) {
|
||||
$graph->setResult($this->branch, $testId, $result['status'], $result['message'], $result['time']);
|
||||
$graph->setResult(
|
||||
$this->branch,
|
||||
$testId,
|
||||
$result['status'],
|
||||
$result['message'],
|
||||
$result['time'],
|
||||
$result['assertions'],
|
||||
);
|
||||
}
|
||||
|
||||
$this->saveGraph($graph);
|
||||
|
||||
47
src/Plugins/Tia/Bootstrapper.php
Normal file
47
src/Plugins/Tia/Bootstrapper.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Plugins\Tia;
|
||||
|
||||
use Pest\Contracts\Bootstrapper as BootstrapperContract;
|
||||
use Pest\Plugins\Tia\Contracts\State;
|
||||
use Pest\Support\Container;
|
||||
|
||||
/**
|
||||
* Plugin-level container registrations for TIA. Runs as part of Kernel's
|
||||
* bootstrapper chain so Tia's own service graph is set up without Kernel
|
||||
* having to know about any of its internals.
|
||||
*
|
||||
* Most Tia services (`Recorder`, `CoverageCollector`, `WatchPatterns`,
|
||||
* `ResultCollector`, `BaselineSync`) are auto-buildable — Pest's container
|
||||
* resolves them lazily via constructor reflection. The only service that
|
||||
* requires an explicit binding is the `State` contract, because the
|
||||
* filesystem implementation needs a root-directory string that reflection
|
||||
* can't infer.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final readonly class Bootstrapper implements BootstrapperContract
|
||||
{
|
||||
public function __construct(private Container $container) {}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
$this->container->add(State::class, new FileState($this->tempDir()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve Pest's `.temp/` directory relative to this file so TIA's
|
||||
* caches share the same location as the rest of Pest's transient
|
||||
* state (PHPUnit result cache, coverage PHP dumps, etc.).
|
||||
*/
|
||||
private function tempDir(): string
|
||||
{
|
||||
return __DIR__
|
||||
.DIRECTORY_SEPARATOR.'..'
|
||||
.DIRECTORY_SEPARATOR.'..'
|
||||
.DIRECTORY_SEPARATOR.'..'
|
||||
.DIRECTORY_SEPARATOR.'.temp';
|
||||
}
|
||||
}
|
||||
@ -60,7 +60,7 @@ final class Graph
|
||||
* @var array<string, array{
|
||||
* sha: ?string,
|
||||
* tree: array<string, string>,
|
||||
* results: array<string, array{status: int, message: string, time: float}>
|
||||
* results: array<string, array{status: int, message: string, time: float, assertions?: int}>
|
||||
* }>
|
||||
*/
|
||||
private array $baselines = [];
|
||||
@ -257,14 +257,36 @@ final class Graph
|
||||
$this->baselines[$branch]['sha'] = $sha;
|
||||
}
|
||||
|
||||
public function setResult(string $branch, string $testId, int $status, string $message, float $time): void
|
||||
public function setResult(string $branch, string $testId, int $status, string $message, float $time, int $assertions = 0): void
|
||||
{
|
||||
$this->ensureBaseline($branch);
|
||||
$this->baselines[$branch]['results'][$testId] = [
|
||||
'status' => $status, 'message' => $message, 'time' => $time,
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
'time' => $time,
|
||||
'assertions' => $assertions,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached assertion count for a test, or `null` if unknown.
|
||||
* Callers use this to feed `addToAssertionCount()` at replay time so
|
||||
* the "Tests: N passed (M assertions)" banner matches the recorded run
|
||||
* instead of defaulting to 1 assertion per test.
|
||||
*/
|
||||
public function getAssertions(string $branch, string $testId, string $fallbackBranch = 'main'): ?int
|
||||
{
|
||||
$baseline = $this->baselineFor($branch, $fallbackBranch);
|
||||
|
||||
if (! isset($baseline['results'][$testId]['assertions'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = $baseline['results'][$testId]['assertions'];
|
||||
|
||||
return is_int($value) ? $value : null;
|
||||
}
|
||||
|
||||
public function getResult(string $branch, string $testId, string $fallbackBranch = 'main'): ?TestStatus
|
||||
{
|
||||
$baseline = $this->baselineFor($branch, $fallbackBranch);
|
||||
@ -310,7 +332,7 @@ final class Graph
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{sha: ?string, tree: array<string, string>, results: array<string, array{status: int, message: string, time: float}>}
|
||||
* @return array{sha: ?string, tree: array<string, string>, results: array<string, array{status: int, message: string, time: float, assertions?: int}>}
|
||||
*/
|
||||
private function baselineFor(string $branch, string $fallbackBranch): array
|
||||
{
|
||||
|
||||
@ -118,6 +118,17 @@ final class ResultCollector
|
||||
$this->startTime = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the Finished subscriber after a test's outcome + assertion
|
||||
* events have all fired. Clears the "currently recording" pointer so
|
||||
* the next test's events don't get mis-attributed.
|
||||
*/
|
||||
public function finishTest(): void
|
||||
{
|
||||
$this->currentTestId = null;
|
||||
$this->startTime = null;
|
||||
}
|
||||
|
||||
private function record(int $status, string $message): void
|
||||
{
|
||||
if ($this->currentTestId === null) {
|
||||
@ -128,14 +139,17 @@ final class ResultCollector
|
||||
? round(microtime(true) - $this->startTime, 3)
|
||||
: 0.0;
|
||||
|
||||
// PHPUnit can fire more than one outcome event per test — the
|
||||
// canonical case is a risky pass (`Passed` then `ConsideredRisky`).
|
||||
// Last-wins semantics preserve the most specific status; the
|
||||
// existing assertion count (if any) survives the overwrite.
|
||||
$existing = $this->results[$this->currentTestId] ?? null;
|
||||
|
||||
$this->results[$this->currentTestId] = [
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
'time' => $time,
|
||||
'assertions' => 0,
|
||||
'assertions' => $existing['assertions'] ?? 0,
|
||||
];
|
||||
|
||||
$this->currentTestId = null;
|
||||
$this->startTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user