diff --git a/AGENTS.md b/AGENTS.md index 2cc65d4..306faa7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -128,3 +128,75 @@ tests/Sniffs/Generic.Files/LineLength/ - Second line: Comment explaining test (e.g., `// Test: lineLimit=120`) - Use tabs for indentation - Include code that exercises the specific parameter being tested + +## Issue Testing + +Issue tests validate that specific GitHub issues are properly handled. These tests are located in `tests/Issue/{number}/`. + +### Creating Issue Tests + +1. **Create issue directory**: `tests/Issue/{number}/` +2. **Create test files**: + - `good.php` - Code that should pass without errors (regression test) + - `good.ruleset.xml` - Ruleset with relevant sniffs + - Optionally: `bad.php` / `bad.ruleset.xml` for cases that should produce errors +3. **Regenerate snapshots**: `php bin/snapshots --issues` or `php bin/snapshots --issue={number}` +4. **Run tests**: `make tests` + +**Example issue test structure:** + +``` +tests/Issue/19/ +├── good.php # Code demonstrating the fix works +├── good.ruleset.xml # Ruleset with relevant sniffs +└── good.snapshot.json # Expected output (0 errors for good.php) +``` + +**Example good.php:** + +```php + + + + + + + +``` + +**Commands for issue testing:** + +```bash +# Generate all issue snapshots +php bin/snapshots --issues + +# Generate specific issue snapshot +php bin/snapshots --issue=19 + +# Test code manually against an issue ruleset +vendor/bin/phpcs --standard=tests/Issue/19/good.ruleset.xml tests/Issue/19/good.php +``` diff --git a/bin/snapshots b/bin/snapshots index a1825c9..f1a553f 100755 --- a/bin/snapshots +++ b/bin/snapshots @@ -9,6 +9,8 @@ * php bin/snapshots --set=8.0 # Generate only set 8.0 * php bin/snapshots --sniffs # Generate only sniff snapshots * php bin/snapshots --sniff=Generic.Arrays.DisallowLongArraySyntax + * php bin/snapshots --issues # Generate only issue snapshots + * php bin/snapshots --issue=19 # Generate only specific issue snapshot */ $rootDir = dirname(__DIR__); @@ -23,8 +25,10 @@ use Tests\Toolkit\Codesniffer; // Parse CLI arguments $filterSet = null; $filterSniff = null; +$filterIssue = null; $sniffsOnly = false; $setsOnly = false; +$issuesOnly = false; foreach ($argv as $arg) { if (str_starts_with($arg, '--set=')) { @@ -37,6 +41,11 @@ foreach ($argv as $arg) { $sniffsOnly = true; } + if (str_starts_with($arg, '--issue=')) { + $filterIssue = substr($arg, 8); + $issuesOnly = true; + } + if ($arg === '--sniffs') { $sniffsOnly = true; } @@ -44,13 +53,17 @@ foreach ($argv as $arg) { if ($arg === '--sets') { $setsOnly = true; } + + if ($arg === '--issues') { + $issuesOnly = true; + } } // ============================================================================ // Part 1: Generate Set Snapshots // ============================================================================ -if (!$sniffsOnly) { +if (!$sniffsOnly && !$issuesOnly) { $setsDir = $rootDir . '/tests/Sets'; echo "=== Generating Set Snapshots ===\n\n"; @@ -126,7 +139,7 @@ if (!$sniffsOnly) { // Part 2: Generate Sniff Snapshots // ============================================================================ -if (!$setsOnly) { +if (!$setsOnly && !$issuesOnly) { $sniffsDir = $rootDir . '/tests/Sniffs'; echo "\n=== Generating Sniff Snapshots ===\n\n"; @@ -196,4 +209,71 @@ if (!$setsOnly) { echo "\nSniff snapshots: {$generated} generated.\n"; } +// ============================================================================ +// Part 3: Generate Issue Snapshots +// ============================================================================ + +if (!$setsOnly && !$sniffsOnly) { + $issuesDir = $rootDir . '/tests/Issue'; + + echo "\n=== Generating Issue Snapshots ===\n\n"; + + $generated = 0; + + if (is_dir($issuesDir)) { + // Find all issue directories (e.g., 19) + foreach (Finder::findDirectories('*')->in($issuesDir) as $issueDir) { + $issueName = $issueDir->getBasename(); + + if ($filterIssue !== null && $filterIssue !== $issueName) { + continue; + } + + // Find all PHP test files in the issue directory + foreach (Finder::findFiles('*.php')->in($issueDir->getPathname()) as $phpFile) { + $baseName = $phpFile->getBasename('.php'); + $snapshotPath = $issueDir->getPathname() . '/' . $baseName . '.snapshot.json'; + $rulesetPath = $issueDir->getPathname() . '/' . $baseName . '.ruleset.xml'; + + if (!file_exists($rulesetPath)) { + echo "Warning: Ruleset not found: {$rulesetPath}\n"; + + continue; + } + + $process = new Process([ + 'vendor/bin/phpcs', + '--standard=' . $rulesetPath, + '--report=json', + '-q', + $phpFile->getPathname(), + ], $rootDir); + $process->run(); + + $data = json_decode($process->getOutput(), true); + + if ($data === null) { + echo "Error: Failed to parse phpcs output for Issue/{$issueName}/{$baseName}.php\n"; + + continue; + } + + $normalized = Codesniffer::normalize($data); + $json = json_encode($normalized, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; + + file_put_contents($snapshotPath, $json); + + $errorCount = $normalized['totals']['errors']; + $warningCount = $normalized['totals']['warnings']; + echo "Generated: Issue/{$issueName}/{$baseName}.snapshot.json ({$errorCount} errors, {$warningCount} warnings)\n"; + $generated++; + } + } + } else { + echo "No Issue directory found.\n"; + } + + echo "\nIssue snapshots: {$generated} generated.\n"; +} + echo "\nDone!\n"; diff --git a/tests/Issue/19/good.php b/tests/Issue/19/good.php new file mode 100644 index 0000000..6ea19b4 --- /dev/null +++ b/tests/Issue/19/good.php @@ -0,0 +1,51 @@ + + */ + public static function values(): array + { + return array_column(self::cases(), 'value'); + } + +} + +trait EnumNames +{ + + /** + * @return array + */ + public static function names(): array + { + return array_column(self::cases(), 'name'); + } + +} + +enum ImageTransform: int +{ + + use EnumValues; + use EnumNames; + + case Fit = 1; + + case Exact = 2; + + case Fill = 3; + + case Stretch = 4; + + case Shrink = 5; + +} diff --git a/tests/Issue/19/good.ruleset.xml b/tests/Issue/19/good.ruleset.xml new file mode 100644 index 0000000..af44b67 --- /dev/null +++ b/tests/Issue/19/good.ruleset.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Issue/19/good.snapshot.json b/tests/Issue/19/good.snapshot.json new file mode 100644 index 0000000..c963db6 --- /dev/null +++ b/tests/Issue/19/good.snapshot.json @@ -0,0 +1,13 @@ +{ + "totals": { + "errors": 0, + "warnings": 0 + }, + "files": { + "good.php": { + "errors": 0, + "warnings": 0, + "messages": [] + } + } +}