Skip to content

Instantly share code, notes, and snippets.

@zonuexe
Created November 19, 2019 13:14
Show Gist options
  • Save zonuexe/2fd33134556c355ee4ea3d26282a5277 to your computer and use it in GitHub Desktop.
Save zonuexe/2fd33134556c355ee4ea3d26282a5277 to your computer and use it in GitHub Desktop.
リフレクションを使った正規表現のためのDocTest
<?php
namespace PixivTest\Util\RegexPattern;
/**
* 正規表現のためのDocTest
*
* {@see \Util_RegexPattern} クラスの定数定義ごとに正規表現をテストする。
*
* ## 記法
*
* 正規表現が受理する文字列 `@regex\expected` と、受理しない文字列 `@regex\unexpected` の
* 二種類のタグを利用する。タグは必ず1行に収まるように記述しなければいけない。
* タグ中に改行を書くことはできないので、そのような文字列を受理する正規表現を書く場合は
* DocTestではなく、別途ユニットテストを書いて対応すること。
*
* @regex\expected aaaaaaa
* @regex\expected bbbbbbb //←ここから行末までは説明
* @regex\expected cccc //←余分な空白をトリムしない("cccc "が検査対象)ので注意
*/
final class DocCommentTest extends \PixivLibTestCase
{
/**
* @group doctest
* @dataProvider dataProvider_test
*/
public function test($name, \ReflectionClassConstant $constant, $expected, $subject, $describe)
{
$pattern = $constant->getValue();
// TODO: もし必要になることがあったら配列向けにも実装する
if (!is_string($pattern)) {
throw new \PxvException('このDocTestは配列は未実装です');
}
// preg_match() の返り値(0, 1) に変換する
$expected_value = ['expected' => 1, 'unexpected' => 0][$expected];
$this->assertSame($expected_value, preg_match($pattern, $subject), $describe);
}
/**
* ジェネレータを使ったデータプロバイダ
*
* 配列を返すのではなく、DocCommentのパースを継続しながら yield でデータセットを返す
*
* @see http://php.net/manual/language.generators.overview.php ジェネレータ
*/
public function dataProvider_test()
{
$ref = new \ReflectionClass(\Util_RegexPattern::class);
foreach ($ref->getReflectionConstants() as $constant) {
$lines = $constant->getDocComment();
if ($lines === false) {
continue;
}
foreach (explode("\n", $lines) as $line) {
$test = self::_getDocTest($constant, $line);
if ($test) {
yield $test;
}
}
}
}
/**
* DocCommentの行から @regex\expected, unexpected のテスト行を取得する
*
* @param \ReflectionClassConstant $ref
* @param string $input
* @return array|false
*/
private static function _getDocTest(\ReflectionClassConstant $ref, $input)
{
if (!preg_match('#\* @regex\\\\(?<type>expected|unexpected) (?<subject>.+?)(?<describe>(?: //[^/]+?)?)$#', $input, $m)) {
return false;
}
return [
$ref->getName(),
$ref,
$m['type'],
$m['subject'],
ltrim($m['describe'], ' //'),
];
}
}
<?php
final class Util_RegexPattern
{
/**
* @regex\expected ああああ
* @regex\expected ゑeeeeee
* @regex\unexpected xxxxxx
*/
const HIRAGANA_START = '/^[ぁ-ん]/u';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment