diff --git a/.github/workflows/formats.yml b/.github/workflows/formats.yml index f3598b3b..bbdd5771 100644 --- a/.github/workflows/formats.yml +++ b/.github/workflows/formats.yml @@ -30,7 +30,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: mbstring, zip + extensions: dom, mbstring, zip tools: prestissimo coverage: pcov diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 10188221..8c600d9d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,7 +29,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: mbstring, zip + extensions: dom, mbstring, zip coverage: none - name: Install Composer dependencies diff --git a/bin/pest b/bin/pest index 9b66a2b6..5ff4eea1 100755 --- a/bin/pest +++ b/bin/pest @@ -1,6 +1,7 @@ #!/usr/bin/env php register(); + (new Provider())->register(); $rootPath = getcwd(); diff --git a/composer.json b/composer.json index 44aaf9ad..1c29cfa7 100644 --- a/composer.json +++ b/composer.json @@ -67,9 +67,9 @@ "lint": "rector process src && php-cs-fixer fix -v", "test:lint": "php-cs-fixer fix -v --dry-run && rector process src --dry-run", "test:types": "phpstan analyse --ansi", - "test:unit": "bin/pest --colors=always --exclude-group=integration", - "test:integration": "bin/pest --colors=always --group=integration", - "test:integration:snapshots": "REBUILD_SNAPSHOTS=true bin/pest --colors=always", + "test:unit": "php bin/pest --colors=always --exclude-group=integration", + "test:integration": "php bin/pest --colors=always --group=integration", + "test:integration:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always", "test": [ "@test:lint", "@test:types", diff --git a/src/Factories/TestCaseFactory.php b/src/Factories/TestCaseFactory.php index e36613ab..49c6eaad 100644 --- a/src/Factories/TestCaseFactory.php +++ b/src/Factories/TestCaseFactory.php @@ -158,16 +158,25 @@ final class TestCaseFactory */ public function makeClassFromFilename(string $filename): string { + if ('\\' === DIRECTORY_SEPARATOR) { + // In case Windows, strtolower drive name, like in UsesCall. + $filename = (string) preg_replace_callback('~^(?P[a-z]+:\\\)~i', function ($match): string { + return strtolower($match['drive']); + }, $filename); + } + + $filename = (string) realpath($filename); $rootPath = TestSuite::getInstance()->rootPath; $relativePath = str_replace($rootPath . DIRECTORY_SEPARATOR, '', $filename); + $relativePath = dirname(ucfirst($relativePath)) . DIRECTORY_SEPARATOR . basename($relativePath, '.php'); + $relativePath = str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath); + // Strip out any %-encoded octets. $relativePath = (string) preg_replace('|%[a-fA-F0-9][a-fA-F0-9]|', '', $relativePath); - // Limit to A-Z, a-z, 0-9, '_', '-'. - $relativePath = (string) preg_replace('/[^A-Za-z0-9.\/]/', '', $relativePath); - - $classFQN = 'P\\' . basename(ucfirst(str_replace(DIRECTORY_SEPARATOR, '\\', $relativePath)), '.php'); + $relativePath = (string) preg_replace('/[^A-Za-z0-9.\\\]/', '', $relativePath); + $classFQN = 'P\\' . $relativePath; if (class_exists($classFQN)) { return $classFQN; } diff --git a/src/PendingObjects/UsesCall.php b/src/PendingObjects/UsesCall.php index d7cfc1f6..f9418fd5 100644 --- a/src/PendingObjects/UsesCall.php +++ b/src/PendingObjects/UsesCall.php @@ -59,7 +59,17 @@ final class UsesCall public function in(string ...$targets): void { $targets = array_map(function ($path): string { - return $path[0] === DIRECTORY_SEPARATOR + $startChar = DIRECTORY_SEPARATOR; + + if ('\\' === DIRECTORY_SEPARATOR || preg_match('~\A[A-Z]:(?![^/\\\\])~i', $path) > 0) { + $path = (string) preg_replace_callback('~^(?P[a-z]+:\\\)~i', function ($match): string { + return strtolower($match['drive']); + }, $path); + + $startChar = strtolower((string) preg_replace('~^([a-z]+:\\\).*$~i', '$1', __DIR__)); + } + + return 0 === strpos($path, $startChar) ? $path : implode(DIRECTORY_SEPARATOR, [ dirname($this->filename), @@ -68,12 +78,12 @@ final class UsesCall }, $targets); $this->targets = array_map(function ($target): string { - $realTarget = realpath($target); - if ($realTarget === false) { + $isValid = is_dir($target) || file_exists($target); + if (!$isValid) { throw new InvalidUsesPath($target); } - return $realTarget; + return (string) realpath($target); }, $targets); } diff --git a/src/Support/Backtrace.php b/src/Support/Backtrace.php index 0347932f..cf90ab03 100644 --- a/src/Support/Backtrace.php +++ b/src/Support/Backtrace.php @@ -24,7 +24,7 @@ final class Backtrace $current = null; foreach (debug_backtrace() as $trace) { - if (Str::endsWith($trace[self::FILE], 'vendor/phpunit/phpunit/src/Util/FileLoader.php')) { + if (Str::endsWith($trace[self::FILE], (string) realpath('vendor/phpunit/phpunit/src/Util/FileLoader.php'))) { break; } diff --git a/src/TestSuite.php b/src/TestSuite.php index 2d2bbfd8..b9c232b2 100644 --- a/src/TestSuite.php +++ b/src/TestSuite.php @@ -83,7 +83,7 @@ final class TestSuite $this->afterEach = new AfterEachRepository(); $this->afterAll = new AfterAllRepository(); - $this->rootPath = $rootPath; + $this->rootPath = (string) realpath($rootPath); } /** diff --git a/tests/.snapshots/success.txt b/tests/.snapshots/success.txt index 1a8a5130..82705172 100644 --- a/tests/.snapshots/success.txt +++ b/tests/.snapshots/success.txt @@ -81,10 +81,10 @@ ✓ higher order message test PASS Tests\Fixtures\DirectoryWithTests\ExampleTest - ✓ it example + ✓ it example 1 PASS Tests\Fixtures\ExampleTest - ✓ it example + ✓ it example 2 PASS Tests\PHPUnit\CustomTestCase\UsesPerDirectory ✓ closure was bound to CustomTestCase @@ -135,4 +135,4 @@ s visual snapshot of test suite on success Tests: 6 skipped, 71 passed - Time: 2.96s + Time: 2.89s diff --git a/tests/Fixtures/DirectoryWithTests/ExampleTest.php b/tests/Fixtures/DirectoryWithTests/ExampleTest.php index 8553ad34..81ce02ff 100644 --- a/tests/Fixtures/DirectoryWithTests/ExampleTest.php +++ b/tests/Fixtures/DirectoryWithTests/ExampleTest.php @@ -1,3 +1,3 @@ assertTrue(true); +it('example 1')->assertTrue(true); diff --git a/tests/Fixtures/ExampleTest.php b/tests/Fixtures/ExampleTest.php index 8553ad34..a2704020 100644 --- a/tests/Fixtures/ExampleTest.php +++ b/tests/Fixtures/ExampleTest.php @@ -1,3 +1,3 @@ assertTrue(true); +it('example 2')->assertTrue(true); diff --git a/tests/Visual/SingleTestOrDirectory.php b/tests/Visual/SingleTestOrDirectory.php index d86fc4c9..52ccf3e6 100644 --- a/tests/Visual/SingleTestOrDirectory.php +++ b/tests/Visual/SingleTestOrDirectory.php @@ -3,7 +3,7 @@ use Symfony\Component\Process\Process; $run = function (string $target) { - $process = new Process(['./bin/pest', $target], dirname(__DIR__, 2)); + $process = new Process(['php', 'bin/pest', $target], dirname(__DIR__, 2)); $process->run(); @@ -13,7 +13,7 @@ $run = function (string $target) { test('allows to run a single test', function () use ($run) { assertStringContainsString(<<getOutput(); assertStringContainsString(<< 'integration', 'REBUILD_SNAPSHOTS' => false])); + $process = (new Symfony\Component\Process\Process(['php', 'bin/pest'], dirname($testsPath), ['EXCLUDE' => 'integration', 'REBUILD_SNAPSHOTS' => false])); $process->run(); @@ -24,4 +24,5 @@ test('visual snapshot of test suite on success', function () { array_pop($output); assertStringContainsString(implode("\n", $output), file_get_contents($snapshot)); } -})->skip(!getenv('REBUILD_SNAPSHOTS') && getenv('EXCLUDE')); +})->skip(!getenv('REBUILD_SNAPSHOTS') && getenv('EXCLUDE')) + ->skip(PHP_OS_FAMILY === 'Windows', 'File sorting algorithm causes different test order on Windows');