jenkins-bot has submitted this change and it was merged. Change subject: (bug 54333) Validate time precision. ......................................................................
(bug 54333) Validate time precision. This validates the precision parameter for time values. Change-Id: I78d0dd46f478dffc9a879b8c645c7468b00949fd --- M lib/WikibaseLib.classes.php M lib/WikibaseLib.i18n.php A lib/includes/Validators/NumberRangeValidator.php M lib/includes/WikibaseDataTypeBuilders.php A lib/tests/phpunit/Validators/NumberRangeValidatorTest.php M lib/tests/phpunit/WikibaseDataTypeBuildersTest.php 6 files changed, 210 insertions(+), 24 deletions(-) Approvals: Aude: Looks good to me, approved jenkins-bot: Verified diff --git a/lib/WikibaseLib.classes.php b/lib/WikibaseLib.classes.php index ddf631a..fac3726 100644 --- a/lib/WikibaseLib.classes.php +++ b/lib/WikibaseLib.classes.php @@ -192,6 +192,7 @@ 'Wikibase\Validators\NumberValidator' => 'includes/Validators/NumberValidator.php', 'Wikibase\Validators\RegexValidator' => 'includes/Validators/RegexValidator.php', 'Wikibase\Validators\StringLengthValidator' => 'includes/Validators/StringLengthValidator.php', + 'Wikibase\Validators\NumberRangeValidator' => 'includes/Validators/NumberRangeValidator.php', 'Wikibase\Validators\TypeValidator' => 'includes/Validators/TypeValidator.php', 'Wikibase\Validators\ValidatorErrorLocalizer' => 'includes/Validators/ValidatorErrorLocalizer.php', 'Wikibase\Validators\UrlValidator' => 'includes/Validators/UrlValidator.php', diff --git a/lib/WikibaseLib.i18n.php b/lib/WikibaseLib.i18n.php index 0c16d7f..ecc36e3 100644 --- a/lib/WikibaseLib.i18n.php +++ b/lib/WikibaseLib.i18n.php @@ -57,6 +57,8 @@ 'wikibase-validator-bad-type' => '$2 instead of $1', 'wikibase-validator-too-long' => 'Must be no more than {{PLURAL:$1|one character|$1 characters}} long', 'wikibase-validator-too-short' => 'Must be at least {{PLURAL:$1|one character|$1 characters}} long', + 'wikibase-validator-too-high' => 'Out of range, must be no higher than $1', + 'wikibase-validator-too-low' => 'Out of range, must be no lower than $1', 'wikibase-validator-malformed-value' => 'Malformed input: $1', 'wikibase-validator-bad-entity-id' => 'Malformed ID: $1', 'wikibase-validator-bad-entity-type' => 'Unexpected entity type $1', @@ -164,13 +166,21 @@ * $2 - the actual type {{Related|Wikibase-validator}}', 'wikibase-validator-too-long' => 'Input validation error shown when the input is too long. Parameters: -* $1 - the minimum length +* $1 - the maximum length * $2 - (Unused) the actual length {{Related|Wikibase-validator}}', 'wikibase-validator-too-short' => 'Input validation error shown when the input is too short. Parameters: * $1 - the minimum length * $2 - (Unused) the actual length {{Related|Wikibase-validator}}', + 'wikibase-validator-too-high' => 'Input validation error shown when the input is too high. Parameters: +* $1 - the maximum value +* $2 - (Unused) the actual length +{{Related|Wikibase-validator}}', + 'wikibase-validator-too-low' => 'Input validation error shown when the input is too low. Parameters: +* $1 - the minimum value +* $2 - (Unused) the actual length +{{Related|Wikibase-validator}}', 'wikibase-validator-malformed-value' => "Input validation error shown when the user's input was malformed in some way. Parameters: diff --git a/lib/includes/Validators/NumberRangeValidator.php b/lib/includes/Validators/NumberRangeValidator.php new file mode 100644 index 0000000..4ece070 --- /dev/null +++ b/lib/includes/Validators/NumberRangeValidator.php @@ -0,0 +1,74 @@ +<?php + +namespace Wikibase\Validators; + +use ValueValidators\Error; +use ValueValidators\Result; +use ValueValidators\ValueValidator; + +/** + * NumberRangeValidator checks that a numerical value is in a given range. + * + * @license GPL 2+ + * @author Daniel Kinzler + */ +class NumberRangeValidator implements ValueValidator { + + /** + * @var int + */ + protected $min; + + /** + * @var int + */ + protected $max; + + /** + * @var callable + */ + protected $measure; + + /** + * @param int|float $min + * @param int|float $max + */ + public function __construct( $min, $max ) { + $this->min = $min; + $this->max = $max; + } + + /** + * @see ValueValidator::validate() + * + * @param string $value The value to validate + * + * @return \ValueValidators\Result + * @throws \InvalidArgumentException + */ + public function validate( $value ) { + if ( $value < $this->min ) { + // XXX: having to provide an array is quite inconvenient + return Result::newError( array( + Error::newError( 'Value out of range, the minimum value is ' . $this->min, null, 'too-low', array( $this->min, $value ) ) + ) ); + } + + if ( $value > $this->max ) { + return Result::newError( array( + Error::newError( 'Value out of range, the maximum value is ' . $this->max, null, 'too-high', array( $this->max, $value ) ) + ) ); + } + + return Result::newSuccess(); + } + + /** + * @see ValueValidator::setOptions() + * + * @param array $options + */ + public function setOptions( array $options ) { + // Do nothing. This method shouldn't even be in the interface. + } +} \ No newline at end of file diff --git a/lib/includes/WikibaseDataTypeBuilders.php b/lib/includes/WikibaseDataTypeBuilders.php index 22dc925..c0aa899 100644 --- a/lib/includes/WikibaseDataTypeBuilders.php +++ b/lib/includes/WikibaseDataTypeBuilders.php @@ -3,6 +3,7 @@ namespace Wikibase\Lib; use DataTypes\DataType; +use DataValues\TimeValue; use Parser; use Wikibase\EntityLookup; use Wikibase\Item; @@ -10,6 +11,7 @@ use Wikibase\Validators\DataFieldValidator; use Wikibase\Validators\DataValueValidator; use Wikibase\Validators\EntityExistsValidator; +use Wikibase\Validators\NumberRangeValidator; use Wikibase\Validators\NumberValidator; use Wikibase\Validators\RegexValidator; use Wikibase\Validators\StringLengthValidator; @@ -150,13 +152,28 @@ $timeStringValidators = array(); $timeStringValidators[] = new TypeValidator( 'string' ); - $isoDataPattern = '!^[-+]\d{1,16}-(0\d|1[012])-([012]\d|3[01])T([01]\d|2[0123]):[0-5]\d:([0-5]\d|6[012])Z$!'; + // down to the second + //$maxPrecision = TimeValue::PRECISION_SECOND; + //$isoDataPattern = '!^[-+]\d{1,16}-(0\d|1[012])-([012]\d|3[01])T([01]\d|2[0123]):[0-5]\d:([0-5]\d|6[012])Z$!'; + + // down to the day + $maxPrecision = TimeValue::PRECISION_DAY; + $isoDataPattern = '!^[-+]\d{1,16}-(0\d|1[012])-([012]\d|3[01])T00:00:00Z$!'; + $timeStringValidators[] = new RegexValidator( $isoDataPattern ); - $validators[] = new DataFieldValidator( 'time', // Note: validate the 'calendarmodel' field + $validators[] = new DataFieldValidator( 'time', // Note: validate the 'time' field new CompositeValidator( $timeStringValidators, true ) //Note: each validator is fatal ); + $precisionValidators = array(); + $precisionValidators[] = new TypeValidator( 'integer' ); + $precisionValidators[] = new NumberRangeValidator( TimeValue::PRECISION_Ga, $maxPrecision ); + + $validators[] = new DataFieldValidator( 'precision', // Note: validate the 'precision' field + new CompositeValidator( $precisionValidators, true ) //Note: each validator is fatal + ); + // top validator $topValidator = new DataValueValidator( //Note: validate the DataValue's native value. new CompositeValidator( $validators, true ) //Note: each validator is fatal diff --git a/lib/tests/phpunit/Validators/NumberRangeValidatorTest.php b/lib/tests/phpunit/Validators/NumberRangeValidatorTest.php new file mode 100644 index 0000000..1b466a1 --- /dev/null +++ b/lib/tests/phpunit/Validators/NumberRangeValidatorTest.php @@ -0,0 +1,79 @@ +<?php + /** + * + * Copyright © 14.06.13 by the authors listed below. + * + * 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 + * + * @license GPL 2+ + * @file + * + * @ingroup WikibaseLib + * @ingroup Test + * + * @group WikibaseLib + * @group Wikibase + * @group WikibaseValidators + * + * @author Daniel Kinzler + */ + + +namespace Wikibase\Test\Validators; + + +use Wikibase\Validators\NumberRangeValidator; +use Wikibase\Validators\ValidatorErrorLocalizer; + +/** + * Class StringLengthValidatorTest + * @covers Wikibase\Validators\StringLengthValidator + * @package Wikibase\Test\Validators + */ +class NumberRangeValidatorTest extends \PHPUnit_Framework_TestCase { + + public static function provideValidate() { + return array( + array( 1, 10, 3, true, "normal fit" ), + array( 0, 10, 0, true, "0 ok" ), + array( 1, 10, 0, false, "0 not allowed" ), + array( -2, 1, -2, true, "negative match" ), + array( 1, 2, 3, false, "too high" ), + array( -1, 0, -3, false, "too low" ), + ); + } + + /** + * @dataProvider provideValidate() + */ + public function testValidate( $minLength, $maxLength, $value, $expected, $message ) { + $validator = new NumberRangeValidator( $minLength, $maxLength ); + $result = $validator->validate( $value ); + + $this->assertEquals( $expected, $result->isValid(), $message ); + + if ( !$expected ) { + $errors = $result->getErrors(); + $this->assertCount( 1, $errors, $message ); + $this->assertTrue( in_array( $errors[0]->getCode(), array( 'too-low', 'too-high' ) ), $message . "\n" . $errors[0]->getCode() ); + + $localizer = new ValidatorErrorLocalizer( ); + $msg = $localizer->getErrorMessage( $errors[0] ); + $this->assertTrue( $msg->exists(), $msg ); + } + } + +} \ No newline at end of file diff --git a/lib/tests/phpunit/WikibaseDataTypeBuildersTest.php b/lib/tests/phpunit/WikibaseDataTypeBuildersTest.php index 4fe2084..89a97ae 100644 --- a/lib/tests/phpunit/WikibaseDataTypeBuildersTest.php +++ b/lib/tests/phpunit/WikibaseDataTypeBuildersTest.php @@ -86,11 +86,15 @@ array( 'time', new NumberValue( 7 ), false, 'TimeValue expected' ), //time['calendar-model'] - array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, 0, '' ), false, 'calendar: empty string should be invalid' ), - array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, 0, 'http://' . str_repeat('x', 256) ), false, 'calendar: too long' ), - array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, 0, 'http://acme.com/calendar' ), true, 'calendar: URL' ), - array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, 0, ' http://acme.com/calendar ' ), false, 'calendar: untrimmed' ), - array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, 0, ' javascript:alert(1)' ), false, 'calendar: bad URL' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, '' ), false, 'calendar: empty string should be invalid' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, 'http://' . str_repeat('x', 256) ), false, 'calendar: too long' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, 'http://acme.com/calendar' ), true, 'calendar: URL' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, ' http://acme.com/calendar ' ), false, 'calendar: untrimmed' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_DAY, ' javascript:alert(1)' ), false, 'calendar: bad URL' ), + + //precision to the second (currently not allowed) + array( 'time', new TimeValue( '+0000000000002013-06-06T11:22:33Z', 0, 0, 0, TimeValue::PRECISION_DAY, 'http://acme.com/calendar' ), false, 'time given to the second' ), + array( 'time', new TimeValue( '+0000000000002013-06-06T00:00:00Z', 0, 0, 0, TimeValue::PRECISION_SECOND, 'http://acme.com/calendar' ), false, 'precision: second' ), //time['time'] //NOTE: The below will fail with a IllegalValueExcpetion once the TimeValue constructor enforces the time format. @@ -133,26 +137,27 @@ array( 'globe-coordinate', new GlobeCoordinateValue( $latLonValue, 1, ' javascript:alert(1) ' ), false, 'globe: bad URL scheme' ), //TODO: globe must be an item reference //TODO: globe must be from a list of configured values + + // url + array( 'url', 'Foo', false, 'StringValue expected, string supplied' ), + array( 'url', new NumberValue( 7 ), false, 'StringValue expected' ), + + array( 'url', new StringValue( 'http://acme.com' ), true, 'Simple HTTP URL' ), + array( 'url', new StringValue( 'https://acme.com/' ), true, 'Simple HTTPS URL' ), + array( 'url', new StringValue( 'http://acme.com/foo/bar?some=stuff#fragment' ), true, 'Complex HTTP URL' ), + + // evil url + array( 'url', new StringValue( '//bla' ), false, 'Protocol-relative' ), + array( 'url', new StringValue( '/bla/bla' ), false, 'relative path' ), + array( 'url', new StringValue( 'just stuff' ), false, 'just words' ), + array( 'url', new StringValue( 'javascript:alert("evil")' ), false, 'JavaScript URL' ), + array( 'url', new StringValue( 'http://' ), false, 'bad http URL' ), + array( 'url', new StringValue( 'http://' . str_repeat('x', 505) ), false, 'URL too long' ), ); if ( defined( 'WB_EXPERIMENTAL_FEATURES' ) && WB_EXPERIMENTAL_FEATURES ) { $cases = array_merge( $cases, array( - - // url - array( 'url', 'Foo', false, 'StringValue expected, string supplied' ), - array( 'url', new NumberValue( 7 ), false, 'StringValue expected' ), - - array( 'url', new StringValue( 'http://acme.com' ), true, 'Simple HTTP URL' ), - array( 'url', new StringValue( 'https://acme.com/' ), true, 'Simple HTTPS URL' ), - array( 'url', new StringValue( 'http://acme.com/foo/bar?some=stuff#fragment' ), true, 'Complex HTTP URL' ), - - // evil url - array( 'url', new StringValue( '//bla' ), false, 'Protocol-relative' ), - array( 'url', new StringValue( '/bla/bla' ), false, 'relative path' ), - array( 'url', new StringValue( 'just stuff' ), false, 'just words' ), - array( 'url', new StringValue( 'javascript:alert("evil")' ), false, 'JavaScript URL' ), - array( 'url', new StringValue( 'http://' ), false, 'bad http URL' ), - array( 'url', new StringValue( 'http://' . str_repeat('x', 505) ), false, 'URL too long' ), + // .... ) ); } -- To view, visit https://gerrit.wikimedia.org/r/84996 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I78d0dd46f478dffc9a879b8c645c7468b00949fd Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Lydia Pintscher <lydia.pintsc...@wikimedia.de> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits