Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Plugins/Parallel/Paratest/ResultPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ public function printResults(TestResult $testResult, array $teamcityFiles, array

$state = (new StateGenerator)->fromPhpUnitTestResult($this->passedTests, $testResult);

if ($testResult->numberOfTestsRun() === 0 && $state->testSuiteTestsCount() === 0) {
$this->output->writeln([
'',
' <fg=white;options=bold;bg=blue> INFO </> No tests found.',
'',
]);
}

$this->compactPrinter->errors($state);
$this->compactPrinter->recap($state, $testResult, $duration, $this->options);
}
Expand Down
55 changes: 47 additions & 8 deletions src/Plugins/Parallel/Paratest/WrapperRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use function file_get_contents;
use function max;
use function realpath;
use function str_starts_with;
use function unlink;
use function unserialize;
use function usleep;
Expand Down Expand Up @@ -485,14 +486,52 @@ private function clearFiles(array $files): void
private function getTestFiles(SuiteLoader $suiteLoader): array
{
/** @var array<string, non-empty-string> $files */
$files = [
...array_values(array_filter(
$suiteLoader->tests,
fn (string $filename): bool => ! str_ends_with($filename, "eval()'d code")
)),
...TestSuite::getInstance()->tests->getFilenames(),
];
$files = array_fill_keys(array_values(array_filter(
$suiteLoader->tests,
fn (string $filename): bool => ! str_ends_with($filename, "eval()'d code")
)), null);

foreach (TestSuite::getInstance()->tests->getFilenames() as $filename) {
if ($this->shouldIncludeBootstrappedTestFile($filename)) {
$files[$filename] = null;
}
}

return array_keys($files); // @phpstan-ignore-line
}

private function shouldIncludeBootstrappedTestFile(string $filename): bool
{
if (! $this->options->configuration->hasCliArguments()) {
return true;
}

$resolvedFilename = realpath($filename);

if ($resolvedFilename === false) {
$resolvedFilename = realpath($this->options->cwd.DIRECTORY_SEPARATOR.$filename);
}

if ($resolvedFilename === false) {
return false;
}

foreach ($this->options->configuration->cliArguments() as $path) {
$resolvedPath = realpath($path);

if ($resolvedPath === false) {
continue;
}

if ($resolvedFilename === $resolvedPath) {
return true;
}

if (is_dir($resolvedPath) && str_starts_with($resolvedFilename, $resolvedPath.DIRECTORY_SEPARATOR)) {
return true;
}
}

return $files; // @phpstan-ignore-line
return false;
}
}
61 changes: 59 additions & 2 deletions src/Support/DatasetInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class DatasetInfo

public static function isInsideADatasetsDirectory(string $file): bool
{
return basename(dirname($file)) === self::DATASETS_DIR_NAME;
return in_array(self::DATASETS_DIR_NAME, self::directorySegmentsInsideTestsDirectory($file), true);
}

public static function isADatasetsFile(string $file): bool
Expand All @@ -32,7 +32,23 @@ public static function scope(string $file): string
}

if (self::isInsideADatasetsDirectory($file)) {
return dirname($file, 2);
$scope = [];

foreach (self::directorySegmentsInsideTestsDirectory($file) as $segment) {
if ($segment === self::DATASETS_DIR_NAME) {
break;
}

$scope[] = $segment;
}

$testsDirectoryPath = self::testsDirectoryPath($file);

if ($scope === []) {
return $testsDirectoryPath;
}

return $testsDirectoryPath.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $scope);
}

if (self::isADatasetsFile($file)) {
Expand All @@ -41,4 +57,45 @@ public static function scope(string $file): string

return $file;
}

/**
* @return list<string>
*/
private static function directorySegmentsInsideTestsDirectory(string $file): array
{
$directory = dirname(self::pathInsideTestsDirectory($file));

if ($directory === '.' || $directory === DIRECTORY_SEPARATOR) {
return [];
}

return array_values(array_filter(
explode(DIRECTORY_SEPARATOR, trim($directory, DIRECTORY_SEPARATOR)),
static fn (string $segment): bool => $segment !== '',
));
}

private static function pathInsideTestsDirectory(string $file): string
{
$testsDirectory = DIRECTORY_SEPARATOR.trim(testDirectory(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
$position = strrpos($file, $testsDirectory);

if ($position === false) {
return $file;
}

return substr($file, $position + strlen($testsDirectory));
}

private static function testsDirectoryPath(string $file): string
{
$testsDirectory = DIRECTORY_SEPARATOR.trim(testDirectory(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
$position = strrpos($file, $testsDirectory);

if ($position === false) {
return dirname($file);
}

return substr($file, 0, $position + strlen($testsDirectory) - 1);
}
}
28 changes: 28 additions & 0 deletions src/Support/StateGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Event\Code\ThrowableBuilder;
use PHPUnit\Event\Test\Errored;
use PHPUnit\Event\Test\PhpunitDeprecationTriggered;
use PHPUnit\Event\Test\PhpunitErrorTriggered;
use PHPUnit\Event\Test\PhpunitNoticeTriggered;
use PHPUnit\Event\Test\PhpunitWarningTriggered;
use PHPUnit\Event\TestData\TestDataCollection;
use PHPUnit\Framework\SkippedWithMessageException;
use PHPUnit\Metadata\MetadataCollection;
Expand Down Expand Up @@ -43,6 +47,8 @@ public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testR
));
}

