diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php
index 6596d9c8b..e63df021a 100644
--- a/src/Composer/Downloader/FileDownloader.php
+++ b/src/Composer/Downloader/FileDownloader.php
@@ -215,8 +215,8 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
public function update(PackageInterface $initial, PackageInterface $target, $path)
{
$name = $target->getName();
- $from = $initial->getPrettyVersion();
- $to = $target->getPrettyVersion();
+ $from = $initial->getFullPrettyVersion();
+ $to = $target->getFullPrettyVersion();
$actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
$this->io->writeError(" - " . $actionName . " " . $name . " (" . $from . " => " . $to . "): ", false);
diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php
index 6df73ceb3..8a0ff1e2d 100644
--- a/src/Composer/Factory.php
+++ b/src/Composer/Factory.php
@@ -347,7 +347,7 @@ class Factory
// load package
$parser = new VersionParser;
$guesser = new VersionGuesser($config, new ProcessExecutor($io), $parser);
- $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser);
+ $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, $guesser, $io);
$package = $loader->load($localConfig, 'Composer\Package\RootPackage', $cwd);
$composer->setPackage($package);
@@ -546,7 +546,7 @@ class Factory
$im->addInstaller(new Installer\LibraryInstaller($io, $composer, null));
$im->addInstaller(new Installer\PearInstaller($io, $composer, 'pear-library'));
$im->addInstaller(new Installer\PluginInstaller($io, $composer));
- $im->addInstaller(new Installer\MetapackageInstaller());
+ $im->addInstaller(new Installer\MetapackageInstaller($io));
}
/**
diff --git a/src/Composer/Installer/MetapackageInstaller.php b/src/Composer/Installer/MetapackageInstaller.php
index 3f99ec03c..e1f31c1bf 100644
--- a/src/Composer/Installer/MetapackageInstaller.php
+++ b/src/Composer/Installer/MetapackageInstaller.php
@@ -14,6 +14,8 @@ namespace Composer\Installer;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Package\PackageInterface;
+use Composer\Package\Version\VersionParser;
+use Composer\IO\IOInterface;
/**
* Metapackage installation manager.
@@ -22,6 +24,13 @@ use Composer\Package\PackageInterface;
*/
class MetapackageInstaller implements InstallerInterface
{
+ private $io;
+
+ public function __construct(IOInterface $io)
+ {
+ $this->io = $io;
+ }
+
/**
* {@inheritDoc}
*/
@@ -43,6 +52,8 @@ class MetapackageInstaller implements InstallerInterface
*/
public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
+ $this->io->writeError(" - Installing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
+
$repo->addPackage(clone $package);
}
@@ -55,6 +66,12 @@ class MetapackageInstaller implements InstallerInterface
throw new \InvalidArgumentException('Package is not installed: '.$initial);
}
+ $name = $target->getName();
+ $from = $initial->getFullPrettyVersion();
+ $to = $target->getFullPrettyVersion();
+ $actionName = VersionParser::isUpgrade($initial->getVersion(), $target->getVersion()) ? 'Updating' : 'Downgrading';
+ $this->io->writeError(" - " . $actionName . " " . $name . " (" . $from . " => " . $to . ")");
+
$repo->removePackage($initial);
$repo->addPackage(clone $target);
}
@@ -68,6 +85,8 @@ class MetapackageInstaller implements InstallerInterface
throw new \InvalidArgumentException('Package is not installed: '.$package);
}
+ $this->io->writeError(" - Removing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ")");
+
$repo->removePackage($package);
}
diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php
index f917eb838..84e99a857 100644
--- a/src/Composer/Package/Loader/RootPackageLoader.php
+++ b/src/Composer/Package/Loader/RootPackageLoader.php
@@ -15,6 +15,7 @@ namespace Composer\Package\Loader;
use Composer\Package\BasePackage;
use Composer\Package\AliasPackage;
use Composer\Config;
+use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
use Composer\Repository\RepositoryFactory;
use Composer\Package\Version\VersionGuesser;
@@ -46,13 +47,19 @@ class RootPackageLoader extends ArrayLoader
*/
private $versionGuesser;
- public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null)
+ /**
+ * @var IOInterface
+ */
+ private $io;
+
+ public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, VersionGuesser $versionGuesser = null, IOInterface $io = null)
{
parent::__construct($parser);
$this->manager = $manager;
$this->config = $config;
$this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor(), $this->versionParser);
+ $this->io = $io;
}
/**
@@ -65,6 +72,10 @@ class RootPackageLoader extends ArrayLoader
{
if (!isset($config['name'])) {
$config['name'] = '__root__';
+ } elseif ($this->io) {
+ if ($err = ValidatingArrayLoader::hasPackageNamingError($config['name'])) {
+ $this->io->writeError('Deprecation warning: Your package name '.$err.' Make sure you fix this as Composer 2.0 will error.');
+ }
}
$autoVersioned = false;
if (!isset($config['version'])) {
@@ -131,6 +142,18 @@ class RootPackageLoader extends ArrayLoader
}
}
+ if ($this->io) {
+ foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
+ if (isset($config[$linkType])) {
+ foreach ($config[$linkType] as $linkName => $constraint) {
+ if ($err = ValidatingArrayLoader::hasPackageNamingError($linkName, true)) {
+ $this->io->writeError('Deprecation warning: '.$linkType.'.'.$err.' Make sure you fix this as Composer 2.0 will error.');
+ }
+ }
+ }
+ }
+ }
+
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']));
diff --git a/src/Composer/Package/Loader/ValidatingArrayLoader.php b/src/Composer/Package/Loader/ValidatingArrayLoader.php
index f4753025b..405e567f0 100644
--- a/src/Composer/Package/Loader/ValidatingArrayLoader.php
+++ b/src/Composer/Package/Loader/ValidatingArrayLoader.php
@@ -336,6 +336,38 @@ class ValidatingArrayLoader implements LoaderInterface
return $this->errors;
}
+ public static function hasPackageNamingError($name, $isLink = false)
+ {
+ if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
+ return;
+ }
+
+ if (!preg_match('{^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*$}iD', $name)) {
+ return $name.' is invalid, it should have a vendor name, a forward slash, and a package name. The vendor and package name can be words separated by -, . or _. The complete name should match "[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*".';
+ }
+
+ $reservedNames = array('nul', 'con', 'prn', 'aux', 'com1', 'com2', 'com3', 'com4', 'com5', 'com6', 'com7', 'com8', 'com9', 'lpt1', 'lpt2', 'lpt3', 'lpt4', 'lpt5', 'lpt6', 'lpt7', 'lpt8', 'lpt9');
+ $bits = explode('/', strtolower($name));
+ if (in_array($bits[0], $reservedNames, true) || in_array($bits[1], $reservedNames, true)) {
+ return $name.' is reserved, package and vendor names can not match any of: '.implode(', ', $reservedNames).'.';
+ }
+
+ if (preg_match('{\.json$}', $name)) {
+ return $name.' is invalid, package names can not end in .json, consider renaming it or perhaps using a -json suffix instead.';
+ }
+
+ if (preg_match('{[A-Z]}', $name)) {
+ if ($isLink) {
+ return $name.' is invalid, it should not contain uppercase characters. Please use '.strtolower($name).' instead.';
+ }
+
+ $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
+ $suggestName = strtolower($suggestName);
+
+ return $name.' is invalid, it should not contain uppercase characters. We suggest using '.$suggestName.' instead.';
+ }
+ }
+
private function validateRegex($property, $regex, $mandatory = false)
{
if (!$this->validateString($property, $mandatory)) {
diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php
index 6d6e04d2f..4d74d8ed2 100644
--- a/src/Composer/Repository/PlatformRepository.php
+++ b/src/Composer/Repository/PlatformRepository.php
@@ -24,7 +24,7 @@ use Composer\XdebugHandler\XdebugHandler;
*/
class PlatformRepository extends ArrayRepository
{
- const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[^/ ]+)$}i';
+ const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit|-ipv6|-zts|-debug)?|hhvm|(?:ext|lib)-[a-z0-9](?:-?[a-z0-9]+)*)$}iD';
private $versionParser;
diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php
index 37410eecd..74e5c286f 100644
--- a/src/Composer/Util/Git.php
+++ b/src/Composer/Util/Git.php
@@ -153,6 +153,28 @@ class Git
return;
}
}
+ } elseif (preg_match('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}', $url, $match)) {
+ if (!$this->io->hasAuthentication($match[2])) {
+ $gitLabUtil = new GitLab($this->io, $this->config, $this->process);
+ $message = 'Cloning failed, enter your GitLab credentials to access private repos';
+
+ if (!$gitLabUtil->authorizeOAuth($match[2]) && $this->io->isInteractive()) {
+ $gitLabUtil->authorizeOAuthInteractively($match[1], $match[2], $message);
+ }
+ }
+
+ if ($this->io->hasAuthentication($match[2])) {
+ $auth = $this->io->getAuthentication($match[2]);
+ if($auth['password'] === 'private-token' || $auth['password'] === 'oauth2') {
+ $authUrl = $match[1] . '://' . rawurlencode($auth['password']) . ':' . rawurlencode($auth['username']) . '@' . $match[2] . '/' . $match[3]; // swap username and password
+ } else {
+ $authUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . '/' . $match[3];
+ }
+ $command = call_user_func($commandCallable, $authUrl);
+ if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
+ return;
+ }
+ }
} elseif ($this->isAuthenticationFailure($url, $match)) { // private non-github repo that failed to authenticate
if (strpos($match[2], '@')) {
list($authParts, $match[2]) = explode('@', $match[2], 2);
@@ -304,6 +326,11 @@ class Git
return '(' . implode('|', array_map('preg_quote', $config->get('github-domains'))) . ')';
}
+ public static function getGitLabDomainsRegex(Config $config)
+ {
+ return '(' . implode('|', array_map('preg_quote', $config->get('gitlab-domains'))) . ')';
+ }
+
public static function sanitizeUrl($message)
{
return preg_replace_callback('{://(?P[^@]+?):(?P.+?)@}', function ($m) {
diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php
index 476b9a8f7..b09065f85 100644
--- a/tests/Composer/Test/Downloader/FileDownloaderTest.php
+++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php
@@ -210,7 +210,7 @@ class FileDownloaderTest extends TestCase
{
$oldPackage = $this->getMock('Composer\Package\PackageInterface');
$oldPackage->expects($this->once())
- ->method('getPrettyVersion')
+ ->method('getFullPrettyVersion')
->will($this->returnValue('1.2.0'));
$oldPackage->expects($this->once())
->method('getVersion')
@@ -218,7 +218,7 @@ class FileDownloaderTest extends TestCase
$newPackage = $this->getMock('Composer\Package\PackageInterface');
$newPackage->expects($this->once())
- ->method('getPrettyVersion')
+ ->method('getFullPrettyVersion')
->will($this->returnValue('1.0.0'));
$newPackage->expects($this->once())
->method('getVersion')
diff --git a/tests/Composer/Test/Fixtures/installer/github-issues-4319.test b/tests/Composer/Test/Fixtures/installer/github-issues-4319.test
index d97aefc8d..ee221dab0 100644
--- a/tests/Composer/Test/Fixtures/installer/github-issues-4319.test
+++ b/tests/Composer/Test/Fixtures/installer/github-issues-4319.test
@@ -13,12 +13,12 @@ Present a clear error message when config.platform.php version results in a conf
{
"type": "package",
"package": [
- { "name": "a", "version": "1.0.0", "require": { "php": "5.5" } }
+ { "name": "a/a", "version": "1.0.0", "require": { "php": "5.5" } }
]
}
],
"require": {
- "a": "~1.0"
+ "a/a": "~1.0"
},
"config": {
"platform": {
@@ -36,8 +36,8 @@ Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- - Installation request for a ~1.0 -> satisfiable by a[1.0.0].
- - a 1.0.0 requires php 5.5 -> your PHP version (%s) overridden by "config.platform.php" version (5.3) does not satisfy that requirement.
+ - Installation request for a/a ~1.0 -> satisfiable by a/a[1.0.0].
+ - a/a 1.0.0 requires php 5.5 -> your PHP version (%s) overridden by "config.platform.php" version (5.3) does not satisfy that requirement.
--EXPECT--
diff --git a/tests/Composer/Test/Fixtures/installer/github-issues-4795-2.test b/tests/Composer/Test/Fixtures/installer/github-issues-4795-2.test
index d807c6df8..877ac3653 100644
--- a/tests/Composer/Test/Fixtures/installer/github-issues-4795-2.test
+++ b/tests/Composer/Test/Fixtures/installer/github-issues-4795-2.test
@@ -11,27 +11,27 @@ that are also a root package, when that root package is also explicitly whitelis
{
"type": "package",
"package": [
- { "name": "a", "version": "1.0.0" },
- { "name": "a", "version": "1.1.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } },
- { "name": "b", "version": "1.1.0", "require": { "a": "~1.1" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "a/a", "version": "1.1.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } },
+ { "name": "b/b", "version": "1.1.0", "require": { "a/a": "~1.1" } }
]
}
],
"require": {
- "a": "~1.0",
- "b": "~1.0"
+ "a/a": "~1.0",
+ "b/b": "~1.0"
}
}
--INSTALLED--
[
- { "name": "a", "version": "1.0.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
]
--RUN--
-update a b --with-dependencies
+update a/a b/b --with-dependencies
--EXPECT-OUTPUT--
Loading composer repositories with package information
@@ -41,5 +41,5 @@ Writing lock file
Generating autoload files
--EXPECT--
-Updating a (1.0.0) to a (1.1.0)
-Updating b (1.0.0) to b (1.1.0)
+Updating a/a (1.0.0) to a/a (1.1.0)
+Updating b/b (1.0.0) to b/b (1.1.0)
diff --git a/tests/Composer/Test/Fixtures/installer/github-issues-4795.test b/tests/Composer/Test/Fixtures/installer/github-issues-4795.test
index 5a1158f26..1f4b1af27 100644
--- a/tests/Composer/Test/Fixtures/installer/github-issues-4795.test
+++ b/tests/Composer/Test/Fixtures/installer/github-issues-4795.test
@@ -11,30 +11,30 @@ dependency of one the requirements that is whitelisted for update.
{
"type": "package",
"package": [
- { "name": "a", "version": "1.0.0" },
- { "name": "a", "version": "1.1.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } },
- { "name": "b", "version": "1.1.0", "require": { "a": "~1.1" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "a/a", "version": "1.1.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } },
+ { "name": "b/b", "version": "1.1.0", "require": { "a/b": "~1.1" } }
]
}
],
"require": {
- "a": "~1.0",
- "b": "~1.0"
+ "a/a": "~1.0",
+ "b/b": "~1.0"
}
}
--INSTALLED--
[
- { "name": "a", "version": "1.0.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
]
--RUN--
-update b --with-dependencies
+update b/b --with-dependencies
--EXPECT-OUTPUT--
-Dependency "a" is also a root requirement, but is not explicitly whitelisted. Ignoring.
+Dependency "a/a" is also a root requirement, but is not explicitly whitelisted. Ignoring.
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
diff --git a/tests/Composer/Test/Fixtures/installer/solver-problems.test b/tests/Composer/Test/Fixtures/installer/solver-problems.test
index e0359a151..cab45f9dc 100644
--- a/tests/Composer/Test/Fixtures/installer/solver-problems.test
+++ b/tests/Composer/Test/Fixtures/installer/solver-problems.test
@@ -8,30 +8,30 @@ Test the error output of solver problems.
"package": [
{ "name": "unstable/package", "version": "2.0.0-alpha" },
{ "name": "unstable/package", "version": "1.0.0" },
- { "name": "requirer", "version": "1.0.0", "require": {"dependency": "1.0.0" } },
- { "name": "dependency", "version": "2.0.0" },
- { "name": "dependency", "version": "1.0.0" },
- { "name": "stable-requiree-excluded", "version": "1.0.1" },
- { "name": "stable-requiree-excluded", "version": "1.0.0" }
+ { "name": "requirer/pkg", "version": "1.0.0", "require": {"dependency/pkg": "1.0.0" } },
+ { "name": "dependency/pkg", "version": "2.0.0" },
+ { "name": "dependency/pkg", "version": "1.0.0" },
+ { "name": "stable-requiree-excluded/pkg", "version": "1.0.1" },
+ { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" }
]
}
],
"require": {
"unstable/package": "2.*",
- "bogus": "1.*",
- "requirer": "1.*",
- "dependency": "2.*",
- "stable-requiree-excluded": "1.0.1"
+ "bogus/pkg": "1.*",
+ "requirer/pkg": "1.*",
+ "dependency/pkg": "2.*",
+ "stable-requiree-excluded/pkg": "1.0.1"
}
}
--INSTALLED--
[
- { "name": "stable-requiree-excluded", "version": "1.0.0" }
+ { "name": "stable-requiree-excluded/pkg", "version": "1.0.0" }
]
--RUN--
-update unstable/package requirer dependency
+update unstable/package requirer/pkg dependency/pkg
--EXPECT-EXIT-CODE--
2
@@ -44,12 +44,12 @@ Your requirements could not be resolved to an installable set of packages.
Problem 1
- The requested package unstable/package 2.* exists as unstable/package[1.0.0] but these are rejected by your constraint.
Problem 2
- - The requested package bogus could not be found in any version, there may be a typo in the package name.
+ - The requested package bogus/pkg could not be found in any version, there may be a typo in the package name.
Problem 3
- - The requested package stable-requiree-excluded (installed at 1.0.0, required as 1.0.1) is satisfiable by stable-requiree-excluded[1.0.0] but these conflict with your requirements or minimum-stability.
+ - The requested package stable-requiree-excluded/pkg (installed at 1.0.0, required as 1.0.1) is satisfiable by stable-requiree-excluded/pkg[1.0.0] but these conflict with your requirements or minimum-stability.
Problem 4
- - Installation request for requirer 1.* -> satisfiable by requirer[1.0.0].
- - requirer 1.0.0 requires dependency 1.0.0 -> satisfiable by dependency[1.0.0] but these conflict with your requirements or minimum-stability.
+ - Installation request for requirer/pkg 1.* -> satisfiable by requirer/pkg[1.0.0].
+ - requirer/pkg 1.0.0 requires dependency/pkg 1.0.0 -> satisfiable by dependency/pkg[1.0.0] but these conflict with your requirements or minimum-stability.
Potential causes:
- A typo in the package name
diff --git a/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test b/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test
index f4fbfce9b..c0019e6ca 100644
--- a/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test
+++ b/tests/Composer/Test/Fixtures/installer/update-with-all-dependencies.test
@@ -10,27 +10,27 @@ When `--with-all-dependencies` is used, Composer\Installer::whitelistUpdateDepen
{
"type": "package",
"package": [
- { "name": "a", "version": "1.0.0" },
- { "name": "a", "version": "1.1.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } },
- { "name": "b", "version": "1.1.0", "require": { "a": "~1.1" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "a/a", "version": "1.1.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } },
+ { "name": "b/b", "version": "1.1.0", "require": { "a/a": "~1.1" } }
]
}
],
"require": {
- "a": "~1.0",
- "b": "~1.0"
+ "a/a": "~1.0",
+ "b/b": "~1.0"
}
}
--INSTALLED--
[
- { "name": "a", "version": "1.0.0" },
- { "name": "b", "version": "1.0.0", "require": { "a": "~1.0" } }
+ { "name": "a/a", "version": "1.0.0" },
+ { "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
]
--RUN--
-update b --with-all-dependencies
+update b/b --with-all-dependencies
--EXPECT-OUTPUT--
Loading composer repositories with package information
@@ -40,5 +40,5 @@ Writing lock file
Generating autoload files
--EXPECT--
-Updating a (1.0.0) to a (1.1.0)
-Updating b (1.0.0) to b (1.1.0)
\ No newline at end of file
+Updating a/a (1.0.0) to a/a (1.1.0)
+Updating b/b (1.0.0) to b/b (1.1.0)
diff --git a/tests/Composer/Test/Installer/MetapackageInstallerTest.php b/tests/Composer/Test/Installer/MetapackageInstallerTest.php
index 1a6b7a264..171773579 100644
--- a/tests/Composer/Test/Installer/MetapackageInstallerTest.php
+++ b/tests/Composer/Test/Installer/MetapackageInstallerTest.php
@@ -27,7 +27,7 @@ class MetapackageInstallerTest extends TestCase
$this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
- $this->installer = new MetapackageInstaller();
+ $this->installer = new MetapackageInstaller($this->io);
}
public function testInstall()
@@ -45,7 +45,13 @@ class MetapackageInstallerTest extends TestCase
public function testUpdate()
{
$initial = $this->createPackageMock();
+ $initial->expects($this->once())
+ ->method('getVersion')
+ ->will($this->returnValue('1.0.0'));
$target = $this->createPackageMock();
+ $target->expects($this->once())
+ ->method('getVersion')
+ ->will($this->returnValue('1.0.1'));
$this->repository
->expects($this->exactly(2))