Skip to content

Commit

Permalink
Add PHPStorm integration (#672)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Shvets <[email protected]>
  • Loading branch information
Slamdunk and neochief authored Jun 21, 2022
1 parent 2b83410 commit bdc8416
Show file tree
Hide file tree
Showing 13 changed files with 286 additions and 9 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ code-coverage: coverage/junit.xml
--skip-initial-tests \
--coverage=coverage \
--show-mutations \
--verbose \
--min-msi=100 \
$(INFECTION_ARGS)
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,16 @@ if (getenv('TEST_TOKEN') !== false) { // Using paratest
Before creating a Pull Request be sure to run all the necessary checks with `make` command.

For an example of ParaTest out in the wild check out the [example](https://github.com/brianium/paratest-selenium).

# Integration with PHPStorm

ParaTest provides a dedicated binary to work with PHPStorm; follow these steps to have ParaTest working within it:

1. Be sure you have PHPUnit already configured in PHPStorm: https://www.jetbrains.com/help/phpstorm/using-phpunit-framework.html#php_test_frameworks_phpunit_integrate
2. Go to `Run` -> `Edit configurations...`
3. Select `Add new Configuration`, select the `PHPUnit` type and name it `ParaTest`
4. In the `Command Line` -> `Interpreter options` add `./vendor/bin/paratest_for_phpstorm`
5. Any additional ParaTest options you want to pass to ParaTest should go within the `Test runner` -> `Test runner options` section

You should now have a `ParaTest` run within your configurations list.
It should natively work with the `Rerun failed tests` and `Toggle auto-test` buttons of the `Run` overlay.
10 changes: 10 additions & 0 deletions bin/paratest_for_phpstorm
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use ParaTest\Util\PhpstormHelper;

require dirname(__DIR__, 1) . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Util' . DIRECTORY_SEPARATOR . 'PhpstormHelper.php';

require PhpstormHelper::handleArgvFromPhpstorm($_SERVER['argv'], __DIR__ . '/paratest');
2 changes: 1 addition & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="160"/>
<property name="lineLimit" value="320"/>
<property name="absoluteLineLimit" value="0"/>
</properties>
</rule>
Expand Down
22 changes: 22 additions & 0 deletions src/Runners/PHPUnit/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ final class Options
private $cwd;
/** @var string|null */
private $logJunit;
/** @var bool */
private $teamcity;
/** @var string|null */
private $logTeamcity;
/** @var string|null */
Expand Down Expand Up @@ -249,6 +251,7 @@ private function __construct(
bool $functional,
array $group,
?string $logJunit,
bool $teamcity,
?string $logTeamcity,
?int $maxBatchSize,
bool $noCoverage,
Expand Down Expand Up @@ -287,6 +290,7 @@ private function __construct(
$this->functional = $functional;
$this->group = $group;
$this->logJunit = $logJunit;
$this->teamcity = $teamcity;
$this->logTeamcity = $logTeamcity;
$this->maxBatchSize = $maxBatchSize;
$this->noCoverage = $noCoverage;
Expand Down Expand Up @@ -326,6 +330,7 @@ public static function fromConsoleInput(InputInterface $input, string $cwd): sel
assert($options['filter'] === null || is_string($options['filter']));
assert(is_bool($options['functional']));
assert($options['log-junit'] === null || is_string($options['log-junit']));
assert(is_bool($options['teamcity']));
assert($options['log-teamcity'] === null || is_string($options['log-teamcity']));
assert(is_bool($options['no-coverage']));
assert(is_bool($options['no-test-tokens']));
Expand Down Expand Up @@ -541,6 +546,7 @@ public static function fromConsoleInput(InputInterface $input, string $cwd): sel
$options['functional'],
$group,
$options['log-junit'],
$options['teamcity'],
$options['log-teamcity'],
(int) $options['max-batch-size'],
$options['no-coverage'],
Expand Down Expand Up @@ -782,6 +788,12 @@ public static function setInputDefinition(InputDefinition $inputDefinition): voi
InputOption::VALUE_NONE,
'Don\'t start any more processes after a failure.'
),
new InputOption(
'teamcity',
null,
InputOption::VALUE_NONE,
'Output test results in Teamcity format.'
),
new InputOption(
'testsuite',
null,
Expand Down Expand Up @@ -1085,6 +1097,11 @@ public function logJunit(): ?string
return $this->logJunit;
}

public function teamcity(): bool
{
return $this->teamcity;
}

public function logTeamcity(): ?string
{
return $this->logTeamcity;
Expand All @@ -1095,6 +1112,11 @@ public function hasLogTeamcity(): bool
return $this->logTeamcity !== null;
}

public function needsTeamcity(): bool
{
return $this->teamcity() || $this->hasLogTeamcity();
}

public function tmpDir(): string
{
return $this->tmpDir;
Expand Down
23 changes: 20 additions & 3 deletions src/Runners/PHPUnit/ResultPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ final class ResultPrinter
private $output;
/** @var Options */
private $options;
/** @var bool */
private $needsTeamcity;
/** @var bool */
private $printsTeamcity;
/** @var resource|null */
private $teamcityLogFileHandle;

Expand All @@ -123,6 +127,9 @@ public function __construct(LogInterpreter $results, OutputInterface $output, Op
$this->output = $output;
$this->options = $options;

$this->printsTeamcity = $this->options->teamcity();
$this->needsTeamcity = $this->options->needsTeamcity();

if (($teamcityLogFile = $this->options->logTeamcity()) === null) {
return;
}
Expand Down Expand Up @@ -235,7 +242,7 @@ public function printFeedback(ExecutableTest $test): Reader
);
}

if ($this->teamcityLogFileHandle !== null) {
if ($this->needsTeamcity) {
$teamcityLogFile = $test->getTeamcityTempFile();

if (filesize($teamcityLogFile) === 0) {
Expand All @@ -244,11 +251,21 @@ public function printFeedback(ExecutableTest $test): Reader

$result = file_get_contents($teamcityLogFile);
assert($result !== false);
fwrite($this->teamcityLogFileHandle, $result);

if ($this->teamcityLogFileHandle !== null) {
fwrite($this->teamcityLogFileHandle, $result);
}

if ($this->printsTeamcity) {
$this->output->write($result);
}
}

$this->results->addReader($reader);
$this->processReaderFeedback($reader, $test->getTestCount());

if (! $this->printsTeamcity) {
$this->processReaderFeedback($reader, $test->getTestCount());
}

return $reader;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Runners/PHPUnit/SuiteLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ private function executableTests(string $path, ParsedClass $class): array
$path,
$methodBatch,
$this->options->hasCoverage(),
$this->options->hasLogTeamcity(),
$this->options->needsTeamcity(),
$this->options->tmpDir()
);
}
Expand Down Expand Up @@ -399,7 +399,7 @@ private function createSuite(string $path, ParsedClass $class): Suite
$class
),
$this->options->hasCoverage(),
$this->options->hasLogTeamcity(),
$this->options->needsTeamcity(),
$this->options->tmpDir()
);
}
Expand All @@ -409,7 +409,7 @@ private function createFullSuite(string $suiteName): FullSuite
return new FullSuite(
$suiteName,
$this->options->hasCoverage(),
$this->options->hasLogTeamcity(),
$this->options->needsTeamcity(),
$this->options->tmpDir()
);
}
Expand Down
40 changes: 40 additions & 0 deletions src/Util/PhpstormHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace ParaTest\Util;

use function array_unshift;
use function in_array;

/**
* @internal
*/
final class PhpstormHelper
{
/**
* @param array<int, string> $argv
*/
public static function handleArgvFromPhpstorm(array &$argv, string $paratestBinary): string
{
if (! in_array('--filter', $argv, true)) {
unset($argv[1]);

return $paratestBinary;
}

unset($argv[0]);
$phpunitBinary = $argv[1];
foreach ($argv as $index => $value) {
if ($value === '--configuration' || $value === '--bootstrap') {
break;
}

unset($argv[$index]);
}

array_unshift($argv, $phpunitBinary);

return $phpunitBinary;
}
}
28 changes: 27 additions & 1 deletion test/Unit/ResultTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@

abstract class ResultTester extends TestBase
{
protected const SINGLE_PASSING_TEAMCITY_OUTPUT = <<<'EOF'
##teamcity[testCount count='3' flowId='118852']
##teamcity[testSuiteStarted name='ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest' locationHint='php_qn:///repos/paratest/test/fixtures/passing_tests/level1/AnotherUnitTestInSubLevelTest.php::\ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest' flowId='118852']
##teamcity[testStarted name='testTruth' locationHint='php_qn:///repos/paratest/test/fixtures/passing_tests/level1/AnotherUnitTestInSubLevelTest.php::\ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest::testTruth' flowId='118852']
##teamcity[testFinished name='testTruth' duration='1' flowId='118852']
##teamcity[testStarted name='testFalsehood' locationHint='php_qn:///repos/paratest/test/fixtures/passing_tests/level1/AnotherUnitTestInSubLevelTest.php::\ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest::testFalsehood' flowId='118852']
##teamcity[testFinished name='testFalsehood' duration='0' flowId='118852']
##teamcity[testStarted name='testArrayLength' locationHint='php_qn:///repos/paratest/test/fixtures/passing_tests/level1/AnotherUnitTestInSubLevelTest.php::\ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest::testArrayLength' flowId='118852']
##teamcity[testFinished name='testArrayLength' duration='0' flowId='118852']
##teamcity[testSuiteFinished name='ParaTest\Tests\fixtures\passthru_tests\level1\AnotherUnitTestInSubLevelTest' flowId='118852']
EOF;


/** @var Suite */
protected $failureSuite;
/** @var Suite */
Expand Down Expand Up @@ -58,7 +79,12 @@ final protected function getSuiteWithResult(string $result, int $methodCount): S

$suite = new Suite('', $functions, false, true, $this->tmpDir);
file_put_contents($suite->getTempFile(), (string) file_get_contents(FIXTURES . DS . 'results' . DS . $result));
file_put_contents($suite->getTeamcityTempFile(), 'no data');
$teamcityData = 'no data';
if ($result === 'single-passing.xml') {
$teamcityData = self::SINGLE_PASSING_TEAMCITY_OUTPUT;
}

file_put_contents($suite->getTeamcityTempFile(), $teamcityData);

return $suite;
}
Expand Down
16 changes: 16 additions & 0 deletions test/Unit/Runners/PHPUnit/OptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ public function testDefaultOptions(): void
static::assertNull($options->whitelist());
static::assertSame(Options::ORDER_DEFAULT, $options->orderBy());
static::assertSame(0, $options->randomOrderSeed());
static::assertFalse($options->teamcity());
static::assertFalse($options->hasLogTeamcity());
static::assertFalse($options->needsTeamcity());
static::assertFalse($options->hasCoverage());
static::assertSame(0, $options->repeat());
}
Expand All @@ -288,6 +290,7 @@ public function testProvidedOptions(): void
'--functional' => true,
'--group' => 'GROUP',
'--log-junit' => 'LOG-JUNIT',
'--teamcity' => true,
'--log-teamcity' => 'LOG-TEAMCITY',
'--max-batch-size' => 5,
'--no-test-tokens' => true,
Expand Down Expand Up @@ -326,7 +329,9 @@ public function testProvidedOptions(): void
static::assertTrue($options->functional());
static::assertSame(['GROUP'], $options->group());
static::assertSame('LOG-JUNIT', $options->logJunit());
static::assertTrue($options->teamcity());
static::assertSame('LOG-TEAMCITY', $options->logTeamcity());
static::assertTrue($options->needsTeamcity());
static::assertSame(5, $options->maxBatchSize());
static::assertTrue($options->noTestTokens());
static::assertTrue($options->parallelSuite());
Expand Down Expand Up @@ -450,4 +455,15 @@ public function testFillEnvWithTokens(): void
static::assertArrayNotHasKey(Options::ENV_KEY_TOKEN, $env);
static::assertArrayNotHasKey(Options::ENV_KEY_UNIQUE_TOKEN, $env);
}

