1
0
Fork 0

Add IOMock and get rid of all withConsecutive calls in tests (#11497)

pull/11499/head
Jordi Boggiano 2023-06-07 14:35:16 +02:00 committed by GitHub
parent ebd0a60411
commit 9f3e2105da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 394 additions and 265 deletions

View File

@ -5301,6 +5301,16 @@ parameters:
count: 1
path: ../tests/Composer/Test/Json/JsonManipulatorTest.php
-
message: "#^Offset 'ask' might not exist on array\\{ask\\: string, reply\\?\\: string\\}\\|array\\{auth\\: array\\{string, string, string\\|null\\}\\}\\|array\\{text\\: string, verbosity\\?\\: 1\\|2\\|4\\|8\\|16\\}\\.$#"
count: 2
path: ../tests/Composer/Test/Mock/IOMock.php
-
message: "#^Offset 'text' might not exist on array\\{ask\\: string, reply\\?\\: string\\}\\|array\\{auth\\: array\\{string, string, string\\|null\\}\\}\\|array\\{text\\: string, verbosity\\?\\: 1\\|2\\|4\\|8\\|16\\}\\.$#"
count: 1
path: ../tests/Composer/Test/Mock/IOMock.php
-
message: "#^Composer\\\\Test\\\\Mock\\\\InstallationManagerMock\\:\\:__construct\\(\\) does not call parent constructor from Composer\\\\Installer\\\\InstallationManager\\.$#"
count: 1

View File

@ -1328,10 +1328,16 @@ EOF;
$this->eventDispatcher
->expects($this->exactly(2))
->method('dispatchScript')
->withConsecutive(
[ScriptEvents::PRE_AUTOLOAD_DUMP, false],
[ScriptEvents::POST_AUTOLOAD_DUMP, false]
);
->willReturnCallback(function ($type, $dev) {
static $series = [
[ScriptEvents::PRE_AUTOLOAD_DUMP, false],
[ScriptEvents::POST_AUTOLOAD_DUMP, false]
];
$this->assertSame(array_shift($series), [$type, $dev]);
return 0;
});
$package = new RootPackage('root/a', '1.0', '1.0');
$package->setAutoload(['psr-0' => ['Prefix' => 'foo/bar/non/existing/']]);

View File

@ -307,12 +307,9 @@ class ConfigTest extends TestCase
public function testProhibitedUrlsWarningVerifyPeer(): void
{
$io = $this->getMockBuilder(IOInterface::class)->disableOriginalConstructor()->getMock();
$io = $this->getIOMock();
$io
->expects($this->once())
->method('writeError')
->with($this->equalTo('<warning>Warning: Accessing example.org with verify_peer and verify_peer_name disabled.</warning>'));
$io->expects([['text' => '<warning>Warning: Accessing example.org with verify_peer and verify_peer_name disabled.</warning>']], true);
$config = new Config(false);
$config->prohibitUrlByConfig('https://example.org', $io, [

View File

@ -258,10 +258,14 @@ class DownloadManagerTest extends TestCase
$package
->expects($this->exactly(2))
->method('setInstallationSource')
->withConsecutive(
['dist'],
['source']
);
->willReturnCallback(function ($type) {
static $series = [
'dist',
'source',
];
$this->assertSame(array_shift($series), $type);
});
$downloaderFail = $this->createDownloaderMock();
$downloaderFail

View File

@ -375,13 +375,11 @@ class FileDownloaderTest extends TestCase
$newPackage = self::getPackage('dummy/pkg', '1.0.0');
$newPackage->setDistUrl($distUrl = 'http://example.com/script.js');
$ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$ioMock->expects($this->atLeast(2))
->method('writeError')
->withConsecutive(
[$this->stringContains('Downloading')],
[$this->stringContains('Downgrading')]
);
$ioMock = $this->getIOMock();
$ioMock->expects([
['text' => '{Downloading .*}', 'regex' => true],
['text' => '{Downgrading .*}', 'regex' => true],
]);
$path = self::getUniqueTmpDirectory();
$config = $this->getConfig(['vendor-dir' => $path.'/vendor']);

View File

@ -547,12 +547,10 @@ composer https://github.com/old/url (push)
$process = $this->getProcessExecutorMock();
$ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$ioMock->expects($this->atLeastOnce())
->method('writeError')
->withConsecutive(
[$this->stringContains('Downgrading')]
);
$ioMock = $this->getIOMock();
$ioMock->expects([
['text' => '{Downgrading .*}', 'regex' => true],
]);
$this->fs->ensureDirectoryExists($this->workingDir.'/.git');
$downloader = $this->getDownloaderMock($ioMock, null, $process);
@ -591,12 +589,10 @@ composer https://github.com/old/url (push)
$process = $this->getProcessExecutorMock();
$ioMock = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$ioMock->expects($this->atLeastOnce())
->method('writeError')
->withConsecutive(
[$this->stringContains('Upgrading')]
);
$ioMock = $this->getIOMock();
$ioMock->expects([
['text' => '{Upgrading .*}', 'regex' => true],
]);
$this->fs->ensureDirectoryExists($this->workingDir.'/.git');
$downloader = $this->getDownloaderMock($ioMock, null, $process);

View File

@ -14,6 +14,7 @@ namespace Composer\Test\EventDispatcher;
use Composer\EventDispatcher\Event;
use Composer\EventDispatcher\EventDispatcher;
use Composer\EventDispatcher\ScriptExecutionException;
use Composer\Installer\InstallerEvents;
use Composer\Config;
use Composer\Composer;
@ -32,21 +33,15 @@ class EventDispatcherTest extends TestCase
{
self::expectException('RuntimeException');
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$io = $this->getIOMock(IOInterface::NORMAL);
$dispatcher = $this->getDispatcherStubForListenersTest([
'Composer\Test\EventDispatcher\EventDispatcherTest::call',
], $io);
$io->expects($this->once())
->method('isVerbose')
->willReturn(0);
$io->expects($this->atLeast(2))
->method('writeError')
->withConsecutive(
['> Composer\Test\EventDispatcher\EventDispatcherTest::call'],
['<error>Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception</error>']
);
$io->expects([
['text' => '> Composer\Test\EventDispatcher\EventDispatcherTest::call'],
['text' => 'Script Composer\Test\EventDispatcher\EventDispatcherTest::call handling the post-install-cmd event terminated with an exception'],
], true);
$dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
}
@ -528,7 +523,7 @@ class EventDispatcherTest extends TestCase
$dispatcher = $this->getMockBuilder('Composer\EventDispatcher\EventDispatcher')
->setConstructorArgs([
$this->createComposerInstance(),
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(),
$io = $this->getIOMock(IOInterface::NORMAL),
new ProcessExecutor,
])
->onlyMethods(['getListeners'])
@ -540,22 +535,13 @@ class EventDispatcherTest extends TestCase
->method('getListeners')
->will($this->returnValue($listener));
$io->expects($this->once())
->method('isVerbose')
->willReturn(0);
$io->expects([
['text' => '> exit 1'],
['text' => 'Script '.$code.' handling the post-install-cmd event returned with error code 1'],
], true);
$io->expects($this->atLeast(2))
->method('writeError')
->withConsecutive(
['> exit 1'],
['<error>Script '.$code.' handling the post-install-cmd event returned with error code 1</error>']
);
$io->expects($this->once())
->method('isInteractive')
->willReturn(1);
self::expectException('RuntimeException');
self::expectException(ScriptExecutionException::class);
self::expectExceptionMessage('Error Output: ');
$dispatcher->dispatchScript(ScriptEvents::POST_INSTALL_CMD, false);
}

View File

@ -111,15 +111,25 @@ class ConsoleIOTest extends TestCase
->willReturn(OutputInterface::VERBOSITY_NORMAL);
$outputMock->expects($this->atLeast(7))
->method('write')
->withConsecutive(
[$this->equalTo('something (<question>strlen = 23</question>)')],
[$this->equalTo(str_repeat("\x08", 23)), $this->equalTo(false)],
[$this->equalTo('shorter (<comment>12</comment>)'), $this->equalTo(false)],
[$this->equalTo(str_repeat(' ', 11)), $this->equalTo(false)],
[$this->equalTo(str_repeat("\x08", 11)), $this->equalTo(false)],
[$this->equalTo(str_repeat("\x08", 12)), $this->equalTo(false)],
[$this->equalTo('something longer than initial (<info>34</info>)')]
);
->willReturnCallback(function (...$args) {
static $series = null;
if ($series === null) {
$series = [
['something (<question>strlen = 23</question>)', true],
[str_repeat("\x08", 23), false],
['shorter (<comment>12</comment>)', false],
[str_repeat(' ', 11), false],
[str_repeat("\x08", 11), false],
[str_repeat("\x08", 12), false],
['something longer than initial (<info>34</info>)', false],
];
}
if (count($series) > 0) {
$this->assertSame(array_shift($series), [$args[0], $args[1]]);
}
});
$helperMock = $this->getMockBuilder('Symfony\Component\Console\Helper\HelperSet')->getMock();

View File

@ -15,6 +15,7 @@ namespace Composer\Test\Installer;
use Composer\InstalledVersions;
use Composer\Installer\SuggestedPackagesReporter;
use Composer\Semver\VersionParser;
use Composer\Test\Mock\IOMock;
use Composer\Test\TestCase;
/**
@ -23,7 +24,7 @@ use Composer\Test\TestCase;
class SuggestedPackagesReporterTest extends TestCase
{
/**
* @var \PHPUnit\Framework\MockObject\MockObject
* @var IOMock
*/
private $io;
@ -34,7 +35,7 @@ class SuggestedPackagesReporterTest extends TestCase
protected function setUp(): void
{
$this->io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$this->io = $this->getIOMock();
$this->suggestedPackagesReporter = new SuggestedPackagesReporter($this->io);
}
@ -44,8 +45,7 @@ class SuggestedPackagesReporterTest extends TestCase
*/
public function testConstructor(): void
{
$this->io->expects($this->once())
->method('write');
$this->io->expects([['text' => 'b']], true);
$this->suggestedPackagesReporter->addPackage('a', 'b', 'c');
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_LIST);
@ -143,13 +143,11 @@ class SuggestedPackagesReporterTest extends TestCase
{
$this->suggestedPackagesReporter->addPackage('a', 'b', 'c');
$this->io->expects($this->exactly(3))
->method('write')
->withConsecutive(
['<comment>a</comment> suggests:'],
[' - <info>b</info>: c'],
['']
);
$this->io->expects([
['text' => 'a suggests:'],
['text' => ' - b: c'],
['text' => ''],
], true);
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_BY_PACKAGE);
}
@ -161,13 +159,11 @@ class SuggestedPackagesReporterTest extends TestCase
{
$this->suggestedPackagesReporter->addPackage('a', 'b', '');
$this->io->expects($this->exactly(3))
->method('write')
->withConsecutive(
['<comment>a</comment> suggests:'],
[' - <info>b</info>'],
['']
);
$this->io->expects([
['text' => 'a suggests:'],
['text' => ' - b'],
['text' => ''],
], true);
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_BY_PACKAGE);
}
@ -180,18 +176,12 @@ class SuggestedPackagesReporterTest extends TestCase
$this->suggestedPackagesReporter->addPackage('source', 'target1', "\x1b[1;37;42m Like us\r\non Facebook \x1b[0m");
$this->suggestedPackagesReporter->addPackage('source', 'target2', "<bg=green>Like us on Facebook</>");
$expectedWrite = InstalledVersions::satisfies(new VersionParser(), 'symfony/console', '^4.4.37 || ~5.3.14 || ^5.4.3 || ^6.0.3')
? ' - <info>target2</info>: \\<bg=green\\>Like us on Facebook\\</\\>'
: ' - <info>target2</info>: \\<bg=green>Like us on Facebook\\</>';
$this->io->expects($this->exactly(4))
->method('write')
->withConsecutive(
['<comment>source</comment> suggests:'],
[' - <info>target1</info>: [1;37;42m Like us on Facebook [0m'],
[$expectedWrite],
['']
);
$this->io->expects([
['text' => 'source suggests:'],
['text' => ' - target1: [1;37;42m Like us on Facebook [0m'],
['text' => ' - target2: <bg=green>Like us on Facebook</>'],
['text' => ''],
], true);
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_BY_PACKAGE);
}
@ -204,16 +194,14 @@ class SuggestedPackagesReporterTest extends TestCase
$this->suggestedPackagesReporter->addPackage('a', 'b', 'c');
$this->suggestedPackagesReporter->addPackage('source package', 'target', 'because reasons');
$this->io->expects($this->exactly(6))
->method('write')
->withConsecutive(
['<comment>a</comment> suggests:'],
[' - <info>b</info>: c'],
[''],
['<comment>source package</comment> suggests:'],
[' - <info>target</info>: because reasons'],
['']
);
$this->io->expects([
['text' => 'a suggests:'],
['text' => ' - b: c'],
['text' => ''],
['text' => 'source package suggests:'],
['text' => ' - target: because reasons'],
['text' => ''],
], true);
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_BY_PACKAGE);
}
@ -245,13 +233,11 @@ class SuggestedPackagesReporterTest extends TestCase
$this->suggestedPackagesReporter->addPackage('a', 'b', 'c');
$this->suggestedPackagesReporter->addPackage('source package', 'target', 'because reasons');
$this->io->expects($this->exactly(3))
->method('write')
->withConsecutive(
['<comment>source package</comment> suggests:'],
[' - <info>target</info>: because reasons'],
['']
);
$this->io->expects([
['text' => 'source package suggests:'],
['text' => ' - target: because reasons'],
['text' => ''],
], true);
$this->suggestedPackagesReporter->output(SuggestedPackagesReporter::MODE_BY_PACKAGE, $repository);
}

