From a48159b2838bcbd429ee57e31b848e5db26239a1 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Tue, 26 Jan 2016 23:39:39 +0100 Subject: [PATCH 1/7] Bail out if root package attempts to include itself. --- src/Composer/Package/Loader/RootPackageLoader.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 0fc7c49af..6f8d45f31 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -113,6 +113,9 @@ class RootPackageLoader extends ArrayLoader } } + if (isset($links[$config['name']])) + throw new \InvalidArgumentException(sprintf('Root package \'%s\' cannot require itself in its composer.json', $config['name'])); + $realPackage->setAliases($aliases); $realPackage->setStabilityFlags($stabilityFlags); $realPackage->setReferences($references); From 7b6ccde97afe1e85029dab144cc57224d2986d02 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 09:09:29 +0100 Subject: [PATCH 2/7] Clarified error message and added braces. --- src/Composer/Package/Loader/RootPackageLoader.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 6f8d45f31..565ff39c4 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -113,8 +113,10 @@ class RootPackageLoader extends ArrayLoader } } - if (isset($links[$config['name']])) - throw new \InvalidArgumentException(sprintf('Root package \'%s\' cannot require itself in its composer.json', $config['name'])); + if (isset($links[$config['name']])) { + throw new \InvalidArgumentException(sprintf('Root package \'%s\' cannot require itself in its composer.json' . PHP_EOL . + 'Did you accidentally name your root package after an external package?', $config['name'])); + } $realPackage->setAliases($aliases); $realPackage->setStabilityFlags($stabilityFlags); From e5fe3d8a3bf3e5048a5ec3ad4c6a7ea15792cf09 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 10:04:45 +0100 Subject: [PATCH 3/7] Expanded InstallerTest to support expecting Exceptions by supplying "EXCEPTION" as "--EXPECT--" --- tests/Composer/Test/InstallerTest.php | 181 ++++++++++++++------------ 1 file changed, 97 insertions(+), 84 deletions(-) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 5339b8ff3..f72c6d9d5 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -158,96 +158,109 @@ class InstallerTest extends TestCase ->method('writeError') ->will($this->returnCallback($callback)); - $composer = FactoryMock::create($io, $composerConfig); + // Prepare for exceptions + try { + $composer = FactoryMock::create($io, $composerConfig); - $jsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); - $jsonMock->expects($this->any()) - ->method('read') - ->will($this->returnValue($installed)); - $jsonMock->expects($this->any()) - ->method('exists') - ->will($this->returnValue(true)); + $jsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); + $jsonMock->expects($this->any()) + ->method('read') + ->will($this->returnValue($installed)); + $jsonMock->expects($this->any()) + ->method('exists') + ->will($this->returnValue(true)); - $repositoryManager = $composer->getRepositoryManager(); - $repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock)); + $repositoryManager = $composer->getRepositoryManager(); + $repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock)); - $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); - $lockJsonMock->expects($this->any()) - ->method('read') - ->will($this->returnValue($lock)); - $lockJsonMock->expects($this->any()) - ->method('exists') - ->will($this->returnValue(true)); + $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); + $lockJsonMock->expects($this->any()) + ->method('read') + ->will($this->returnValue($lock)); + $lockJsonMock->expects($this->any()) + ->method('exists') + ->will($this->returnValue(true)); - if ($expectLock) { - $actualLock = array(); - $lockJsonMock->expects($this->atLeastOnce()) - ->method('write') - ->will($this->returnCallback(function ($hash, $options) use (&$actualLock) { - // need to do assertion outside of mock for nice phpunit output - // so store value temporarily in reference for later assetion - $actualLock = $hash; - })); + if ($expectLock) { + $actualLock = array(); + $lockJsonMock->expects($this->atLeastOnce()) + ->method('write') + ->will($this->returnCallback(function ($hash, $options) use (&$actualLock) { + // need to do assertion outside of mock for nice phpunit output + // so store value temporarily in reference for later assetion + $actualLock = $hash; + })); + } + + $contents = json_encode($composerConfig); + $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents); + $composer->setLocker($locker); + + $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); + $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator', array(), array($eventDispatcher)); + $composer->setAutoloadGenerator($autoloadGenerator); + $composer->setEventDispatcher($eventDispatcher); + + $installer = Installer::create($io, $composer); + + $application = new Application; + $application->get('install')->setCode(function ($input, $output) use ($installer) { + $installer + ->setDevMode(!$input->getOption('no-dev')) + ->setDryRun($input->getOption('dry-run')) + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); + + return $installer->run(); + }); + + $application->get('update')->setCode(function ($input, $output) use ($installer) { + $installer + ->setDevMode(!$input->getOption('no-dev')) + ->setUpdate(true) + ->setDryRun($input->getOption('dry-run')) + ->setUpdateWhitelist($input->getArgument('packages')) + ->setWhitelistDependencies($input->getOption('with-dependencies')) + ->setPreferStable($input->getOption('prefer-stable')) + ->setPreferLowest($input->getOption('prefer-lowest')) + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); + + return $installer->run(); + }); + + if (!preg_match('{^(install|update)\b}', $run)) { + throw new \UnexpectedValueException('The run command only supports install and update'); + } + + $application->setAutoExit(false); + $appOutput = fopen('php://memory', 'w+'); + $result = $application->run(new StringInput($run), new StreamOutput($appOutput)); + fseek($appOutput, 0); + $this->assertEquals($expectExitCode, $result, $output . stream_get_contents($appOutput)); + + if ($expectLock) { + unset($actualLock['hash']); + unset($actualLock['content-hash']); + unset($actualLock['_readme']); + $this->assertEquals($expectLock, $actualLock); + } + + $installationManager = $composer->getInstallationManager(); + $this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace())); + + if ($expectOutput) { + $this->assertEquals(rtrim($expectOutput), rtrim($output)); + } } - - $contents = json_encode($composerConfig); - $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents); - $composer->setLocker($locker); - - $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); - $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator', array(), array($eventDispatcher)); - $composer->setAutoloadGenerator($autoloadGenerator); - $composer->setEventDispatcher($eventDispatcher); - - $installer = Installer::create($io, $composer); - - $application = new Application; - $application->get('install')->setCode(function ($input, $output) use ($installer) { - $installer - ->setDevMode(!$input->getOption('no-dev')) - ->setDryRun($input->getOption('dry-run')) - ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); - - return $installer->run(); - }); - - $application->get('update')->setCode(function ($input, $output) use ($installer) { - $installer - ->setDevMode(!$input->getOption('no-dev')) - ->setUpdate(true) - ->setDryRun($input->getOption('dry-run')) - ->setUpdateWhitelist($input->getArgument('packages')) - ->setWhitelistDependencies($input->getOption('with-dependencies')) - ->setPreferStable($input->getOption('prefer-stable')) - ->setPreferLowest($input->getOption('prefer-lowest')) - ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); - - return $installer->run(); - }); - - if (!preg_match('{^(install|update)\b}', $run)) { - throw new \UnexpectedValueException('The run command only supports install and update'); - } - - $application->setAutoExit(false); - $appOutput = fopen('php://memory', 'w+'); - $result = $application->run(new StringInput($run), new StreamOutput($appOutput)); - fseek($appOutput, 0); - $this->assertEquals($expectExitCode, $result, $output . stream_get_contents($appOutput)); - - if ($expectLock) { - unset($actualLock['hash']); - unset($actualLock['content-hash']); - unset($actualLock['_readme']); - $this->assertEquals($expectLock, $actualLock); - } - - $installationManager = $composer->getInstallationManager(); - $this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace())); - - if ($expectOutput) { - $this->assertEquals(rtrim($expectOutput), rtrim($output)); + catch(\Exception $e) { + // Exception was thrown during execution + if (!$expect || !$expectOutput) { + throw $e; + } + $this->assertEquals('EXCEPTION', rtrim($expect)); + $normalizedOutput = rtrim(str_replace("\n", PHP_EOL, $expectOutput)); + $this->assertEquals($normalizedOutput, rtrim($e->getMessage())); } + return; } public function getIntegrationTests() From bd241cb896a2205ec651e1651e942650d9ad59b8 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 10:05:10 +0100 Subject: [PATCH 4/7] Included unit test for circular root dependencies. --- .../installer/install-self-from-root.test | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/Composer/Test/Fixtures/installer/install-self-from-root.test diff --git a/tests/Composer/Test/Fixtures/installer/install-self-from-root.test b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test new file mode 100644 index 000000000..35a50754a --- /dev/null +++ b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test @@ -0,0 +1,16 @@ +--TEST-- +Tries to require a package with the same name as the root package +--COMPOSER-- +{ + "name": "foo/bar", + "require": { + "foo/bar": "@dev" + } +} +--RUN-- +install +--EXPECT-OUTPUT-- +Root package 'foo/bar' cannot require itself in its composer.json +Did you accidentally name your root package after an external package? +--EXPECT-- +EXCEPTION From 639ee0701c86b7b38fe90b091358a063ce0f2d99 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 13:19:08 +0100 Subject: [PATCH 5/7] Introduced more generic, less invasive way to test for exceptions in fixtures, more in line with how phpunit works. --- .../installer/install-self-from-root.test | 6 +- tests/Composer/Test/InstallerTest.php | 202 +++++++++--------- 2 files changed, 104 insertions(+), 104 deletions(-) diff --git a/tests/Composer/Test/Fixtures/installer/install-self-from-root.test b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test index 35a50754a..ceeef8b7c 100644 --- a/tests/Composer/Test/Fixtures/installer/install-self-from-root.test +++ b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test @@ -9,8 +9,8 @@ Tries to require a package with the same name as the root package } --RUN-- install ---EXPECT-OUTPUT-- +--EXPECT-EXIT-CODE-- +InvalidArgumentException +--EXPECT-- Root package 'foo/bar' cannot require itself in its composer.json Did you accidentally name your root package after an external package? ---EXPECT-- -EXCEPTION diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index f72c6d9d5..518a395e1 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -159,108 +159,108 @@ class InstallerTest extends TestCase ->will($this->returnCallback($callback)); // Prepare for exceptions - try { - $composer = FactoryMock::create($io, $composerConfig); - - $jsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); - $jsonMock->expects($this->any()) - ->method('read') - ->will($this->returnValue($installed)); - $jsonMock->expects($this->any()) - ->method('exists') - ->will($this->returnValue(true)); - - $repositoryManager = $composer->getRepositoryManager(); - $repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock)); - - $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); - $lockJsonMock->expects($this->any()) - ->method('read') - ->will($this->returnValue($lock)); - $lockJsonMock->expects($this->any()) - ->method('exists') - ->will($this->returnValue(true)); - - if ($expectLock) { - $actualLock = array(); - $lockJsonMock->expects($this->atLeastOnce()) - ->method('write') - ->will($this->returnCallback(function ($hash, $options) use (&$actualLock) { - // need to do assertion outside of mock for nice phpunit output - // so store value temporarily in reference for later assetion - $actualLock = $hash; - })); - } - - $contents = json_encode($composerConfig); - $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents); - $composer->setLocker($locker); - - $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); - $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator', array(), array($eventDispatcher)); - $composer->setAutoloadGenerator($autoloadGenerator); - $composer->setEventDispatcher($eventDispatcher); - - $installer = Installer::create($io, $composer); - - $application = new Application; - $application->get('install')->setCode(function ($input, $output) use ($installer) { - $installer - ->setDevMode(!$input->getOption('no-dev')) - ->setDryRun($input->getOption('dry-run')) - ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); - - return $installer->run(); - }); - - $application->get('update')->setCode(function ($input, $output) use ($installer) { - $installer - ->setDevMode(!$input->getOption('no-dev')) - ->setUpdate(true) - ->setDryRun($input->getOption('dry-run')) - ->setUpdateWhitelist($input->getArgument('packages')) - ->setWhitelistDependencies($input->getOption('with-dependencies')) - ->setPreferStable($input->getOption('prefer-stable')) - ->setPreferLowest($input->getOption('prefer-lowest')) - ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); - - return $installer->run(); - }); - - if (!preg_match('{^(install|update)\b}', $run)) { - throw new \UnexpectedValueException('The run command only supports install and update'); - } - - $application->setAutoExit(false); - $appOutput = fopen('php://memory', 'w+'); - $result = $application->run(new StringInput($run), new StreamOutput($appOutput)); - fseek($appOutput, 0); - $this->assertEquals($expectExitCode, $result, $output . stream_get_contents($appOutput)); - - if ($expectLock) { - unset($actualLock['hash']); - unset($actualLock['content-hash']); - unset($actualLock['_readme']); - $this->assertEquals($expectLock, $actualLock); - } - - $installationManager = $composer->getInstallationManager(); - $this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace())); - - if ($expectOutput) { - $this->assertEquals(rtrim($expectOutput), rtrim($output)); - } + if (is_int($expectExitCode) || ctype_digit($expectExitCode)) { + $expectExitCode = (int) $expectExitCode; + } else { + $normalizedOutput = rtrim(str_replace("\n", PHP_EOL, $expect)); + $this->setExpectedException($expectExitCode, $normalizedOutput); } - catch(\Exception $e) { - // Exception was thrown during execution - if (!$expect || !$expectOutput) { - throw $e; - } - $this->assertEquals('EXCEPTION', rtrim($expect)); - $normalizedOutput = rtrim(str_replace("\n", PHP_EOL, $expectOutput)); - $this->assertEquals($normalizedOutput, rtrim($e->getMessage())); + + // Create Composer mock object according to configuration + $composer = FactoryMock::create($io, $composerConfig); + + $jsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); + $jsonMock->expects($this->any()) + ->method('read') + ->will($this->returnValue($installed)); + $jsonMock->expects($this->any()) + ->method('exists') + ->will($this->returnValue(true)); + + $repositoryManager = $composer->getRepositoryManager(); + $repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock)); + + $lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock(); + $lockJsonMock->expects($this->any()) + ->method('read') + ->will($this->returnValue($lock)); + $lockJsonMock->expects($this->any()) + ->method('exists') + ->will($this->returnValue(true)); + + if ($expectLock) { + $actualLock = array(); + $lockJsonMock->expects($this->atLeastOnce()) + ->method('write') + ->will($this->returnCallback(function ($hash, $options) use (&$actualLock) { + // need to do assertion outside of mock for nice phpunit output + // so store value temporarily in reference for later assetion + $actualLock = $hash; + })); + } + + $contents = json_encode($composerConfig); + $locker = new Locker($io, $lockJsonMock, $repositoryManager, $composer->getInstallationManager(), $contents); + $composer->setLocker($locker); + + $eventDispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')->disableOriginalConstructor()->getMock(); + $autoloadGenerator = $this->getMock('Composer\Autoload\AutoloadGenerator', array(), array($eventDispatcher)); + $composer->setAutoloadGenerator($autoloadGenerator); + $composer->setEventDispatcher($eventDispatcher); + + $installer = Installer::create($io, $composer); + + $application = new Application; + $application->get('install')->setCode(function ($input, $output) use ($installer) { + $installer + ->setDevMode(!$input->getOption('no-dev')) + ->setDryRun($input->getOption('dry-run')) + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); + + return $installer->run(); + }); + + $application->get('update')->setCode(function ($input, $output) use ($installer) { + $installer + ->setDevMode(!$input->getOption('no-dev')) + ->setUpdate(true) + ->setDryRun($input->getOption('dry-run')) + ->setUpdateWhitelist($input->getArgument('packages')) + ->setWhitelistDependencies($input->getOption('with-dependencies')) + ->setPreferStable($input->getOption('prefer-stable')) + ->setPreferLowest($input->getOption('prefer-lowest')) + ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs')); + + return $installer->run(); + }); + + if (!preg_match('{^(install|update)\b}', $run)) { + throw new \UnexpectedValueException('The run command only supports install and update'); + } + + $application->setAutoExit(false); + $appOutput = fopen('php://memory', 'w+'); + $result = $application->run(new StringInput($run), new StreamOutput($appOutput)); + fseek($appOutput, 0); + if (!is_int($expectExitCode)) { + // Shouldn't check output and results if an exception was expected by this point + return; + } + + $this->assertEquals($expectExitCode, $result, $output . stream_get_contents($appOutput)); + if ($expectLock) { + unset($actualLock['hash']); + unset($actualLock['content-hash']); + unset($actualLock['_readme']); + $this->assertEquals($expectLock, $actualLock); + } + + $installationManager = $composer->getInstallationManager(); + $this->assertSame(rtrim($expect), implode("\n", $installationManager->getTrace())); + + if ($expectOutput) { + $this->assertEquals(rtrim($expectOutput), rtrim($output)); } - return; } public function getIntegrationTests() @@ -316,7 +316,7 @@ class InstallerTest extends TestCase } $expectOutput = isset($testData['EXPECT-OUTPUT']) ? $testData['EXPECT-OUTPUT'] : null; $expect = $testData['EXPECT']; - $expectExitCode = isset($testData['EXPECT-EXIT-CODE']) ? (int) $testData['EXPECT-EXIT-CODE'] : 0; + $expectExitCode = isset($testData['EXPECT-EXIT-CODE']) ? $testData['EXPECT-EXIT-CODE'] : 0; } catch (\Exception $e) { die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file))); } From 523362c7c5a5058174de6389baebf1d82078c73f Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 13:46:14 +0100 Subject: [PATCH 6/7] Cleaner notation for expected exceptions in fixtures. --- .../installer/install-self-from-root.test | 2 +- tests/Composer/Test/InstallerTest.php | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/Composer/Test/Fixtures/installer/install-self-from-root.test b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test index ceeef8b7c..82092c77f 100644 --- a/tests/Composer/Test/Fixtures/installer/install-self-from-root.test +++ b/tests/Composer/Test/Fixtures/installer/install-self-from-root.test @@ -9,7 +9,7 @@ Tries to require a package with the same name as the root package } --RUN-- install ---EXPECT-EXIT-CODE-- +--EXPECT-EXCEPTION-- InvalidArgumentException --EXPECT-- Root package 'foo/bar' cannot require itself in its composer.json diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index 518a395e1..a50563280 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -137,7 +137,7 @@ class InstallerTest extends TestCase /** * @dataProvider getIntegrationTests */ - public function testIntegration($file, $message, $condition, $composerConfig, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectExitCode) + public function testIntegration($file, $message, $condition, $composerConfig, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectResult) { if ($condition) { eval('$res = '.$condition.';'); @@ -159,11 +159,11 @@ class InstallerTest extends TestCase ->will($this->returnCallback($callback)); // Prepare for exceptions - if (is_int($expectExitCode) || ctype_digit($expectExitCode)) { - $expectExitCode = (int) $expectExitCode; + if (is_int($expectResult) || ctype_digit($expectResult)) { + $expectResult = (int) $expectResult; } else { $normalizedOutput = rtrim(str_replace("\n", PHP_EOL, $expect)); - $this->setExpectedException($expectExitCode, $normalizedOutput); + $this->setExpectedException($expectResult, $normalizedOutput); } // Create Composer mock object according to configuration @@ -242,12 +242,12 @@ class InstallerTest extends TestCase $appOutput = fopen('php://memory', 'w+'); $result = $application->run(new StringInput($run), new StreamOutput($appOutput)); fseek($appOutput, 0); - if (!is_int($expectExitCode)) { + if (!is_int($expectResult)) { // Shouldn't check output and results if an exception was expected by this point return; } - $this->assertEquals($expectExitCode, $result, $output . stream_get_contents($appOutput)); + $this->assertEquals($expectResult, $result, $output . stream_get_contents($appOutput)); if ($expectLock) { unset($actualLock['hash']); unset($actualLock['content-hash']); @@ -279,7 +279,7 @@ class InstallerTest extends TestCase $installedDev = array(); $lock = array(); $expectLock = array(); - $expectExitCode = 0; + $expectResult = 0; try { $message = $testData['TEST']; @@ -316,12 +316,21 @@ class InstallerTest extends TestCase } $expectOutput = isset($testData['EXPECT-OUTPUT']) ? $testData['EXPECT-OUTPUT'] : null; $expect = $testData['EXPECT']; - $expectExitCode = isset($testData['EXPECT-EXIT-CODE']) ? $testData['EXPECT-EXIT-CODE'] : 0; + if (!empty($testData['EXPECT-EXCEPTION'])) { + $expectResult = $testData['EXPECT-EXCEPTION']; + if (!empty($testData['EXPECT-EXIT-CODE'])) { + throw new \LogicException('EXPECT-EXCEPTION and EXPECT-EXIT-CODE are mutually exclusive'); + } + } elseif (!empty($testData['EXPECT-EXIT-CODE'])) { + $expectResult = (int) $testData['EXPECT-EXIT-CODE']; + } else { + $expectResult = 0; + } } catch (\Exception $e) { die(sprintf('Test "%s" is not valid: '.$e->getMessage(), str_replace($fixturesDir.'/', '', $file))); } - $tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $composer, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectExitCode); + $tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $composer, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectResult); } return $tests; @@ -341,6 +350,7 @@ class InstallerTest extends TestCase 'EXPECT-LOCK' => false, 'EXPECT-OUTPUT' => false, 'EXPECT-EXIT-CODE' => false, + 'EXPECT-EXCEPTION' => false, 'EXPECT' => true, ); From 3e06c801f4a2c0da9d70dad55e05e9fe28eebc8d Mon Sep 17 00:00:00 2001 From: Niels Keurentjes Date: Wed, 27 Jan 2016 13:49:52 +0100 Subject: [PATCH 7/7] Cleaned up check+conversion that was no longer required. --- tests/Composer/Test/InstallerTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/Composer/Test/InstallerTest.php b/tests/Composer/Test/InstallerTest.php index a50563280..4f599bf21 100644 --- a/tests/Composer/Test/InstallerTest.php +++ b/tests/Composer/Test/InstallerTest.php @@ -159,9 +159,7 @@ class InstallerTest extends TestCase ->will($this->returnCallback($callback)); // Prepare for exceptions - if (is_int($expectResult) || ctype_digit($expectResult)) { - $expectResult = (int) $expectResult; - } else { + if (!is_int($expectResult)) { $normalizedOutput = rtrim(str_replace("\n", PHP_EOL, $expect)); $this->setExpectedException($expectResult, $normalizedOutput); }