Skip to content

Commit 775ff9f

Browse files
staabmclxmstaab
andauthored
implement initial phpstan-baseline-trend (#8)
Co-authored-by: Markus Staab <[email protected]>
1 parent a14dc92 commit 775ff9f

12 files changed

+237
-14
lines changed

bin/phpstan-baseline-analyze.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
if ($argc <= 1) {
2020
$app->help();
21-
exit(1);
21+
exit(254);
2222
}
2323

2424

@@ -27,5 +27,5 @@
2727
$format = \staabm\PHPStanBaselineAnalysis\ResultPrinter::FORMAT_JSON;
2828
}
2929

30-
$app->start($argv[1], $format);
31-
exit(0);
30+
$exitCode = $app->start($argv[1], $format);
31+
exit($exitCode);

bin/phpstan-baseline-trend

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
require __DIR__ .'/phpstan-baseline-trend.php';

bin/phpstan-baseline-trend.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
// Finding composer
4+
5+
$paths = [
6+
__DIR__.'/../vendor/autoload.php',
7+
__DIR__.'/../../../autoload.php',
8+
];
9+
10+
foreach ($paths as $path) {
11+
if (file_exists($path)) {
12+
include $path;
13+
break;
14+
}
15+
}
16+
17+
$app = new \staabm\PHPStanBaselineAnalysis\TrendApplication();
18+
19+
if ($argc <= 2) {
20+
$app->help();
21+
exit(254);
22+
}
23+
24+
$exitCode = $app->start($argv[1], $argv[2]);
25+
exit($exitCode);

lib/AnalyzeApplication.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ final class AnalyzeApplication
1111
* @param ResultPrinter::FORMAT_* $format
1212
* @throws \Safe\Exceptions\FilesystemException
1313
*/
14-
public function start(string $glob, string $format): void
14+
public function start(string $glob, string $format): int
1515
{
1616
$printer = new ResultPrinter();
1717
$baselines = BaselineFinder::forGlob($glob);
@@ -33,6 +33,8 @@ public function start(string $glob, string $format): void
3333

3434
$this->printResult($format, $isFirst, $isLast, $stream);
3535
}
36+
37+
return 0;
3638
}
3739

3840
public function help(): void

lib/TrendApplication.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace staabm\PHPStanBaselineAnalysis;
4+
5+
use \Iterator;
6+
7+
final class TrendApplication
8+
{
9+
const EXIT_IMPROVED = 0;
10+
const EXIT_STEADY = 1;
11+
const EXIT_WORSE = 2;
12+
13+
/**
14+
* @throws \Safe\Exceptions\FilesystemException
15+
* @throws \Safe\Exceptions\JsonException
16+
*
17+
* @return self::EXIT_*
18+
*/
19+
public function start(string $referenceFilePath, string $comparingFilePath): int
20+
{
21+
$exitCode = self::EXIT_IMPROVED;
22+
23+
$reference = $this->decodeFile($referenceFilePath);
24+
$comparing = $this->decodeFile($comparingFilePath);
25+
26+
foreach ($reference as $baselinePath => $result) {
27+
echo 'Analyzing Trend for ' . $baselinePath . "\n";
28+
29+
if (isset($comparing[$baselinePath])) {
30+
if ($comparing[$baselinePath]->overallComplexity > $result->overallComplexity) {
31+
printf(' %s: %d -> %d => worse', ResultPrinter::KEY_OVERALL_CLASS_COMPLEXITY, $result->overallComplexity, $comparing[$baselinePath]->overallComplexity);
32+
33+
$exitCode = max($exitCode, self::EXIT_WORSE);
34+
} elseif ($comparing[$baselinePath]->overallComplexity < $result->overallComplexity) {
35+
printf(' %s: %d -> %d => improved', ResultPrinter::KEY_OVERALL_CLASS_COMPLEXITY, $result->overallComplexity, $comparing[$baselinePath]->overallComplexity);
36+
37+
$exitCode = max($exitCode, self::EXIT_IMPROVED);
38+
} else {
39+
printf(' %s: %d -> %d => good', ResultPrinter::KEY_OVERALL_CLASS_COMPLEXITY, $result->overallComplexity, $comparing[$baselinePath]->overallComplexity);
40+
41+
$exitCode = max($exitCode, self::EXIT_STEADY);
42+
}
43+
}
44+
}
45+
46+
return $exitCode;
47+
}
48+
49+
public function help(): void
50+
{
51+
printf('USAGE: phpstan-baseline-trend <reference-result.json> <comparing-result.json>');
52+
}
53+
54+
/**
55+
* @return array<string, AnalyzerResult>
56+
* @throws \Safe\Exceptions\FilesystemException
57+
* @throws \Safe\Exceptions\JsonException
58+
*/
59+
private function decodeFile(string $filePath): array
60+
{
61+
$content = \Safe\file_get_contents($filePath);
62+
$json = \Safe\json_decode($content, true);
63+
64+
if (!is_array($json)) {
65+
throw new \RuntimeException('Expecting array, got ' . gettype($json));
66+
}
67+
68+
$decoded = [];
69+
foreach ($json as $data) {
70+
71+
if (!is_array($data)) {
72+
throw new \RuntimeException('Expecting array, got ' . gettype($data));
73+
}
74+
75+
foreach ($data as $baselinePath => $resultArray) {
76+
77+
if (!is_string($baselinePath)) {
78+
throw new \RuntimeException('Expecting string, got ' . gettype($baselinePath));
79+
}
80+
if (!is_array($resultArray)) {
81+
throw new \RuntimeException('Expecting string, got ' . gettype($resultArray));
82+
}
83+
84+
$result = new AnalyzerResult();
85+
$result->overallComplexity = $resultArray[ResultPrinter::KEY_OVERALL_CLASS_COMPLEXITY];
86+
87+
$decoded[$baselinePath] = $result;
88+
}
89+
}
90+
91+
return $decoded;
92+
}
93+
}

