mediawiki-extensions-AbuseF.../tests/phpunit/AFPDataTest.php
Daimona Eaytoy ec110c657b Add tests for various data type casts
These are the ones which other tests don't cover, mostly because no
filter syntax can trigger those cases. This patch should bring coverage
for AFPData to 100%.

Bug: T201193
Change-Id: I997576141943959d4602a9f839311108928ec766
2019-04-14 14:08:57 +02:00

252 lines
7 KiB
PHP

<?php
/**
* Tests for the AFPData class
*
* 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
*
* @license GPL-2.0-or-later
*/
/**
* @group Test
* @group AbuseFilter
*
* @covers AFPData
* @covers AbuseFilterTokenizer
* @covers AFPToken
* @covers AFPUserVisibleException
* @covers AFPException
* @covers AbuseFilterParser
*/
class AFPDataTest extends MediaWikiTestCase {
/**
* @return AbuseFilterParser
*/
public static function getParser() {
/** @var AbuseFilterParser|null The parser used for tests */
static $parser = null;
if ( !$parser ) {
$parser = new AbuseFilterParser();
} else {
$parser->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 AFPData::$caller"
);
return;
}
$this->fail( "Exception $excep not thrown in AFPData::$caller" );
}
/**
* Test the 'regexfailure' exception
*
* @param string $expr The expression to test
* @param string $caller The function where the exception is thrown
* @covers AFPData::keywordRegex
* @dataProvider regexFailure
*/
public function testRegexFailureException( $expr, $caller ) {
$this->exceptionTest( 'regexfailure', $expr, $caller );
}
/**
* Data provider for testRegexFailureException
* The second parameter is the function where the exception is raised.
* One expression for each throw.
*
* @return array
*/
public function regexFailure() {
return [
[ "'a' rlike '('", 'keywordRegex' ],
];
}
/**
* Test the 'dividebyzero' exception
*
* @param string $expr The expression to test
* @param string $caller The function where the exception is thrown
* @covers AFPData::mulRel
* @dataProvider divideByZero
*/
public function testDivideByZeroException( $expr, $caller ) {
$this->exceptionTest( 'dividebyzero', $expr, $caller );
}
/**
* Data provider for testRegexFailureException
* The second parameter is the function where the exception is raised.
* One expression for each throw.
*
* @return array
*/
public function divideByZero() {
return [
[ '1/0', 'mulRel' ],
[ '1/0.0', 'mulRel' ],
];
}
/**
* @param mixed $raw
* @param AFPData|null $expected If null, we expect an exception due to unsupported data type
* @covers AFPData::newFromPHPVar
* @dataProvider providePHPVars
*/
public function testNewFromPHPVar( $raw, $expected ) {
if ( $expected === null ) {
$this->setExpectedException( AFPException::class );
}
$this->assertEquals( $expected, AFPData::newFromPHPVar( $raw ) );
}
/**
* Data provider for testNewFromPHPVar
*
* @return array
*/
public function providePHPVars() {
return [
[ 15, new AFPData( AFPData::DINT, 15 ) ],
[ '42', new AFPData( AFPData::DSTRING, '42' ) ],
[ 0.123, new AFPData( AFPData::DFLOAT, 0.123 ) ],
[ false, new AFPData( AFPData::DBOOL, false ) ],
[ true, new AFPData( AFPData::DBOOL, true ) ],
[ null, new AFPData() ],
[
[ 1, 'foo', [], [ null ], false ],
new AFPData( AFPData::DARRAY, [
new AFPData( AFPData::DINT, 1 ),
new AFPData( AFPData::DSTRING, 'foo' ),
new AFPData( AFPData::DARRAY, [] ),
new AFPData( AFPData::DARRAY, [ new AFPData() ] ),
new AFPData( AFPData::DBOOL, false )
] )
],
// Invalid data types
[ new stdClass, null ],
[ new AFPData, null ]
];
}
/**
* Test casts to null and to arrays, for which we don't expose any method for use in actual
* filters. Other casts are already covered in parserTests.
*
* @param AFPData $orig
* @param string $newType One of the AFPData::D* constants
* @param AFPData|null $expected If null, we expect an exception due to unsupported data type
* @covers AFPData::castTypes
* @dataProvider provideMissingCastTypes
*/
public function testMissingCastTypes( $orig, $newType, $expected ) {
if ( $expected === null ) {
$this->setExpectedException( AFPException::class );
}
$this->assertEquals( $expected, AFPData::castTypes( $orig, $newType ) );
}
/**
* Data provider for testMissingCastTypes
*
* @return array
*/
public function provideMissingCastTypes() {
return [
[ new AFPData( AFPData::DINT, 1 ), AFPData::DNULL, new AFPData() ],
[ new AFPData( AFPData::DBOOL, false ), AFPData::DNULL, new AFPData() ],
[ new AFPData( AFPData::DSTRING, 'foo' ), AFPData::DNULL, new AFPData() ],
[ new AFPData( AFPData::DFLOAT, 3.14 ), AFPData::DNULL, new AFPData() ],
[
new AFPData( AFPData::DARRAY, [ new AFPData( AFPData::DSTRING, 'foo' ), new AFPData() ] ),
AFPData::DNULL,
new AFPData()
],
[
new AFPData( AFPData::DINT, 1 ),
AFPData::DARRAY,
new AFPData( AFPData::DARRAY, [ new AFPData( AFPData::DINT, 1 ) ] )
],
[
new AFPData( AFPData::DBOOL, false ),
AFPData::DARRAY,
new AFPData( AFPData::DARRAY, [ new AFPData( AFPData::DBOOL, false ) ] )
],
[
new AFPData( AFPData::DSTRING, 'foo' ),
AFPData::DARRAY,
new AFPData( AFPData::DARRAY, [ new AFPData( AFPData::DSTRING, 'foo' ) ] )
],
[
new AFPData( AFPData::DFLOAT, 3.14 ),
AFPData::DARRAY,
new AFPData( AFPData::DARRAY, [ new AFPData( AFPData::DFLOAT, 3.14 ) ] )
],
[ new AFPData(), AFPData::DARRAY, new AFPData( AFPData::DARRAY, [ new AFPData() ] ) ],
[ new AFPData( AFPData::DSTRING, 'foo' ), 'foobaz', null ],
[ new AFPData(), null, null ]
];
}
/**
* Test a couple of toNative cases which aren't already covered in other tests.
*
* @param AFPData $orig
* @param mixed $expected
* @covers AFPData::toNative
* @dataProvider provideMissingToNative
*/
public function testMissingToNative( $orig, $expected ) {
$this->assertEquals( $expected, $orig->toNative() );
}
/**
* Data provider for testMissingToNative
*
* @return array
*/
public function provideMissingToNative() {
return [
[ new AFPData( AFPData::DFLOAT, 1.2345 ), 1.2345 ],
[ new AFPData( AFPData::DFLOAT, 0.1 ), 0.1 ],
[ new AFPData(), null ],
[ new AFPData( AFPData::DNULL, null ), null ],
];
}
}