Skip to content

Commit

Permalink
Add support for phpunit configure, testsuite and filter options
Browse files Browse the repository at this point in the history
Covered by tests that use intensively the new ->lastCmd
introduced a couple of commits ago.

Also, added a TODO about something, pre-existing, that is
an incorrect unit tests, some day will be investigated. Not today.

Fixes moodlehq#100
  • Loading branch information
stronk7 committed Nov 7, 2023
1 parent d230053 commit 632a21f
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 29 deletions.
3 changes: 2 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ The format of this change log follows the advice given at [Keep a CHANGELOG](htt

## [Unreleased]
### Added
- Added support for the `--tags` and `--name` options into the `behat` command.
- Added support for the `--tags` and `--name` options to the `behat` command.
- Added support for the `--configure`, `--testsuite` and `--filter` options to the `phpunit` command.

### Changed
- ACTION SUGGESTED: If you are using GitHub Actions, it's recomended to use `!cancelled()` instead of `always()` for moodle-plugin-ci tests. Adding a final step that always returns failure when the workflow is cancelled will ensure that cancelled workflows are not marked as successful. For a working example, please reference the updated `gha.dist.yml` file.
Expand Down
52 changes: 41 additions & 11 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -1975,7 +1975,7 @@ Run PHPUnit on a plugin

### Usage

* `phpunit [-m|--moodle MOODLE] [--coverage-text] [--coverage-clover] [--coverage-pcov] [--coverage-xdebug] [--coverage-phpdbg] [--fail-on-incomplete] [--fail-on-risky] [--fail-on-skipped] [--fail-on-warning] [--testdox] [--] <plugin>`
* `phpunit [-m|--moodle MOODLE] [-c|--configuration CONFIGURATION] [--testsuite TESTSUITE] [--filter FILTER] [--testdox] [--coverage-text] [--coverage-clover] [--coverage-pcov] [--coverage-xdebug] [--coverage-phpdbg] [--fail-on-incomplete] [--fail-on-risky] [--fail-on-skipped] [--fail-on-warning] [--] <plugin>`

Run PHPUnit on a plugin

Expand All @@ -2001,6 +2001,46 @@ Path to Moodle
* Is negatable: no
* Default: `'.'`

#### `--configuration|-c`

PHPUnit configuration XML file (relative to plugin directory)

* Accept value: yes
* Is value required: yes
* Is multiple: no
* Is negatable: no
* Default: `NULL`

#### `--testsuite`

PHPUnit testsuite option to use (must exist in the configuration file being used)

* Accept value: yes
* Is value required: yes
* Is multiple: no
* Is negatable: no
* Default: `NULL`

#### `--filter`

PHPUnit filter option to use

* Accept value: yes
* Is value required: yes
* Is multiple: no
* Is negatable: no
* Default: `NULL`

#### `--testdox`

Enable testdox formatter

* Accept value: no
* Is value required: no
* Is multiple: no
* Is negatable: no
* Default: `false`

#### `--coverage-text`

Generate and print code coverage report in text format
Expand Down Expand Up @@ -2091,16 +2131,6 @@ Treat tests with warnings as failures
* Is negatable: no
* Default: `false`

#### `--testdox`

Enable testdox formatter

* Accept value: no
* Is value required: no
* Is multiple: no
* Is negatable: no
* Default: `false`

#### `--help|-h`

Display help for the given command. When no command is given display help for the list command
Expand Down
68 changes: 56 additions & 12 deletions src/Command/PHPUnitCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ protected function configure(): void

$this->setName('phpunit')
->setDescription('Run PHPUnit on a plugin')
->addOption(
'configuration',
'c',
InputOption::VALUE_REQUIRED,
'PHPUnit configuration XML file (relative to plugin directory)'
)
->addOption(
'testsuite',
null,
InputOption::VALUE_REQUIRED,
'PHPUnit testsuite option to use (must exist in the configuration file being used)'
)
->addOption('filter', null, InputOption::VALUE_REQUIRED, 'PHPUnit filter option to use')
->addOption('testdox', null, InputOption::VALUE_NONE, 'Enable testdox formatter')
->addOption('coverage-text', null, InputOption::VALUE_NONE, 'Generate and print code coverage report in text format')
->addOption('coverage-clover', null, InputOption::VALUE_NONE, 'Generate code coverage report in Clover XML format')
->addOption('coverage-pcov', null, InputOption::VALUE_NONE, 'Use the pcov extension to calculate code coverage')
Expand All @@ -37,8 +51,7 @@ protected function configure(): void
->addOption('fail-on-incomplete', null, InputOption::VALUE_NONE, 'Treat incomplete tests as failures')
->addOption('fail-on-risky', null, InputOption::VALUE_NONE, 'Treat risky tests as failures')
->addOption('fail-on-skipped', null, InputOption::VALUE_NONE, 'Treat skipped tests as failures')
->addOption('fail-on-warning', null, InputOption::VALUE_NONE, 'Treat tests with warnings as failures')
->addOption('testdox', null, InputOption::VALUE_NONE, 'Enable testdox formatter');
->addOption('fail-on-warning', null, InputOption::VALUE_NONE, 'Treat tests with warnings as failures');
}

protected function initialize(InputInterface $input, OutputInterface $output): void
Expand Down Expand Up @@ -80,6 +93,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int
private function resolveOptions(InputInterface $input): array
{
$options = [];

if ($input->getOption('configuration')) {
$options[] = [
'--configuration',
$this->plugin->directory . '/' . $input->getOption('configuration'),
];
}

if ($input->getOption('testsuite')) {
$options[] = [
'--testsuite',
$input->getOption('testsuite'),
];
}

if ($input->getOption('filter')) {
$options[] = [
'--filter',
$input->getOption('filter'),
];
}

if ($this->supportsCoverage() && $input->getOption('coverage-text')) {
$options[] = [
'--coverage-text',
Expand All @@ -103,16 +138,25 @@ private function resolveOptions(InputInterface $input): array
];
}
}
if (is_file($this->plugin->directory . '/phpunit.xml')) {
$options[] = [
'--configuration',
$this->plugin->directory,
];
} else {
$options[] = [
'--testsuite',
$this->plugin->getComponent(),
];

// Only can set configuration or testsuite here (auto) if the former has not been set via command line option.
if (!$input->getOption('configuration')) {
// Use default configuration (phpunit.xml) only if it exists.
if (is_file($this->plugin->directory . '/phpunit.xml')) {
$options[] = [
'--configuration',
$this->plugin->directory . '/phpunit.xml',
];
} else {
// Fallback to try to use the best testsuite potentially available.
// Only can set automatic testsuite if it has not been passed via command line option.
if (!$input->getOption('testsuite')) {
$options[] = [
'--testsuite',
$this->plugin->getComponent() . '_testsuite', // This is our best guess.
];
}
}
}

return array_merge(...$options); // Merge all options into a single array.
Expand Down
60 changes: 55 additions & 5 deletions tests/Command/PHPUnitCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

class PHPUnitCommandTest extends MoodleTestCase
{
protected function executeCommand($pluginDir = null, $moodleDir = null): CommandTester
protected function executeCommand($pluginDir = null, $moodleDir = null, array $cmdOptions = []): CommandTester
{
if ($pluginDir === null) {
$pluginDir = $this->pluginDir;
Expand All @@ -37,10 +37,15 @@ protected function executeCommand($pluginDir = null, $moodleDir = null): Command
$application->add($command);

$commandTester = new CommandTester($application->find('phpunit'));
$commandTester->execute([
'plugin' => $pluginDir,
'--moodle' => $moodleDir,
]);
$cmdOptions = array_merge(
[
'plugin' => $pluginDir,
'--moodle' => $moodleDir,
],
$cmdOptions
);
$commandTester->execute($cmdOptions);
$this->lastCmd = $command->execute->lastCmd; // We need this for assertions against the command run.

return $commandTester;
}
Expand All @@ -49,6 +54,50 @@ public function testExecute()
{
$commandTester = $this->executeCommand();
$this->assertSame(0, $commandTester->getStatusCode());
$this->assertMatchesRegularExpression('/vendor.bin.phpunit/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--testsuite.*local_ci_testsuite/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--configuration.*local\/ci/', $this->lastCmd);
}

public function testExecuteWithCustomPHPUnitXMLFile()
{
$commandTester = $this->executeCommand(null, null, ['--configuration' => 'some_config.xml']);
$this->assertSame(0, $commandTester->getStatusCode());
$this->assertMatchesRegularExpression('/vendor.bin.phpunit/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--configuration.*.*local\/ci\/some_config.xml/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--configuration.*local\/ci\/phpunit.xml/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--testsuite.*local_ci_testsuite/', $this->lastCmd);
}

public function testExecuteWithGeneratedPHPUnitXMLFile()
{
$fs = new Filesystem();
$fs->touch($this->pluginDir . '/phpunit.xml');
$commandTester = $this->executeCommand();
$this->assertSame(0, $commandTester->getStatusCode());
$this->assertMatchesRegularExpression('/vendor.bin.phpunit/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--configuration.*local\/ci\/phpunit.xml/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--testsuite.*local_ci_testsuite/', $this->lastCmd);
}

public function testExecuteWithTestSuite()
{
$commandTester = $this->executeCommand(null, null, ['--testsuite' => 'some_testsuite']);
$this->assertSame(0, $commandTester->getStatusCode());
$this->assertMatchesRegularExpression('/vendor.bin.phpunit/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--testsuite.*some_testsuite/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--configuration.*local\/ci/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--testsuite.*local_ci_testsuite/', $this->lastCmd);
}

public function testExecuteWithFilter()
{
$commandTester = $this->executeCommand(null, null, ['--filter' => 'some_filter']);
$this->assertSame(0, $commandTester->getStatusCode());
$this->assertMatchesRegularExpression('/vendor.bin.phpunit/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--filter.*some_filter/', $this->lastCmd);
$this->assertMatchesRegularExpression('/--testsuite.*local_ci_testsuite/', $this->lastCmd);
$this->assertDoesNotMatchRegularExpression('/--configuration.*local\/ci/', $this->lastCmd);
}

public function testExecuteNoTests()
Expand All @@ -70,6 +119,7 @@ public function testExecuteNoPlugin()
public function testExecuteNoMoodle()
{
$this->expectException(\InvalidArgumentException::class);
// TODO: Check what's happening here. moodleDir should be the 2nd parameter, but then the test fails.
$this->executeCommand($this->moodleDir . '/no/moodle');
}
}

0 comments on commit 632a21f

Please sign in to comment.