Skip to content

Commit 7342c00

Browse files
Adding approval tests for the console output to detect changes (#47)
* Approval testing setup * Fixing the config usage in the text renderer * Adding more tests * Attempt to fix the file order * Refactor DirectoryScanner to improve file collection and sorting - Extracted file collection and sorting logic into separate methods for better readability and maintainability. - Added `getFilesFromIterator` method to handle file collection with exclusion filters. - Introduced `sortFilesByPathname` method to ensure consistent file order across platforms.
1 parent f9000e8 commit 7342c00

23 files changed

+625
-31
lines changed

src/Application.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ private function registerServices(): void
9090

9191
$this->containerBuilder->register(CognitiveMetricTextRendererInterface::class, CognitiveMetricTextRenderer::class)
9292
->setArguments([
93-
new Reference(OutputInterface::class),
9493
new Reference(ConfigService::class)
9594
])
9695
->setPublic(true);

src/Business/Cognitive/CognitiveMetricsCollector.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,19 @@ private function findMetrics(iterable $files): CognitiveMetricsCollection
9898
continue;
9999
}
100100

101+
$filename = $file->getRealPath();
102+
103+
if (getenv('APP_ENV') === 'test') {
104+
$projectRoot = $this->getProjectRoot();
105+
if ($projectRoot && str_starts_with($filename, $projectRoot)) {
106+
$filename = substr($filename, strlen($projectRoot) + 1);
107+
}
108+
}
109+
101110
$metricsCollection = $this->processMethodMetrics(
102111
$metrics,
103112
$metricsCollection,
104-
$file->getRealPath()
113+
$filename
105114
);
106115

107116
$this->messageBus->dispatch(new FileProcessed(
@@ -202,4 +211,24 @@ public function getIgnoredMethods(): array
202211
{
203212
return $this->ignoredItems['methods'] ?? [];
204213
}
214+
215+
/**
216+
* Get the project root directory path.
217+
*
218+
* @return string|null The project root path or null if not found
219+
*/
220+
private function getProjectRoot(): ?string
221+
{
222+
// Start from the current file's directory and traverse up to find composer.json
223+
$currentDir = __DIR__;
224+
225+
while ($currentDir !== dirname($currentDir)) {
226+
if (file_exists($currentDir . DIRECTORY_SEPARATOR . 'composer.json')) {
227+
return $currentDir;
228+
}
229+
$currentDir = dirname($currentDir);
230+
}
231+
232+
return null;
233+
}
205234
}

src/Business/DirectoryScanner.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,44 @@ private function traverseDirectory(string $directory, array $exclude): Generator
8181
RecursiveIteratorIterator::LEAVES_ONLY
8282
);
8383

84+
$files = $this->getFilesFromIterator($iterator, $exclude);
85+
$this->sortFilesByPathname($files);
86+
87+
// Yield sorted files
88+
foreach ($files as $fileInfo) {
89+
yield $fileInfo;
90+
}
91+
}
92+
93+
/**
94+
* Sort files by their pathname to ensure consistent order across platforms.
95+
*
96+
* @param array<SplFileInfo> $files Array of SplFileInfo objects to sort
97+
*/
98+
private function sortFilesByPathname(array &$files): void
99+
{
100+
usort($files, function (SplFileInfo $alpha, SplFileInfo $beta) {
101+
return strcmp($alpha->getPathname(), $beta->getPathname());
102+
});
103+
}
104+
105+
/**
106+
* Collect files from an iterator, applying exclusion filters.
107+
*
108+
* @param \Iterator<SplFileInfo> $iterator Iterator to collect files from
109+
* @param array<string> $exclude Array of regex patterns to exclude files
110+
* @return array<SplFileInfo> Array of SplFileInfo objects
111+
*/
112+
private function getFilesFromIterator(\Iterator $iterator, array $exclude): array
113+
{
114+
$files = [];
84115
foreach ($iterator as $fileInfo) {
85116
if ($fileInfo->isFile() && !$this->isExcluded($fileInfo, $exclude)) {
86-
yield $fileInfo;
117+
$files[] = $fileInfo;
87118
}
88119
}
120+
121+
return $files;
89122
}
90123

