Passed
Pull Request — master (#75)
by Dave
02:11
created

EndToEndTest   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 364
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 173
c 2
b 0
f 0
dl 0
loc 364
rs 10
wmc 25

22 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 6 1
A testInvalidProjectRoot() 0 20 1
A testInvalidBaselineContents() 0 17 1
A testInvalidBaselineFileNameSupplied() 0 15 1
A testInvalidAnalysisResults() 0 20 1
A testHappyPath() 0 26 1
A testInvalidConfig() 0 18 1
A createTestDirectory() 0 8 1
A runCreateBaseLineCommand() 0 12 1
A runStripBaseLineFromResultsCommand() 0 21 1
A runCommand() 0 20 2
A updatePathsInJsonFiles() 0 13 3
A getProjectRootFilename() 0 3 1
A removeTestDirectory() 0 3 1
A commit() 0 6 1
A addNonCheckedInFile() 0 7 1
A testAttemptToCreateBaselineWithNonCleanGitStatus() 0 20 1
A getStaticAnalysisResultsAsString() 0 9 1
A testListSupportedStaticAnalysisTools() 0 3 1
A getBaselineFilePath() 0 3 1
A testListSupportedHistoryAnalysers() 0 3 1
A testForceCreateBaselineWithNonCleanGitStatus() 0 21 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace DaveLiddament\StaticAnalysisResultsBaseliner\Tests\Integration;
6
7
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\ProjectRoot;
8
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Common\RelativeFileName;
9
use DaveLiddament\StaticAnalysisResultsBaseliner\Domain\Utils\StringUtils;
10
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Command\CreateBaseLineCommand;
11
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Command\ListHistoryAnalysersCommand;
12
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Command\ListResultsParsesCommand;
13
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Command\RemoveBaseLineFromResultsCommand;
14
use DaveLiddament\StaticAnalysisResultsBaseliner\Framework\Container\Container;
15
use DaveLiddament\StaticAnalysisResultsBaseliner\Plugins\GitDiffHistoryAnalyser\internal\GitCliWrapper;
16
use DaveLiddament\StaticAnalysisResultsBaseliner\Tests\Helpers\ResourceLoaderTrait;
17
use PHPUnit\Framework\TestCase;
18
use Symfony\Component\Console\Application;
19
use Symfony\Component\Console\Tester\CommandTester;
20
use Symfony\Component\Filesystem\Filesystem;
21
use Webmozart\PathUtil\Path;
22
23
// TODO this is getting a bit big. Split into multiple files.
24
class EndToEndTest extends TestCase
25
{
26
    use ResourceLoaderTrait;
27
28
    private const COMMIT_1_DIRECTORY = 'integration/commit1';
29
    private const COMMIT_1_RESULTS = 'commit1.json';
30
31
    private const COMMIT_2_DIRECTORY = 'integration/commit2';
32
    private const COMMIT_2_RESULTS = 'commit2.json';
33
    private const COMMIT_2_BASELINE_REMOVED_EXPECTED_RESULTS = 'baseline-removed.json';
34
35
    private const COMMIT_3_DIRECTORY = 'integration/commit3';
36
    private const COMMIT_3_RESULTS = 'commit3.json';
37
38
    private const INVALID_RESULTS = 'invalid_analysis_results.json';
39
40
    /**
41
     * @var Filesystem
42
     */
43
    private $fileSystem;
44
45
    /**
46
     * @var GitCliWrapper
47
     */
48
    private $gitWrapper;
49
50
    /**
51
     * @var ProjectRoot
52
     */
53
    private $projectRoot;
54
55
    /**
56
     * @var Application
57
     */
58
    private $application;
59
60
    protected function setUp(): void
61
    {
62
        $this->fileSystem = new Filesystem();
63
        $this->gitWrapper = new GitCliWrapper();
64
        $container = new Container();
65
        $this->application = $container->getApplication();
66
    }
67
68
    public function testInvalidConfig(): void
69
    {
70
        $this->createTestDirectory();
71
72
        $arguments = [
73
            '--input-format' => 'rubbish',
74
            'baseline-file' => $this->getBaselineFilePath(),
75
        ];
76
77
        $this->runCommand(
78
            CreateBaseLineCommand::COMMAND_NAME,
79
            $arguments,
80
            11,
81
            self::COMMIT_1_RESULTS
82
        );
83
84
        // Only delete test directory if tests passed. Keep to investigate test failures
85
        $this->removeTestDirectory();
86
    }
87
88
    public function testInvalidAnalysisResults(): void
89
    {
90
        $this->createTestDirectory();
91
        $this->gitWrapper->init($this->projectRoot);
92
        $this->commit(self::COMMIT_1_DIRECTORY);
93
94
        $arguments = [
95
            'baseline-file' => $this->getBaselineFilePath(),
96
            '--project-root' => (string) $this->projectRoot,
97
        ];
98
99
        $this->runCommand(
100
            CreateBaseLineCommand::COMMAND_NAME,
101
            $arguments,
102
            13,
103
            self::INVALID_RESULTS
104
        );
105
106
        // Only delete test directory if tests passed. Keep to investigate test failures
107
        $this->removeTestDirectory();
108
    }
109
110
    public function testInvalidProjectRoot(): void
111
    {
112
        $this->createTestDirectory();
113
        $this->gitWrapper->init($this->projectRoot);
114
        $this->commit(self::COMMIT_1_DIRECTORY);
115
116
        $arguments = [
117
            'baseline-file' => $this->getProjectRootFilename('InvalidFileName.json'),
118
            '--project-root' => '/tmp/foo/bar',
119
        ];
120
121
        $this->runCommand(
122
            CreateBaseLineCommand::COMMAND_NAME,
123
            $arguments,
124
            15,
125
            self::COMMIT_1_RESULTS
126
        );
127
128
        // Only delete test directory if tests passed. Keep to investigate test failures
129
        $this->removeTestDirectory();
130
    }
131
132
    public function testInvalidBaselineFileNameSupplied(): void
133
    {
134
        $this->createTestDirectory();
135
        $arguments = [
136
            'baseline-file' => $this->getProjectRootFilename('InvalidFileName.json'),
137
        ];
138
139
        $this->runCommand(
140
            RemoveBaseLineFromResultsCommand::COMMAND_NAME,
141
            $arguments,
142
            14,
143
            self::COMMIT_1_RESULTS);
144
145
        // Only delete test directory if tests passed. Keep to investigate test failures
146
        $this->removeTestDirectory();
147
    }
148
149
    public function testInvalidBaselineContents(): void
150
    {
151
        $this->createTestDirectory();
152
        $this->gitWrapper->init($this->projectRoot);
153
        $this->commit(self::COMMIT_1_DIRECTORY);
154
        $arguments = [
155
            'baseline-file' => $this->getProjectRootFilename('src/Person.php'),
156
        ];
157
158
        $this->runCommand(
159
            RemoveBaseLineFromResultsCommand::COMMAND_NAME,
160
            $arguments,
161
            12,
162
            self::COMMIT_1_RESULTS);
163
164
        // Only delete test directory if tests passed. Keep to investigate test failures
165
        $this->removeTestDirectory();
166
    }
167
168
    public function testHappyPath(): void
169
    {
170
        $this->createTestDirectory();
171
        $this->gitWrapper->init($this->projectRoot);
172
173
        $this->commit(self::COMMIT_1_DIRECTORY);
174
        $this->runCreateBaseLineCommand();
175
176
        // Now create commit 2. THis introduces some new errors
177
        $this->commit(self::COMMIT_2_DIRECTORY);
178
        $this->runStripBaseLineFromResultsCommand(
179
            self::COMMIT_2_RESULTS,
180
            1,
181
            $this->getStaticAnalysisResultsAsString(self::COMMIT_2_BASELINE_REMOVED_EXPECTED_RESULTS)
182
        );
183
184
        // Now create commit 3. This has errors that were only in the baseline.
185
        $this->commit(self::COMMIT_3_DIRECTORY);
186
        $this->runStripBaseLineFromResultsCommand(
187
            self::COMMIT_3_RESULTS,
188
            0,
189
        ''
190
        );
191
192
        // Only delete test directory if tests passed. Keep to investigate test failures
193
        $this->removeTestDirectory();
194
    }
195
196
    public function testAttemptToCreateBaselineWithNonCleanGitStatus(): void
197
    {
198
        var_dump('Failing test');
0 ignored issues
show
Security Debugging Code introduced by
var_dump('Failing test') looks like debug code. Are you sure you do not want to remove it?
Loading history...
199
        $this->createTestDirectory();
200
        $this->gitWrapper->init($this->projectRoot);
201
        $this->commit(self::COMMIT_1_DIRECTORY);
202
        $this->addNonCheckedInFile();
203
204
        $arguments = [
205
            'baseline-file' => $this->getProjectRootFilename('baseline.json'),
206
        ];
207
208
        $this->runCommand(
209
            CreateBaseLineCommand::COMMAND_NAME,
210
            $arguments,
211
            15,
212
            self::COMMIT_1_RESULTS
213
        );
214
215
        $this->removeTestDirectory();
216
    }
217
218
    public function testForceCreateBaselineWithNonCleanGitStatus(): void
219
    {
220
        $this->createTestDirectory();
221
        $this->gitWrapper->init($this->projectRoot);
222
        $this->commit(self::COMMIT_1_DIRECTORY);
223
        $this->addNonCheckedInFile();
224
225
        $arguments = [
226
            'baseline-file' => $this->getProjectRootFilename('baseline.json'),
227
            '--force' => null,
228
        ];
229
230
        $this->runCommand(
231
            CreateBaseLineCommand::COMMAND_NAME,
232
            $arguments,
233
            0,
234
            self::COMMIT_1_RESULTS
235
        );
236
237
        // Only delete test directory if tests passed. Keep to investigate test failures
238
        $this->removeTestDirectory();
239
    }
240
241
    /**
242
     * This is just a smoke test.
243
     */
244
    public function testListSupportedStaticAnalysisTools(): void
245
    {
246
        $this->runCommand(ListResultsParsesCommand::COMMAND_NAME, [], 0, null);
247
    }
248
249
    /**
250
     * This is just a smoke test.
251
     */
252
    public function testListSupportedHistoryAnalysers(): void
253
    {
254
        $this->runCommand(ListHistoryAnalysersCommand::COMMAND_NAME, [], 0, null);
255
    }
256
257
    private function createTestDirectory(): void
258
    {
259
        $dateTimeFolderName = date('Ymd_His');
260
        $testDirectory = __DIR__."/../scratchpad/{$dateTimeFolderName}";
261
        $this->fileSystem->mkdir($testDirectory);
262
        $cwd = getcwd();
263
        $this->assertNotFalse($cwd);
264
        $this->projectRoot = new ProjectRoot($testDirectory, $cwd);
265
    }
266
267
    private function commit(string $directory): void
268
    {
269
        $source = $this->getPath($directory);
270
        $this->fileSystem->mirror($source, (string) $this->projectRoot, null, ['override' => true]);
271
        $this->updatePathsInJsonFiles($this->projectRoot);
272
        $this->gitWrapper->addAndCommit("Updating code to $directory", $this->projectRoot);
273
    }
274
275
    private function runCreateBaseLineCommand(): void
276
    {
277
        $arguments = [
278
            'baseline-file' => $this->getBaselineFilePath(),
279
            '--project-root' => (string) $this->projectRoot,
280
        ];
281
282
        $this->runCommand(
283
            CreateBaseLineCommand::COMMAND_NAME,
284
            $arguments,
285
            0,
286
            self::COMMIT_1_RESULTS
287
        );
288
    }
289
290
    private function runStripBaseLineFromResultsCommand(
291
        string $psalmResults,
292
        int $expectedExitCode,
293
        string $expectedResultsJson
294
    ): void {
295
        $arguments = [
296
            'baseline-file' => $this->getBaselineFilePath(),
297
            '--output-format' => 'json',
298
            '--project-root' => (string) $this->projectRoot,
299
        ];
300
301
        $output = $this->runCommand(
302
            RemoveBaseLineFromResultsCommand::COMMAND_NAME,
303
            $arguments,
304
            $expectedExitCode,
305
            $psalmResults
306
        );
307
308
        $output = str_replace('\/', '/', $output);
309
310
        $this->assertStringContainsString($expectedResultsJson, $output);
311
    }
312
313
    /**
314
     * @param array<string, string|null> $arguments
315
     */
316
    private function runCommand(
317
        string $commandName,
318
        array $arguments,
319
        int $expectedExitCode,
320
        ?string $resourceContainStdinContents
321
    ): string {
322
        $command = $this->application->find($commandName);
323
        $commandTester = new CommandTester($command);
324
        $arguments['command'] = $command->getName();
325
326
        if (null !== $resourceContainStdinContents) {
327
            $stdin = $this->getStaticAnalysisResultsAsString($resourceContainStdinContents);
328
            $commandTester->setInputs([$stdin]);
329
        }
330
331
        $actualExitCode = $commandTester->execute($arguments);
332
        $output = $commandTester->getDisplay();
333
        $this->assertEquals($expectedExitCode, $actualExitCode, $output);
334
335
        return $output;
336
    }
337
338
    private function getBaselineFilePath(): string
339
    {
340
        return "{$this->projectRoot}/baseline.json";
341
    }
342
343
    private function removeTestDirectory(): void
344
    {
345
        $this->fileSystem->remove((string) $this->projectRoot);
346
    }
347
348
    private function getStaticAnalysisResultsAsString(string $resourceName): string
349
    {
350
        $fileName = __DIR__.'/../resources/integration/staticAnalysisOutput/'.$resourceName;
351
        $rawResults = file_get_contents($fileName);
352
        $this->assertNotFalse($rawResults);
353
        $projectRootDirectory = (string) $this->projectRoot;
354
        $resultsWithPathsCorrected = str_replace('__SCRATCH_PAD_PATH__', $projectRootDirectory, $rawResults);
355
356
        return $resultsWithPathsCorrected;
357
    }
358
359
    private function getProjectRootFilename(string $resourceName): string
360
    {
361
        return $this->projectRoot->getAbsoluteFileName(new RelativeFileName($resourceName))->getFileName();
362
    }
363
364
    private function updatePathsInJsonFiles(ProjectRoot $projectRoot): void
365
    {
366
        $directory = $projectRoot->getProjectRootDirectory();
367
368
        $files = scandir($directory);
369
        $this->assertNotFalse($files);
370
        foreach ($files as $file) {
371
            if (StringUtils::endsWith('.json', $file)) {
372
                $fullPath = Path::makeAbsolute($file, $directory);
373
                $contents = file_get_contents($fullPath);
374
                $this->assertNotFalse($contents);
375
                $newContents = str_replace('__SCRATCH_PAD_PATH__', $directory, $contents);
376
                file_put_contents($fullPath, $newContents);
377
            }
378
        }
379
    }
380
381
    private function addNonCheckedInFile(): void
382
    {
383
        // Add a new file that is not checked in
384
        $relativeFileName = new RelativeFileName('new.php');
385
        $absoluteFileName = $this->projectRoot->getAbsoluteFileName($relativeFileName);
386
        $this->fileSystem->dumpFile($absoluteFileName->getFileName(), 'new');
387
        var_dump($absoluteFileName->getFileName());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($absoluteFileName->getFileName()) looks like debug code. Are you sure you do not want to remove it?
Loading history...
388
    }
389
}
390