public function testNeedsTeamcityGetsActivatedBothByLogTeamcityAndTeamcityFlags(): void
{
$options = $this->createOptionsFromArgv(['--teamcity' => true], __DIR__);

self::assertTrue($options->needsTeamcity());

$options = $this->createOptionsFromArgv(['--log-teamcity' => 'LOG-TEAMCITY'], __DIR__);

self::assertTrue($options->needsTeamcity());
}
}
24 changes: 23 additions & 1 deletion test/Unit/Runners/PHPUnit/ResultPrinterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use Symfony\Component\Console\Output\BufferedOutput;

use function defined;
use function file_get_contents;
use function file_put_contents;
use function preg_match_all;
use function sprintf;
use function str_repeat;
use function uniqid;
Expand Down Expand Up @@ -553,7 +555,7 @@ public function testTeamcityEmptyLogFileRaiseException(): void
$this->printer->printFeedback($test);
}

public function testTeamcityFeedback(): void
public function testTeamcityFeedbackOnFile(): void
{
$teamcityLog = $this->tmpDir . DS . 'teamcity2.log';

Expand All @@ -567,6 +569,26 @@ public function testTeamcityFeedback(): void

static::assertStringContainsString('OK', $this->output->fetch());
static::assertFileExists($teamcityLog);

$logContent = file_get_contents($teamcityLog);

self::assertNotFalse($logContent);
self::assertSame(9, preg_match_all('/^##teamcity/m', $logContent));
}

public function testTeamcityFeedbackOnStdout(): void
{
$this->options = $this->createOptionsFromArgv(['--teamcity' => true]);
$this->printer = new ResultPrinter($this->interpreter, $this->output, $this->options);
$this->printer->addTest($this->passingSuite);

$this->printer->start();
$this->printer->printFeedback($this->passingSuite);
$this->printer->printResults();

$output = $this->output->fetch();
static::assertStringContainsString('OK', $output);
self::assertSame(9, preg_match_all('/^##teamcity/m', $output));
}

private function getStartOutput(): string
Expand Down
12 changes: 12 additions & 0 deletions test/Unit/Runners/PHPUnit/RunnerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,18 @@ final public function testTeamcityLog(): void
self::assertSame(66, preg_match_all('/^##teamcity/m', $content));
}

final public function testTeamcityOutput(): void
{
$this->bareOptions = [
'--configuration' => $this->fixture('phpunit-passing.xml'),
'--teamcity' => true,
];

$result = $this->runRunner();

self::assertSame(66, preg_match_all('/^##teamcity/m', $result->getOutput()));
}

/**
* @requires OSFAMILY Linux
*/
Expand Down
Loading

0 comments on commit bdc8416

Please sign in to comment.