assertFalse($regex->apply("Hello", $match));
$this->assertEquals($match, "");
}
function testNoSubject() {
$regex = new ParallelRegex(false);
$regex->addPattern(".*");
$this->assertTrue($regex->apply("", $match));
$this->assertEquals($match, "");
}
function testMatchAll() {
$regex = new ParallelRegex(false);
$regex->addPattern(".*");
$this->assertTrue($regex->apply("Hello", $match));
$this->assertEquals($match, "Hello");
}
function testCaseSensitive() {
$regex = new ParallelRegex(true);
$regex->addPattern("abc");
$this->assertTrue($regex->apply("abcdef", $match));
$this->assertEquals($match, "abc");
$this->assertTrue($regex->apply("AAABCabcdef", $match));
$this->assertEquals($match, "abc");
}
function testCaseInsensitive() {
$regex = new ParallelRegex(false);
$regex->addPattern("abc");
$this->assertTrue($regex->apply("abcdef", $match));
$this->assertEquals($match, "abc");
$this->assertTrue($regex->apply("AAABCabcdef", $match));
$this->assertEquals($match, "ABC");
}
function testMatchMultiple() {
$regex = new ParallelRegex(true);
$regex->addPattern("abc");
$regex->addPattern("ABC");
$this->assertTrue($regex->apply("abcdef", $match));
$this->assertEquals($match, "abc");
$this->assertTrue($regex->apply("AAABCabcdef", $match));
$this->assertEquals($match, "ABC");
$this->assertFalse($regex->apply("Hello", $match));
}
function testPatternLabels() {
$regex = new ParallelRegex(false);
$regex->addPattern("abc", "letter");
$regex->addPattern("123", "number");
$this->assertEquals($regex->apply("abcdef", $match), "letter");
$this->assertEquals($match, "abc");
$this->assertEquals($regex->apply("0123456789", $match), "number");
$this->assertEquals($match, "123");
}
function testMatchMultipleWithLookaheadNot() {
$regex = new ParallelRegex(true);
$regex->addPattern("abc");
$regex->addPattern("ABC");
$regex->addPattern("a(?!\n).{1}");
$this->assertTrue($regex->apply("abcdef", $match));
$this->assertEquals($match, "abc");
$this->assertTrue($regex->apply("AAABCabcdef", $match));
$this->assertEquals($match, "ABC");
$this->assertTrue($regex->apply("a\nab", $match));
$this->assertEquals($match, "ab");
$this->assertFalse($regex->apply("Hello", $match));
}
function testMatchSetOptionCaseless() {
$regex = new ParallelRegex(true);
$regex->addPattern("a(?i)b(?i)c");
$this->assertTrue($regex->apply("aBc", $match));
$this->assertEquals($match, "aBc");
}
function testMatchSetOptionUngreedy() {
$regex = new ParallelRegex(true);
$regex->addPattern("(?U)\w+");
$this->assertTrue($regex->apply("aaaaaa", $match));
$this->assertEquals($match, "a");
}
function testMatchLookaheadEqual() {
$regex = new ParallelRegex(true);
$regex->addPattern("\w(?=c)");
$this->assertTrue($regex->apply("xbyczd", $match));
$this->assertEquals($match, "y");
}
function testMatchLookaheadNot() {
$regex = new ParallelRegex(true);
$regex->addPattern("\w(?!b|c)");
$this->assertTrue($regex->apply("xbyczd", $match));
$this->assertEquals($match, "b");
}
function testMatchLookbehindEqual() {
$regex = new ParallelRegex(true);
$regex->addPattern("(?<=c)\w");
$this->assertTrue($regex->apply("xbyczd", $match));
$this->assertEquals($match, "z");
}
function testMatchLookbehindNot() {
$regex = new ParallelRegex(true);
$regex->addPattern("(?assertTrue($regex->apply("xbyczd", $match));
$this->assertEquals($match, "c");
}
}
class TestOfLexerStateStack extends DokuWikiTest {
function testStartState() {
$stack = new StateStack("one");
$this->assertEquals($stack->getCurrent(), "one");
}
function testExhaustion() {
$stack = new StateStack("one");
$this->assertFalse($stack->leave());
}
function testStateMoves() {
$stack = new StateStack("one");
$stack->enter("two");
$this->assertEquals($stack->getCurrent(), "two");
$stack->enter("three");
$this->assertEquals($stack->getCurrent(), "three");
$this->assertTrue($stack->leave());
$this->assertEquals($stack->getCurrent(), "two");
$stack->enter("third");
$this->assertEquals($stack->getCurrent(), "third");
$this->assertTrue($stack->leave());
$this->assertTrue($stack->leave());
$this->assertEquals($stack->getCurrent(), "one");
}
}
class TestParser {
function __construct() {
}
function accept() {
}
function a() {
}
function b() {
}
}
class TestOfLexer extends DokuWikiTest {
function testNoPatterns() {
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
$lexer = new Lexer($handler);
$this->assertFalse($lexer->parse("abcdef"));
}
function testEmptyPage() {
$handler = $this->createMock('TestParser');
$handler->expects($this->never())->method('accept');
$lexer = new Lexer($handler);
$lexer->addPattern("a+");
$this->assertTrue($lexer->parse(""));
}
function testSinglePattern() {
$acceptArguments = [
["aaa", DOKU_LEXER_MATCHED, 0],
["x", DOKU_LEXER_UNMATCHED, 3],
["a", DOKU_LEXER_MATCHED, 4],
["yyy", DOKU_LEXER_UNMATCHED, 5],
["a", DOKU_LEXER_MATCHED, 8],
["x", DOKU_LEXER_UNMATCHED, 9],
["aaa", DOKU_LEXER_MATCHED, 10],
["z", DOKU_LEXER_UNMATCHED, 13],
];
$acceptArgumentCount = count($acceptArguments);
$handler = $this->createMock('TestParser');
$handler
->expects($this->exactly($acceptArgumentCount))
->method('accept')
->withConsecutive(...$acceptArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $acceptArgumentCount, true));
$lexer = new Lexer($handler);
$lexer->addPattern("a+");
$this->assertTrue($lexer->parse("aaaxayyyaxaaaz"));
}
function testMultiplePattern() {
$acceptArguments = [
["a", $this->anything(), 0],
["b", $this->anything(), 1],
["a", $this->anything(), 2],
["bb", $this->anything(), 3],
["x", $this->anything(), 5],
["b", $this->anything(), 6],
["a", $this->anything(), 7],
["xxxxxx", $this->anything(), 8],
["a", $this->anything(), 14],
["x", $this->anything(), 15],
];
$acceptArgumentCount = count($acceptArguments);
$handler = $this->createPartialMock('TestParser', ['accept']);
$handler
->expects($this->exactly($acceptArgumentCount))
->method('accept')
->withConsecutive(...$acceptArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $acceptArgumentCount, true));
$lexer = new Lexer($handler);
$lexer->addPattern("a+");
$lexer->addPattern("b+");
$this->assertTrue($lexer->parse("ababbxbaxxxxxxax"));
}
}
class TestOfLexerModes extends DokuWikiTest {
function testIsolatedPattern() {
$aArguments = [
["a", DOKU_LEXER_MATCHED, 0],
["b", DOKU_LEXER_UNMATCHED, 1],
["aa", DOKU_LEXER_MATCHED, 2],
["bxb", DOKU_LEXER_UNMATCHED, 4],
["aaa", DOKU_LEXER_MATCHED, 7],
["x", DOKU_LEXER_UNMATCHED, 10],
["aaaa", DOKU_LEXER_MATCHED, 11],
["x", DOKU_LEXER_UNMATCHED, 15],
];
$aArgumentCount = count($aArguments);
$handler = $this->createMock('TestParser');
$handler
->expects($this->exactly($aArgumentCount))
->method('a')
->withConsecutive(...$aArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $aArgumentCount, true));
$lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addPattern("b+", "b");
$this->assertTrue($lexer->parse("abaabxbaaaxaaaax"));
}
function testModeChange() {
$methodArguments = [
'a' => [
["a", DOKU_LEXER_MATCHED, 0],
["b", DOKU_LEXER_UNMATCHED, 1],
["aa", DOKU_LEXER_MATCHED, 2],
["b", DOKU_LEXER_UNMATCHED, 4],
["aaa", DOKU_LEXER_MATCHED, 5],
],
'b' => [
[":", DOKU_LEXER_ENTER, 8],
["a", DOKU_LEXER_UNMATCHED, 9],
["b", DOKU_LEXER_MATCHED, 10],
["a", DOKU_LEXER_UNMATCHED, 11],
["bb", DOKU_LEXER_MATCHED, 12],
["a", DOKU_LEXER_UNMATCHED, 14],
["bbb", DOKU_LEXER_MATCHED, 15],
["a", DOKU_LEXER_UNMATCHED, 18],
],
];
$handler = $this->createMock('TestParser');
foreach ($methodArguments as $method => $arguments) {
$count = count($arguments);
$handler
->expects($this->exactly($count))
->method($method)
->withConsecutive(...$arguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $count, true));
}
$lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addEntryPattern(":", "a", "b");
$lexer->addPattern("b+", "b");
$this->assertTrue($lexer->parse("abaabaaa:ababbabbba"));
}
function testNesting() {
$methodArguments = [
'a' => [
["aa", DOKU_LEXER_MATCHED, 0],
["b", DOKU_LEXER_UNMATCHED, 2],
["aa", DOKU_LEXER_MATCHED, 3],
["b", DOKU_LEXER_UNMATCHED, 5],
// some b calls in between here
["aa", DOKU_LEXER_MATCHED, 13],
["b", DOKU_LEXER_UNMATCHED, 15],
],
'b' => [
["(", DOKU_LEXER_ENTER, 6],
["bb", DOKU_LEXER_MATCHED, 7],
["a", DOKU_LEXER_UNMATCHED, 9],
["bb", DOKU_LEXER_MATCHED, 10],
[")", DOKU_LEXER_EXIT, 12],
],
];
$handler = $this->createMock('TestParser');
foreach ($methodArguments as $method => $arguments) {
$count = count($arguments);
$handler
->expects($this->exactly($count))
->method($method)
->withConsecutive(...$arguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $count, true));
}
$lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addEntryPattern("(", "a", "b");
$lexer->addPattern("b+", "b");
$lexer->addExitPattern(")", "b");
$this->assertTrue($lexer->parse("aabaab(bbabb)aab"));
}
function testSingular() {
$methodArguments = [
'a' => [
["aa", DOKU_LEXER_MATCHED, 0],
["aa", DOKU_LEXER_MATCHED, 3],
["xx", DOKU_LEXER_UNMATCHED, 5],
["xx", DOKU_LEXER_UNMATCHED, 10],
],
'b' => [
["b", DOKU_LEXER_SPECIAL, 2],
["bbb", DOKU_LEXER_SPECIAL, 7],
],
];
$handler = $this->createMock('TestParser');
foreach ($methodArguments as $method => $arguments) {
$count = count($arguments);
$handler
->expects($this->exactly($count))
->method($method)
->withConsecutive(...$arguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $count, true));
}
$lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addSpecialPattern("b+", "a", "b");
$this->assertTrue($lexer->parse("aabaaxxbbbxx"));
}
function testUnwindTooFar() {
$aArguments = [
["aa", DOKU_LEXER_MATCHED,0],
[")", DOKU_LEXER_EXIT,2],
];
$aArgumentCount = count($aArguments);
$handler = $this->createMock('TestParser');
$handler
->expects($this->exactly($aArgumentCount))
->method('a')
->withConsecutive(...$aArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $aArgumentCount, true));
$lexer = new Lexer($handler, "a");
$lexer->addPattern("a+", "a");
$lexer->addExitPattern(")", "a");
$this->assertFalse($lexer->parse("aa)aa"));
}
}
class TestOfLexerHandlers extends DokuWikiTest {
function testModeMapping() {
$aArguments = [
["aa", DOKU_LEXER_MATCHED, 0],
["(", DOKU_LEXER_ENTER, 2],
["bb", DOKU_LEXER_MATCHED, 3],
["a", DOKU_LEXER_UNMATCHED, 5],
["bb", DOKU_LEXER_MATCHED, 6],
[")", DOKU_LEXER_EXIT, 8],
["b", DOKU_LEXER_UNMATCHED, 9],
];
$aArgumentCount = count($aArguments);
$handler = $this->createMock('TestParser');
$handler
->expects($this->exactly($aArgumentCount))
->method('a')
->withConsecutive(...$aArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $aArgumentCount, true));
$lexer = new Lexer($handler, "mode_a");
$lexer->addPattern("a+", "mode_a");
$lexer->addEntryPattern("(", "mode_a", "mode_b");
$lexer->addPattern("b+", "mode_b");
$lexer->addExitPattern(")", "mode_b");
$lexer->mapHandler("mode_a", "a");
$lexer->mapHandler("mode_b", "a");
$this->assertTrue($lexer->parse("aa(bbabb)b"));
}
}
class TestParserByteIndex {
function __construct() {}
function ignore() {}
function caught() {}
}
class TestOfLexerByteIndices extends DokuWikiTest {
function testIndex() {
$doc = "aaabcdeee";
$caughtArguments = [
["", DOKU_LEXER_ENTER, strpos($doc, '')],
["b", DOKU_LEXER_SPECIAL, strpos($doc, 'b')],
["c", DOKU_LEXER_MATCHED, strpos($doc, 'c')],
["d", DOKU_LEXER_UNMATCHED, strpos($doc, 'd')],
["", DOKU_LEXER_EXIT, strpos($doc, '')],
];
$caughtArgumentCount = count($caughtArguments);
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler
->expects($this->exactly($caughtArgumentCount))
->method('caught')
->withConsecutive(...$caughtArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $caughtArgumentCount, true));
$lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern("", "ignore", "caught");
$lexer->addExitPattern("", "caught");
$lexer->addSpecialPattern('b','caught','special');
$lexer->mapHandler('special','caught');
$lexer->addPattern('c','caught');
$this->assertTrue($lexer->parse($doc));
}
function testIndexLookaheadEqual() {
$doc = "aaabcdeee";
$caughtArguments = [
["", DOKU_LEXER_ENTER, strpos($doc, '')],
["b", DOKU_LEXER_SPECIAL, strpos($doc, 'b')],
["c", DOKU_LEXER_MATCHED, strpos($doc, 'c')],
["d", DOKU_LEXER_UNMATCHED, strpos($doc, 'd')],
["", DOKU_LEXER_EXIT, strpos($doc, '')],
];
$caughtArgumentCount = count($caughtArguments);
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler
->expects($this->exactly($caughtArgumentCount))
->method('caught')
->withConsecutive(...$caughtArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $caughtArgumentCount, true));
$lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('(?=.*)', "ignore", "caught");
$lexer->addExitPattern("", "caught");
$lexer->addSpecialPattern('b','caught','special');
$lexer->mapHandler('special','caught');
$lexer->addPattern('c','caught');
$this->assertTrue($lexer->parse($doc));
}
function testIndexLookaheadNotEqual() {
$doc = "aaabcdeee";
$caughtArguments = [
["", DOKU_LEXER_ENTER, strpos($doc, '')],
["b", DOKU_LEXER_SPECIAL, strpos($doc, 'b')],
["c", DOKU_LEXER_MATCHED, strpos($doc, 'c')],
["d", DOKU_LEXER_UNMATCHED, strpos($doc, 'd')],
["", DOKU_LEXER_EXIT, strpos($doc, '')],
];
$caughtArgumentCount = count($caughtArguments);
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler
->expects($this->exactly($caughtArgumentCount))
->method('caught')
->withConsecutive(...$caughtArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $caughtArgumentCount, true));
$lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('(?!foo)', "ignore", "caught");
$lexer->addExitPattern("", "caught");
$lexer->addSpecialPattern('b','caught','special');
$lexer->mapHandler('special','caught');
$lexer->addPattern('c','caught');
$this->assertTrue($lexer->parse($doc));
}
function testIndexLookbehindEqual() {
$doc = "aaabcdeee";
$caughtArguments = [
["", DOKU_LEXER_ENTER, strpos($doc, '')],
["b", DOKU_LEXER_SPECIAL, strpos($doc, 'b')],
["c", DOKU_LEXER_MATCHED, strpos($doc, 'c')],
["d", DOKU_LEXER_UNMATCHED, strpos($doc, 'd')],
["", DOKU_LEXER_EXIT, strpos($doc, '')],
];
$caughtArgumentCount = count($caughtArguments);
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler
->expects($this->exactly($caughtArgumentCount))
->method('caught')
->withConsecutive(...$caughtArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $caughtArgumentCount, true));
$lexer = new Lexer($handler, "ignore");
$lexer->addEntryPattern('', "ignore", "caught");
$lexer->addExitPattern("(?<=d)", "caught");
$lexer->addSpecialPattern('b','caught','special');
$lexer->mapHandler('special','caught');
$lexer->addPattern('c','caught');
$this->assertTrue($lexer->parse($doc));
}
function testIndexLookbehindNotEqual() {
$doc = "aaabcdeee";
$caughtArguments = [
["", DOKU_LEXER_ENTER, strpos($doc, '')],
["b", DOKU_LEXER_SPECIAL, strpos($doc, 'b')],
["c", DOKU_LEXER_MATCHED, strpos($doc, 'c')],
["d", DOKU_LEXER_UNMATCHED, strpos($doc, 'd')],
["", DOKU_LEXER_EXIT, strpos($doc, '')],
];
$caughtArgumentCount = count($caughtArguments);
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$handler
->expects($this->exactly($caughtArgumentCount))
->method('caught')
->withConsecutive(...$caughtArguments)
->willReturnOnConsecutiveCalls(...array_fill(0, $caughtArgumentCount, true));
$lexer = new Lexer($handler, 'ignore');
$lexer->addEntryPattern('', 'ignore', 'caught');
$lexer->addExitPattern('(?', 'caught');
$lexer->addSpecialPattern('b','caught','special');
$lexer->mapHandler('special','caught');
$lexer->addPattern('c','caught');
$this->assertTrue($lexer->parse($doc));
}
/**
* This test is primarily to ensure the correct match is chosen
* when there are non-captured elements in the pattern.
*/
function testIndexSelectCorrectMatch() {
$doc = "ALL FOOLS ARE FOO";
$pattern = '\bFOO\b';
$handler = $this->createMock('TestParserByteIndex');
$handler->expects($this->any())->method('ignore')->will($this->returnValue(true));
$matches = [];
preg_match('/'.$pattern.'/',$doc,$matches,PREG_OFFSET_CAPTURE);
$handler->expects($this->once())->method('caught')
->with("FOO", DOKU_LEXER_SPECIAL, $matches[0][1])->will($this->returnValue(true));
$lexer = new Lexer($handler, "ignore");
$lexer->addSpecialPattern($pattern,'ignore','caught');
$this->assertTrue($lexer->parse($doc));
}
}