tests/AnalyzeApplicationTest.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22

33
namespace staabm\PHPStanBaselineAnalysis\Tests;
44

5-
use PHPUnit\Framework\TestCase;
65
use staabm\PHPStanBaselineAnalysis\AnalyzeApplication;
7-
use staabm\PHPStanBaselineAnalysis\Baseline;
8-
use staabm\PHPStanBaselineAnalysis\BaselineAnalyzer;
96
use staabm\PHPStanBaselineAnalysis\ResultPrinter;
107

11-
class AnalyzeApplicationTest extends TestCase
8+
class AnalyzeApplicationTest extends BaseTestCase
129
{
1310
function testTextPrinting():void
1411
{
@@ -19,14 +16,12 @@ function testTextPrinting():void
1916
$rendered = ob_get_clean();
2017

2118
$rendered = str_replace(__DIR__, '', $rendered);
22-
$rendered = $this->normalizeNewlines($rendered);
2319

2420
$expected = <<<PHP
2521
Analyzing /fixtures/all-in.neon
2622
Overall-Class-Cognitive-Complexity: 70
2723
2824
PHP;
29-
$expected = $this->normalizeNewlines($expected);
3025

3126
$this->assertSame($expected, $rendered);
3227
}
@@ -47,8 +42,4 @@ function testJsonPrinting():void
4742

4843
$this->assertSame($expected, $rendered);
4944
}
50-
51-
private function normalizeNewlines(string $string):string {
52-
return str_replace("\r\n", "\n", $string);
53-
}
5445
}

tests/BaseTestCase.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace staabm\PHPStanBaselineAnalysis\Tests;
4+
5+
use PHPUnit\Framework\Constraint\IsIdentical;
6+
use PHPUnit\Framework\ExpectationFailedException;
7+
use PHPUnit\Framework\TestCase;
8+
9+
abstract class BaseTestCase extends TestCase {
10+
/**
11+
* Asserts that two variables have the same type and value.
12+
* Used on objects, it asserts that two variables reference
13+
* the same object.
14+
*
15+
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
16+
* @throws ExpectationFailedException
17+
*
18+
* @param mixed $actual
19+
*
20+
* @psalm-template ExpectedType
21+
* @psalm-param ExpectedType $expected
22+
* @psalm-assert =ExpectedType $actual
23+
*/
24+
public static function assertSame($expected, $actual, string $message = ''): void
25+
{
26+
$expected = self::normalizeNewlines($expected);
27+
$actual = self::normalizeNewlines($actual);
28+
29+
static::assertThat(
30+
$actual,
31+
new IsIdentical($expected),
32+
$message
33+
);
34+
}
35+
36+
static private function normalizeNewlines(string $string):string {
37+
return str_replace("\r\n", "\n", $string);
38+
}
39+
}

tests/TrendApplicationTest.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace staabm\PHPStanBaselineAnalysis\Tests;
4+
5+
use staabm\PHPStanBaselineAnalysis\TrendApplication;
6+
7+
class TrendApplicationTest extends BaseTestCase
8+
{
9+
function testSameTrend():void
10+
{
11+
$app = new TrendApplication();
12+
13+
ob_start();
14+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-same-result.json');
15+
$rendered = ob_get_clean();
16+
17+
$rendered = str_replace(__DIR__, '', $rendered);
18+
19+
$expected = <<<PHP
20+
Analyzing Trend for /fixtures/all-in.neon
21+
Overall-Class-Cognitive-Complexity: 70 -> 70 => good
22+
PHP;
23+
24+
$this->assertSame($expected, $rendered);
25+
$this->assertSame(TrendApplication::EXIT_STEADY, $exitCode);
26+
}
27+
28+
function testHigherTrend():void
29+
{
30+
$app = new TrendApplication();
31+
32+
ob_start();
33+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-higher-result.json');
34+
$rendered = ob_get_clean();
35+
36+
$rendered = str_replace(__DIR__, '', $rendered);
37+
38+
$expected = <<<PHP
39+
Analyzing Trend for /fixtures/all-in.neon
40+
Overall-Class-Cognitive-Complexity: 70 -> 90 => worse
41+
PHP;
42+
43+
$this->assertSame($expected, $rendered);
44+
$this->assertSame(TrendApplication::EXIT_WORSE, $exitCode);
45+
}
46+
47+
function testLowerTrend():void
48+
{
49+
$app = new TrendApplication();
50+
51+
ob_start();
52+
$exitCode = $app->start(__DIR__.'/fixtures/reference-result.json', __DIR__.'/fixtures/compare-lower-result.json');
53+
$rendered = ob_get_clean();
54+
55+
$rendered = str_replace(__DIR__, '', $rendered);
56+
57+
$expected = <<<PHP
58+
Analyzing Trend for /fixtures/all-in.neon
59+
Overall-Class-Cognitive-Complexity: 70 -> 50 => improved
60+
PHP;
61+
62+
$this->assertSame($expected, $rendered);
63+
$this->assertSame(TrendApplication::EXIT_IMPROVED, $exitCode);
64+
}
65+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"\/fixtures\/all-in.neon":{"Overall-Class-Cognitive-Complexity":90}}]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"\/fixtures\/all-in.neon":{"Overall-Class-Cognitive-Complexity":50}}]

0 commit comments

Comments
 (0)