diff --git a/phpunit.xml.dist b/phpunit.xml.dist index dd72dd5ee4fa..c10b2486552b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,7 +15,7 @@ bootstrap="tests/bootstrap.php" > - + diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php index d756d9b9ddcf..1b790ad5ea20 100644 --- a/src/Composer/IO/ConsoleIO.php +++ b/src/Composer/IO/ConsoleIO.php @@ -36,9 +36,9 @@ class ConsoleIO extends BaseIO /** @var HelperSet */ protected $helperSet; /** @var string */ - protected $lastMessage; + protected $lastMessage = ''; /** @var string */ - protected $lastMessageErr; + protected $lastMessageErr = ''; /** @var float */ private $startTime; diff --git a/src/Composer/Json/JsonValidationException.php b/src/Composer/Json/JsonValidationException.php index 2fa5eb48945d..2d113a8021f8 100644 --- a/src/Composer/Json/JsonValidationException.php +++ b/src/Composer/Json/JsonValidationException.php @@ -24,7 +24,7 @@ class JsonValidationException extends Exception public function __construct($message, $errors = array(), Exception $previous = null) { $this->errors = $errors; - parent::__construct($message, 0, $previous); + parent::__construct((string) $message, 0, $previous); } public function getErrors() diff --git a/src/Composer/Package/Archiver/ArchiveManager.php b/src/Composer/Package/Archiver/ArchiveManager.php index 13dd7c7feba8..356c53646143 100644 --- a/src/Composer/Package/Archiver/ArchiveManager.php +++ b/src/Composer/Package/Archiver/ArchiveManager.php @@ -88,7 +88,7 @@ public function getPackageFilename(CompletePackageInterface $package) } $nameParts = array($baseName); - if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) { + if (null !== $package->getDistReference() && preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) { array_push($nameParts, $package->getDistReference(), $package->getDistType()); } else { array_push($nameParts, $package->getPrettyVersion(), $package->getDistReference()); diff --git a/src/Composer/Package/BasePackage.php b/src/Composer/Package/BasePackage.php index a7a075099231..f8199a0bb352 100644 --- a/src/Composer/Package/BasePackage.php +++ b/src/Composer/Package/BasePackage.php @@ -217,6 +217,10 @@ public function getFullPrettyVersion($truncate = true, $displayMode = PackageInt throw new \UnexpectedValueException('Display mode '.$displayMode.' is not supported'); } + if (null === $reference) { + return $this->getPrettyVersion(); + } + // if source reference is a sha1 hash -- truncate if ($truncate && \strlen($reference) === 40 && $this->getSourceType() !== 'svn') { return $this->getPrettyVersion() . ' ' . substr($reference, 0, 7); diff --git a/src/Composer/Package/Package.php b/src/Composer/Package/Package.php index 1f1cdf5534e1..9afbd64296c3 100644 --- a/src/Composer/Package/Package.php +++ b/src/Composer/Package/Package.php @@ -27,11 +27,14 @@ class Package extends BasePackage protected $installationSource; protected $sourceType; protected $sourceUrl; + /** @var ?string */ protected $sourceReference; protected $sourceMirrors; protected $distType; protected $distUrl; + /** @var ?string */ protected $distReference; + /** @var ?string */ protected $distSha1Checksum; protected $distMirrors; protected $version; diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 7f0fb1023a2a..355cf49f0d7b 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -131,7 +131,7 @@ public function getSourceUrls(); /** * Returns the repository reference of this package, e.g. master, 1.0.0 or a commit hash for git * - * @return string The repository reference + * @return ?string The repository reference */ public function getSourceReference(); @@ -172,14 +172,14 @@ public function getDistUrls(); /** * Returns the reference of the distribution archive of this version, e.g. master, 1.0.0 or a commit hash for git * - * @return string + * @return ?string */ public function getDistReference(); /** * Returns the sha1 checksum for the distribution archive of this version * - * @return string + * @return ?string */ public function getDistSha1Checksum(); diff --git a/src/Composer/Util/Bitbucket.php b/src/Composer/Util/Bitbucket.php index 5970aa631fc2..445dbed7e3da 100644 --- a/src/Composer/Util/Bitbucket.php +++ b/src/Composer/Util/Bitbucket.php @@ -151,7 +151,7 @@ public function authorizeOAuthInteractively($originUrl, $message = null) $this->io->writeError(sprintf('to create a consumer. It will be stored in "%s" for future use by Composer.', $this->config->getAuthConfigSource()->getName())); $this->io->writeError('Ensure you enter a "Callback URL" (http://example.com is fine) or it will not be possible to create an Access Token (this callback url will not be used by composer)'); - $consumerKey = trim($this->io->askAndHideAnswer('Consumer Key (hidden): ')); + $consumerKey = trim((string) $this->io->askAndHideAnswer('Consumer Key (hidden): ')); if (!$consumerKey) { $this->io->writeError('No consumer key given, aborting.'); @@ -160,7 +160,7 @@ public function authorizeOAuthInteractively($originUrl, $message = null) return false; } - $consumerSecret = trim($this->io->askAndHideAnswer('Consumer Secret (hidden): ')); + $consumerSecret = trim((string) $this->io->askAndHideAnswer('Consumer Secret (hidden): ')); if (!$consumerSecret) { $this->io->writeError('No consumer secret given, aborting.'); diff --git a/src/Composer/Util/Perforce.php b/src/Composer/Util/Perforce.php index 0bde7fb3e214..ea2b1152c0aa 100644 --- a/src/Composer/Util/Perforce.php +++ b/src/Composer/Util/Perforce.php @@ -160,7 +160,7 @@ public function setStream($stream) public function isStream() { - return (strcmp($this->p4DepotType, 'stream') === 0); + return is_string($this->p4DepotType) && (strcmp($this->p4DepotType, 'stream') === 0); } public function getStream() @@ -204,11 +204,11 @@ public function setUser($user) public function queryP4User() { $this->getUser(); - if (strlen($this->p4User) > 0) { + if (strlen((string) $this->p4User) > 0) { return; } $this->p4User = $this->getP4variable('P4USER'); - if (strlen($this->p4User) > 0) { + if (strlen((string) $this->p4User) > 0) { return; } $this->p4User = $this->io->ask('Enter P4 User:'); @@ -262,7 +262,7 @@ public function queryP4Password() return $this->p4Password; } $password = $this->getP4variable('P4PASSWD'); - if (strlen($password) <= 0) { + if (strlen((string) $password) <= 0) { $password = $this->io->askAndHideAnswer('Enter password for Perforce user ' . $this->getUser() . ': '); } $this->p4Password = $password; diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php index 03c5aa519dfb..c00e8fd20c86 100644 --- a/src/Composer/Util/ProcessExecutor.php +++ b/src/Composer/Util/ProcessExecutor.php @@ -356,9 +356,9 @@ public function markJobDone() */ public function splitLines($output) { - $output = trim($output); + $output = trim((string) $output); - return ((string) $output === '') ? array() : preg_split('{\r?\n}', $output); + return $output === '' ? array() : preg_split('{\r?\n}', $output); } /** @@ -371,6 +371,9 @@ public function getErrorOutput() return $this->errorOutput; } + /** + * @private + */ public function outputHandler($type, $buffer) { if ($this->captureOutput) { diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php index ead8bc1c1753..036410407ecb 100644 --- a/tests/Composer/Test/Downloader/FileDownloaderTest.php +++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php @@ -18,6 +18,7 @@ use Composer\Plugin\PluginEvents; use Composer\Plugin\PreFileDownloadEvent; use Composer\Test\TestCase; +use Composer\Test\Mock\ProcessExecutorMock; use Composer\Util\Filesystem; use Composer\Util\Http\Response; use Composer\Util\Loop; @@ -194,7 +195,7 @@ public function testDownloadWithCustomProcessedUrl() $dispatcher = new EventDispatcher( $composerMock, $this->getMockBuilder('Composer\IO\IOInterface')->getMock(), - $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock() + new ProcessExecutorMock ); $dispatcher->addListener(PluginEvents::PRE_FILE_DOWNLOAD, function (PreFileDownloadEvent $event) use ($expectedUrl) { $event->setProcessedUrl($expectedUrl); @@ -288,7 +289,7 @@ public function testDownloadWithCustomCacheKey() $dispatcher = new EventDispatcher( $composerMock, $this->getMockBuilder('Composer\IO\IOInterface')->getMock(), - $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock() + new ProcessExecutorMock ); $dispatcher->addListener(PluginEvents::PRE_FILE_DOWNLOAD, function (PreFileDownloadEvent $event) use ($customCacheKey) { $event->setCustomCacheKey($customCacheKey); diff --git a/tests/Composer/Test/Downloader/FossilDownloaderTest.php b/tests/Composer/Test/Downloader/FossilDownloaderTest.php index 41f4ec17ec5b..69a810977664 100644 --- a/tests/Composer/Test/Downloader/FossilDownloaderTest.php +++ b/tests/Composer/Test/Downloader/FossilDownloaderTest.php @@ -16,6 +16,7 @@ use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\Platform; +use Composer\Test\Mock\ProcessExecutorMock; class FossilDownloaderTest extends TestCase { @@ -39,7 +40,7 @@ protected function getDownloaderMock($io = null, $config = null, $executor = nul { $io = $io ?: $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $config = $config ?: $this->getMockBuilder('Composer\Config')->getMock(); - $executor = $executor ?: $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $executor = $executor ?: new ProcessExecutorMock; $filesystem = $filesystem ?: $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); return new FossilDownloader($io, $config, $executor, $filesystem); @@ -67,28 +68,18 @@ public function testInstall() $packageMock->expects($this->once()) ->method('getSourceUrls') ->will($this->returnValue(array('http://fossil.kd2.org/kd2fw/'))); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - - $expectedFossilCommand = $this->getCmd('fossil clone -- \'http://fossil.kd2.org/kd2fw/\' \'repo.fossil\''); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedFossilCommand)) - ->will($this->returnValue(0)); - - $expectedFossilCommand = $this->getCmd('fossil open --nested -- \'repo.fossil\''); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($expectedFossilCommand)) - ->will($this->returnValue(0)); - - $expectedFossilCommand = $this->getCmd('fossil update -- \'trunk\''); - $processExecutor->expects($this->at(2)) - ->method('execute') - ->with($this->equalTo($expectedFossilCommand)) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd('fossil clone -- \'http://fossil.kd2.org/kd2fw/\' \'repo.fossil\''), + $this->getCmd('fossil open --nested -- \'repo.fossil\''), + $this->getCmd('fossil update -- \'trunk\''), + ), true); + + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->install($packageMock, 'repo'); + + $process->assertComplete($this); } public function testUpdateforPackageWithoutSourceReference() @@ -126,42 +117,46 @@ public function testUpdate() $packageMock->expects($this->any()) ->method('getVersion') ->will($this->returnValue('1.0.0.0')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - - $expectedFossilCommand = $this->getCmd("fossil changes"); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedFossilCommand)) - ->will($this->returnValue(0)); - $expectedFossilCommand = $this->getCmd("fossil pull && fossil up 'trunk'"); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($expectedFossilCommand)) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd("fossil changes"), + $this->getCmd("fossil pull && fossil up 'trunk'"), + ), true); + + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); } public function testRemove() { - $expectedResetCommand = $this->getCmd('cd \'composerPath\' && fossil status'); + // Ensure file exists + $file = $this->workingDir . '/.fslckout'; + touch($file); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->any()) - ->method('execute') - ->with($this->equalTo($expectedResetCommand)); + + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd('fossil changes'), + ), true); + $filesystem = $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $filesystem->expects($this->once()) ->method('removeDirectoryAsync') - ->with($this->equalTo('composerPath')) + ->with($this->equalTo($this->workingDir)) ->will($this->returnValue(\React\Promise\resolve(true))); - $downloader = $this->getDownloaderMock(null, null, $processExecutor, $filesystem); - $downloader->remove($packageMock, 'composerPath'); + $downloader = $this->getDownloaderMock(null, null, $process, $filesystem); + $downloader->prepare('uninstall', $packageMock, $this->workingDir); + $downloader->remove($packageMock, $this->workingDir); + $downloader->cleanup('uninstall', $packageMock, $this->workingDir); + + $process->assertComplete($this); } public function testGetInstallationSource() diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index a2030b38d683..248ee8074a39 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -17,7 +17,7 @@ use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\Platform; -use Prophecy\Argument; +use Composer\Test\Mock\ProcessExecutorMock; class GitDownloaderTest extends TestCase { @@ -69,7 +69,7 @@ protected function setupConfig($config = null) protected function getDownloaderMock($io = null, $config = null, $executor = null, $filesystem = null) { $io = $io ?: $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); - $executor = $executor ?: $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $executor = $executor ?: new ProcessExecutorMock; $filesystem = $filesystem ?: $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $config = $this->setupConfig($config); @@ -107,29 +107,21 @@ public function testDownload() $packageMock->expects($this->any()) ->method('getPrettyVersion') ->will($this->returnValue('dev-master')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'"); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'"), + $this->winCompat("git branch -r"), + $this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --"), + ), true); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(2)) - ->method('execute') - ->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->download($packageMock, 'composerPath'); $downloader->prepare('install', $packageMock, 'composerPath'); $downloader->install($packageMock, 'composerPath'); $downloader->cleanup('install', $packageMock, 'composerPath'); + + $process->assertComplete($this); } public function testDownloadWithCache() @@ -147,7 +139,6 @@ public function testDownloadWithCache() $packageMock->expects($this->any()) ->method('getPrettyVersion') ->will($this->returnValue('dev-master')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $this->initGitVersion('2.17.0'); @@ -158,50 +149,24 @@ public function testDownloadWithCache() $filesystem = new \Composer\Util\Filesystem; $filesystem->removeDirectory($cachePath); - $expectedGitCommand = $this->winCompat(sprintf("git clone --mirror -- 'https://example.com/composer/composer' '%s'", $cachePath)); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnCallback(function () use ($cachePath) { - @mkdir($cachePath, 0777, true); - - return 0; - })); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo('git rev-parse --git-dir'), $this->anything(), $this->equalTo($this->winCompat($cachePath))) - ->will($this->returnCallback(function ($command, &$output = null) { - $output = '.'; - - return 0; - })); - $processExecutor->expects($this->at(2)) - ->method('execute') - ->with($this->equalTo($this->winCompat('git rev-parse --quiet --verify \'1234567890123456789012345678901234567890^{commit}\'')), $this->equalTo(null), $this->equalTo($this->winCompat($cachePath))) - ->will($this->returnValue(0)); - - $expectedGitCommand = $this->winCompat(sprintf("git clone --no-checkout '%1\$s' 'composerPath' --dissociate --reference '%1\$s' && cd 'composerPath' && git remote set-url origin -- 'https://example.com/composer/composer' && git remote add composer -- 'https://example.com/composer/composer'", $cachePath)); - $processExecutor->expects($this->at(3)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(4)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git branch -r")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(5)) - ->method('execute') - ->with($this->equalTo($this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, $config, $processExecutor); + $process = new ProcessExecutorMock; + $process->expects(array( + array('cmd' => $this->winCompat(sprintf("git clone --mirror -- 'https://example.com/composer/composer' '%s'", $cachePath)), 'callback' => function () use ($cachePath) { @mkdir($cachePath, 0777, true); }), + array('cmd' => 'git rev-parse --git-dir', 'stdout' => '.'), + $this->winCompat('git rev-parse --quiet --verify \'1234567890123456789012345678901234567890^{commit}\''), + $this->winCompat(sprintf("git clone --no-checkout '%1\$s' 'composerPath' --dissociate --reference '%1\$s' && cd 'composerPath' && git remote set-url origin -- 'https://example.com/composer/composer' && git remote add composer -- 'https://example.com/composer/composer'", $cachePath)), + 'git branch -r', + $this->winCompat("(git checkout 'master' -- || git checkout -B 'master' 'composer/master' --) && git reset --hard '1234567890123456789012345678901234567890' --") + ), true); + + $downloader = $this->getDownloaderMock(null, $config, $process); $downloader->download($packageMock, 'composerPath'); $downloader->prepare('install', $packageMock, 'composerPath'); $downloader->install($packageMock, 'composerPath'); $downloader->cleanup('install', $packageMock, 'composerPath'); @rmdir($cachePath); + + $process->assertComplete($this); } public function testDownloadUsesVariousProtocolsAndSetsPushUrlForGithub() @@ -219,52 +184,28 @@ public function testDownloadUsesVariousProtocolsAndSetsPushUrlForGithub() $packageMock->expects($this->any()) ->method('getPrettyVersion') ->will($this->returnValue('1.0.0')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - - $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'https://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://github.com/mirrors/composer' && git fetch composer && git remote set-url origin -- 'https://github.com/mirrors/composer' && git remote set-url composer -- 'https://github.com/mirrors/composer'"); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(1)); - - $processExecutor->expects($this->at(1)) - ->method('getErrorOutput') - ->with() - ->will($this->returnValue('Error1')); - - $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'git@github.com:mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'git@github.com:mirrors/composer' && git fetch composer && git remote set-url origin -- 'git@github.com:mirrors/composer' && git remote set-url composer -- 'git@github.com:mirrors/composer'"); - $processExecutor->expects($this->at(2)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); - - $expectedGitCommand = $this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'"); - $processExecutor->expects($this->at(3)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $expectedGitCommand = $this->winCompat("git remote set-url --push origin -- 'git@github.com:composer/composer.git'"); - $processExecutor->expects($this->at(4)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(5)) - ->method('execute') - ->with($this->equalTo('git branch -r')) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->at(6)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor); + + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => $this->winCompat("git clone --no-checkout -- 'https://github.com/mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://github.com/mirrors/composer' && git fetch composer && git remote set-url origin -- 'https://github.com/mirrors/composer' && git remote set-url composer -- 'https://github.com/mirrors/composer'"), + 'return' => 1, + 'stderr' => 'Error1', + ), + $this->winCompat("git clone --no-checkout -- 'git@github.com:mirrors/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'git@github.com:mirrors/composer' && git fetch composer && git remote set-url origin -- 'git@github.com:mirrors/composer' && git remote set-url composer -- 'git@github.com:mirrors/composer'"), + $this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'"), + $this->winCompat("git remote set-url --push origin -- 'git@github.com:composer/composer.git'"), + 'git branch -r', + $this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), + ), true); + + $downloader = $this->getDownloaderMock(null, new Config(), $process); $downloader->download($packageMock, 'composerPath'); $downloader->prepare('install', $packageMock, 'composerPath'); $downloader->install($packageMock, 'composerPath'); $downloader->cleanup('install', $packageMock, 'composerPath'); + + $process->assertComplete($this); } public function pushUrlProvider() @@ -297,37 +238,29 @@ public function testDownloadAndSetPushUrlUseCustomVariousProtocolsForGithub($pro $packageMock->expects($this->any()) ->method('getPrettyVersion') ->will($this->returnValue('1.0.0')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $expectedGitCommand = $this->winCompat("git clone --no-checkout -- '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer -- '{$url}' && git fetch composer && git remote set-url origin -- '{$url}' && git remote set-url composer -- '{$url}'"); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); - - $expectedGitCommand = $this->winCompat("git remote set-url --push origin -- '{$pushUrl}'"); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand), $this->equalTo(null), $this->equalTo($this->winCompat('composerPath'))) - ->will($this->returnValue(0)); - - $processExecutor->expects($this->exactly(4)) - ->method('execute') - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat("git clone --no-checkout -- '{$url}' 'composerPath' && cd 'composerPath' && git remote add composer -- '{$url}' && git fetch composer && git remote set-url origin -- '{$url}' && git remote set-url composer -- '{$url}'"), + $this->winCompat("git remote set-url --push origin -- '{$pushUrl}'"), + 'git branch -r', + $this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), + ), true); $config = new Config(); $config->merge(array('config' => array('github-protocols' => $protocols))); - $downloader = $this->getDownloaderMock(null, $config, $processExecutor); + $downloader = $this->getDownloaderMock(null, $config, $process); $downloader->download($packageMock, 'composerPath'); $downloader->prepare('install', $packageMock, 'composerPath'); $downloader->install($packageMock, 'composerPath'); $downloader->cleanup('install', $packageMock, 'composerPath'); + + $process->assertComplete($this); } public function testDownloadThrowsRuntimeExceptionIfGitCommandFails() { - $expectedGitCommand = $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'"); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); $packageMock->expects($this->any()) ->method('getSourceReference') @@ -335,19 +268,31 @@ public function testDownloadThrowsRuntimeExceptionIfGitCommandFails() $packageMock->expects($this->any()) ->method('getSourceUrls') ->will($this->returnValue(array('https://example.com/composer/composer'))); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(1)); + $packageMock->expects($this->any()) + ->method('getSourceUrl') + ->will($this->returnValue('https://example.com/composer/composer')); + $packageMock->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); + + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => $this->winCompat("git clone --no-checkout -- 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git remote add composer -- 'https://example.com/composer/composer' && git fetch composer && git remote set-url origin -- 'https://example.com/composer/composer' && git remote set-url composer -- 'https://example.com/composer/composer'"), + 'return' => 1, + ), + )); // not using PHPUnit's expected exception because Prophecy exceptions extend from RuntimeException too so it is not safe try { - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->download($packageMock, 'composerPath'); $downloader->prepare('install', $packageMock, 'composerPath'); $downloader->install($packageMock, 'composerPath'); $downloader->cleanup('install', $packageMock, 'composerPath'); + + $process->assertComplete($this); + $this->fail('This test should throw'); } catch (\RuntimeException $e) { if ('RuntimeException' !== get_class($e)) { @@ -388,21 +333,29 @@ public function testUpdate() $packageMock->expects($this->any()) ->method('getVersion') ->will($this->returnValue('1.0.0.0')); + $packageMock->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); - $process = $this->prophesize('Composer\Util\ProcessExecutor'); - $process->execute($this->winCompat('git show-ref --head -d'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git status --porcelain --untracked-files=no'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git remote -v'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git branch -r'), Argument::cetera())->willReturn(0); - $process->execute($expectedGitUpdateCommand, null, $this->winCompat($this->workingDir))->willReturn(0)->shouldBeCalled(); - $process->execute($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), null, $this->winCompat($this->workingDir))->willReturn(0)->shouldBeCalled(); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat('git show-ref --head -d'), + $this->winCompat('git status --porcelain --untracked-files=no'), + $this->winCompat('git remote -v'), + $expectedGitUpdateCommand, + $this->winCompat('git branch -r'), + $this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), + $this->winCompat('git remote -v'), + ), true); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); - $downloader = $this->getDownloaderMock(null, new Config(), $process->reveal()); + $downloader = $this->getDownloaderMock(null, new Config(), $process); $downloader->download($packageMock, $this->workingDir, $packageMock); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); } public function testUpdateWithNewRepoUrl() @@ -422,59 +375,38 @@ public function testUpdateWithNewRepoUrl() $packageMock->expects($this->any()) ->method('getVersion') ->will($this->returnValue('1.0.0.0')); + $packageMock->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git show-ref --head -d"))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no"))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(2)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git remote -v"))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(3)) - ->method('execute') - ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(4)) - ->method('execute') - ->with($this->equalTo('git branch -r')) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(5)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(6)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git remote -v"))) - ->will($this->returnCallback(function ($cmd, &$output, $cwd) { - $output = 'origin https://github.com/old/url (fetch) + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat("git show-ref --head -d"), + $this->winCompat("git status --porcelain --untracked-files=no"), + $this->winCompat("git remote -v"), + $this->winCompat($expectedGitUpdateCommand), + 'git branch -r', + $this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), + array( + 'cmd' => $this->winCompat("git remote -v"), + 'stdout' => 'origin https://github.com/old/url (fetch) origin https://github.com/old/url (push) composer https://github.com/old/url (fetch) composer https://github.com/old/url (push) -'; - - return 0; - })); - $processExecutor->expects($this->at(7)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) - ->will($this->returnValue(0)); - $processExecutor->expects($this->at(8)) - ->method('execute') - ->with($this->equalTo($this->winCompat("git remote set-url --push origin -- 'git@github.com:composer/composer.git'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) - ->will($this->returnValue(0)); +', + ), + $this->winCompat("git remote set-url origin -- 'https://github.com/composer/composer'"), + $this->winCompat("git remote set-url --push origin -- 'git@github.com:composer/composer.git'"), + ), true); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); - $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor); + $downloader = $this->getDownloaderMock(null, new Config(), $process); $downloader->download($packageMock, $this->workingDir, $packageMock); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); } /** @@ -496,25 +428,35 @@ public function testUpdateThrowsRuntimeExceptionIfGitCommandFails() ->method('getVersion') ->will($this->returnValue('1.0.0.0')); - $process = $this->prophesize('Composer\Util\ProcessExecutor'); - $process->execute($this->winCompat('git --version'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git show-ref --head -d'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git status --porcelain --untracked-files=no'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git remote -v'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git branch -r'), Argument::cetera())->willReturn(0); - $process->execute($expectedGitUpdateCommand, null, $this->winCompat($this->workingDir))->willReturn(1)->shouldBeCalled(); - $process->execute($expectedGitUpdateCommand2, null, $this->winCompat($this->workingDir))->willReturn(1)->shouldBeCalled(); - $process->getErrorOutput()->willReturn(''); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat('git show-ref --head -d'), + $this->winCompat('git status --porcelain --untracked-files=no'), + $this->winCompat('git remote -v'), + array( + 'cmd' => $expectedGitUpdateCommand, + 'return' => 1, + ), + array( + 'cmd' => $expectedGitUpdateCommand2, + 'return' => 1, + ), + $this->winCompat('git --version'), + $this->winCompat('git branch -r'), + ), true); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); // not using PHPUnit's expected exception because Prophecy exceptions extend from RuntimeException too so it is not safe try { - $downloader = $this->getDownloaderMock(null, new Config(), $process->reveal()); + $downloader = $this->getDownloaderMock(null, new Config(), $process); $downloader->download($packageMock, $this->workingDir, $packageMock); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); + $this->fail('This test should throw'); } catch (\RuntimeException $e) { if ('RuntimeException' !== get_class($e)) { @@ -539,24 +481,38 @@ public function testUpdateDoesntThrowsRuntimeExceptionIfGitCommandFailsAtFirstBu $packageMock->expects($this->any()) ->method('getSourceUrls') ->will($this->returnValue(array(Platform::isWindows() ? 'C:\\' : '/', 'https://github.com/composer/composer'))); + $packageMock->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); - $process = $this->prophesize('Composer\Util\ProcessExecutor'); - $process->execute($this->winCompat('git --version'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git show-ref --head -d'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git status --porcelain --untracked-files=no'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git remote -v'), Argument::cetera())->willReturn(0); - $process->execute($this->winCompat('git branch -r'), Argument::cetera())->willReturn(0); - $process->execute($expectedFirstGitUpdateCommand, Argument::cetera())->willReturn(1)->shouldBeCalled(); - $process->execute($expectedSecondGitUpdateCommand, Argument::cetera())->willReturn(0)->shouldBeCalled(); - $process->execute($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), null, $this->winCompat($this->workingDir))->willReturn(0)->shouldBeCalled(); - $process->getErrorOutput()->willReturn(''); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->winCompat('git show-ref --head -d'), + $this->winCompat('git status --porcelain --untracked-files=no'), + $this->winCompat('git remote -v'), + array( + 'cmd' => $expectedFirstGitUpdateCommand, + 'return' => 1, + ), + $this->winCompat('git --version'), + $this->winCompat('git remote -v'), + array( + 'cmd' => $expectedSecondGitUpdateCommand, + 'return' => 0, + ), + $this->winCompat('git branch -r'), + $this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --"), + $this->winCompat('git remote -v'), + ), true); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); - $downloader = $this->getDownloaderMock(null, new Config(), $process->reveal()); + $downloader = $this->getDownloaderMock(null, new Config(), $process); $downloader->download($packageMock, $this->workingDir, $packageMock); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); } public function testDowngradeShowsAppropriateMessage() @@ -585,14 +541,14 @@ public function testDowngradeShowsAppropriateMessage() $newPackage->expects($this->any()) ->method('getVersion') ->will($this->returnValue('1.0.0.0')); + $newPackage->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); $newPackage->expects($this->any()) ->method('getFullPrettyVersion') ->will($this->returnValue('1.0.0')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->any()) - ->method('execute') - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; $ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $ioMock->expects($this->at(0)) @@ -600,7 +556,7 @@ public function testDowngradeShowsAppropriateMessage() ->with($this->stringContains('Downgrading')); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); - $downloader = $this->getDownloaderMock($ioMock, null, $processExecutor); + $downloader = $this->getDownloaderMock($ioMock, null, $process); $downloader->download($newPackage, $this->workingDir, $oldPackage); $downloader->prepare('update', $newPackage, $this->workingDir, $oldPackage); $downloader->update($oldPackage, $newPackage, $this->workingDir); @@ -630,11 +586,11 @@ public function testNotUsingDowngradingWithReferences() $newPackage->expects($this->any()) ->method('getVersion') ->will($this->returnValue('dev-ref2')); + $newPackage->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('dev-ref2')); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->any()) - ->method('execute') - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; $ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $ioMock->expects($this->at(0)) @@ -642,7 +598,7 @@ public function testNotUsingDowngradingWithReferences() ->with($this->stringContains('Upgrading')); $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); - $downloader = $this->getDownloaderMock($ioMock, null, $processExecutor); + $downloader = $this->getDownloaderMock($ioMock, null, $process); $downloader->download($newPackage, $this->workingDir, $oldPackage); $downloader->prepare('update', $newPackage, $this->workingDir, $oldPackage); $downloader->update($oldPackage, $newPackage, $this->workingDir); @@ -651,24 +607,29 @@ public function testNotUsingDowngradingWithReferences() public function testRemove() { - $expectedGitResetCommand = $this->winCompat("cd 'composerPath' && git status --porcelain --untracked-files=no"); + $expectedGitResetCommand = $this->winCompat("git status --porcelain --untracked-files=no"); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->any()) - ->method('execute') - ->with($this->equalTo($expectedGitResetCommand)) - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; + $process->expects(array( + 'git show-ref --head -d', + $expectedGitResetCommand, + ), true); + + $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); + $filesystem = $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $filesystem->expects($this->once()) ->method('removeDirectoryAsync') - ->with($this->equalTo('composerPath')) + ->with($this->equalTo($this->workingDir)) ->will($this->returnValue(\React\Promise\resolve(true))); - $downloader = $this->getDownloaderMock(null, null, $processExecutor, $filesystem); - $downloader->prepare('uninstall', $packageMock, 'composerPath'); - $downloader->remove($packageMock, 'composerPath'); - $downloader->cleanup('uninstall', $packageMock, 'composerPath'); + $downloader = $this->getDownloaderMock(null, null, $process, $filesystem); + $downloader->prepare('uninstall', $packageMock, $this->workingDir); + $downloader->remove($packageMock, $this->workingDir); + $downloader->cleanup('uninstall', $packageMock, $this->workingDir); + + $process->assertComplete($this); } public function testGetInstallationSource() diff --git a/tests/Composer/Test/Downloader/HgDownloaderTest.php b/tests/Composer/Test/Downloader/HgDownloaderTest.php index 7e606a607adb..e31262b1d170 100644 --- a/tests/Composer/Test/Downloader/HgDownloaderTest.php +++ b/tests/Composer/Test/Downloader/HgDownloaderTest.php @@ -16,6 +16,7 @@ use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\Platform; +use Composer\Test\Mock\ProcessExecutorMock; class HgDownloaderTest extends TestCase { @@ -39,7 +40,7 @@ protected function getDownloaderMock($io = null, $config = null, $executor = nul { $io = $io ?: $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $config = $config ?: $this->getMockBuilder('Composer\Config')->getMock(); - $executor = $executor ?: $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $executor = $executor ?: new ProcessExecutorMock; $filesystem = $filesystem ?: $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); return new HgDownloader($io, $config, $executor, $filesystem); @@ -67,22 +68,17 @@ public function testDownload() $packageMock->expects($this->once()) ->method('getSourceUrls') ->will($this->returnValue(array('https://mercurial.dev/l3l0/composer'))); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $expectedGitCommand = $this->getCmd('hg clone -- \'https://mercurial.dev/l3l0/composer\' \'composerPath\''); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd('hg clone -- \'https://mercurial.dev/l3l0/composer\' \'composerPath\''), + $this->getCmd('hg up -- \'ref\''), + ), true); - $expectedGitCommand = $this->getCmd('hg up -- \'ref\''); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($expectedGitCommand)) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->install($packageMock, 'composerPath'); + + $process->assertComplete($this); } public function testUpdateforPackageWithoutSourceReference() @@ -115,44 +111,44 @@ public function testUpdate() $packageMock->expects($this->any()) ->method('getSourceUrls') ->will($this->returnValue(array('https://github.com/l3l0/composer'))); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - - $expectedHgCommand = $this->getCmd("hg st"); - $processExecutor->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo($expectedHgCommand)) - ->will($this->returnValue(0)); - $expectedHgCommand = $this->getCmd("hg pull -- 'https://github.com/l3l0/composer' && hg up -- 'ref'"); - $processExecutor->expects($this->at(1)) - ->method('execute') - ->with($this->equalTo($expectedHgCommand)) - ->will($this->returnValue(0)); - - $downloader = $this->getDownloaderMock(null, null, $processExecutor); + + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd('hg st'), + $this->getCmd("hg pull -- 'https://github.com/l3l0/composer' && hg up -- 'ref'"), + ), true); + + $downloader = $this->getDownloaderMock(null, null, $process); $downloader->prepare('update', $packageMock, $this->workingDir, $packageMock); $downloader->update($packageMock, $packageMock, $this->workingDir); $downloader->cleanup('update', $packageMock, $this->workingDir, $packageMock); + + $process->assertComplete($this); } public function testRemove() { - $expectedResetCommand = $this->getCmd('cd \'composerPath\' && hg st'); - + $fs = new Filesystem; + $fs->ensureDirectoryExists($this->workingDir.'/.hg'); $packageMock = $this->getMockBuilder('Composer\Package\PackageInterface')->getMock(); - $processExecutor = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $processExecutor->expects($this->any()) - ->method('execute') - ->with($this->equalTo($expectedResetCommand)); + + $process = new ProcessExecutorMock; + $process->expects(array( + $this->getCmd('hg st'), + ), true); + $filesystem = $this->getMockBuilder('Composer\Util\Filesystem')->getMock(); $filesystem->expects($this->once()) ->method('removeDirectoryAsync') - ->with($this->equalTo('composerPath')) + ->with($this->equalTo($this->workingDir)) ->will($this->returnValue(\React\Promise\resolve(true))); - $downloader = $this->getDownloaderMock(null, null, $processExecutor, $filesystem); - $downloader->prepare('uninstall', $packageMock, 'composerPath'); - $downloader->remove($packageMock, 'composerPath'); - $downloader->cleanup('uninstall', $packageMock, 'composerPath'); + $downloader = $this->getDownloaderMock(null, null, $process, $filesystem); + $downloader->prepare('uninstall', $packageMock, $this->workingDir); + $downloader->remove($packageMock, $this->workingDir); + $downloader->cleanup('uninstall', $packageMock, $this->workingDir); + + $process->assertComplete($this); } public function testGetInstallationSource() diff --git a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php index 370fc9d313ce..cd47d8ecfa92 100644 --- a/tests/Composer/Test/Downloader/PerforceDownloaderTest.php +++ b/tests/Composer/Test/Downloader/PerforceDownloaderTest.php @@ -19,6 +19,7 @@ use Composer\Test\TestCase; use Composer\Factory; use Composer\Util\Filesystem; +use Composer\Test\Mock\ProcessExecutorMock; /** * @author Matt Whittom @@ -41,7 +42,7 @@ protected function setUp() $this->repoConfig = $this->getRepoConfig(); $this->config = $this->getConfig(); $this->io = $this->getMockIoInterface(); - $this->processExecutor = $this->getMockProcessExecutor(); + $this->processExecutor = new ProcessExecutorMock; $this->repository = $this->getMockRepository($this->repoConfig, $this->io, $this->config); $this->package = $this->getMockPackageInterface($this->repository); $this->downloader = new PerforceDownloader($this->io, $this->config, $this->processExecutor); @@ -61,11 +62,6 @@ protected function tearDown() } } - protected function getMockProcessExecutor() - { - return $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - } - protected function getConfig() { $config = new Config(); diff --git a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php index bbf3e6b98691..400f4dec9142 100644 --- a/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php +++ b/tests/Composer/Test/EventDispatcher/EventDispatcherTest.php @@ -22,6 +22,7 @@ use Composer\Script\ScriptEvents; use Composer\Script\Event as ScriptEvent; use Composer\Util\ProcessExecutor; +use Composer\Test\Mock\ProcessExecutorMock; use Symfony\Component\Console\Output\OutputInterface; class EventDispatcherTest extends TestCase @@ -56,7 +57,11 @@ public function testListenerExceptionsAreCaught() */ public function testDispatcherCanExecuteSingleCommandLineScript($command) { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $process = new ProcessExecutorMock; + $process->expects(array( + $command, + ), true); + $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $this->createComposerInstance(), @@ -71,12 +76,9 @@ public function testDispatcherCanExecuteSingleCommandLineScript($command) ->method('getListeners') ->will($this->returnValue($listener)); - $process->expects($this->once()) - ->method('execute') - ->with($command) - ->will($this->returnValue(0)); - $dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false); + + $process->assertComplete($this); } /** @@ -104,7 +106,7 @@ public function testDispatcherPassDevModeToAutoloadGeneratorForScriptEvents($dev $dispatcher = new EventDispatcher( $composer, $this->getMockBuilder('Composer\IO\IOInterface')->getMock(), - $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock() + new ProcessExecutorMock ); $event = $this->getMockBuilder('Composer\Script\Event') @@ -179,7 +181,7 @@ public function testDispatcherRemoveListener() $dispatcher = new EventDispatcher( $composer, $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE), - $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock() + new ProcessExecutorMock ); $listener = array($this, 'someMethod'); @@ -214,7 +216,12 @@ public function testDispatcherRemoveListener() public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $process = new ProcessExecutorMock; + $process->expects(array( + 'echo -n foo', + 'echo -n bar', + ), true); + $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $this->createComposerInstance(), @@ -226,10 +233,6 @@ public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack() )) ->getMock(); - $process->expects($this->exactly(2)) - ->method('execute') - ->will($this->returnValue(0)); - $listeners = array( 'echo -n foo', 'Composer\\Test\\EventDispatcher\\EventDispatcherTest::someMethod', @@ -246,16 +249,17 @@ public function testDispatcherCanExecuteCliAndPhpInSameEventScriptStack() '> post-install-cmd: Composer\Test\EventDispatcher\EventDispatcherTest::someMethod'.PHP_EOL. '> post-install-cmd: echo -n bar'.PHP_EOL; $this->assertEquals($expected, $io->getOutput()); + + $process->assertComplete($this); } public function testDispatcherCanPutEnv() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $this->createComposerInstance(), $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE), - $process, + new ProcessExecutorMock, )) ->setMethods(array( 'getListeners', @@ -285,11 +289,10 @@ public function testDispatcherAppendsDirBinOnPathForEveryListener() chdir(__DIR__); putenv('COMPOSER_BIN_DIR=' . __DIR__ . sprintf('%svendor%sbin', DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR)); - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->setConstructorArgs(array( $this->createComposerInstance(), $io = new BufferIO('', OutputInterface::VERBOSITY_VERBOSE), - $process, + new ProcessExecutorMock, ))->setMethods(array( 'getListeners', ))->getMock(); @@ -342,7 +345,13 @@ public static function getTestEnv() public function testDispatcherCanExecuteComposerScriptGroups() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $process = new ProcessExecutorMock; + $process->expects(array( + 'echo -n foo', + 'echo -n baz', + 'echo -n bar', + ), true); + $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $composer = $this->createComposerInstance(), @@ -354,10 +363,6 @@ public function testDispatcherCanExecuteComposerScriptGroups() )) ->getMock(); - $process->expects($this->exactly(3)) - ->method('execute') - ->will($this->returnValue(0)); - $dispatcher->expects($this->atLeastOnce()) ->method('getListeners') ->will($this->returnCallback(function (Event $event) { @@ -383,11 +388,17 @@ public function testDispatcherCanExecuteComposerScriptGroups() '> subgroup: echo -n baz'.PHP_EOL. '> group: echo -n bar'.PHP_EOL; $this->assertEquals($expected, $io->getOutput()); + + $process->assertComplete($this); } public function testRecursionInScriptsNames() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); + $process = new ProcessExecutorMock; + $process->expects(array( + 'echo Hello '.ProcessExecutor::escape('World'), + ), true); + $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $composer = $this->createComposerInstance(), @@ -399,10 +410,6 @@ public function testRecursionInScriptsNames() )) ->getMock(); - $process->expects($this->exactly(1)) - ->method('execute') - ->will($this->returnValue(0)); - $dispatcher->expects($this->atLeastOnce()) ->method('getListeners') ->will($this->returnCallback(function (Event $event) { @@ -422,18 +429,19 @@ public function testRecursionInScriptsNames() "> hello: echo Hello " .escapeshellarg('World').PHP_EOL; $this->assertEquals($expected, $io->getOutput()); + + $process->assertComplete($this); } public function testDispatcherDetectInfiniteRecursion() { $this->setExpectedException('RuntimeException'); - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $composer = $this->createComposerInstance(), $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(), - $process, + new ProcessExecutorMock, )) ->setMethods(array( 'getListeners', @@ -549,12 +557,11 @@ public function testDispatcherOutputsErrorOnFailedCommand() public function testDispatcherInstallerEvents() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); $dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher') ->setConstructorArgs(array( $this->createComposerInstance(), $this->getMockBuilder('Composer\IO\IOInterface')->getMock(), - $process, + new ProcessExecutorMock, )) ->setMethods(array('getListeners')) ->getMock(); diff --git a/tests/Composer/Test/Fixtures/installer/update-installed-reference.test b/tests/Composer/Test/Fixtures/installer/update-installed-reference.test index ae0b2d5374fb..9f91322ebaf7 100644 --- a/tests/Composer/Test/Fixtures/installer/update-installed-reference.test +++ b/tests/Composer/Test/Fixtures/installer/update-installed-reference.test @@ -28,4 +28,4 @@ Updating a dev package forcing it's reference should not do anything if the refe --RUN-- update --EXPECT-- -Upgrading a/a (dev-master def000 => dev-master ) +Upgrading a/a (dev-master def000 => dev-master) diff --git a/tests/Composer/Test/InstalledVersionsTest.php b/tests/Composer/Test/InstalledVersionsTest.php index d48cdf09a501..380114a2e9b2 100644 --- a/tests/Composer/Test/InstalledVersionsTest.php +++ b/tests/Composer/Test/InstalledVersionsTest.php @@ -205,6 +205,9 @@ public function testGetRootPackage() ), InstalledVersions::getRootPackage()); } + /** + * @group legacy + */ public function testGetRawData() { $dir = $this->root; diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 3526db5c1835..c4202511ce66 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -67,6 +67,21 @@ public function testInstaller(RootPackageInterface $rootPackage, $repositories, ->setConstructorArgs(array($io)) ->getMock(); $config = $this->getMockBuilder('Composer\Config')->getMock(); + $config->expects($this->any()) + ->method('get') + ->will($this->returnCallback(function ($key) { + switch ($key) { + case 'vendor-dir': + return 'foo'; + case 'lock'; + case 'notify-on-install'; + return true; + case 'platform'; + return array(); + } + + throw new \UnexpectedValueException('Unknown key '.$key); + })); $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); $httpDownloader = $this->getMockBuilder('Composer\Util\HttpDownloader')->disableOriginalConstructor()->getMock(); diff --git a/tests/Composer/Test/Mock/ProcessExecutorMock.php b/tests/Composer/Test/Mock/ProcessExecutorMock.php new file mode 100644 index 000000000000..1d1889f0fca2 --- /dev/null +++ b/tests/Composer/Test/Mock/ProcessExecutorMock.php @@ -0,0 +1,150 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Mock; + +use Composer\Util\ProcessExecutor; +use Composer\Util\Platform; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\AssertionFailedError; +use Symfony\Component\Process\Process; +use React\Promise\Promise; + +/** + * @author Jordi Boggiano + */ +class ProcessExecutorMock extends ProcessExecutor +{ + private $expectations = array(); + private $strict = false; + private $defaultHandler = array('return' => 0, 'stdout' => '', 'stderr' => ''); + private $log = array(); + + /** + * @param array $expectations + * @param bool $strict set to true if you want to provide *all* expected commands, and not just a subset you are interested in testing + * @param array{return: int, stdout?: string, stderr?: string} $defaultHandler default command handler for undefined commands if not in strict mode + */ + public function expects(array $expectations, $strict = false, array $defaultHandler = array('return' => 0, 'stdout' => '', 'stderr' => '')) + { + $default = array('cmd' => '', 'return' => 0, 'stdout' => '', 'stderr' => '', 'callback' => null); + $this->expectations = array_map(function ($expect) use ($default) { + if (is_string($expect)) { + $expect = array('cmd' => $expect); + } elseif ($diff = array_diff_key(array_merge($default, $expect), $default)) { + throw new \UnexpectedValueException('Unexpected keys in process execution step: '.implode(', ', array_keys($diff))); + } + + return array_merge($default, $expect); + }, $expectations); + $this->strict = $strict; + $this->defaultHandler = array_merge($default, $defaultHandler); + } + + public function assertComplete(TestCase $testCase) + { + if ($this->expectations) { + $expectations = array_map(function ($expect) { + return $expect['cmd']; + }, $this->expectations); + throw new AssertionFailedError( + 'There are still '.count($this->expectations).' expected process calls which have not been consumed:'.PHP_EOL. + implode(PHP_EOL, $expectations).PHP_EOL.PHP_EOL. + 'Received calls:'.PHP_EOL.implode(PHP_EOL, $this->log) + ); + } + + $testCase->assertTrue(true); + } + + public function execute($command, &$output = null, $cwd = null) + { + if (func_num_args() > 1) { + return $this->doExecute($command, $cwd, false, $output); + } + + return $this->doExecute($command, $cwd, false); + } + + public function executeTty($command, $cwd = null) + { + if (Platform::isTty()) { + return $this->doExecute($command, $cwd, true); + } + + return $this->doExecute($command, $cwd, false); + } + + private function doExecute($command, $cwd, $tty, &$output = null) + { + $this->captureOutput = func_num_args() > 3; + $this->errorOutput = ''; + + $callback = is_callable($output) ? $output : array($this, 'outputHandler'); + + $this->log[] = $command; + + if ($this->expectations && $command === $this->expectations[0]['cmd']) { + $expect = array_shift($this->expectations); + $stdout = $expect['stdout']; + $stderr = $expect['stderr']; + $return = $expect['return']; + if (isset($expect['callback'])) { + call_user_func($expect['callback']); + } + } elseif (!$this->strict) { + $stdout = $this->defaultHandler['stdout']; + $stderr = $this->defaultHandler['stderr']; + $return = $this->defaultHandler['return']; + } else { + throw new AssertionFailedError( + 'Received unexpected command "'.$command.'" in "'.$cwd.'"'.PHP_EOL. + ($this->expectations ? 'Expected "'.$this->expectations[0]['cmd'].'" at this point.' : 'Expected no more calls at this point.').PHP_EOL. + 'Received calls:'.PHP_EOL.implode(PHP_EOL, array_slice($this->log, 0, -1)) + ); + } + + if ($stdout) { + call_user_func($callback, Process::STDOUT, $stdout); + } + if ($stderr) { + call_user_func($callback, Process::ERR, $stderr); + } + + if ($this->captureOutput && !is_callable($output)) { + $output = $stdout; + } + + $this->errorOutput = $stderr; + + return $return; + } + + public function executeAsync($command, $cwd = null) + { + $resolver = function ($resolve, $reject) { + // TODO strictly speaking this should resolve with a mock Process instance here + $resolve(); + }; + + $canceler = function () { + throw new \RuntimeException('Aborted process'); + }; + + return new Promise($resolver, $canceler); + } + + public function getErrorOutput() + { + return $this->errorOutput; + } +} diff --git a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php index 880b6f766fb2..d8320863236f 100644 --- a/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php +++ b/tests/Composer/Test/Package/Loader/RootPackageLoaderTest.php @@ -19,13 +19,14 @@ use Composer\Package\Version\VersionGuesser; use Composer\Semver\VersionParser; use Composer\Test\TestCase; +use Composer\Test\Mock\ProcessExecutorMock; use Prophecy\Argument; class RootPackageLoaderTest extends TestCase { protected function loadPackage($data) { - $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') + $manager = $this->getMockBuilder('Composer\\Repository\\RepositoryManager') ->disableOriginalConstructor() ->getMock(); @@ -67,38 +68,28 @@ public function testStabilityFlagsParsing() public function testNoVersionIsVisibleInPrettyVersion() { - $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') + $manager = $this->getMockBuilder('Composer\\Repository\\RepositoryManager') ->disableOriginalConstructor() ->getMock() ; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $executor - ->expects($this->any()) - ->method('execute') - ->willReturn(null) - ; - $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser())); + $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $process = new ProcessExecutorMock, new VersionParser())); + $process->expects(array(), false, array('return' => 1)); + $package = $loader->load(array()); $this->assertEquals("1.0.0.0", $package->getVersion()); $this->assertEquals(RootPackage::DEFAULT_PRETTY_VERSION, $package->getPrettyVersion()); + } public function testPrettyVersionForRootPackageInVersionBranch() { // see #6845 - $manager = $this->prophesize('\\Composer\\Repository\\RepositoryManager'); - $versionGuesser = $this->prophesize('\\Composer\\Package\\Version\\VersionGuesser'); + $manager = $this->prophesize('Composer\\Repository\\RepositoryManager'); + $versionGuesser = $this->prophesize('Composer\\Package\\Version\\VersionGuesser'); $versionGuesser->guessVersion(Argument::cetera()) ->willReturn(array( 'name' => 'A', @@ -120,48 +111,28 @@ public function testFeatureBranchPrettyVersion() $this->markTestSkipped('proc_open() is not available'); } - $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') + $manager = $this->getMockBuilder('Composer\\Repository\\RepositoryManager') ->disableOriginalConstructor() ->getMock() ; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n"; - - return 0; - }) - ; - - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git rev-list master..latest-production', $command); - $output = ""; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n", + ), + 'git rev-list master..latest-production', + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser())); + $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $process, new VersionParser())); $package = $loader->load(array('require' => array('foo/bar' => 'self.version'))); $this->assertEquals("dev-master", $package->getPrettyVersion()); + + $process->assertComplete($this); } public function testNonFeatureBranchPrettyVersion() @@ -170,36 +141,26 @@ public function testNonFeatureBranchPrettyVersion() $this->markTestSkipped('proc_open() is not available'); } - $manager = $this->getMockBuilder('\\Composer\\Repository\\RepositoryManager') - ->disableOriginalConstructor() - ->getMock() - ; - - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() + $manager = $this->getMockBuilder('Composer\\Repository\\RepositoryManager') ->disableOriginalConstructor() ->getMock() ; - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n" + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $executor, new VersionParser())); + $loader = new RootPackageLoader($manager, $config, null, new VersionGuesser($config, $process, new VersionParser())); $package = $loader->load(array('require' => array('foo/bar' => 'self.version'), "non-feature-branches" => array("latest-.*"))); $this->assertEquals("dev-latest-production", $package->getPrettyVersion()); + + $process->assertComplete($this); } } diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php index 8df182d66d79..d932f92238c6 100644 --- a/tests/Composer/Test/Package/Version/VersionGuesserTest.php +++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php @@ -18,6 +18,7 @@ use Composer\Test\TestCase; use Composer\Util\Git as GitUtil; use Composer\Util\ProcessExecutor; +use Composer\Test\Mock\ProcessExecutorMock; class VersionGuesserTest extends TestCase { @@ -32,70 +33,28 @@ public function testHgGuessVersionReturnsData() { $branch = 'default'; - $executor = $this->getMockBuilder('Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - $step = 0; + $process = new ProcessExecutorMock; + $process->expects(array( + array('cmd' => 'git branch -a --no-color --no-abbrev -v', 'return' => 128), + array('cmd' => 'git describe --exact-match --tags', 'return' => 128), + array('cmd' => 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($process), 'return' => 128), + array('cmd' => 'hg branch', 'return' => 0, 'stdout' => $branch), + array('cmd' => 'hg branches', 'return' => 0), + array('cmd' => 'hg bookmarks', 'return' => 0), + ), true); GitUtil::getVersion(new ProcessExecutor); - $executor - ->expects($this->at($step)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - - return 128; - }) - ; - - ++$step; - $executor - ->expects($this->at($step)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git describe --exact-match --tags', $command); - - return 128; - }) - ; - - ++$step; - $executor - ->expects($this->at($step)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $executor) { - $self->assertEquals('git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($executor), $command); - - return 128; - }) - ; - - ++$step; - $executor - ->expects($this->at($step)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $branch) { - $self->assertEquals('hg branch', $command); - $output = $branch; - - return 0; - }) - ; - $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-".$branch, $versionArray['version']); $this->assertEquals("dev-".$branch, $versionArray['pretty_version']); $this->assertEmpty($versionArray['commit']); + + $process->assertComplete($this); } public function testGuessVersionReturnsData() @@ -103,29 +62,17 @@ public function testGuessVersionReturnsData() $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; $anotherCommitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash, $anotherCommitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* master $commitHash Commit message\n(no branch) $anotherCommitHash Commit message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* master $commitHash Commit message\n(no branch) $anotherCommitHash Commit message\n" + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-master", $versionArray['version']); @@ -133,6 +80,8 @@ public function testGuessVersionReturnsData() $this->assertArrayNotHasKey('feature_version', $versionArray); $this->assertArrayNotHasKey('feature_pretty_version', $versionArray); $this->assertEquals($commitHash, $versionArray['commit']); + + $process->assertComplete($this); } public function testGuessVersionDoesNotSeeCustomDefaultBranchAsNonFeatureBranch() @@ -140,34 +89,24 @@ public function testGuessVersionDoesNotSeeCustomDefaultBranchAsNonFeatureBranch( $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - // Assumption here is that arbitrary would be the default branch - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash, $anotherCommitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = " arbitrary $commitHash Commit message\n* current $anotherCommitHash Another message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + // Assumption here is that arbitrary would be the default branch + 'stdout' => " arbitrary $commitHash Commit message\n* current $anotherCommitHash Another message\n" + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array('version' => 'self.version'), 'dummy/path'); $this->assertEquals("dev-current", $versionArray['version']); $this->assertEquals($anotherCommitHash, $versionArray['commit']); + + $process->assertComplete($this); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNaming() @@ -175,46 +114,29 @@ public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationF $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash, $anotherCommitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = " arbitrary $commitHash Commit message\n* feature $anotherCommitHash Another message\n"; - - return 0; - }) - ; - - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output, $path) use ($self, $anotherCommitHash) { - $self->assertEquals('git rev-list arbitrary..feature', $command); - $output = "$anotherCommitHash\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => " arbitrary $commitHash Commit message\n* feature $anotherCommitHash Another message\n" + ), + array( + 'cmd' => 'git rev-list arbitrary..feature', + 'stdout' => "$anotherCommitHash\n" + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array('version' => 'self.version', 'non-feature-branches' => array('arbitrary')), 'dummy/path'); $this->assertEquals("dev-arbitrary", $versionArray['version']); $this->assertEquals($anotherCommitHash, $versionArray['commit']); $this->assertEquals("dev-feature", $versionArray['feature_version']); $this->assertEquals("dev-feature", $versionArray['feature_pretty_version']); + + $process->assertComplete($this); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNamingRegex() @@ -222,45 +144,29 @@ public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationF $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash, $anotherCommitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = " latest-testing $commitHash Commit message\n* feature $anotherCommitHash Another message\n"; - - return 0; - }) - ; - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output, $path) use ($self, $anotherCommitHash) { - $self->assertEquals('git rev-list latest-testing..feature', $command); - $output = "$anotherCommitHash\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => " latest-testing $commitHash Commit message\n* feature $anotherCommitHash Another message\n", + ), + array( + 'cmd' => 'git rev-list latest-testing..feature', + 'stdout' => "$anotherCommitHash\n", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array('version' => 'self.version', 'non-feature-branches' => array('latest-.*')), 'dummy/path'); $this->assertEquals("dev-latest-testing", $versionArray['version']); $this->assertEquals($anotherCommitHash, $versionArray['commit']); $this->assertEquals("dev-feature", $versionArray['feature_version']); $this->assertEquals("dev-feature", $versionArray['feature_pretty_version']); + + $process->assertComplete($this); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNamingWhenOnNonFeatureBranch() @@ -268,310 +174,209 @@ public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationF $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash, $anotherCommitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* latest-testing $commitHash Commit message\n current $anotherCommitHash Another message\n master $anotherCommitHash Another message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* latest-testing $commitHash Commit message\n current $anotherCommitHash Another message\n master $anotherCommitHash Another message\n", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionArray = $guesser->guessVersion(array('version' => 'self.version', 'non-feature-branches' => array('latest-.*')), 'dummy/path'); $this->assertEquals("dev-latest-testing", $versionArray['version']); $this->assertEquals($commitHash, $versionArray['commit']); $this->assertArrayNotHasKey('feature_version', $versionArray); $this->assertArrayNotHasKey('feature_pretty_version', $versionArray); + + $process->assertComplete($this); } public function testDetachedHeadBecomesDevHash() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* (no branch) $commitHash Commit message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* (no branch) $commitHash Commit message\n", + ), + 'git describe --exact-match --tags', + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-$commitHash", $versionData['version']); + + $process->assertComplete($this); } public function testDetachedFetchHeadBecomesDevHashGit2() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock(); - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* (HEAD detached at FETCH_HEAD) $commitHash Commit message\n"; - - return 0; - }); + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* (HEAD detached at FETCH_HEAD) $commitHash Commit message\n", + ), + 'git describe --exact-match --tags', + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-$commitHash", $versionData['version']); + + $process->assertComplete($this); } public function testDetachedCommitHeadBecomesDevHashGit2() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock(); - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self, $commitHash) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* (HEAD detached at 03a15d220) $commitHash Commit message\n"; - - return 0; - }); + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* (HEAD detached at 03a15d220) $commitHash Commit message\n", + ), + 'git describe --exact-match --tags', + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-$commitHash", $versionData['version']); + + $process->assertComplete($this); } public function testTagBecomesVersion() { - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* (HEAD detached at v2.0.5-alpha2) 433b98d4218c181bae01865901aac045585e8a1a Commit message\n"; - - return 0; - }) - ; - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git describe --exact-match --tags', $command); - $output = "v2.0.5-alpha2"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* (HEAD detached at v2.0.5-alpha2) 433b98d4218c181bae01865901aac045585e8a1a Commit message\n", + ), + array( + 'cmd' => 'git describe --exact-match --tags', + 'stdout' => "v2.0.5-alpha2", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("2.0.5.0-alpha2", $versionData['version']); + + $process->assertComplete($this); } public function testTagBecomesPrettyVersion() { - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* (HEAD detached at 1.0.0) c006f0c12bbbf197b5c071ffb1c0e9812bb14a4d Commit message\n"; - - return 0; - }) - ; - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git describe --exact-match --tags', $command); - $output = '1.0.0'; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* (HEAD detached at 1.0.0) c006f0c12bbbf197b5c071ffb1c0e9812bb14a4d Commit message\n", + ), + array( + 'cmd' => 'git describe --exact-match --tags', + 'stdout' => '1.0.0', + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals('1.0.0.0', $versionData['version']); $this->assertEquals('1.0.0', $versionData['pretty_version']); + + $process->assertComplete($this); } public function testInvalidTagBecomesVersion() { - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* foo 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("dev-foo", $versionData['version']); + + $process->assertComplete($this); } public function testNumericBranchesShowNicely() { - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* 1.5 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* 1.5 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array(), 'dummy/path'); $this->assertEquals("1.5.x-dev", $versionData['pretty_version']); $this->assertEquals("1.5.9999999.9999999-dev", $versionData['version']); + + $process->assertComplete($this); } public function testRemoteBranchesAreSelected() { - $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') - ->setMethods(array('execute')) - ->disableArgumentCloning() - ->disableOriginalConstructor() - ->getMock() - ; - - $self = $this; - - $executor - ->expects($this->at(0)) - ->method('execute') - ->willReturnCallback(function ($command, &$output) use ($self) { - $self->assertEquals('git branch -a --no-color --no-abbrev -v', $command); - $output = "* feature-branch 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n". - "remotes/origin/1.5 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n"; - - return 0; - }) - ; - - $executor - ->expects($this->at(1)) - ->method('execute') - ->willReturnCallback(function ($command, &$output, $path) use ($self) { - $self->assertEquals('git rev-list remotes/origin/1.5..feature-branch', $command); - $output = "\n"; - - return 0; - }) - ; + $process = new ProcessExecutorMock; + $process->expects(array( + array( + 'cmd' => 'git branch -a --no-color --no-abbrev -v', + 'stdout' => "* feature-branch 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n". + "remotes/origin/1.5 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n", + ), + array( + 'cmd' => 'git rev-list remotes/origin/1.5..feature-branch', + 'stdout' => "\n", + ), + ), true); $config = new Config; $config->merge(array('repositories' => array('packagist' => false))); - $guesser = new VersionGuesser($config, $executor, new VersionParser()); + $guesser = new VersionGuesser($config, $process, new VersionParser()); $versionData = $guesser->guessVersion(array('version' => 'self.version'), 'dummy/path'); $this->assertEquals("1.5.x-dev", $versionData['pretty_version']); $this->assertEquals("1.5.9999999.9999999-dev", $versionData['version']); + + $process->assertComplete($this); } } diff --git a/tests/Composer/Test/Package/Version/VersionSelectorTest.php b/tests/Composer/Test/Package/Version/VersionSelectorTest.php index 2dc840793797..abe77ba0f22d 100644 --- a/tests/Composer/Test/Package/Version/VersionSelectorTest.php +++ b/tests/Composer/Test/Package/Version/VersionSelectorTest.php @@ -270,42 +270,17 @@ public function testFalseReturnedOnNoPackages() /** * @dataProvider getRecommendedRequireVersionPackages */ - public function testFindRecommendedRequireVersion($prettyVersion, $isDev, $stability, $expectedVersion, $branchAlias = null, $packageName = null) + public function testFindRecommendedRequireVersion($prettyVersion, $expectedVersion, $branchAlias = null, $packageName = 'foo/bar') { $repositorySet = $this->createMockRepositorySet(); $versionSelector = new VersionSelector($repositorySet); $versionParser = new VersionParser(); - $package = $this->getMockBuilder('\Composer\Package\PackageInterface')->getMock(); - $package - ->expects($this->any()) - ->method('getPrettyVersion') - ->will($this->returnValue($prettyVersion)); - $package - ->expects($this->any()) - ->method('getName') - ->will($this->returnValue($packageName)); - $package - ->expects($this->any()) - ->method('getVersion') - ->will($this->returnValue($versionParser->normalize($prettyVersion))); - $package - ->expects($this->any()) - ->method('isDev') - ->will($this->returnValue($isDev)); - $package - ->expects($this->any()) - ->method('getStability') - ->will($this->returnValue($stability)); - $package - ->expects($this->any()) - ->method('getTransportOptions') - ->will($this->returnValue(array())); + $package = new Package($packageName, $versionParser->normalize($prettyVersion), $prettyVersion); - $branchAlias = $branchAlias === null ? array() : array('branch-alias' => array($prettyVersion => $branchAlias)); - $package->expects($this->any()) - ->method('getExtra') - ->will($this->returnValue($branchAlias)); + if ($branchAlias) { + $package->setExtra(array('branch-alias' => array($prettyVersion => $branchAlias))); + } $recommended = $versionSelector->findRecommendedRequireVersion($package); @@ -316,40 +291,40 @@ public function testFindRecommendedRequireVersion($prettyVersion, $isDev, $stabi public function getRecommendedRequireVersionPackages() { return array( - // real version, is dev package, stability, expected recommendation, [branch-alias], [pkg name] - array('1.2.1', false, 'stable', '^1.2'), - array('1.2', false, 'stable', '^1.2'), - array('v1.2.1', false, 'stable', '^1.2'), - array('3.1.2-pl2', false, 'stable', '^3.1'), - array('3.1.2-patch', false, 'stable', '^3.1'), - array('2.0-beta.1', false, 'beta', '^2.0@beta'), - array('3.1.2-alpha5', false, 'alpha', '^3.1@alpha'), - array('3.0-RC2', false, 'RC', '^3.0@RC'), - array('0.1.0', false, 'stable', '^0.1.0'), - array('0.1.3', false, 'stable', '^0.1.3'), - array('0.0.3', false, 'stable', '^0.0.3'), - array('0.0.3-alpha', false, 'alpha', '^0.0.3@alpha'), + // real version, expected recommendation, [branch-alias], [pkg name] + array('1.2.1', '^1.2'), + array('1.2', '^1.2'), + array('v1.2.1', '^1.2'), + array('3.1.2-pl2', '^3.1'), + array('3.1.2-patch', '^3.1'), + array('2.0-beta.1', '^2.0@beta'), + array('3.1.2-alpha5', '^3.1@alpha'), + array('3.0-RC2', '^3.0@RC'), + array('0.1.0', '^0.1.0'), + array('0.1.3', '^0.1.3'), + array('0.0.3', '^0.0.3'), + array('0.0.3-alpha', '^0.0.3@alpha'), // date-based versions are not touched at all - array('v20121020', false, 'stable', 'v20121020'), - array('v20121020.2', false, 'stable', 'v20121020.2'), + array('v20121020', 'v20121020'), + array('v20121020.2', 'v20121020.2'), // dev packages without alias are not touched at all - array('dev-master', true, 'dev', 'dev-master'), - array('3.1.2-dev', true, 'dev', '3.1.2-dev'), + array('dev-master', 'dev-master'), + array('3.1.2-dev', '3.1.2-dev'), // dev packages with alias inherit the alias - array('dev-master', true, 'dev', '^2.1@dev', '2.1.x-dev'), - array('dev-master', true, 'dev', '^2.1@dev', '2.1-dev'), - array('dev-master', true, 'dev', '^2.1@dev', '2.1.3.x-dev'), - array('dev-master', true, 'dev', '^2.0@dev', '2.x-dev'), - array('dev-master', true, 'dev', '^0.3.0@dev', '0.3.x-dev'), - array('dev-master', true, 'dev', '^0.0.3@dev', '0.0.3.x-dev'), - array('dev-master', true, 'dev', 'dev-master', VersionParser::DEFAULT_BRANCH_ALIAS), + array('dev-master', '^2.1@dev', '2.1.x-dev'), + array('dev-master', '^2.1@dev', '2.1-dev'), + array('dev-master', '^2.1@dev', '2.1.3.x-dev'), + array('dev-master', '^2.0@dev', '2.x-dev'), + array('dev-master', '^0.3.0@dev', '0.3.x-dev'), + array('dev-master', '^0.0.3@dev', '0.0.3.x-dev'), + array('dev-master', 'dev-master', VersionParser::DEFAULT_BRANCH_ALIAS), // numeric alias - array('3.x-dev', true, 'dev', '^3.0@dev', '3.0.x-dev'), - array('3.x-dev', true, 'dev', '^3.0@dev', '3.0-dev'), + array('3.x-dev', '^3.0@dev', '3.0.x-dev'), + array('3.x-dev', '^3.0@dev', '3.0-dev'), // ext in sync with php - array(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, false, 'stable', '*', null, 'ext-filter'), + array(PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, '*', null, 'ext-filter'), // ext versioned individually - array('3.0.5', false, 'stable', '^3.0', null, 'ext-xdebug'), + array('3.0.5', '^3.0', null, 'ext-xdebug'), ); } diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 7c2727c207a4..38dd7bc34ab1 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -17,7 +17,10 @@ use Composer\Test\TestCase; use Composer\Util\Filesystem; use Composer\Util\Http\Response; +use Composer\Test\Mock\ProcessExecutorMock; use Composer\Config; +use Composer\Util\ProcessExecutor; +use Symfony\Component\Process\Process; class GitHubDriverTest extends TestCase { @@ -58,10 +61,8 @@ public function testPrivateRepository() ->setConstructorArgs(array($io, $this->config)) ->getMock(); - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $process->expects($this->any()) - ->method('execute') - ->will($this->returnValue(1)); + $process = new ProcessExecutorMock; + $process->expects(array(), false, array('return' => 1)); $httpDownloader->expects($this->at(0)) ->method('get') @@ -139,11 +140,7 @@ public function testPublicRepository() ); $repoUrl = 'https://github.com/composer/packagist.git'; - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor') - ->disableOriginalConstructor() - ->getMock(); - - $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, $process); + $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, new ProcessExecutorMock); $gitHubDriver->initialize(); $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); @@ -201,11 +198,7 @@ public function testPublicRepository2() ); $repoUrl = 'https://github.com/composer/packagist.git'; - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor') - ->disableOriginalConstructor() - ->getMock(); - - $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, $process); + $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, new ProcessExecutorMock); $gitHubDriver->initialize(); $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); @@ -239,10 +232,6 @@ public function testPublicRepositoryArchived() ->method('isInteractive') ->will($this->returnValue(true)); - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor') - ->disableOriginalConstructor() - ->getMock(); - $httpDownloader = $this->getMockBuilder('Composer\Util\HttpDownloader') ->setConstructorArgs(array($io, $this->config)) ->getMock(); @@ -271,7 +260,7 @@ public function testPublicRepositoryArchived() 'url' => $repoUrl, ); - $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, $process); + $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, $httpDownloader, new ProcessExecutorMock); $gitHubDriver->initialize(); $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); @@ -288,10 +277,6 @@ public function testPrivateRepositoryNoInteraction() $identifier = 'v0.0.0'; $sha = 'SOMESHA'; - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor') - ->disableOriginalConstructor() - ->getMock(); - $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $io->expects($this->any()) ->method('isInteractive') @@ -310,39 +295,23 @@ public function testPrivateRepositoryNoInteraction() $fs = new Filesystem(); $fs->removeDirectory(sys_get_temp_dir() . '/composer-test'); - $process->expects($this->at(0)) - ->method('execute') - ->with($this->equalTo('git config github.accesstoken')) - ->will($this->returnValue(1)); - - $process->expects($this->at(1)) - ->method('execute') - ->with($this->stringContains($repoSshUrl)) - ->will($this->returnValue(0)); - - $process->expects($this->at(2)) - ->method('execute') - ->with($this->stringContains('git show-ref --tags')); - - $process->expects($this->at(3)) - ->method('splitLines') - ->will($this->returnValue(array($sha.' refs/tags/'.$identifier))); - - $process->expects($this->at(4)) - ->method('execute') - ->with($this->stringContains('git branch --no-color --no-abbrev -v')); - - $process->expects($this->at(5)) - ->method('splitLines') - ->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior'))); - - $process->expects($this->at(6)) - ->method('execute') - ->with($this->stringContains('git branch --no-color')); - - $process->expects($this->at(7)) - ->method('splitLines') - ->will($this->returnValue(array('* test_master'))); + $process = new ProcessExecutorMock; + $process->expects(array( + array('cmd' => 'git config github.accesstoken', 'return' => 1), + 'git clone --mirror -- '.ProcessExecutor::escape($repoSshUrl).' '.ProcessExecutor::escape($this->config->get('cache-vcs-dir').'/git-github.com-composer-packagist.git/'), + array( + 'cmd' => 'git show-ref --tags --dereference', + 'stdout' => $sha.' refs/tags/'.$identifier, + ), + array( + 'cmd' => 'git branch --no-color --no-abbrev -v', + 'stdout' => ' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior', + ), + array( + 'cmd' => 'git branch --no-color', + 'stdout' => '* test_master', + ), + ), true); $repoConfig = array( 'url' => $repoUrl, @@ -367,6 +336,8 @@ public function testPrivateRepositoryNoInteraction() $this->assertEquals('git', $source['type']); $this->assertEquals($repoSshUrl, $source['url']); $this->assertEquals($sha, $source['reference']); + + $process->assertComplete($this); } protected function setAttribute($object, $attribute, $value) diff --git a/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php b/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php index 1c44e82ddf51..11f1524d3bd0 100644 --- a/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/PerforceDriverTest.php @@ -17,6 +17,7 @@ use Composer\Util\Filesystem; use Composer\Config; use Composer\Util\Perforce; +use Composer\Test\Mock\ProcessExecutorMock; /** * @author Matt Whittom @@ -42,7 +43,7 @@ protected function setUp() $this->config = $this->getTestConfig($this->testPath); $this->repoConfig = $this->getTestRepoConfig(); $this->io = $this->getMockIOInterface(); - $this->process = $this->getMockProcessExecutor(); + $this->process = new ProcessExecutorMock; $this->httpDownloader = $this->getMockHttpDownloader(); $this->perforce = $this->getMockPerforce(); $this->driver = new PerforceDriver($this->repoConfig, $this->io, $this->config, $this->httpDownloader, $this->process); @@ -94,11 +95,6 @@ protected function getMockIOInterface() return $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); } - protected function getMockProcessExecutor() - { - return $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - } - protected function getMockHttpDownloader() { return $this->getMockBuilder('Composer\Util\HttpDownloader')->disableOriginalConstructor()->getMock(); diff --git a/tests/Composer/Test/Repository/Vcs/SvnDriverTest.php b/tests/Composer/Test/Repository/Vcs/SvnDriverTest.php index 9c61c3105a76..b2699e61b439 100644 --- a/tests/Composer/Test/Repository/Vcs/SvnDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/SvnDriverTest.php @@ -16,6 +16,7 @@ use Composer\Config; use Composer\Test\TestCase; use Composer\Util\Filesystem; +use Composer\Test\Mock\ProcessExecutorMock; class SvnDriverTest extends TestCase { @@ -50,16 +51,11 @@ public function testWrongCredentialsInUrl() $output .= " authorization failed: Could not authenticate to server:"; $output .= " rejected Basic challenge (https://corp.svn.local/)"; - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $process->expects($this->at(1)) - ->method('execute') - ->will($this->returnValue(1)); - $process->expects($this->exactly(7)) - ->method('getErrorOutput') - ->will($this->returnValue($output)); - $process->expects($this->at(2)) - ->method('execute') - ->will($this->returnValue(0)); + $process = new ProcessExecutorMock; + $process->expects(array( + 'svn --version', + array('cmd' => '', 'return' => 1, 'stderr' => $output), + ), true); $repoConfig = array( 'url' => 'https://till:secret@corp.svn.local/repo', @@ -67,6 +63,8 @@ public function testWrongCredentialsInUrl() $svn = new SvnDriver($repoConfig, $console, $this->config, $httpDownloader, $process); $svn->initialize(); + + $process->assertComplete($this); } public static function supportProvider() diff --git a/tests/Composer/Test/Util/BitbucketTest.php b/tests/Composer/Test/Util/BitbucketTest.php index 3262c2fe883a..3182ac014ef7 100644 --- a/tests/Composer/Test/Util/BitbucketTest.php +++ b/tests/Composer/Test/Util/BitbucketTest.php @@ -15,6 +15,7 @@ use Composer\Util\Bitbucket; use Composer\Util\Http\Response; use Composer\Test\TestCase; +use Composer\Test\Mock\ProcessExecutorMock; /** * @author Paul Wenke @@ -456,10 +457,8 @@ public function testAuthorizeOAuthWithWrongOriginUrl() public function testAuthorizeOAuthWithoutAvailableGitConfigToken() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $process->expects($this->once()) - ->method('execute') - ->willReturn(-1); + $process = new ProcessExecutorMock; + $process->expects(array(), false, array('return' => -1)); $bitbucket = new Bitbucket($this->io, $this->config, $process, $this->httpDownloader, $this->time); @@ -468,10 +467,7 @@ public function testAuthorizeOAuthWithoutAvailableGitConfigToken() public function testAuthorizeOAuthWithAvailableGitConfigToken() { - $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock(); - $process->expects($this->once()) - ->method('execute') - ->willReturn(0); + $process = new ProcessExecutorMock; $bitbucket = new Bitbucket($this->io, $this->config, $process, $this->httpDownloader, $this->time); diff --git a/tests/Composer/Test/Util/GitLabTest.php b/tests/Composer/Test/Util/GitLabTest.php index 7c671afc0065..e5ba33db68c1 100644 --- a/tests/Composer/Test/Util/GitLabTest.php +++ b/tests/Composer/Test/Util/GitLabTest.php @@ -93,8 +93,9 @@ public function testUsernamePasswordFailure() $httpDownloader ->expects($this->exactly(5)) ->method('get') - ->will($this->throwException(new TransportException('', 401))) + ->will($this->throwException($e = new TransportException('', 401))) ; + $e->setResponse('{}'); $config = $this->getConfigMock(); $config diff --git a/tests/Composer/Test/Util/GitTest.php b/tests/Composer/Test/Util/GitTest.php index 4fbc1826abfa..f1df7c2f75a4 100644 --- a/tests/Composer/Test/Util/GitTest.php +++ b/tests/Composer/Test/Util/GitTest.php @@ -16,7 +16,7 @@ use Composer\IO\IOInterface; use Composer\Util\Filesystem; use Composer\Util\Git; -use Composer\Util\ProcessExecutor; +use Composer\Test\Mock\ProcessExecutorMock; use Composer\Test\TestCase; class GitTest extends TestCase @@ -27,7 +27,7 @@ class GitTest extends TestCase private $io; /** @var Config&\PHPUnit\Framework\MockObject\MockObject */ private $config; - /** @var ProcessExecutor&\PHPUnit\Framework\MockObject\MockObject */ + /** @var ProcessExecutorMock */ private $process; /** @var Filesystem&\PHPUnit\Framework\MockObject\MockObject */ private $fs; @@ -36,7 +36,7 @@ protected function setUp() { $this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); $this->config = $this->getMockBuilder('Composer\Config')->disableOriginalConstructor()->getMock(); - $this->process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->disableOriginalConstructor()->getMock(); + $this->process = new ProcessExecutorMock; $this->fs = $this->getMockBuilder('Composer\Util\Filesystem')->disableOriginalConstructor()->getMock(); $this->git = new Git($this->io, $this->config, $this->process, $this->fs); } @@ -55,13 +55,11 @@ public function testRunCommandPublicGitHubRepositoryNotInitialClone($protocol, $ $this->mockConfig($protocol); - $this->process - ->expects($this->once()) - ->method('execute') - ->with($this->equalTo('git command')) - ->willReturn(0); + $this->process->expects(array('git command'), true); $this->git->runCommand($commandCallable, 'https://github.com/acme/repo', null, true); + + $this->process->assertComplete($this); } public function publicGithubNoCredentialsProvider() @@ -85,20 +83,21 @@ public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteracti $this->mockConfig('https'); - $this->process - ->method('execute') - ->willReturnMap(array( - array('git command', null, null, 1), - array('git --version', null, null, 0), - )); + + $this->process->expects(array( + array('cmd' => 'git command', 'return' => 1), + array('cmd' => 'git --version', 'return' => 0), + ), true); $this->git->runCommand($commandCallable, 'https://github.com/acme/repo', null, true); + + $this->process->assertComplete($this); } /** * @dataProvider privateGithubWithCredentialsProvider */ - public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteractiveWithAuthentication($gitUrl, $protocol, $gitHubToken, $expectedUrl) + public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteractiveWithAuthentication($gitUrl, $protocol, $gitHubToken, $expectedUrl, $expectedFailuresBeforeSuccess) { $commandCallable = function ($url) use ($expectedUrl) { if ($url !== $expectedUrl) { @@ -110,13 +109,10 @@ public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteracti $this->mockConfig($protocol); - $this->process - ->expects($this->atLeast(2)) - ->method('execute') - ->willReturnMap(array( - array('git command failing', null, null, 1), - array('git command ok', null, null, 0), - )); + $expectedCalls = array_fill(0, $expectedFailuresBeforeSuccess, array('cmd' => 'git command failing', 'return' => 1)); + $expectedCalls[] = array('cmd' => 'git command ok', 'return' => 0); + + $this->process->expects($expectedCalls, true); $this->io ->method('isInteractive') @@ -135,13 +131,15 @@ public function testRunCommandPrivateGitHubRepositoryNotInitialCloneNotInteracti ->willReturn(array('username' => 'token', 'password' => $gitHubToken)); $this->git->runCommand($commandCallable, $gitUrl, null, true); + + $this->process->assertComplete($this); } public function privateGithubWithCredentialsProvider() { return array( - array('git@github.com:acme/repo.git', 'ssh', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git'), - array('https://github.com/acme/repo', 'https', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git'), + array('git@github.com:acme/repo.git', 'ssh', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git', 1), + array('https://github.com/acme/repo', 'https', 'MY_GITHUB_TOKEN', 'https://token:MY_GITHUB_TOKEN@github.com/acme/repo.git', 2), ); } diff --git a/tests/Composer/Test/Util/MetadataMinifierTest.php b/tests/Composer/Test/Util/MetadataMinifierTest.php index ad8d3abade87..043c3356cb92 100644 --- a/tests/Composer/Test/Util/MetadataMinifierTest.php +++ b/tests/Composer/Test/Util/MetadataMinifierTest.php @@ -12,7 +12,7 @@ namespace Composer\Test\Util; -use Composer\Util\MetadataMinifier; +use Composer\MetadataMinifier\MetadataMinifier; use Composer\Package\CompletePackage; use Composer\Package\Dumper\ArrayDumper; use PHPUnit\Framework\TestCase;