mediawiki-extensions-AbuseF.../tests/phpunit/parserTest.php
Bartosz Dziewoński e79b45b71f Improve ignoring short-circuited operations
Previously, 'false & a == b' would actually execute the comparison and
count it against the condition limit, while 'false & (a == b)' wouldn't.
They behave the same now.

mShortCircuit was only checked for the most potentially expensive
operations (computing functions and getting variables), all the other
operations on bogus values generated by this would be executed and the
results ignored later.

This probably doesn't noticeably improve performance, but it corrects
how the condition limit is counted.

Bug: T43693
Change-Id: Id1d5f577b14b6ae6d987ded12689788eb7922474
2016-04-09 16:25:52 +02:00

131 lines
3.8 KiB
PHP

<?php
/**
* Tests for the AbuseFilter parser
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*
* @group Test
* @group AbuseFilter
*
* @licence GNU GPL v2+
* @author Marius Hoch < hoo@online.de >
*/
class AbuseFilterParserTest extends MediaWikiTestCase {
/**
* @return AbuseFilterParser
*/
static function getParser() {
static $parser = null;
if ( !$parser ) {
$parser = new AbuseFilterParser();
}
return $parser;
}
/**
* @dataProvider readTests
*/
public function testParser( $testName, $rule, $expected ) {
if ( !class_exists( 'AntiSpoof' ) && preg_match( '/(cc)?norm\(/i', $rule ) ) {
// The norm and ccnorm parser functions aren't working correctly without AntiSpoof
$this->markTestSkipped( 'Parser test ' . $testName . ' requires the AntiSpoof extension' );
}
$parser = self::getParser();
$actual = $parser->parse( $rule );
$this->assertEquals( $expected, $actual, 'Running parser test ' . $testName );
}
/**
* @return array
*/
public function readTests() {
$tests = array();
$testPath = __DIR__ . "/../parserTests";
$testFiles = glob( $testPath . "/*.t" );
foreach ( $testFiles as $testFile ) {
$testName = substr( $testFile, 0, -2 );
$resultFile = $testName . '.r';
$rule = trim( file_get_contents( $testFile ) );
$result = trim( file_get_contents( $resultFile ) ) == 'MATCH';
$tests[] = array(
basename( $testName ),
$rule,
$result
);
}
return $tests;
}
/**
* Ensure that AbuseFilterTokenizer::OPERATOR_RE matches the contents
* and order of AbuseFilterTokenizer::$operators.
*/
public function testOperatorRe() {
$operatorRe = '/(' . implode( '|', array_map( function ( $op ) {
return preg_quote( $op, '/' );
}, AbuseFilterTokenizer::$operators ) ) . ')/A';
$this->assertEquals( $operatorRe, AbuseFilterTokenizer::OPERATOR_RE );
}
/**
* Ensure that AbuseFilterTokenizer::RADIX_RE matches the contents
* and order of AbuseFilterTokenizer::$bases.
*/
public function testRadixRe() {
$baseClass = implode( '', array_keys( AbuseFilterTokenizer::$bases ) );
$radixRe = "/([0-9A-Fa-f]+(?:\.\d*)?|\.\d+)([$baseClass])?/Au";
$this->assertEquals( $radixRe, AbuseFilterTokenizer::RADIX_RE );
}
/**
* Ensure the number of conditions counted for given expressions is right.
*
* @dataProvider condCountCases
*/
public function testCondCount( $rule, $expected ) {
$parser = self::getParser();
// Set some variables for convenience writing test cases
$parser->setVars( array_combine( range( 'a', 'f' ), range( 'a', 'f' ) ) );
$countBefore = AbuseFilter::$condCount;
$parser->parse( $rule );
$countAfter = AbuseFilter::$condCount;
$actual = $countAfter - $countBefore;
$this->assertEquals( $expected, $actual, 'Condition count for ' . $rule );
}
/**
* @return array
*/
public function condCountCases() {
return array(
array( '(((a == b)))', 1 ),
array( 'contains_any(a, b, c)', 1 ),
array( 'a == b == c', 2 ),
array( 'a in b + c in d + e in f', 3 ),
array( 'true', 0 ),
array( 'a == a | c == d', 1 ),
array( 'a == b & c == d', 1 ),
);
}
}