$this->addTriggeredPhpunitEvents($state, $testResult->testTriggeredPhpunitErrorEvents(), TestResult::FAIL);

foreach ($testResult->testMarkedIncompleteEvents() as $testResultEvent) {
$state->add(TestResult::fromPestParallelTestCase(
$testResultEvent->test(),
Expand Down Expand Up @@ -99,6 +105,8 @@ public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testR
}
}

$this->addTriggeredPhpunitEvents($state, $testResult->testTriggeredPhpunitDeprecationEvents(), TestResult::DEPRECATED);

foreach ($testResult->notices() as $testResultEvent) {
foreach ($testResultEvent->triggeringTests() as $triggeringTest) {
['test' => $test] = $triggeringTest;
Expand All @@ -123,6 +131,8 @@ public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testR
}
}

$this->addTriggeredPhpunitEvents($state, $testResult->testTriggeredPhpunitNoticeEvents(), TestResult::NOTICE);

foreach ($testResult->warnings() as $testResultEvent) {
foreach ($testResultEvent->triggeringTests() as $triggeringTest) {
['test' => $test] = $triggeringTest;
Expand All @@ -135,6 +145,8 @@ public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testR
}
}

$this->addTriggeredPhpunitEvents($state, $testResult->testTriggeredPhpunitWarningEvents(), TestResult::WARN);

foreach ($testResult->phpWarnings() as $testResultEvent) {
foreach ($testResultEvent->triggeringTests() as $triggeringTest) {
['test' => $test] = $triggeringTest;
Expand Down Expand Up @@ -165,4 +177,20 @@ public function fromPhpUnitTestResult(int $passedTests, PHPUnitTestResult $testR

return $state;
}

/**
* @param array<string, list<PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered>> $testResultEvents
*/
private function addTriggeredPhpunitEvents(State $state, array $testResultEvents, string $type): void
{
foreach ($testResultEvents as $events) {
foreach ($events as $event) {
$state->add(TestResult::fromPestParallelTestCase(
$event->test(),
$type,
ThrowableBuilder::from(new TestOutcome($event->message()))
));
}
}
}
}
31 changes: 25 additions & 6 deletions tests/.snapshots/success.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1490,6 +1490,10 @@
PASS Tests\Fixtures\ExampleTest
✓ it example 2

PASS Tests\Fixtures\ParallelNestedDatasets\TestFileWithNestedDataset
✓ loads nested dataset with ('alice')
✓ loads nested dataset with ('bob')

WARN Tests\Fixtures\UnexpectedOutput
- output

Expand Down Expand Up @@ -1640,22 +1644,33 @@
✓ it cannot resolve a parameter without type

PASS Tests\Unit\Support\DatasetInfo
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase…rs.php', true)
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/Datasets/project/tes…rs.php', true) #1
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/Datasets/project/tes…rs.php', true) #2
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase…rs.php', true) #1
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datase…rs.php', true) #2
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Datasets.php', false)
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true)
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true) #1
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true) #2
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', true) #3
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…rs.php', false)
✓ it can check if dataset is defined inside a Datasets directory with ('/var/www/project/tests/Featur…ts.php', false)
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datase…rs.php', false)
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Datasets.php', true)
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #1
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…rs.php', false) #2
✓ it can check if dataset is defined inside a Datasets.php file with ('/var/www/project/tests/Featur…ts.php', true)
✓ it computes the dataset scope with ('/var/www/project/tests/Datase…rs.php', '/var/www/project/tests')
✓ it computes the dataset scope with ('/var/www/Datasets/project/tes…rs.php', '/var/www/Datasets/project/tests')
✓ it computes the dataset scope with ('/var/www/Datasets/project/tes…rs.php', '/var/www/Datasets/project/tes…atures')
✓ it computes the dataset scope with ('/var/www/project/tests/Datase…rs.php', '/var/www/project/tests') #1
✓ it computes the dataset scope with ('/var/www/project/tests/Datase…rs.php', '/var/www/project/tests') #2
✓ it computes the dataset scope with ('/var/www/project/tests/Datasets.php', '/var/www/project/tests')
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features')
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features') #1
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features') #2
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #1
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Features')
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…ollers')
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…ollers') #1
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…ollers') #2
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Features') #3
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…rs.php', '/var/www/project/tests/Featur…rs.php') #2
✓ it computes the dataset scope with ('/var/www/project/tests/Featur…ts.php', '/var/www/project/tests/Featur…ollers')

Expand Down Expand Up @@ -1756,6 +1771,10 @@
PASS Tests\Visual\Parallel
✓ parallel
✓ a parallel test can extend another test with same name
✓ parallel reports invalid datasets as failures

PASS Tests\Visual\ParallelNestedDatasets
✓ parallel loads nested datasets from nested directories