View File

@ -0,0 +1,196 @@
<?php declare(strict_types=1);
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* 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\Config;
use Composer\IO\BufferIO;
use Composer\IO\IOInterface;
use Composer\Pcre\PcreException;
use Composer\Pcre\Preg;
use Composer\Util\HttpDownloader;
use Composer\Util\Http\Response;
use Composer\Downloader\TransportException;
use Composer\Util\Platform;
use LogicException;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\AssertionFailedError;
use Symfony\Component\Console\Output\OutputInterface;
class IOMock extends BufferIO
{
/**
* @var list<array{text: string, verbosity?: IOInterface::*}|array{ask: string, reply?: string}|array{auth: array{string, string, string|null}}>|null
*/
private $expectations = null;
/**
* @var bool
*/
private $strict = false;
/**
* @var list<array{string, string, string|null}>
*/
private $authLog = [];
/**
* @param IOInterface::* $verbosity
*/
public function __construct(int $verbosity)
{
$sfVerbosity = [
self::QUIET => OutputInterface::VERBOSITY_QUIET,
self::NORMAL => OutputInterface::VERBOSITY_NORMAL,
self::VERBOSE => OutputInterface::VERBOSITY_VERBOSE,
self::VERY_VERBOSE => OutputInterface::VERBOSITY_VERY_VERBOSE,
self::DEBUG => OutputInterface::VERBOSITY_DEBUG,
][$verbosity];
parent::__construct('', $sfVerbosity);
}
/**
* @param list<array{text: string, verbosity?: IOInterface::*, regex?: true}|array{ask: string, reply: string}|array{auth: array{string, string, string|null}}> $expectations
* @param bool $strict set to true if you want to provide *all* expected messages, and not just a subset you are interested in testing
*/
public function expects(array $expectations, bool $strict = false): void
{
$this->expectations = $expectations;
$inputs = [];
foreach ($expectations as $expect) {
if (isset($expect['ask'], $expect['reply'])) {
if (!is_string($expect['reply'])) {
throw new \LogicException('A question\'s reply must be a string, use empty string for null replies');
}
$inputs[] = $expect['reply'];
}
}
if (count($inputs) > 0) {
$this->setUserInputs($inputs);
}
$this->strict = $strict;
}
public function assertComplete(): void
{
$output = $this->getOutput();
if (Platform::getEnv('DEBUG_OUTPUT') === '1') {
echo PHP_EOL.'Collected output: '.$output.PHP_EOL;
}
// this was not configured to expect anything, so no need to react here
if (!is_array($this->expectations)) {
return;
}
if (count($this->expectations) > 0) {
$lines = Preg::split("{\r?\n}", $output);
foreach ($this->expectations as $expect) {
if (isset($expect['auth'])) {
while (count($this->authLog) > 0) {
$auth = array_shift($this->authLog);
if ($auth === $expect['auth']) {
continue 2;
}
if ($this->strict) {
throw new AssertionFailedError('IO authentication mismatch. Expected:'.PHP_EOL.json_encode($expect['auth']).PHP_EOL.'Got:'.PHP_EOL.json_encode($auth));
}
}
throw new AssertionFailedError('Expected "'.json_encode($expect['auth']).'" auth to be set but there are no setAuthentication calls left to consume.');
}
if (isset($expect['ask'], $expect['reply'])) {
$pattern = '{^'.preg_quote($expect['ask']).'$}';
} elseif (isset($expect['regex']) && $expect['regex']) {
$pattern = $expect['text'];
} else {
$pattern = '{^'.preg_quote($expect['text']).'$}';
}
while (count($lines) > 0) {
$line = array_shift($lines);
try {
if (Preg::isMatch($pattern, $line)) {
continue 2;
}
} catch (PcreException $e) {
throw new LogicException('Invalid regex pattern in IO expectation "'.$pattern.'": '.$e->getMessage());
}
if ($this->strict) {
throw new AssertionFailedError('IO output mismatch. Expected:'.PHP_EOL.($expect['text'] ?? $expect['ask']).PHP_EOL.'Got:'.PHP_EOL.$line);
}
}
throw new AssertionFailedError('Expected "'.($expect['text'] ?? $expect['ask']).'" to be output still but there is no output left to consume. Complete output:'.PHP_EOL.$output);
}
} elseif ($output !== '' && $this->strict) {
throw new AssertionFailedError('There was strictly no output expected but some output occurred: '.$output);
}
// dummy assertion to ensure the test is not marked as having no assertions
Assert::assertTrue(true); // @phpstan-ignore-line
}
/**
* @inheritDoc
*/
public function ask($question, $default = null)
{
return parent::ask(rtrim($question, "\r\n").PHP_EOL, $default);
}
/**
* @inheritDoc
*/
public function askConfirmation($question, $default = true)
{
return parent::askConfirmation(rtrim($question, "\r\n").PHP_EOL, $default);
}
/**
* @inheritDoc
*/
public function askAndValidate($question, $validator, $attempts = null, $default = null)
{
return parent::askAndValidate(rtrim($question, "\r\n").PHP_EOL, $validator, $attempts, $default);
}
/**
* @inheritDoc
*/
public function askAndHideAnswer($question)
{
// do not hide answer in tests because that blocks on windows with hiddeninput.exe
return parent::ask(rtrim($question, "\r\n").PHP_EOL);
}
/**
* @inheritDoc
*/
public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
{
return parent::select(rtrim($question, "\r\n").PHP_EOL, $choices, $default, $attempts, $errorMessage, $multiselect);
}
public function setAuthentication($repositoryName, $username, $password = null)
{
$this->authentications[$repositoryName] = ['username' => $username, 'password' => $password];
$this->authLog[] = [$repositoryName, $username, $password];
parent::setAuthentication($repositoryName, $username, $password);
}
}

