Created
September 15, 2023 13:02
-
-
Save inxilpro/0c295cf11e09f371bf2cc32e426a65cd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests\Project; | |
use RecursiveCallbackFilterIterator; | |
use RecursiveDirectoryIterator; | |
use RecursiveIteratorIterator; | |
use SplFileInfo; | |
use Tests\Constraints; | |
use Tests\TestCase; | |
class FixMeTest extends TestCase | |
{ | |
protected $exclude = [ | |
'.git', | |
'.idea', | |
'docs', | |
'node_modules', | |
'public', | |
'storage', | |
'vendor', | |
'tests/Project/FixMeTest.php', | |
'tests/Constraints/HasNoFixmes.php', | |
]; | |
protected $extensions = [ | |
'.php', | |
'.blade.php', | |
'.js', | |
'.jsx', | |
'.less', | |
]; | |
protected $baseDirectory; | |
protected function setUp(): void | |
{ | |
parent::setUp(); | |
foreach ($this->exclude as $key => $value) { | |
$this->exclude[$key] = $this->app->basePath($value); | |
} | |
} | |
public function test_project_has_no_fixme_comments(): void | |
{ | |
$directory_iterator = new RecursiveDirectoryIterator( | |
$this->app->basePath(), | |
RecursiveDirectoryIterator::SKIP_DOTS | |
); | |
$filtered_iterator = new RecursiveIteratorIterator( | |
new RecursiveCallbackFilterIterator($directory_iterator, function(SplFileInfo $file, $key, RecursiveDirectoryIterator $iterator) { | |
// Exclude root directories | |
if (starts_with($file->getPathname(), $this->exclude)) { | |
return false; | |
} | |
// Allow iteration | |
if ($iterator->hasChildren()) { | |
return true; | |
} | |
// Only include our file types | |
if (! ends_with($file->getFilename(), $this->extensions)) { | |
return false; | |
} | |
return $file->isFile(); | |
}) | |
); | |
$this->assertThat($filtered_iterator, new Constraints\HasNoFixmes($this->app->basePath())); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests\Constraints; | |
use PHPUnit\Framework\Constraint\Constraint; | |
class HasNoFixmes extends Constraint | |
{ | |
protected $base_path; | |
protected $fixme_comments = []; | |
protected $ran = false; | |
public function __construct(string $base_path) | |
{ | |
$this->base_path = $base_path; | |
} | |
public function toString(): string | |
{ | |
return 'has no FIXME comments'; | |
} | |
protected function matches($iterator): bool | |
{ | |
if (! $this->ran) { | |
foreach ($iterator as $pathname => $file_info) { | |
$content = file_get_contents($pathname); | |
if (stripos($content, 'fixme') === false) { | |
continue; | |
} | |
$comments = stripos($pathname, '.php') === false | |
? $this->readGenericComments($content) | |
: $this->readPhpComments($content); | |
if (count($comments)) { | |
$this->fixme_comments[$pathname] = (object) [ | |
'filename' => str_replace($this->base_path, '', $pathname), | |
'comments' => $comments, | |
]; | |
} | |
} | |
$this->ran = true; | |
} | |
return empty($this->fixme_comments); | |
} | |
protected function readPhpComments(string $code): array | |
{ | |
$tokens = token_get_all($code); | |
return collect($tokens) | |
->filter(function($token) { | |
return is_array($token); | |
}) | |
->map(function($token) { | |
return (object) [ | |
'type' => $token[0], | |
'source_code' => $token[1], | |
'line_number' => $token[2], | |
]; | |
}) | |
->filter(function($token) { | |
return T_COMMENT === $token->type || T_DOC_COMMENT === $token->type; | |
}) | |
->filter(function($token) { | |
return stripos($token->source_code, 'fixme') !== false; | |
}) | |
->map(function($token) { | |
$trim_syntax = '~(^\s*(?://\s?|/\*\s?|\*\s)|\*/\s*$|FIXME:?\s?)~m'; | |
$comment = trim(preg_replace($trim_syntax, '', $token->source_code)); | |
return (object) [ | |
'line_number' => $token->line_number, | |
'comment' => $comment, | |
]; | |
}) | |
->toArray(); | |
} | |
protected function readGenericComments(string $code): array | |
{ | |
return collect(explode(PHP_EOL, $code)) | |
->map(function($code, $line_number) { | |
return (object) [ | |
'source_code' => (string) $code, | |
'line_number' => $line_number, | |
]; | |
}) | |
->filter(function($line) { | |
return stripos($line->source_code, 'fixme') !== false; | |
}) | |
->map(function($line) { | |
$trim_syntax = '~(^\s*(?://\s?|/\*\s?|\*\s)|\*/\s*$|FIXME:?\s?)~m'; | |
$comment = trim(preg_replace($trim_syntax, '', $line->source_code)); | |
return (object) [ | |
'line_number' => $line->line_number, | |
'comment' => (string) $comment, | |
]; | |
}) | |
->toArray(); | |
} | |
protected function failureDescription($other): string | |
{ | |
return 'the project has no FIXME comments'; | |
} | |
protected function additionalFailureDescription($other): string | |
{ | |
return collect($this->fixme_comments) | |
->map(function($file) { | |
$comments = collect($file->comments) | |
->map(function($comment) { | |
$text = str_replace("\n", ' ', trim($comment->comment)); | |
return empty($text) | |
? "Line {$comment->line_number}" | |
: "{$comment->line_number}: {$text}"; | |
}); | |
if (1 === count($comments)) { | |
return " - {$file->filename}: {$comments->first()}"; | |
} | |
return " - {$file->filename}\n + ".$comments->implode("\n + "); | |
}) | |
->implode("\n"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment