2018-10-30 15:32:20 +01:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
2019-07-05 22:24:00 +02:00
|
|
|
use const LIBXML_NOBLANKS;
|
2018-10-30 15:32:20 +01:00
|
|
|
use Prophecy\Argument;
|
|
|
|
use Prophecy\Prophecy\ObjectProphecy;
|
|
|
|
use Psalm\ErrorBaseline;
|
|
|
|
use Psalm\Exception\ConfigException;
|
2018-11-06 03:57:36 +01:00
|
|
|
use Psalm\Internal\Provider\FileProvider;
|
2018-10-30 15:32:20 +01:00
|
|
|
|
|
|
|
class ErrorBaselineTest extends TestCase
|
|
|
|
{
|
|
|
|
/** @var ObjectProphecy */
|
|
|
|
private $fileProvider;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
2019-05-17 00:36:36 +02:00
|
|
|
public function setUp() : void
|
2018-10-30 15:32:20 +01:00
|
|
|
{
|
|
|
|
$this->fileProvider = $this->prophesize(FileProvider::class);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testLoadShouldParseXmlBaselineToPhpArray()
|
|
|
|
{
|
|
|
|
$baselineFilePath = 'baseline.xml';
|
|
|
|
|
|
|
|
$this->fileProvider->fileExists($baselineFilePath)->willReturn(true);
|
|
|
|
$this->fileProvider->getContents($baselineFilePath)->willReturn(
|
|
|
|
'<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<files>
|
|
|
|
<file src="sample/sample-file.php">
|
2018-11-09 06:46:13 +01:00
|
|
|
<MixedAssignment occurrences="2">
|
|
|
|
<code>foo</code>
|
|
|
|
<code>bar</code>
|
|
|
|
</MixedAssignment>
|
2018-10-30 15:32:20 +01:00
|
|
|
<InvalidReturnStatement occurrences="1"/>
|
|
|
|
</file>
|
2019-01-10 06:10:09 +01:00
|
|
|
<file src="sample\sample-file2.php">
|
2018-11-09 06:46:13 +01:00
|
|
|
<PossiblyUnusedMethod occurrences="2">
|
|
|
|
<code>foo</code>
|
|
|
|
<code>bar</code>
|
|
|
|
</PossiblyUnusedMethod>
|
2018-10-30 15:32:20 +01:00
|
|
|
</file>
|
|
|
|
</files>'
|
|
|
|
);
|
|
|
|
|
|
|
|
$expectedParsedBaseline = [
|
|
|
|
'sample/sample-file.php' => [
|
2018-11-09 06:46:13 +01:00
|
|
|
'MixedAssignment' => ['o' => 2, 's' => ['foo', 'bar']],
|
|
|
|
'InvalidReturnStatement' => ['o' => 1, 's' => []],
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
'sample/sample-file2.php' => [
|
2018-11-09 06:46:13 +01:00
|
|
|
'PossiblyUnusedMethod' => ['o' => 2, 's' => ['foo', 'bar']],
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
];
|
|
|
|
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame(
|
2018-10-30 15:32:20 +01:00
|
|
|
$expectedParsedBaseline,
|
|
|
|
ErrorBaseline::read($this->fileProvider->reveal(), $baselineFilePath)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testLoadShouldThrowExceptionWhenFilesAreNotDefinedInBaselineFile()
|
|
|
|
{
|
|
|
|
$this->expectException(ConfigException::class);
|
|
|
|
|
|
|
|
$baselineFile = 'baseline.xml';
|
|
|
|
|
|
|
|
$this->fileProvider->fileExists($baselineFile)->willReturn(true);
|
|
|
|
$this->fileProvider->getContents($baselineFile)->willReturn(
|
|
|
|
'<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<other>
|
|
|
|
</other>
|
|
|
|
'
|
|
|
|
);
|
|
|
|
|
|
|
|
ErrorBaseline::read($this->fileProvider->reveal(), $baselineFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testLoadShouldThrowExceptionWhenBaselineFileDoesNotExist()
|
|
|
|
{
|
|
|
|
$this->expectException(ConfigException::class);
|
|
|
|
|
|
|
|
$baselineFile = 'baseline.xml';
|
|
|
|
|
|
|
|
$this->fileProvider->fileExists($baselineFile)->willReturn(false);
|
|
|
|
|
|
|
|
ErrorBaseline::read($this->fileProvider->reveal(), $baselineFile);
|
|
|
|
}
|
|
|
|
|
2019-02-09 12:13:58 +01:00
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testCountTotalIssuesShouldReturnCorrectNumber()
|
|
|
|
{
|
|
|
|
$existingIssues = [
|
|
|
|
'sample/sample-file.php' => [
|
|
|
|
'MixedAssignment' => ['o' => 2, 's' => ['bar']],
|
|
|
|
'MixedOperand' => ['o' => 2, 's' => []],
|
|
|
|
],
|
|
|
|
'sample/sample-file2.php' => [
|
|
|
|
'TypeCoercion' => ['o' => 1, 's' => []],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
$totalIssues = ErrorBaseline::countTotalIssues($existingIssues);
|
|
|
|
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame($totalIssues, 5);
|
2019-02-09 12:13:58 +01:00
|
|
|
}
|
|
|
|
|
2018-10-30 15:32:20 +01:00
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testCreateShouldAggregateIssuesPerFile()
|
|
|
|
{
|
|
|
|
$baselineFile = 'baseline.xml';
|
|
|
|
|
|
|
|
$documentContent = null;
|
|
|
|
|
|
|
|
$this->fileProvider->setContents(
|
|
|
|
$baselineFile,
|
|
|
|
Argument::that(function (string $document) use (&$documentContent): bool {
|
|
|
|
$documentContent = $document;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
})
|
|
|
|
)->willReturn(null);
|
|
|
|
|
|
|
|
ErrorBaseline::create($this->fileProvider->reveal(), $baselineFile, [
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'foo',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
2019-06-09 16:30:14 +02:00
|
|
|
'file_name' => 'sample\sample-file.php',
|
2018-10-30 15:32:20 +01:00
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bar',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bat',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
2019-06-09 16:30:14 +02:00
|
|
|
'file_name' => 'sample\sample-file.php',
|
2018-10-30 15:32:20 +01:00
|
|
|
'type' => 'MixedOperand',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bing',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'AssignmentToVoid',
|
|
|
|
'severity' => 'info',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bong',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
2019-06-09 16:30:14 +02:00
|
|
|
'file_name' => 'sample\sample-file.php',
|
2018-10-30 15:32:20 +01:00
|
|
|
'type' => 'CircularReference',
|
|
|
|
'severity' => 'suppress',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'birdy',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file2.php',
|
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'boardy',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
2019-06-09 16:30:14 +02:00
|
|
|
'file_name' => 'sample\sample-file2.php',
|
2018-10-30 15:32:20 +01:00
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bardy',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file2.php',
|
|
|
|
'type' => 'TypeCoercion',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'hardy' . "\n",
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
]);
|
|
|
|
|
|
|
|
$baselineDocument = new \DOMDocument();
|
|
|
|
$baselineDocument->loadXML($documentContent, LIBXML_NOBLANKS);
|
|
|
|
|
|
|
|
/** @var \DOMElement[] $files */
|
|
|
|
$files = $baselineDocument->getElementsByTagName('files')[0]->childNodes;
|
|
|
|
|
|
|
|
$file1 = $files[0];
|
|
|
|
$file2 = $files[1];
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame('sample/sample-file.php', $file1->getAttribute('src'));
|
|
|
|
$this->assertSame('sample/sample-file2.php', $file2->getAttribute('src'));
|
2018-10-30 15:32:20 +01:00
|
|
|
|
|
|
|
/** @var \DOMElement[] $file1Issues */
|
|
|
|
$file1Issues = $file1->childNodes;
|
|
|
|
/** @var \DOMElement[] $file2Issues */
|
|
|
|
$file2Issues = $file2->childNodes;
|
|
|
|
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame('MixedAssignment', $file1Issues[0]->tagName);
|
|
|
|
$this->assertSame('3', $file1Issues[0]->getAttribute('occurrences'));
|
|
|
|
$this->assertSame('MixedOperand', $file1Issues[1]->tagName);
|
|
|
|
$this->assertSame('1', $file1Issues[1]->getAttribute('occurrences'));
|
2018-10-30 15:32:20 +01:00
|
|
|
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame('MixedAssignment', $file2Issues[0]->tagName);
|
|
|
|
$this->assertSame('2', $file2Issues[0]->getAttribute('occurrences'));
|
|
|
|
$this->assertSame('TypeCoercion', $file2Issues[1]->tagName);
|
|
|
|
$this->assertSame('1', $file2Issues[1]->getAttribute('occurrences'));
|
2018-10-30 15:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function testUpdateShouldRemoveExistingIssuesWithoutAddingNewOnes()
|
|
|
|
{
|
|
|
|
$baselineFile = 'baseline.xml';
|
|
|
|
|
|
|
|
$this->fileProvider->fileExists($baselineFile)->willReturn(true);
|
|
|
|
$this->fileProvider->getContents($baselineFile)->willReturn(
|
|
|
|
'<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<files>
|
|
|
|
<file src="sample/sample-file.php">
|
2018-11-09 06:46:13 +01:00
|
|
|
<MixedAssignment occurrences="3">
|
|
|
|
<code>bar</code>
|
|
|
|
<code>bat</code>
|
|
|
|
</MixedAssignment>
|
2018-10-30 15:32:20 +01:00
|
|
|
<MixedOperand occurrences="1"/>
|
|
|
|
</file>
|
|
|
|
<file src="sample/sample-file2.php">
|
|
|
|
<MixedAssignment occurrences="2"/>
|
|
|
|
<TypeCoercion occurrences="1"/>
|
|
|
|
</file>
|
|
|
|
<file src="sample/sample-file3.php">
|
|
|
|
<MixedAssignment occurrences="1"/>
|
|
|
|
</file>
|
|
|
|
</files>'
|
|
|
|
);
|
|
|
|
$this->fileProvider->setContents(Argument::cetera())->willReturn(null);
|
|
|
|
|
|
|
|
$newIssues = [
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'foo',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedAssignment',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bar',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedOperand',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bat',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file.php',
|
|
|
|
'type' => 'MixedOperand',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'bam',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'file_name' => 'sample/sample-file2.php',
|
|
|
|
'type' => 'TypeCoercion',
|
|
|
|
'severity' => 'error',
|
2018-11-09 06:46:13 +01:00
|
|
|
'selected_text' => 'tar',
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
$remainingBaseline = ErrorBaseline::update(
|
|
|
|
$this->fileProvider->reveal(),
|
|
|
|
$baselineFile,
|
|
|
|
$newIssues
|
|
|
|
);
|
|
|
|
|
2019-03-23 19:27:54 +01:00
|
|
|
$this->assertSame([
|
2018-10-30 15:32:20 +01:00
|
|
|
'sample/sample-file.php' => [
|
2018-11-09 06:46:13 +01:00
|
|
|
'MixedAssignment' => ['o' => 2, 's' => ['bar']],
|
|
|
|
'MixedOperand' => ['o' => 1, 's' => []],
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
'sample/sample-file2.php' => [
|
2018-11-09 06:46:13 +01:00
|
|
|
'TypeCoercion' => ['o' => 1, 's' => []],
|
2018-10-30 15:32:20 +01:00
|
|
|
],
|
|
|
|
], $remainingBaseline);
|
|
|
|
}
|
|
|
|
}
|