mirror of
https://github.com/pestphp/pest.git
synced 2026-09-05 06:13:35 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad1850b110 | |||
| 585de259a2 | |||
| 953664dce0 | |||
| 1dd959848c | |||
| 047753c836 |
@@ -280,7 +280,7 @@ trait Testable
|
||||
|
||||
/** @var Tia $tia */
|
||||
$tia = Container::getInstance()->get(Tia::class);
|
||||
$status = $tia->getStatus(self::$__filename, $this::class.'::'.$this->name());
|
||||
$status = $tia->getStatus(self::$__filename, $this->valueObjectForEvents()->id());
|
||||
$replay = ReplayType::fromStatus($status);
|
||||
|
||||
if ($replay !== ReplayType::None) {
|
||||
@@ -319,7 +319,7 @@ trait Testable
|
||||
private function __beginReplay(ReplayType $replay, Tia $tia): void
|
||||
{
|
||||
$this->__replay = $replay;
|
||||
$this->__replayAssertions = $tia->getAssertionCount($this::class.'::'.$this->name());
|
||||
$this->__replayAssertions = $tia->getAssertionCount($this->valueObjectForEvents()->id());
|
||||
$this->__ran = true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ namespace Pest;
|
||||
|
||||
function version(): string
|
||||
{
|
||||
return '5.0.2';
|
||||
return '5.0.3';
|
||||
}
|
||||
|
||||
function testDirectory(string $file = ''): string
|
||||
|
||||
@@ -56,7 +56,7 @@ final class TableExtractor
|
||||
$tables[strtolower($name)] = true;
|
||||
}
|
||||
|
||||
$out = array_keys($tables);
|
||||
$out = array_map(strval(...), array_keys($tables));
|
||||
sort($out);
|
||||
|
||||
return $out;
|
||||
@@ -112,7 +112,7 @@ final class TableExtractor
|
||||
}
|
||||
}
|
||||
|
||||
$out = array_keys($tables);
|
||||
$out = array_map(strval(...), array_keys($tables));
|
||||
sort($out);
|
||||
|
||||
return $out;
|
||||
|
||||
@@ -22,7 +22,7 @@ final readonly class EnsureTiaAssertionsAreRecordedOnFinished implements Finishe
|
||||
|
||||
if ($test instanceof TestMethod) {
|
||||
$this->collector->recordAssertions(
|
||||
$test->className().'::'.$test->methodName(),
|
||||
$test->id(),
|
||||
$event->numberOfAssertionsPerformed(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ final readonly class EnsureTiaResultsAreCollected implements PreparationStartedS
|
||||
$test = $event->test();
|
||||
|
||||
if ($test instanceof TestMethod) {
|
||||
$this->collector->testPrepared($test->className().'::'.$test->methodName(), $test->file());
|
||||
$this->collector->testPrepared($test->id(), $test->file());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
Pest Testing Framework 5.0.2.
|
||||
Pest Testing Framework 5.0.3.
|
||||
|
||||
USAGE: pest <file> [options]
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
|
||||
Pest Testing Framework 5.0.2.
|
||||
Pest Testing Framework 5.0.3.
|
||||
|
||||
|
||||
@@ -1908,6 +1908,11 @@
|
||||
✓ activateLinkTracking() → it tracks linked sources across consecutive tests
|
||||
✓ activateLinkTracking() → it records nothing while inactive
|
||||
|
||||
PASS Tests\Unit\Plugins\Tia\ResultKey
|
||||
✓ it keys a result per dataset row rather than per method
|
||||
✓ it records assertions against the same per-dataset key
|
||||
✓ it leaves a test without a dataset keyed by class and method
|
||||
|
||||
PASS Tests\Unit\Plugins\Tia\TableExtractor
|
||||
✓ fromSql() → it extracts tables from plain DML
|
||||
✓ fromSql() → it extracts tables from joins
|
||||
@@ -2186,4 +2191,4 @@
|
||||
✓ pass with dataset with ('my-datas-set-value')
|
||||
✓ within describe → pass with dataset with ('my-datas-set-value')
|
||||
|
||||
Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1542 passed (3375 assertions)
|
||||
Tests: 1 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1545 passed (3378 assertions)
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Pest\Plugins\Tia\ResultCollector;
|
||||
use Pest\Subscribers\EnsureTiaAssertionsAreRecordedOnFinished;
|
||||
use Pest\Subscribers\EnsureTiaResultsAreCollected;
|
||||
use PHPUnit\Event\Code\TestDox;
|
||||
use PHPUnit\Event\Code\TestMethod;
|
||||
use PHPUnit\Event\Telemetry\Duration;
|
||||
use PHPUnit\Event\Telemetry\Info;
|
||||
use PHPUnit\Event\Telemetry\MemoryUsage;
|
||||
use PHPUnit\Event\Telemetry\System;
|
||||
use PHPUnit\Event\Telemetry\SystemCpuTimeMeter;
|
||||
use PHPUnit\Event\Telemetry\SystemGarbageCollectorStatusProvider;
|
||||
use PHPUnit\Event\Telemetry\SystemMemoryMeter;
|
||||
use PHPUnit\Event\Telemetry\SystemStopWatch;
|
||||
use PHPUnit\Event\Test\Finished;
|
||||
use PHPUnit\Event\Test\PreparationStarted;
|
||||
use PHPUnit\Event\TestData\DataFromDataProvider;
|
||||
use PHPUnit\Event\TestData\TestDataCollection;
|
||||
use PHPUnit\Metadata\MetadataCollection;
|
||||
|
||||
function tiaResultKeyTestMethod(?string $dataSetName): TestMethod
|
||||
{
|
||||
$testData = $dataSetName === null
|
||||
? TestDataCollection::fromArray([])
|
||||
: TestDataCollection::fromArray([DataFromDataProvider::from($dataSetName, '', '')]);
|
||||
|
||||
return new TestMethod(
|
||||
'Tests\Feature\OrderTest',
|
||||
'it prices an order',
|
||||
'/project/tests/Feature/OrderTest.php',
|
||||
1,
|
||||
new TestDox('Order', 'it prices an order', 'it prices an order'),
|
||||
MetadataCollection::fromArray([]),
|
||||
$testData,
|
||||
);
|
||||
}
|
||||
|
||||
function tiaResultKeyTelemetryInfo(): Info
|
||||
{
|
||||
$system = new System(
|
||||
new SystemStopWatch,
|
||||
new SystemMemoryMeter,
|
||||
new SystemGarbageCollectorStatusProvider,
|
||||
new SystemCpuTimeMeter,
|
||||
);
|
||||
|
||||
$zeroDuration = Duration::fromSecondsAndNanoseconds(0, 0);
|
||||
$zeroMemory = MemoryUsage::fromBytes(0);
|
||||
$zeroCpuTime = $system->snapshot()->userCpuTime();
|
||||
|
||||
return new Info(
|
||||
$system->snapshot(),
|
||||
$zeroDuration,
|
||||
$zeroMemory,
|
||||
$zeroDuration,
|
||||
$zeroMemory,
|
||||
$zeroCpuTime,
|
||||
$zeroCpuTime,
|
||||
$zeroCpuTime,
|
||||
$zeroCpuTime,
|
||||
$zeroCpuTime,
|
||||
$zeroCpuTime,
|
||||
);
|
||||
}
|
||||
|
||||
it('keys a result per dataset row rather than per method', function (): void {
|
||||
$collector = new ResultCollector;
|
||||
$subscriber = new EnsureTiaResultsAreCollected($collector);
|
||||
|
||||
$subscriber->notify(new PreparationStarted(tiaResultKeyTelemetryInfo(), tiaResultKeyTestMethod('opp')));
|
||||
$collector->testPassed();
|
||||
$collector->finishTest();
|
||||
|
||||
$subscriber->notify(new PreparationStarted(tiaResultKeyTelemetryInfo(), tiaResultKeyTestMethod('fake')));
|
||||
$collector->testSkipped('the fake driver does not report balances');
|
||||
$collector->finishTest();
|
||||
|
||||
// Without the dataset in the key both rows write to `Class::method`, so the
|
||||
// second one overwrites the first and a replay hands every row the same
|
||||
// status — a passing row reported as skipped, or a failing one as passed.
|
||||
expect(array_keys($collector->all()))->toBe([
|
||||
'Tests\Feature\OrderTest::it prices an order#opp',
|
||||
'Tests\Feature\OrderTest::it prices an order#fake',
|
||||
]);
|
||||
});
|
||||
|
||||
it('records assertions against the same per-dataset key', function (): void {
|
||||
$collector = new ResultCollector;
|
||||
|
||||
new EnsureTiaResultsAreCollected($collector)->notify(
|
||||
new PreparationStarted(tiaResultKeyTelemetryInfo(), tiaResultKeyTestMethod('opp')),
|
||||
);
|
||||
$collector->testPassed();
|
||||
|
||||
new EnsureTiaAssertionsAreRecordedOnFinished($collector)->notify(
|
||||
new Finished(tiaResultKeyTelemetryInfo(), tiaResultKeyTestMethod('opp'), 7),
|
||||
);
|
||||
|
||||
expect($collector->all()['Tests\Feature\OrderTest::it prices an order#opp']['assertions'])->toBe(7);
|
||||
});
|
||||
|
||||
it('leaves a test without a dataset keyed by class and method', function (): void {
|
||||
$collector = new ResultCollector;
|
||||
|
||||
new EnsureTiaResultsAreCollected($collector)->notify(
|
||||
new PreparationStarted(tiaResultKeyTelemetryInfo(), tiaResultKeyTestMethod(null)),
|
||||
);
|
||||
$collector->testPassed();
|
||||
|
||||
expect(array_keys($collector->all()))->toBe(['Tests\Feature\OrderTest::it prices an order']);
|
||||
});
|
||||
@@ -47,6 +47,15 @@ describe('fromSql()', function (): void {
|
||||
->and(TableExtractor::fromSql('select * from information_schema.tables'))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('does not leak int keys for numeric identifiers', function (): void {
|
||||
// `substring(x FROM 1 FOR 3)` is standard SQL, and the `1` matches the
|
||||
// FROM pattern. Collecting names as array keys makes PHP coerce the
|
||||
// numeric string to an int, which then violates the declared
|
||||
// list<string> and blows up Recorder::linkTable(string).
|
||||
expect(TableExtractor::fromSql('select substring(name from 1 for 3) from users'))
|
||||
->each->toBeString();
|
||||
});
|
||||
|
||||
it('returns nothing for non-DML statements', function (): void {
|
||||
expect(TableExtractor::fromSql('PRAGMA foreign_keys = ON'))->toBeEmpty()
|
||||
->and(TableExtractor::fromSql(''))->toBeEmpty()
|
||||
@@ -89,6 +98,14 @@ describe('fromMigrationSource()', function (): void {
|
||||
->toBe(['audits', 'events', 'sessions', 'settings', 'users']);
|
||||
});
|
||||
|
||||
it('does not leak int keys for numeric table names', function (): void {
|
||||
// A table named `123` is a legal quoted identifier. Collecting names as
|
||||
// array keys makes PHP coerce it to an int, breaking the declared
|
||||
// list<string>, so it must survive as a string rather than be dropped.
|
||||
expect(TableExtractor::fromMigrationSource("DB::table('123')->insert([]);"))
|
||||
->toBe(['123']);
|
||||
});
|
||||
|
||||
it('extracts tables from DB::table calls', function (): void {
|
||||
expect(TableExtractor::fromMigrationSource("DB::table('permissions')->insert([]);"))
|
||||
->toBe(['permissions']);
|
||||
|
||||
@@ -24,13 +24,13 @@ test('parallel', function () use ($run): void {
|
||||
$file = file_get_contents(__FILE__);
|
||||
$file = preg_replace(
|
||||
'/\$expected = \'.*?\';/',
|
||||
"\$expected = '1 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1525 passed (3322 assertions)';",
|
||||
"\$expected = '1 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1528 passed (3325 assertions)';",
|
||||
$file,
|
||||
);
|
||||
file_put_contents(__FILE__, $file);
|
||||
}
|
||||
|
||||
$expected = '1 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1525 passed (3322 assertions)';
|
||||
$expected = '1 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1528 passed (3325 assertions)';
|
||||
|
||||
expect($output)
|
||||
->toContain("Tests: {$expected}")
|
||||
|
||||
Reference in New Issue
Block a user