91124
/**

src/Command/CognitiveMetricsCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
142142
return $this->reportHandler->handle($metricsCollection, $reportType, $reportFile);
143143
}
144144

145-
$this->renderer->render($metricsCollection);
145+
$this->renderer->render($metricsCollection, $output);
146146

147147
return Command::SUCCESS;
148148
}

src/Command/Presentation/CognitiveMetricSummaryTextRenderer.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616
class CognitiveMetricSummaryTextRenderer implements CognitiveMetricTextRendererInterface
1717
{
1818
public function __construct(
19-
private readonly OutputInterface $output,
2019
private readonly ConfigService $configService,
2120
) {
2221
}
2322

24-
public function render(CognitiveMetricsCollection $metricsCollection): void
23+
public function render(CognitiveMetricsCollection $metricsCollection, OutputInterface $output): void
2524
{
2625
$highlighted = [];
2726
foreach ($metricsCollection as $metric) {
@@ -35,9 +34,9 @@ public function render(CognitiveMetricsCollection $metricsCollection): void
3534
static fn (CognitiveMetrics $alpha, CognitiveMetrics $beta) => $beta->getScore() <=> $alpha->getScore()
3635
);
3736

38-
$this->output->writeln('<info>Most Complex Methods</info>');
37+
$output->writeln('<info>Most Complex Methods</info>');
3938

40-
$table = new Table($this->output);
39+
$table = new Table($output);
4140
$table->setStyle('box');
4241
$table->setHeaders(['Method', 'Score']);
4342

@@ -51,6 +50,6 @@ public function render(CognitiveMetricsCollection $metricsCollection): void
5150
}
5251

5352
$table->render();
54-
$this->output->writeln('');
53+
$output->writeln('');
5554
}
5655
}

src/Command/Presentation/CognitiveMetricTextRenderer.php

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,9 @@ class CognitiveMetricTextRenderer implements CognitiveMetricTextRendererInterfac
2525
private TableHeaderBuilder $headerBuilder;
2626

2727
public function __construct(
28-
private readonly OutputInterface $output,
2928
private readonly ConfigService $configService,
3029
) {
31-
$config = $this->configService->getConfig();
32-
$this->formatter = new MetricFormatter($config);
33-
$this->rowBuilder = new TableRowBuilder($this->formatter, $config);
34-
$this->headerBuilder = new TableHeaderBuilder($config);
30+
// Don't initialize components here - they'll be created with current config when rendering
3531
}
3632

3733
private function metricExceedsThreshold(CognitiveMetrics $metric, CognitiveConfig $config): bool
@@ -43,26 +39,33 @@ private function metricExceedsThreshold(CognitiveMetrics $metric, CognitiveConfi
4339

4440
/**
4541
* @param CognitiveMetricsCollection $metricsCollection
42+
* @param OutputInterface $output
4643
* @throws CognitiveAnalysisException
4744
*/
48-
public function render(CognitiveMetricsCollection $metricsCollection): void
45+
public function render(CognitiveMetricsCollection $metricsCollection, OutputInterface $output): void
4946
{
5047
$config = $this->configService->getConfig();
5148

49+
// Recreate components with current configuration
50+
$this->formatter = new MetricFormatter($config);
51+
$this->rowBuilder = new TableRowBuilder($this->formatter, $config);
52+
$this->headerBuilder = new TableHeaderBuilder($config);
53+
5254
if ($config->groupByClass) {
53-
$this->renderGroupedByClass($metricsCollection, $config);
55+
$this->renderGroupedByClass($metricsCollection, $config, $output);
5456
return;
5557
}
5658

57-
$this->renderAllMethodsInSingleTable($metricsCollection, $config);
59+
$this->renderAllMethodsInSingleTable($metricsCollection, $config, $output);
5860
}
5961

6062
/**
6163
* @param CognitiveMetricsCollection $metricsCollection
6264
* @param CognitiveConfig $config
65+
* @param OutputInterface $output
6366
* @throws CognitiveAnalysisException
6467
*/
65-
private function renderGroupedByClass(CognitiveMetricsCollection $metricsCollection, CognitiveConfig $config): void
68+
private function renderGroupedByClass(CognitiveMetricsCollection $metricsCollection, CognitiveConfig $config, OutputInterface $output): void
6669
{
6770
$groupedByClass = $metricsCollection->groupBy('class');
6871

@@ -74,7 +77,7 @@ private function renderGroupedByClass(CognitiveMetricsCollection $metricsCollect
7477
$rows = $this->buildRowsForClass($metrics, $config);
7578
if (count($rows) > 0) {
7679
$filename = $this->getFilenameFromMetrics($metrics);
77-
$this->renderTable((string)$className, $rows, $filename);
80+
$this->renderTable((string)$className, $rows, $filename, $output);
7881
}
7982
}
8083
}
@@ -110,15 +113,16 @@ private function getFilenameFromMetrics(CognitiveMetricsCollection $metrics): st
110113
/**
111114
* @param CognitiveMetricsCollection $metricsCollection
112115
* @param CognitiveConfig $config
116+
* @param OutputInterface $output
113117
* @throws CognitiveAnalysisException
114118
*/
115-
private function renderAllMethodsInSingleTable(CognitiveMetricsCollection $metricsCollection, CognitiveConfig $config): void
119+
private function renderAllMethodsInSingleTable(CognitiveMetricsCollection $metricsCollection, CognitiveConfig $config, OutputInterface $output): void
116120
{
117121
$rows = $this->buildRowsForSingleTable($metricsCollection, $config);
118122
$totalMethods = count($rows);
119123

120124
if ($totalMethods > 0) {
121-
$this->renderSingleTable($rows, $totalMethods);
125+
$this->renderSingleTable($rows, $totalMethods, $output);
122126
}
123127
}
124128

