resetState(); } return $parser; } /** * Base method for testing exceptions * * @param string $excep Identifier of the exception (e.g. 'unexpectedtoken') * @param string $expr The expression to test * @param string $caller The function where the exception is thrown */ private function exceptionTest( $excep, $expr, $caller ) { $parser = self::getParser(); try { $parser->parse( $expr ); } catch ( AFPUserVisibleException $e ) { $this->assertEquals( $excep, $e->mExceptionID, "Exception $excep not thrown in AbuseFilterTokenizer::$caller" ); return; } $this->fail( "Exception $excep not thrown in AbuseFilterTokenizer::$caller" ); } /** * Test the 'unclosedcomment' exception * * @param string $expr The expression to test * @param string $caller The function where the exception is thrown * @covers AbuseFilterTokenizer::nextToken * @dataProvider unclosedComment */ public function testUnclosedCommentException( $expr, $caller ) { $this->exceptionTest( 'unclosedcomment', $expr, $caller ); } /** * Data provider for testUnclosedCommentException * The second parameter is the function where the exception is raised. * One expression for each throw. * * @return array */ public function unclosedComment() { return [ [ ' /**** / * /', 'nextToken' ], ]; } /** * Test the 'unrecognisedtoken' exception * * @param string $expr The expression to test * @param string $caller The function where the exception is thrown * @covers AbuseFilterTokenizer::nextToken * @dataProvider unrecognisedToken */ public function testUnrecognisedTokenException( $expr, $caller ) { $this->exceptionTest( 'unrecognisedtoken', $expr, $caller ); } /** * Data provider for testUnrecognisedTokenException * The second parameter is the function where the exception is raised. * One expression for each throw. * * @return array */ public function unrecognisedToken() { return [ [ '#', 'nextToken' ], ]; } /** * Test the 'unclosedstring' exception * * @param string $expr The expression to test * @param string $caller The function where the exception is thrown * @covers AbuseFilterTokenizer::readStringLiteral * @dataProvider unclosedString */ public function testUnclosedStringException( $expr, $caller ) { $this->exceptionTest( 'unclosedstring', $expr, $caller ); } /** * Data provider for testUnclosedStringException * The second parameter is the function where the exception is raised. * One expression for each throw. * * @return array */ public function unclosedString() { return [ [ '"', 'readStringLiteral' ], ]; } /** * Test that tokenized code is saved in cache * * @param string $code To be tokenized * @dataProvider provideCode */ public function testCaching( $code ) { $cache = new HashBagOStuff(); $this->setService( 'LocalServerObjectCache', $cache ); $key = AbuseFilterTokenizer::getCacheKey( $code ); // Other tests may have already cached the same code. $cache->delete( $key ); // Static hell makes code difficult to test... AbuseFilterTokenizer::$tokenizerCache = null; AbuseFilterTokenizer::tokenize( $code ); $this->assertNotFalse( $cache->get( $key ) ); } /** * Data provider for testCaching * * @return array */ public function provideCode() { return [ [ '1 === 1' ], [ 'added_lines irlike "test"' ], [ 'edit_delta > 57 & action === "edit"' ], [ '!("confirmed") in user_groups' ] ]; } }