Skip to content

Commit

Permalink
Rewrite the tests (bamarni#77)
Browse files Browse the repository at this point in the history
- Remove removed property from the PHPUnit config file
- Clarify the types in the tests
- Make the tests more explicit
  - Introduced helper assertions
  - Remove the assert from the test command
- Cleanup the generated directories after running the tests
- No longer generate a new directory for each test run
- Fix running the tests locally on OSX
  • Loading branch information
theofidry committed Jul 6, 2022
1 parent af36703 commit 80b2f1c
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 54 deletions.
6 changes: 2 additions & 4 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
Expand All @@ -8,13 +7,12 @@
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="Composer Bin Plugin Test Suite">
<directory>./tests/</directory>
<directory>tests</directory>
</testsuite>
</testsuites>

</phpunit>
</phpunit>
197 changes: 158 additions & 39 deletions tests/BinCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,110 +2,229 @@

namespace Bamarni\Composer\Bin\Tests;

use Composer\Composer;
use Composer\Console\Application;
use Bamarni\Composer\Bin\BinCommand;
use Bamarni\Composer\Bin\Tests\Fixtures\MyTestCommand;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\NullOutput;
use function array_shift;
use function chdir;
use function count;
use function file_put_contents;
use function getcwd;
use function json_encode;
use function mkdir;
use function putenv;
use function realpath;
use function sprintf;
use function sys_get_temp_dir;
use function uniqid;
use function var_dump;

class BinCommandTest extends TestCase
{
/**
* @var Application
*/
private $application;
private $myTestCommand;
private $rootDir;

/**
* @var MyTestCommand
*/
private $testCommand;

/**
* @var non-empty-string
*/
private $tmpDir;

/**
* @var string
*/
private $previousCwd;

protected function setUp(): void
{
$this->rootDir = sys_get_temp_dir().'/'.uniqid('composer_bin_plugin_tests_');
mkdir($this->rootDir);
chdir($this->rootDir);
$this->previousCwd = getcwd();

file_put_contents($this->rootDir.'/composer.json', '{}');
$tmpDir = sys_get_temp_dir().'/composer_bin_plugin_tests';
mkdir($tmpDir);
chdir($tmpDir);
// On OSX sys_get_temp_dir() may return a symlink
$this->tmpDir = realpath($tmpDir);

file_put_contents(
$this->tmpDir.'/composer.json',
'{}'
);

$this->testCommand = new MyTestCommand();

$this->application = new Application();
$this->application->addCommands([
new BinCommand(),
$this->myTestCommand = new MyTestCommand($this),
$this->testCommand,
]);
}

public function tearDown(): void
{
putenv('COMPOSER_BIN_DIR');
$this->myTestCommand->data = [];

chdir($this->previousCwd);
exec('rm -rf ' . $this->tmpDir);

unset($this->application);
unset($this->testCommand);
unset($this->previousCwd);
unset($this->tmpDir);
}

/**
* @dataProvider namespaceProvider
*/
public function testNamespaceCommand($input)
public function test_it_can_execute_the_bin_command(
string $input,
string $expectedRelativeBinDir,
string $expectedRelativeCwd,
string $expectedRelativeVendorDir
): void
{
$input = new StringInput($input);
$output = new NullOutput();
$this->application->doRun($input, $output);

$this->assertCount(1, $this->myTestCommand->data);
$dataSet = array_shift($this->myTestCommand->data);
$this->assertEquals($dataSet['bin-dir'], $this->rootDir.'/vendor/bin');
$this->assertEquals($dataSet['cwd'], $this->rootDir.'/vendor-bin/mynamespace');
$this->assertEquals($dataSet['vendor-dir'], $this->rootDir.'/vendor-bin/mynamespace/vendor');
}
$this->application->doRun($input, $output);

public static function namespaceProvider()
{
return [
['bin mynamespace mytest'],
['bin mynamespace mytest --myoption'],
];
$this->assertHasAccessToComposer();
$this->assertDataSetRecordedIs(
$this->tmpDir.'/'.$expectedRelativeBinDir,
$this->tmpDir.'/'.$expectedRelativeCwd,
$this->tmpDir.'/'.$expectedRelativeVendorDir
);
$this->assertNoMoreDataFound();
}

public function testAllNamespaceWithoutAnyNamespace()
public function test_the_all_namespace_can_be_called(): void
{
$input = new StringInput('bin all mytest');
$output = new NullOutput();

$this->application->doRun($input, $output);

$this->assertEmpty($this->myTestCommand->data);
$this->assertNoMoreDataFound();
}

public function testAllNamespaceCommand()
public function test_a_command_can_be_executed_in_each_namespace_via_the_all_namespace(): void
{
$namespaces = ['mynamespace', 'yournamespace'];
foreach ($namespaces as $ns) {
mkdir($this->rootDir.'/vendor-bin/'.$ns, 0777, true);
$namespaces = ['namespace1', 'namespace2'];

foreach ($namespaces as $namespace) {
mkdir(
$this->tmpDir.'/vendor-bin/'.$namespace,
0777,
true
);
}

$input = new StringInput('bin all mytest');
$output = new NullOutput();

$this->application->doRun($input, $output);

$this->assertCount(count($namespaces), $this->myTestCommand->data);
$this->assertHasAccessToComposer();

foreach ($namespaces as $ns) {
$dataSet = array_shift($this->myTestCommand->data);
$this->assertEquals($dataSet['bin-dir'], $this->rootDir . '/vendor/bin');
$this->assertEquals($dataSet['cwd'], $this->rootDir . '/vendor-bin/'.$ns);
$this->assertEquals($dataSet['vendor-dir'], $this->rootDir . '/vendor-bin/'.$ns.'/vendor');
foreach ($namespaces as $namespace) {
$this->assertDataSetRecordedIs(
$this->tmpDir . '/vendor/bin',
$this->tmpDir . '/vendor-bin/'.$namespace,
$this->tmpDir . '/vendor-bin/'.$namespace.'/vendor'
);
}

$this->assertNoMoreDataFound();
}

public function testBinDirFromLocalConfig()
public function test_the_bin_dir_can_be_changed(): void
{
$binDir = 'bin';
$composer = [
'config' => [
'bin-dir' => $binDir
]
];
file_put_contents($this->rootDir.'/composer.json', json_encode($composer));

file_put_contents(
$this->tmpDir.'/composer.json',
json_encode($composer)
);

$input = new StringInput('bin theirspace mytest');
$output = new NullOutput();

$this->application->doRun($input, $output);

$this->assertCount(1, $this->myTestCommand->data);
$dataSet = array_shift($this->myTestCommand->data);
$this->assertEquals($dataSet['bin-dir'], $this->rootDir.'/'.$binDir);
$this->assertHasAccessToComposer();
$this->assertDataSetRecordedIs(
$this->tmpDir.'/'.$binDir,
$this->tmpDir.'/'.'vendor-bin/theirspace',
$this->tmpDir.'/'.'vendor-bin/theirspace/vendor',
''
);
$this->assertNoMoreDataFound();
}

public static function namespaceProvider(): iterable
{
yield 'execute command from namespace' => [
'bin testnamespace mytest',
'vendor/bin',
'vendor-bin/testnamespace',
'vendor-bin/testnamespace/vendor',
];

yield 'execute command with options from namespace' => [
'bin testnamespace mytest --myoption',
'vendor/bin',
'vendor-bin/testnamespace',
'vendor-bin/testnamespace/vendor',
];
}

private function assertHasAccessToComposer(): void
{
self::assertInstanceOf(
Composer::class,
$this->testCommand->composer,
'Some plugins may require access to composer file e.g. Symfony Flex'
);
}

private function assertDataSetRecordedIs(
string $expectedBinDir,
string $expectedCwd,
string $expectedVendorDir
): void
{
$data = array_shift($this->testCommand->data);

self::assertNotNull(
$data,
'Expected test command to contain at least one data entry'
);
self::assertSame($expectedBinDir, $data['bin-dir']);
self::assertSame($expectedCwd, $data['cwd']);
self::assertSame($expectedVendorDir, $data['vendor-dir']);
}

private function assertNoMoreDataFound(): void
{
$data = array_shift($this->testCommand->data);

self::assertNull(
$data,
'Expected test command to contain not contain any more data entries.'
);
}
}
29 changes: 18 additions & 11 deletions tests/Fixtures/MyTestCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Bamarni\Composer\Bin\Tests\Fixtures;

use Composer\Composer;
use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
Expand All @@ -12,27 +14,32 @@

class MyTestCommand extends BaseCommand
{
/**
* @var mixed|Composer
*/
public $composer;

/**
* @var list<array{'bin-dir': string, 'cwd': string, 'vendor-bin': string}>
*/
public $data = [];

private $assert;

public function __construct(Assert $assert)
public function __construct()
{
$this->assert = $assert;

parent::__construct('mytest');

$this->setDefinition([
new InputOption('myoption', null, InputOption::VALUE_NONE),
new InputOption(
'myoption',
null,
InputOption::VALUE_NONE
),
]);
}

public function execute(InputInterface $input, OutputInterface $output)
{
$this->assert->assertInstanceOf(
'\Composer\Composer',
$this->getComposer(),
"Some plugins may require access to composer file e.g. Symfony Flex"
);
$this->composer = $this->getComposer();

$factory = Factory::create(new NullIO());
$config = $factory->getConfig();
Expand Down

0 comments on commit 80b2f1c

Please sign in to comment.