PASS Tests\Visual\SingleTestOrDirectory
✓ allows to run a single test
Expand All @@ -1782,4 +1801,4 @@
✓ pass with dataset with ('my-datas-set-value')
✓ within describe → pass with dataset with ('my-datas-set-value')

Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 35 skipped, 1188 passed (2813 assertions)
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 35 skipped, 1203 passed (2835 assertions)
5 changes: 5 additions & 0 deletions tests/.tests/ParallelInvalidDataset/MissingDatasetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

test('missing dataset', function (string $value) {
expect($value)->toBe('x');
})->with('missing.dataset');
3 changes: 3 additions & 0 deletions tests/.tests/ParallelInvalidDataset/PassingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

it('passes')->assertTrue(true);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

dataset('nested.users', [
['alice'],
['bob'],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

test('loads nested dataset', function (string $name) {
expect($name)->not->toBeEmpty();
})->with('nested.users');
11 changes: 11 additions & 0 deletions tests/Unit/Support/DatasetInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
it('can check if dataset is defined inside a Datasets directory', function (string $file, bool $inside) {
expect(DatasetInfo::isInsideADatasetsDirectory($file))->toBe($inside);
})->with([
['file' => '/var/www/Datasets/project/tests/Datasets/Nested/Numbers.php', 'inside' => true],
['file' => '/var/www/Datasets/project/tests/Features/Datasets/Nested/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Datasets/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Datasets/Nested/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Datasets.php', 'inside' => false],
['file' => '/var/www/project/tests/Features/Datasets/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Features/Datasets/Nested/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Features/Datasets/Nested/Datasets/Numbers.php', 'inside' => true],
['file' => '/var/www/project/tests/Features/Numbers.php', 'inside' => false],
['file' => '/var/www/project/tests/Features/Datasets.php', 'inside' => false],
]);
Expand All @@ -25,12 +30,18 @@
it('computes the dataset scope', function (string $file, string $scope) {
expect(DatasetInfo::scope($file))->toBe($scope);
})->with([
['file' => '/var/www/Datasets/project/tests/Datasets/Nested/Numbers.php', 'scope' => '/var/www/Datasets/project/tests'],
['file' => '/var/www/Datasets/project/tests/Features/Datasets/Nested/Numbers.php', 'scope' => '/var/www/Datasets/project/tests/Features'],
['file' => '/var/www/project/tests/Datasets/Numbers.php', 'scope' => '/var/www/project/tests'],
['file' => '/var/www/project/tests/Datasets/Nested/Numbers.php', 'scope' => '/var/www/project/tests'],
['file' => '/var/www/project/tests/Datasets.php', 'scope' => '/var/www/project/tests'],
['file' => '/var/www/project/tests/Features/Datasets/Numbers.php', 'scope' => '/var/www/project/tests/Features'],
['file' => '/var/www/project/tests/Features/Datasets/Nested/Numbers.php', 'scope' => '/var/www/project/tests/Features'],
['file' => '/var/www/project/tests/Features/Numbers.php', 'scope' => '/var/www/project/tests/Features/Numbers.php'],
['file' => '/var/www/project/tests/Features/Datasets.php', 'scope' => '/var/www/project/tests/Features'],
['file' => '/var/www/project/tests/Features/Controllers/Datasets/Numbers.php', 'scope' => '/var/www/project/tests/Features/Controllers'],
['file' => '/var/www/project/tests/Features/Controllers/Datasets/Nested/Numbers.php', 'scope' => '/var/www/project/tests/Features/Controllers'],
['file' => '/var/www/project/tests/Features/Datasets/Nested/Datasets/Numbers.php', 'scope' => '/var/www/project/tests/Features'],
['file' => '/var/www/project/tests/Features/Controllers/Numbers.php', 'scope' => '/var/www/project/tests/Features/Controllers/Numbers.php'],
['file' => '/var/www/project/tests/Features/Controllers/Datasets.php', 'scope' => '/var/www/project/tests/Features/Controllers'],
]);
13 changes: 10 additions & 3 deletions tests/Visual/Parallel.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@

test('parallel', function () use ($run) {
expect($run('--exclude-group=integration'))
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 26 skipped, 1177 passed (2789 assertions)')
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 3 notices, 39 todos, 26 skipped, 1190 passed (2802 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();

test('a parallel test can extend another test with same name', function () use ($run) {
expect($run('tests/Fixtures/Inheritance'))->toContain('Tests: 1 skipped, 2 passed (2 assertions)');
});
expect($run('tests/Fixtures/Inheritance'))->toContain('Tests: 1 skipped, 1 passed (1 assertions)');
})->skipOnWindows();

test('parallel reports invalid datasets as failures', function () use ($run) {
expect($run('tests/.tests/ParallelInvalidDataset'))
->toContain("A dataset with the name `missing.dataset` does not exist. You can create it using `dataset('missing.dataset', ['a', 'b']);`.")
->toContain('Tests: 1 failed, 1 passed (1 assertions)')
->toContain('Parallel: 3 processes');
})->skipOnWindows();
Loading