From d3ba447b79e45d1130e5523224700b97541b16de Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 12 Feb 2021 11:05:13 +0100 Subject: [PATCH] Full functional test-bed improvements --- tests/Composer/Test/AllFunctionalTest.php | 102 +++++++++++------- .../functional/create-project-command.test | 6 +- ...ject-shows-full-hash-for-dev-packages.test | 6 +- .../packages.json | 7 +- tests/Composer/Test/InstalledVersionsTest.php | 5 + 5 files changed, 79 insertions(+), 47 deletions(-) rename tests/Composer/Test/Fixtures/functional/{ => create-project-shows-full-hash-for-dev-packages}/packages.json (90%) diff --git a/tests/Composer/Test/AllFunctionalTest.php b/tests/Composer/Test/AllFunctionalTest.php index a38eda193..cc950b053 100644 --- a/tests/Composer/Test/AllFunctionalTest.php +++ b/tests/Composer/Test/AllFunctionalTest.php @@ -85,7 +85,7 @@ class AllFunctionalTest extends TestCase } } - $proc = new Process('php '.escapeshellarg('./bin/compile'), $target); + $proc = new Process('php -dphar.readonly=0 '.escapeshellarg('./bin/compile'), $target); $exitcode = $proc->run(); if ($exitcode !== 0 || trim($proc->getOutput())) { @@ -102,26 +102,73 @@ class AllFunctionalTest extends TestCase public function testIntegration($testFile) { $testData = $this->parseTestFile($testFile); + $this->testDir = self::getUniqueTmpDirectory(); + + // if a dir is present with the name of the .test file (without .test), we + // copy all its contents in the $testDir to be used to run the test with + $testFileSetupDir = substr($testFile, 0, -5); + if (is_dir($testFileSetupDir)) { + $fs = new Filesystem(); + $fs->copy($testFileSetupDir, $this->testDir); + } $this->oldenv = getenv('COMPOSER_HOME'); $_SERVER['COMPOSER_HOME'] = $this->testDir.'home'; putenv('COMPOSER_HOME='.$_SERVER['COMPOSER_HOME']); $cmd = 'php '.escapeshellarg(self::$pharPath).' --no-ansi '.$testData['RUN']; - $proc = new Process($cmd, __DIR__.'/Fixtures/functional', null, null, 300); - $exitcode = $proc->run(); + $proc = new Process($cmd, $this->testDir, null, null, 300); + $output = ''; + + $exitcode = $proc->run(function ($type, $buffer) use (&$output) { + $output .= $buffer; + }); if (isset($testData['EXPECT'])) { - $this->assertEquals($testData['EXPECT'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput()); + $output = trim($this->cleanOutput($output)); + $expected = $testData['EXPECT']; + + $line = 1; + for ($i = 0, $j = 0; $i < strlen($expected); ) { + if ($expected[$i] === "\n") { + $line++; + } + if ($expected[$i] === '%') { + preg_match('{%(.+?)%}', substr($expected, $i), $match); + $regex = $match[1]; + + if (preg_match('{'.$regex.'}', substr($output, $j), $match)) { + $i += strlen($regex) + 2; + $j += strlen($match[0]); + continue; + } else { + $this->fail( + 'Failed to match pattern '.$regex.' at line '.$line.' / abs offset '.$i.': ' + .substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL. + 'Output:'.PHP_EOL.$output + ); + } + } + if ($expected[$i] !== $output[$j]) { + $this->fail( + 'Output does not match expectation at line '.$line.' / abs offset '.$i.': '.PHP_EOL + .'-'.substr($expected, $i, min(strpos($expected, "\n", $i)-$i, 100)).PHP_EOL + .'+'.substr($output, $j, min(strpos($output, "\n", $j)-$j, 100)).PHP_EOL.PHP_EOL + .'Output:'.PHP_EOL.$output + ); + } + $i++; + $j++; + } } if (isset($testData['EXPECT-REGEX'])) { - $this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($proc->getOutput()), 'Error Output: '.$proc->getErrorOutput()); + $this->assertRegExp($testData['EXPECT-REGEX'], $this->cleanOutput($output)); } - if (isset($testData['EXPECT-ERROR'])) { - $this->assertEquals($testData['EXPECT-ERROR'], $this->cleanOutput($proc->getErrorOutput())); - } - if (isset($testData['EXPECT-ERROR-REGEX'])) { - $this->assertRegExp($testData['EXPECT-ERROR-REGEX'], $this->cleanOutput($proc->getErrorOutput())); + if (isset($testData['EXPECT-REGEXES'])) { + $cleanOutput = $this->cleanOutput($output); + foreach (explode("\n", $testData['EXPECT-REGEXES']) as $regex) { + $this->assertRegExp($regex, $cleanOutput, 'Output: '.$output); + } } if (isset($testData['EXPECT-EXIT-CODE'])) { $this->assertSame($testData['EXPECT-EXIT-CODE'], $exitcode); @@ -132,7 +179,7 @@ class AllFunctionalTest extends TestCase { $tests = array(); foreach (Finder::create()->in(__DIR__.'/Fixtures/functional')->name('*.test')->files() as $file) { - $tests[] = array($file->getRealPath()); + $tests[basename($file)] = array($file->getRealPath()); } return $tests; @@ -144,23 +191,6 @@ class AllFunctionalTest extends TestCase $data = array(); $section = null; - $testDir = self::getUniqueTmpDirectory(); - $this->testDir = $testDir; - $varRegex = '#%([a-zA-Z_-]+)%#'; - $variableReplacer = function ($match) use (&$data, $testDir) { - list(, $var) = $match; - - switch ($var) { - case 'testDir': - $data['test_dir'] = $testDir; - - return $testDir; - - default: - throw new \InvalidArgumentException(sprintf('Unknown variable "%s". Supported variables: "testDir"', $var)); - } - }; - foreach ($tokens as $token) { if ('' === $token && null === $section) { continue; @@ -176,24 +206,20 @@ class AllFunctionalTest extends TestCase // Allow sections to validate, or modify their section data. switch ($section) { - case 'RUN': - $sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData); - break; - case 'EXPECT-EXIT-CODE': $sectionData = (int) $sectionData; break; + case 'RUN': case 'EXPECT': case 'EXPECT-REGEX': - case 'EXPECT-ERROR': - case 'EXPECT-ERROR-REGEX': - $sectionData = preg_replace_callback($varRegex, $variableReplacer, $sectionData); + case 'EXPECT-REGEXES': + $sectionData = trim($sectionData); break; default: throw new \RuntimeException(sprintf( - 'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-ERROR", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-ERROR-REGEX". ' + 'Unknown section "%s". Allowed sections: "RUN", "EXPECT", "EXPECT-EXIT-CODE", "EXPECT-REGEX", "EXPECT-REGEXES". ' .'Section headers must be written as "--HEADER_NAME--".', $section )); @@ -207,8 +233,8 @@ class AllFunctionalTest extends TestCase if (!isset($data['RUN'])) { throw new \RuntimeException('The test file must have a section named "RUN".'); } - if (!isset($data['EXPECT']) && !isset($data['EXPECT-ERROR']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-ERROR-REGEX'])) { - throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-ERROR", "EXPECT-REGEX", or "EXPECT-ERROR-REGEX".'); + if (!isset($data['EXPECT']) && !isset($data['EXPECT-REGEX']) && !isset($data['EXPECT-REGEXES'])) { + throw new \RuntimeException('The test file must have a section named "EXPECT", "EXPECT-REGEX", or "EXPECT-REGEXES".'); } return $data; diff --git a/tests/Composer/Test/Fixtures/functional/create-project-command.test b/tests/Composer/Test/Fixtures/functional/create-project-command.test index 1c4813446..31ce946c3 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-command.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-command.test @@ -1,4 +1,4 @@ --RUN-- -create-project seld/jsonlint %testDir% 1.0.0 --prefer-source -n ---EXPECT-ERROR-REGEX-- -{Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?} +create-project seld/jsonlint foo 1.0.0 --prefer-source -n +--EXPECT-REGEX-- +{- Installing seld/jsonlint \(1.0.0\): Cloning [a-f0-9]{10}( from cache)?} diff --git a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test index 357f51619..993f96e1a 100644 --- a/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test +++ b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages.test @@ -1,4 +1,4 @@ --RUN-- -create-project --repository=packages.json -v seld/jsonlint %testDir% dev-master ---EXPECT-ERROR-REGEX-- -{^Installing seld/jsonlint \(dev-master [a-f0-9]{40}\)}m +create-project --repository=packages.json -v seld/jsonlint foo dev-main +--EXPECT-REGEX-- +{^Installing seld/jsonlint \(dev-main [a-f0-9]{40}\)}m diff --git a/tests/Composer/Test/Fixtures/functional/packages.json b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json similarity index 90% rename from tests/Composer/Test/Fixtures/functional/packages.json rename to tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json index 11dfe2d8e..1069f6581 100644 --- a/tests/Composer/Test/Fixtures/functional/packages.json +++ b/tests/Composer/Test/Fixtures/functional/create-project-shows-full-hash-for-dev-packages/packages.json @@ -9,8 +9,9 @@ "validator" ], "homepage": "", - "version": "dev-master", - "version_normalized": "9999999-dev", + "version": "dev-main", + "version_normalized": "dev-main", + "default-branch": true, "license": [ "MIT" ], @@ -41,4 +42,4 @@ "php": ">=5.3.0" } } -] \ No newline at end of file +] diff --git a/tests/Composer/Test/InstalledVersionsTest.php b/tests/Composer/Test/InstalledVersionsTest.php index 9070a4d67..2d8799727 100644 --- a/tests/Composer/Test/InstalledVersionsTest.php +++ b/tests/Composer/Test/InstalledVersionsTest.php @@ -26,6 +26,11 @@ class InstalledVersionsTest extends TestCase $prop->setValue(array()); } + public static function tearDownAfterClass() + { + self::setUpBeforeClass(); + } + public function setUp() { InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php');