RemoveBaseLineCommandTest   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 267
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 1
Metric Value
eloc 143
c 7
b 0
f 1
dl 0
loc 267
rs 10
wmc 14

13 Methods

Rating   Name   Duplication   Size   Complexity  
A testException() 0 13 1
A getAnalysisResultsWithXResults() 0 21 2
A assertResponseContains() 0 5 1
A testPickNonDefaultOutputFormatterWithIssues() 0 17 1
A createCommandTester() 0 42 1
A testNoNewIssues() 0 16 1
A setUp() 0 11 1
A assertReturnCode() 0 3 1
A testInvalidResultsParser() 0 17 1
A testCleanUpOptions() 0 19 1
A testSpecifyProjectRoot() 0 14 1
A testPickNonDefaultOutputFormatter() 0 17 1
A test1NewIssues() 0 14 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace DaveLiddament\StaticAnalysisResultsBaseliner\Tests\Unit\Framework\Command;
6
7
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\AbsoluteFileName;
8
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\BaseLine;
9
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\LineNumber;
10
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\Location;
11
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\ProjectRoot;
12
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\Severity;
13
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\Type;
14
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\OutputFormatter\OutputFormatter;
15
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Pruner\PrunedResults;
16
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\RandomResultsPicker\RandomResultsPicker;
17
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResult;
18
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResults;
19
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\ResultsParser\AnalysisResultsBuilder;
20
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\RandomNumberGenerator;
21
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Command\RemoveBaseLineFromResultsCommand;
22
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Container\OutputFormatterRegistry;
23
use DaveLiddament\StaticAnalysisResultsBaseliner\Plugins\GitDiffHistoryAnalyser\GitCommit;
24
use DaveLiddament\StaticAnalysisResultsBaseliner\Plugins\OutputFormatters\TableOutputFormatter;
25
use DaveLiddament\StaticAnalysisResultsBaseliner\Plugins\ResultsParsers\SarbJsonResultsParser\SarbJsonResultsParser;
26
use DaveLiddament\StaticAnalysisResultsBaseliner\Tests\Helpers\BaseLineResultsBuilder;
27
use DaveLiddament\StaticAnalysisResultsBaseliner\Tests\TestDoubles\HistoryFactoryStub;
28
use DaveLiddament\StaticAnalysisResultsBaseliner\Tests\TestDoubles\MockResultsPruner;
29
use DaveLiddament\StaticAnalysisResultsBaseliner\Tests\TestDoubles\OutputFormatterStub;
30
use PHPUnit\Framework\TestCase;
31
use Symfony\Component\Console\Tester\CommandTester;
32
33
final class RemoveBaseLineCommandTest extends TestCase
34
{
35
    private const INPUT_STRING_1 = <<<EOF
36
This is
37
a multiline
38
string
39
EOF;
40
    public const BASELINE_FILENAME = 'baseline1.sarb';
41
    public const BASELINE_FILE_ARGUMENT = 'baseline-file';
42
    public const OUTPUT_FORMAT_OPTION = '--output-format';
43
    public const PROJECT_ROOT = '--project-root';
44
    public const CLEAN_UP = '--clean-up';
45
46
    /**
47
     * @var ProjectRoot
48
     */
49
    private $projectRoot;
50
51
    /**
52
     * @var OutputFormatterRegistry
53
     */
54
    private $outputFormatterRegistry;
55
    /**
56
     * @var OutputFormatter
57
     */
58
    private $defaultOutputFormatter;
59
    /**
60
     * @var OutputFormatter
61
     */
62
    private $stubOutputFormatter;
63
64
    protected function setUp(): void
65
    {
66
        $this->defaultOutputFormatter = new TableOutputFormatter();
67
        $this->stubOutputFormatter = new OutputFormatterStub();
68
69
        $this->outputFormatterRegistry = new OutputFormatterRegistry([
70
            $this->defaultOutputFormatter,
71
            $this->stubOutputFormatter,
72
        ]);
73
74
        $this->projectRoot = ProjectRoot::fromProjectRoot('/tmp', '/tmp/foo/bar');
75
    }
76
77
    public function testNoNewIssues(): void
78
    {
79
        $commandTester = $this->createCommandTester(
80
            $this->getAnalysisResultsWithXResults(0),
81
            null,
82
            null,
83
        );
84
85
        $commandTester->execute([
86
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
87
        ]);
88
89
        $this->assertReturnCode(0, $commandTester);
90
        $this->assertResponseContains('Latest analysis issue count: 2', $commandTester);
91
        $this->assertResponseContains('Baseline issue count: 4', $commandTester);
92
        $this->assertResponseContains('Issue count with baseline removed: 0', $commandTester);
93
    }
94
95
    public function test1NewIssues(): void
96
    {
97
        $commandTester = $this->createCommandTester(
98
            $this->getAnalysisResultsWithXResults(1),
99
            null,
100
            null,
101
        );
102
103
        $commandTester->execute([
104
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
105
        ]);
106
107
        $this->assertReturnCode(1, $commandTester);
108
        $this->assertResponseContains('Issue count with baseline removed: 1', $commandTester);
109
    }
110
111
    public function testPickNonDefaultOutputFormatter(): void
112
    {
113
        $commandTester = $this->createCommandTester(
114
            $this->getAnalysisResultsWithXResults(0),
115
            null,
116
            null,
117
        );
118
119
        $commandTester->execute([
120
            self::OUTPUT_FORMAT_OPTION => OutputFormatterStub::CODE,
121
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
122
        ]);
123
124
        $this->assertReturnCode(0, $commandTester);
125
        $this->assertResponseContains(
126
            '[stub output formatter: Issues since baseline 0]',
127
            $commandTester,
128
        );
129
    }
130
131
    public function testPickNonDefaultOutputFormatterWithIssues(): void
132
    {
133
        $commandTester = $this->createCommandTester(
134
            $this->getAnalysisResultsWithXResults(8),
135
            null,
136
            null,
137
        );
138
139
        $commandTester->execute([
140
            self::OUTPUT_FORMAT_OPTION => OutputFormatterStub::CODE,
141
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
142
        ]);
143
144
        $this->assertReturnCode(1, $commandTester);
145
        $this->assertResponseContains(
146
            '[stub output formatter: Issues since baseline 8]',
147
            $commandTester,
148
        );
149
    }
150
151
    public function testInvalidResultsParser(): void
152
    {
153
        $commandTester = $this->createCommandTester(
154
            $this->getAnalysisResultsWithXResults(0),
155
            null,
156
            null,
157
        );
158
159
        $commandTester->execute([
160
            self::OUTPUT_FORMAT_OPTION => 'rubbish',
161
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
162
        ]);
163
164
        $this->assertReturnCode(11, $commandTester);
165
        $this->assertResponseContains(
166
            'Invalid value [rubbish] for option [output-format]. Pick one of: table|stub',
167
            $commandTester,
168
        );
169
    }
170
171
    public function testSpecifyProjectRoot(): void
172
    {
173
        $commandTester = $this->createCommandTester(
174
            $this->getAnalysisResultsWithXResults(0),
175
            $this->projectRoot,
176
            null,
177
        );
178
179
        $commandTester->execute([
180
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
181
            self::PROJECT_ROOT => '/tmp',
182
        ]);
183
184
        $this->assertReturnCode(0, $commandTester);
185
    }
186
187
    public function testException(): void
188
    {
189
        $commandTester = $this->createCommandTester(
190
            $this->getAnalysisResultsWithXResults(1),
191
            null,
192
            new \Exception(),
193
        );
194
195
        $commandTester->execute([
196
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
197
        ]);
198
199
        $this->assertReturnCode(100, $commandTester);
200
    }
201
202
    public function testCleanUpOptions(): void
203
    {
204
        $commandTester = $this->createCommandTester(
205
            $this->getAnalysisResultsWithXResults(0),
206
            null,
207
            null,
208
        );
209
210
        $commandTester->execute([
211
            self::BASELINE_FILE_ARGUMENT => self::BASELINE_FILENAME,
212
            self::CLEAN_UP => true,
213
        ]);
214
215
        $this->assertReturnCode(0, $commandTester);
216
217
        $this->assertResponseContains('Random 2 issues in the baseline to fix...', $commandTester);
218
        $this->assertResponseContains('FILE: /FILE_2', $commandTester);
219
        $this->assertResponseContains('| 2    | MESSAGE_1   |', $commandTester);
220
        $this->assertResponseContains('| 2    | MESSAGE_0   |', $commandTester);
221
    }
222
223
    private function createCommandTester(
224
        AnalysisResults $expectedAnalysisResults,
225
        ?ProjectRoot $projectRoot,
226
        ?\Throwable $exception,
227
    ): CommandTester {
228
        $baseLineResultsBuilder = new BaseLineResultsBuilder();
229
        $baseLineResultsBuilder->add('file1', 1, 'type1', Severity::error());
230
        $baseLineResultsBuilder->add('file2', 2, 'type2', Severity::error());
231
        $baseLineResultsBuilder->add('file3', 3, 'type3', Severity::error());
232
        $baseLineResultsBuilder->add('file4', 4, 'type4', Severity::error());
233
234
        $baseLine = new BaseLine(
235
            new HistoryFactoryStub(),
236
            $baseLineResultsBuilder->build(),
237
            new SarbJsonResultsParser(),
238
            new GitCommit('fae40b3d596780ffd746dbd2300d05dcfbd09033'),
239
        );
240
241
        $prunedResults = new PrunedResults(
242
            $baseLine,
243
            $expectedAnalysisResults,
244
            $this->getAnalysisResultsWithXResults(2),
245
        );
246
247
        $mockResultsPruner = new MockResultsPruner(
248
            self::INPUT_STRING_1,
249
            $prunedResults,
250
            $projectRoot,
251
            $exception,
252
        );
253
254
        $command = new RemoveBaseLineFromResultsCommand(
255
            $mockResultsPruner,
256
            $this->outputFormatterRegistry,
257
            new TableOutputFormatter(),
258
            new RandomResultsPicker(new RandomNumberGenerator()),
259
        );
260
261
        $commandTester = new CommandTester($command);
262
        $commandTester->setInputs([self::INPUT_STRING_1]);
263
264
        return $commandTester;
265
    }
266
267
    private function assertReturnCode(int $expectedReturnCode, CommandTester $commandTester): void
268
    {
269
        $this->assertSame($expectedReturnCode, $commandTester->getStatusCode(), $commandTester->getDisplay());
270
    }
271
272
    private function assertResponseContains(string $expectedMessage, CommandTester $commandTester): void
273
    {
274
        $output = $commandTester->getDisplay();
275
        $position = strpos($output, $expectedMessage);
276
        $this->assertNotFalse($position, "Can't find message [$expectedMessage] in [$output]");
277
    }
278
279
    private function getAnalysisResultsWithXResults(int $count): AnalysisResults
280
    {
281
        $projectRoot = ProjectRoot::fromCurrentWorkingDirectory('/');
282
283
        $analysisResultsBuilder = new AnalysisResultsBuilder();
284
        for ($i = 0; $i < $count; ++$i) {
285
            $analysisResult = new AnalysisResult(
286
                Location::fromAbsoluteFileName(
287
                    new AbsoluteFileName("/FILE_$count"),
288
                    $projectRoot,
289
                    new LineNumber($count),
290
                ),
291
                new Type("TYPE_$i"),
292
                "MESSAGE_$i",
293
                [],
294
                Severity::error(),
295
            );
296
            $analysisResultsBuilder->addAnalysisResult($analysisResult);
297
        }
298
299
        return $analysisResultsBuilder->build();
300
    }
301
}
302