@@ -143,38 +147,40 @@ private function buildRowsForSingleTable(CognitiveMetricsCollection $metricsColl
143147
* @param string $className
144148
* @param array<int, mixed> $rows
145149
* @param string $filename
150+
* @param OutputInterface $output
146151
*/
147-
private function renderTable(string $className, array $rows, string $filename): void
152+
private function renderTable(string $className, array $rows, string $filename, OutputInterface $output): void
148153
{
149-
$table = new Table($this->output);
154+
$table = new Table($output);
150155
$table->setStyle('box');
151156
$table->setHeaders($this->getTableHeaders());
152157

153-
$this->output->writeln("<info>Class: $className</info>");
154-
$this->output->writeln("<info>File: $filename</info>");
158+
$output->writeln("<info>Class: $className</info>");
159+
$output->writeln("<info>File: $filename</info>");
155160

156161
$table->setRows($rows);
157162
$table->render();
158163

159-
$this->output->writeln("");
164+
$output->writeln("");
160165
}
161166

162167
/**
163168
* @param array<int, mixed> $rows
164169
* @param int $totalMethods
170+
* @param OutputInterface $output
165171
*/
166-
private function renderSingleTable(array $rows, int $totalMethods): void
172+
private function renderSingleTable(array $rows, int $totalMethods, OutputInterface $output): void
167173
{
168-
$table = new Table($this->output);
174+
$table = new Table($output);
169175
$table->setStyle('box');
170176
$table->setHeaders($this->getSingleTableHeaders());
171177

172-
$this->output->writeln("<info>All Methods ($totalMethods total)</info>");
178+
$output->writeln("<info>All Methods ($totalMethods total)</info>");
173179

174180
$table->setRows($rows);
175181
$table->render();
176182

177-
$this->output->writeln("");
183+
$output->writeln("");
178184
}
179185

180186
/**

src/Command/Presentation/CognitiveMetricTextRendererInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Phauthentic\CognitiveCodeAnalysis\Business\Cognitive\CognitiveMetricsCollection;
88
use Phauthentic\CognitiveCodeAnalysis\CognitiveAnalysisException;
9+
use Symfony\Component\Console\Output\OutputInterface;
910

1011
/**
1112
*
@@ -14,7 +15,8 @@ interface CognitiveMetricTextRendererInterface
1415
{
1516
/**
1617
* @param CognitiveMetricsCollection $metricsCollection
18+
* @param OutputInterface $output
1719
* @throws CognitiveAnalysisException
1820
*/
19-
public function render(CognitiveMetricsCollection $metricsCollection): void;
21+
public function render(CognitiveMetricsCollection $metricsCollection, OutputInterface $output): void;
2022
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cognitive:
2+
excludeFilePatterns:
3+
excludePatterns:
4+
scoreThreshold: 0.5
5+
showOnlyMethodsExceedingThreshold: false
6+
showHalsteadComplexity: true
7+
showCyclomaticComplexity: true
8+
showDetailedCognitiveMetrics: true
9+
groupByClass: true
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cognitive:
2+
excludeFilePatterns:
3+
excludePatterns:
4+
scoreThreshold: 0.5
5+
showOnlyMethodsExceedingThreshold: false
6+
showHalsteadComplexity: false
7+
showCyclomaticComplexity: true
8+
showDetailedCognitiveMetrics: true
9+
groupByClass: true
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cognitive:
2+
excludeFilePatterns:
3+
excludePatterns:
4+
scoreThreshold: 0.5
5+
showOnlyMethodsExceedingThreshold: false
6+
showHalsteadComplexity: true
7+
showCyclomaticComplexity: false
8+
showDetailedCognitiveMetrics: true
9+
groupByClass: true

0 commit comments

Comments
 (0)