View File

@ -55,7 +55,7 @@ class GitDriverTest extends TestCase
public function testGetRootIdentifierFromRemoteLocalRepository(): void
{
$process = $this->getProcessExecutorMock();
$io = $this->getMockBuilder(IOInterface::class)->getMock();
$io = $this->getIOMock();
$driver = new GitDriver(['url' => $this->home], $io, $this->config, $this->getHttpDownloaderMock(), $process);
$this->setRepoDir($driver, $this->home);
@ -82,11 +82,9 @@ GIT;
public function testGetRootIdentifierFromRemote(): void
{
$process = $this->getProcessExecutorMock();
$io = $this->getMockBuilder(IOInterface::class)->getMock();
$io = $this->getIOMock();
$io
->expects($this->never())
->method('writeError');
$io->expects([], true);
$driver = new GitDriver(['url' => 'https://example.org/acme.git'], $io, $this->config, $this->getHttpDownloaderMock(), $process);
$this->setRepoDir($driver, $this->home);
@ -119,7 +117,7 @@ GIT;
Platform::putEnv('COMPOSER_DISABLE_NETWORK', '1');
$process = $this->getProcessExecutorMock();
$io = $this->getMockBuilder(IOInterface::class)->getMock();
$io = $this->getIOMock();
$driver = new GitDriver(['url' => 'https://example.org/acme.git'], $io, $this->config, $this->getHttpDownloaderMock(), $process);
$this->setRepoDir($driver, $this->home);

View File

@ -24,6 +24,7 @@ use Composer\Package\PackageInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Test\Mock\FactoryMock;
use Composer\Test\Mock\HttpDownloaderMock;
use Composer\Test\Mock\IOMock;
use Composer\Test\Mock\ProcessExecutorMock;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
@ -59,6 +60,10 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
* @var list<ProcessExecutorMock>
*/
private $processExecutorMocks = [];
/**
* @var list<IOMock>
*/
private $ioMocks = [];
/**
* @var list<string>
*/
@ -75,6 +80,9 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
foreach ($this->processExecutorMocks as $mock) {
$mock->assertComplete();
}
foreach ($this->ioMocks as $mock) {
$mock->assertComplete();
}
if (null !== $this->prevCwd) {
chdir($this->prevCwd);
@ -181,7 +189,7 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
{
$factory = new FactoryMock();
$locker = new Locker($this->getMockBuilder(IOInterface::class)->getMock(), new JsonFile('./composer.lock'), $factory->createInstallationManager(), (string) file_get_contents('./composer.json'));
$locker = new Locker($this->getIOMock(), new JsonFile('./composer.lock'), $factory->createInstallationManager(), (string) file_get_contents('./composer.json'));
$locker->setLockData($packages, $devPackages, [], [], [], 'dev', [], false, false, []);
}
@ -356,6 +364,16 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
return $mock;
}
/**
* @param IOInterface::* $verbosity
*/
protected function getIOMock(int $verbosity = IOInterface::DEBUG): IOMock
{
$this->ioMocks[] = $mock = new IOMock($verbosity);
return $mock;
}
protected function createTempFile(?string $dir = null): string
{
$dir = $dir ?? sys_get_temp_dir();

View File

@ -12,6 +12,7 @@
namespace Composer\Test\Util;
use Composer\Test\Mock\IOMock;
use Composer\Util\Bitbucket;
use Composer\Util\Http\Response;
use Composer\Test\TestCase;
@ -36,7 +37,7 @@ class BitbucketTest extends TestCase
/** @var string */
private $token = 'bitbuckettoken';
/** @var \Composer\IO\ConsoleIO&\PHPUnit\Framework\MockObject\MockObject */
/** @var IOMock */
private $io;
/** @var \Composer\Util\HttpDownloader&\PHPUnit\Framework\MockObject\MockObject */
private $httpDownloader;
@ -49,11 +50,7 @@ class BitbucketTest extends TestCase
protected function setUp(): void
{
$this->io = $this
->getMockBuilder('Composer\IO\ConsoleIO')
->disableOriginalConstructor()
->getMock()
;
$this->io = $this->getIOMock();
$this->httpDownloader = $this
->getMockBuilder('Composer\Util\HttpDownloader')
@ -70,9 +67,9 @@ class BitbucketTest extends TestCase
public function testRequestAccessTokenWithValidOAuthConsumer(): void
{
$this->io->expects($this->once())
->method('setAuthentication')
->with($this->origin, $this->consumer_key, $this->consumer_secret);
$this->io->expects([
['auth' => [$this->origin, $this->consumer_key, $this->consumer_secret]],
]);
$this->httpDownloader->expects($this->once())
->method('get')
@ -151,9 +148,9 @@ class BitbucketTest extends TestCase
]
);
$this->io->expects($this->once())
->method('setAuthentication')
->with($this->origin, $this->consumer_key, $this->consumer_secret);
$this->io->expects([
['auth' => [$this->origin, $this->consumer_key, $this->consumer_secret]],
]);
$this->httpDownloader->expects($this->once())
->method('get')
@ -189,19 +186,14 @@ class BitbucketTest extends TestCase
public function testRequestAccessTokenWithUsernameAndPassword(): void
{
$this->io->expects($this->once())
->method('setAuthentication')
->with($this->origin, $this->username, $this->password);
$this->io->expects($this->any())
->method('writeError')
->withConsecutive(
['<error>Invalid OAuth consumer provided.</error>'],
['This can have three reasons:'],
['1. You are authenticating with a bitbucket username/password combination'],
['2. You are using an OAuth consumer, but didn\'t configure a (dummy) callback url'],
['3. You are using an OAuth consumer, but didn\'t configure it as private consumer']
);
$this->io->expects([
['auth' => [$this->origin, $this->username, $this->password]],
['text' => 'Invalid OAuth consumer provided.'],
['text' => 'This can have three reasons:'],
['text' => '1. You are authenticating with a bitbucket username/password combination'],
['text' => '2. You are using an OAuth consumer, but didn\'t configure a (dummy) callback url'],
['text' => '3. You are using an OAuth consumer, but didn\'t configure it as private consumer'],
], true);
$this->httpDownloader->expects($this->once())
->method('get')
@ -240,16 +232,11 @@ class BitbucketTest extends TestCase
->with('bitbucket-oauth')
->willReturn(null);
$this->io->expects($this->once())
->method('setAuthentication')
->with($this->origin, $this->username, $this->password);
$this->io->expects($this->any())
->method('writeError')
->withConsecutive(
['<error>Invalid OAuth consumer provided.</error>'],
['You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"']
);
$this->io->expects([
['auth' => [$this->origin, $this->username, $this->password]],
['text' => 'Invalid OAuth consumer provided.'],
['text' => 'You can also add it manually later by using "composer config --global --auth bitbucket-oauth.bitbucket.org <consumer-key> <consumer-secret>"'],
], true);
$this->httpDownloader->expects($this->once())
->method('get')
@ -276,9 +263,9 @@ class BitbucketTest extends TestCase
->with('bitbucket-oauth')
->willReturn(null);
$this->io->expects($this->once())
->method('setAuthentication')
->with($this->origin, $this->username, $this->password);
$this->io->expects([
['auth' => [$this->origin, $this->username, $this->password]],
]);
$exception = new \Composer\Downloader\TransportException('HTTP/1.1 404 NOT FOUND', 404);
$this->httpDownloader->expects($this->once())
@ -300,19 +287,11 @@ class BitbucketTest extends TestCase
public function testUsernamePasswordAuthenticationFlow(): void
{
$this->io
->expects($this->atLeastOnce())
->method('writeError')
->withConsecutive([$this->message])
;
$this->io->expects($this->exactly(2))
->method('askAndHideAnswer')
->withConsecutive(
['Consumer Key (hidden): '],
['Consumer Secret (hidden): ']
)
->willReturnOnConsecutiveCalls($this->consumer_key, $this->consumer_secret);
$this->io->expects([
['text' => $this->message],
['ask' => 'Consumer Key (hidden): ', 'reply' => $this->consumer_key],
['ask' => 'Consumer Secret (hidden): ', 'reply' => $this->consumer_secret],
]);
$this->httpDownloader
->expects($this->once())
@ -346,10 +325,9 @@ class BitbucketTest extends TestCase
->method('getAuthConfigSource')
->willReturn($authConfigSourceMock);
$this->io->expects($this->once())
->method('askAndHideAnswer')
->with('Consumer Key (hidden): ')
->willReturnOnConsecutiveCalls(null);
$this->io->expects([
['ask' => 'Consumer Key (hidden): ', 'reply' => ''],
]);
$this->assertFalse($this->bitbucket->authorizeOAuthInteractively($this->origin, $this->message));
}
@ -361,13 +339,11 @@ class BitbucketTest extends TestCase
->method('getAuthConfigSource')
->willReturn($authConfigSourceMock);
$this->io->expects($this->exactly(2))
->method('askAndHideAnswer')
->withConsecutive(
['Consumer Key (hidden): '],
['Consumer Secret (hidden): ']
)
->willReturnOnConsecutiveCalls($this->consumer_key, null);
$this->io->expects([
['text' => $this->message],
['ask' => 'Consumer Key (hidden): ', 'reply' => $this->consumer_key],
['ask' => 'Consumer Secret (hidden): ', 'reply' => ''],
]);
$this->assertFalse($this->bitbucket->authorizeOAuthInteractively($this->origin, $this->message));
}
@ -379,13 +355,11 @@ class BitbucketTest extends TestCase
->method('getAuthConfigSource')
->willReturn($authConfigSourceMock);
$this->io->expects($this->exactly(2))
->method('askAndHideAnswer')
->withConsecutive(
['Consumer Key (hidden): '],
['Consumer Secret (hidden): ']
)
->willReturnOnConsecutiveCalls($this->consumer_key, $this->consumer_secret);
$this->io->expects([
['text' => $this->message],
['ask' => 'Consumer Key (hidden): ', 'reply' => $this->consumer_key],
['ask' => 'Consumer Secret (hidden): ', 'reply' => $this->consumer_secret],
]);
$this->httpDownloader
->expects($this->once())

View File

@ -30,17 +30,10 @@ class GitHubTest extends TestCase
public function testUsernamePasswordAuthenticationFlow(): void
{
$io = $this->getIOMock();
$io
->expects($this->atLeastOnce())
->method('writeError')
->withConsecutive([$this->message])
;
$io
->expects($this->once())
->method('askAndHideAnswer')
->with('Token (hidden): ')
->willReturn($this->password)
;
$io->expects([
['text' => $this->message],
['ask' => 'Token (hidden): ', 'reply' => $this->password],
]);
$httpDownloader = $this->getHttpDownloaderMock();
$httpDownloader->expects(
@ -68,12 +61,9 @@ class GitHubTest extends TestCase
public function testUsernamePasswordFailure(): void
{
$io = $this->getIOMock();
$io
->expects($this->exactly(1))
->method('askAndHideAnswer')
->with('Token (hidden): ')
->willReturn($this->password)
;
$io->expects([
['ask' => 'Token (hidden): ', 'reply' => $this->password],
]);
$httpDownloader = $this->getHttpDownloaderMock();
$httpDownloader->expects(
@ -93,20 +83,6 @@ class GitHubTest extends TestCase
$this->assertFalse($github->authorizeOAuthInteractively($this->origin));
}
/**
* @return \PHPUnit\Framework\MockObject\MockObject&\Composer\IO\ConsoleIO
*/
private function getIOMock()
{
$io = $this
->getMockBuilder('Composer\IO\ConsoleIO')
->disableOriginalConstructor()
->getMock()
;
return $io;
}
/**
* @return \PHPUnit\Framework\MockObject\MockObject&\Composer\Config
*/

View File

@ -36,23 +36,11 @@ class GitLabTest extends TestCase
public function testUsernamePasswordAuthenticationFlow(): void
{
$io = $this->getIOMock();
$io
->expects($this->atLeastOnce())
->method('writeError')
->withConsecutive([$this->message])
;
$io
->expects($this->once())
->method('ask')
->with('Username: ')
->willReturn($this->username)
;
$io
->expects($this->once())
->method('askAndHideAnswer')
->with('Password: ')
->willReturn($this->password)
;
$io->expects([
['text' => $this->message],
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
]);
$httpDownloader = $this->getHttpDownloaderMock();
$httpDownloader->expects(
@ -77,18 +65,18 @@ class GitLabTest extends TestCase
self::expectException('RuntimeException');
self::expectExceptionMessage('Invalid GitLab credentials 5 times in a row, aborting.');
$io = $this->getIOMock();
$io
->expects($this->exactly(5))
->method('ask')
->with('Username: ')
->willReturn($this->username)
;
$io
->expects($this->exactly(5))
->method('askAndHideAnswer')
->with('Password: ')
->willReturn($this->password)
;
$io->expects([
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
['ask' => 'Username: ', 'reply' => $this->username],
['ask' => 'Password: ', 'reply' => $this->password],
]);
$httpDownloader = $this->getHttpDownloaderMock();
$httpDownloader->expects(
@ -114,20 +102,6 @@ class GitLabTest extends TestCase
$gitLab->authorizeOAuthInteractively('https', $this->origin);
}
/**
* @return \PHPUnit\Framework\MockObject\MockObject&\Composer\IO\ConsoleIO
*/
private function getIOMock()
{
$io = $this
->getMockBuilder('Composer\IO\ConsoleIO')
->disableOriginalConstructor()
->getMock()
;
return $io;
}
/**
* @return \PHPUnit\Framework\MockObject\MockObject&\Composer\Config
*/