Lucas Werkmeister (WMDE) has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/351628 )

Change subject: Parse and correctly compare time values
......................................................................

Parse and correctly compare time values

RangeCheckerHelper::getComparativeValue() now returns an array for time
values; comparing two such arrays correctly compares the dates.
DiffWithinRangeChecker uses the first component of the array to compute
the difference in years.

RangeCheckerHelper also gains a new method, getComparativeTimeValue(),
which parses a time value using Wikibase’s standard time parser chain.
RangeChecker uses this method to parse its min/max parameters, which
fixes T164279.

The test skipped in 1644986 can be unskipped again, since the parameters
are now properly parsed, and the test added in 7644ede can now use a
zero-padded timestamp like all other timestamps in the file. Two new
tests for RangeChecker are also added, which test that parameters
containing only a year or only a date work correctly, and two new tests
for RangeCheckerHelper test the new function.

Bug: T164279
Change-Id: I902156e4e013e6c5f3c9c73bf35919de9264650a
---
M includes/ConstraintCheck/Checker/DiffWithinRangeChecker.php
M includes/ConstraintCheck/Checker/RangeChecker.php
M includes/ConstraintCheck/Helper/RangeCheckerHelper.php
M includes/ConstraintReportFactory.php
M tests/phpunit/Checker/RangeChecker/DiffWithinRangeCheckerTest.php
M tests/phpunit/Checker/RangeChecker/RangeCheckerHelperTest.php
M tests/phpunit/Checker/RangeChecker/RangeCheckerTest.php
7 files changed, 91 insertions(+), 9 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikibaseQualityConstraints
 refs/changes/28/351628/1

diff --git a/includes/ConstraintCheck/Checker/DiffWithinRangeChecker.php 
b/includes/ConstraintCheck/Checker/DiffWithinRangeChecker.php
index 3f39227..a2acb1d 100644
--- a/includes/ConstraintCheck/Checker/DiffWithinRangeChecker.php
+++ b/includes/ConstraintCheck/Checker/DiffWithinRangeChecker.php
@@ -114,6 +114,13 @@
                                if ( $mainSnak->getDataValue()->getType() === 
$dataValue->getType() && $mainSnak->getType() === 'value' ) {
                                        $thatValue = 
$this->rangeCheckerHelper->getComparativeValue( $mainSnak->getDataValue() );
 
+                                       if ( $dataValue->getType() === 'time' ) 
{
+                                               // getComparativeValue() 
returned an array, take only the year and convert it back to an integer
+                                               // TODO very large years might 
not fit in an integer – TimeValue itself carefully avoids casting the year to 
integer
+                                               $thisValue = (int)$thisValue[0];
+                                               $thatValue = (int)$thatValue[0];
+                                       }
+
                                        // negative difference is possible
                                        $diff = $thisValue - $thatValue;
 
diff --git a/includes/ConstraintCheck/Checker/RangeChecker.php 
b/includes/ConstraintCheck/Checker/RangeChecker.php
index 560d21a..4f3dd89 100644
--- a/includes/ConstraintCheck/Checker/RangeChecker.php
+++ b/includes/ConstraintCheck/Checker/RangeChecker.php
@@ -122,6 +122,8 @@
                                if ( $max === 'now' ) {
                                        $max = $now;
                                }
+                               $min = 
$this->rangeCheckerHelper->getComparativeTimeValue( $min );
+                               $max = 
$this->rangeCheckerHelper->getComparativeTimeValue( $max );
                        }
                } else {
                        $message = wfMessage( 
'wbqc-violation-message-value-needed-of-types-2' )
diff --git a/includes/ConstraintCheck/Helper/RangeCheckerHelper.php 
b/includes/ConstraintCheck/Helper/RangeCheckerHelper.php
index 00338e7..8751760 100644
--- a/includes/ConstraintCheck/Helper/RangeCheckerHelper.php
+++ b/includes/ConstraintCheck/Helper/RangeCheckerHelper.php
@@ -7,6 +7,7 @@
 use DataValues\TimeValue;
 use DataValues\UnboundedQuantityValue;
 use InvalidArgumentException;
+use ValueParsers\ValueParser;
 
 /**
  * Class for helper functions for range checkers.
@@ -17,9 +18,32 @@
  */
 class RangeCheckerHelper {
 
+       /**
+        * @var ValueParser
+        */
+       private $timeParser;
+
+       /**
+        * @param ValueParser $timeParser
+        */
+       public function __construct( ValueParser $timeParser ) {
+               $this->timeParser = $timeParser;
+       }
+
        public function getComparativeValue( DataValue $dataValue ) {
                if ( $dataValue instanceof TimeValue ) {
-                       return $dataValue->getTime();
+                       if ( !preg_match(
+                               // copied from TimeValue::normalizeIsoTimestamp
+                               
'/^([-+])(\d{1,16})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/',
+                               $dataValue->getTime(),
+                               $matches
+                       ) ) {
+                               throw new InvalidArgumentException( 
'TimeValue::getTime() did not match expected format' );
+                       }
+
+                       list( , $sign, $year, $month, $day, $hour, $minute, 
$second ) = $matches;
+
+                       return [ $sign . $year, $sign . $month, $sign . $day, 
$sign . $hour, $sign . $minute, $sign . $second ];
                } elseif ( $dataValue instanceof QuantityValue ) {
                        return $dataValue->getAmount()->getValue();
                } elseif ( $dataValue instanceof UnboundedQuantityValue ) {
@@ -29,4 +53,12 @@
                throw new InvalidArgumentException( 'Unsupported data value 
type' );
        }
 
+       /**
+        * @param string $timeString
+        * @return string
+        */
+       public function getComparativeTimeValue( $timeString ) {
+               return $this->getComparativeValue( $this->timeParser->parse( 
$timeString ) );
+       }
+
 }
diff --git a/includes/ConstraintReportFactory.php 
b/includes/ConstraintReportFactory.php
index 89f2356..d7d78bd 100644
--- a/includes/ConstraintReportFactory.php
+++ b/includes/ConstraintReportFactory.php
@@ -5,6 +5,7 @@
 use Config;
 use MediaWiki\MediaWikiServices;
 use Wikibase\DataModel\Services\Lookup\EntityLookup;
+use Wikibase\Repo\Parsers\TimeParserFactory;
 use Wikibase\Repo\WikibaseRepo;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\DelegatingConstraintChecker;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
@@ -117,7 +118,7 @@
                if ( $this->constraintCheckerMap === null ) {
                        $constraintParameterParser = new 
ConstraintParameterParser();
                        $connectionCheckerHelper = new 
ConnectionCheckerHelper();
-                       $rangeCheckerHelper = new RangeCheckerHelper();
+                       $rangeCheckerHelper = new RangeCheckerHelper( (new 
TimeParserFactory())->getTimeParser() );
                        $typeCheckerHelper = new TypeCheckerHelper( 
$this->lookup, $this->config );
 
                        $this->constraintCheckerMap = array(
diff --git a/tests/phpunit/Checker/RangeChecker/DiffWithinRangeCheckerTest.php 
b/tests/phpunit/Checker/RangeChecker/DiffWithinRangeCheckerTest.php
index 9b329a4..a7759ac 100644
--- a/tests/phpunit/Checker/RangeChecker/DiffWithinRangeCheckerTest.php
+++ b/tests/phpunit/Checker/RangeChecker/DiffWithinRangeCheckerTest.php
@@ -9,6 +9,7 @@
 use DataValues\TimeValue;
 use Wikibase\DataModel\Entity\ItemId;
 use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\Repo\Parsers\TimeParserFactory;
 use WikibaseQuality\ConstraintReport\Constraint;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\DiffWithinRangeChecker;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
@@ -53,7 +54,7 @@
                $this->helper = new ConstraintParameterParser();
                $this->lookup = new JsonFileEntityLookup( __DIR__ );
                $this->timeValue = new TimeValue( 
'+00000001970-01-01T00:00:00Z', 0, 0, 0, 11, 
'http://www.wikidata.org/entity/Q1985727' );
-               $this->checker = new DiffWithinRangeChecker( $this->helper, new 
RangeCheckerHelper() );
+               $this->checker = new DiffWithinRangeChecker( $this->helper, new 
RangeCheckerHelper( (new TimeParserFactory())->getTimeParser() ) );
        }
 
        protected function tearDown() {
diff --git a/tests/phpunit/Checker/RangeChecker/RangeCheckerHelperTest.php 
b/tests/phpunit/Checker/RangeChecker/RangeCheckerHelperTest.php
index 02139e8..8728e46 100644
--- a/tests/phpunit/Checker/RangeChecker/RangeCheckerHelperTest.php
+++ b/tests/phpunit/Checker/RangeChecker/RangeCheckerHelperTest.php
@@ -10,6 +10,7 @@
 use DataValues\UnboundedQuantityValue;
 use InvalidArgumentException;
 use PHPUnit_Framework_TestCase;
+use Wikibase\Repo\Parsers\TimeParserFactory;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\RangeCheckerHelper;
 
 /**
@@ -29,7 +30,7 @@
         * @dataProvider getComparativeValueProvider
         */
        public function testGetComparativeValue( $expected, DataValue 
$dataValue ) {
-               $rangeCheckHelper = new RangeCheckerHelper();
+               $rangeCheckHelper = new RangeCheckerHelper( (new 
TimeParserFactory())->getTimeParser() );
                $comparativeValue = $rangeCheckHelper->getComparativeValue( 
$dataValue );
 
                $this->assertSame( $expected, $comparativeValue );
@@ -37,7 +38,7 @@
 
        public function getComparativeValueProvider() {
                $cases = [
-                       [ '+1970-01-01T00:00:00Z', $this->getTimeValue() ],
+                       [ [ '+1970', '+01', '+01', '+00', '+00', '+00' ], 
$this->getTimeValue() ],
                        [ '+42', $this->getQuantityValue() ],
                        [ '+9000', UnboundedQuantityValue::newFromNumber( 
'+9000' ) ]
                ];
@@ -49,10 +50,24 @@
         * @expectedException InvalidArgumentException
         */
        public function 
testGetComparativeValue_unsupportedDataValueTypeThrowsException() {
-               $rangeCheckHelper = new RangeCheckerHelper();
+               $rangeCheckHelper = new RangeCheckerHelper( (new 
TimeParserFactory())->getTimeParser() );
                $rangeCheckHelper->getComparativeValue( new StringValue( 
'kittens' ) );
        }
 
+       public function testGetComparativeTimeValueY() {
+               $rangeCheckHelper = new RangeCheckerHelper( (new 
TimeParserFactory())->getTimeParser() );
+               $expected = [ '+1970', '+00', '+00', '+00', '+00', '+00' ];
+               $actual = $rangeCheckHelper->getComparativeTimeValue( '1970' );
+               $this->assertSame( $expected, $actual );
+       }
+
+       public function testGetComparativeTimeValueYMD() {
+               $rangeCheckHelper = new RangeCheckerHelper( (new 
TimeParserFactory())->getTimeParser() );
+               $expected = [ '+1970', '+05', '+03', '+00', '+00', '+00' ];
+               $actual = $rangeCheckHelper->getComparativeTimeValue( 
'1970-05-03' );
+               $this->assertSame( $expected, $actual );
+       }
+
        private function getTimeValue() {
                return new TimeValue(
                        '+00000001970-01-01T00:00:00Z',
diff --git a/tests/phpunit/Checker/RangeChecker/RangeCheckerTest.php 
b/tests/phpunit/Checker/RangeChecker/RangeCheckerTest.php
index 72aff88..d56b471 100644
--- a/tests/phpunit/Checker/RangeChecker/RangeCheckerTest.php
+++ b/tests/phpunit/Checker/RangeChecker/RangeCheckerTest.php
@@ -13,6 +13,7 @@
 use Wikibase\DataModel\Entity\Item;
 use Wikibase\DataModel\Entity\ItemId;
 use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\Repo\Parsers\TimeParserFactory;
 use WikibaseQuality\ConstraintReport\Constraint;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\RangeChecker;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
@@ -57,7 +58,7 @@
                $this->helper = new ConstraintParameterParser();
                $this->lookup = new JsonFileEntityLookup( __DIR__ );
                $this->timeValue = new TimeValue( 
'+00000001970-01-01T00:00:00Z', 0, 0, 0, 11, 
'http://www.wikidata.org/entity/Q1985727' );
-               $this->checker = new RangeChecker( $this->helper, new 
RangeCheckerHelper() );
+               $this->checker = new RangeChecker( $this->helper, new 
RangeCheckerHelper( (new TimeParserFactory())->getTimeParser() ) );
        }
 
        protected function tearDown() {
@@ -102,7 +103,6 @@
        }
 
        public function testRangeConstraintTimeWithinRange() {
-               $this->markTestSkipped( 'RangeChecker does not correctly parse 
the parameters to compare – see T164279.' );
                $min = '+00000001960-01-01T00:00:00Z';
                $max = '+00000001980-01-01T00:00:00Z';
                $statement = new Statement( new PropertyValueSnak( new 
PropertyId( 'P1457' ), $this->timeValue ) );
@@ -115,7 +115,7 @@
        }
 
        public function testRangeConstraintTimeWithinRangeToNow() {
-               $min = '+1960-01-01T00:00:00Z'; // TODO add leading zeroes as 
in testRangeConstraintTimeWithinRange
+               $min = '+00000001960-01-01T00:00:00Z';
                $max = 'now';
                $statement = new Statement( new PropertyValueSnak( new 
PropertyId( 'P1457' ), $this->timeValue ) );
                $constraintParameters = array(
@@ -126,6 +126,30 @@
                $this->assertEquals( 'compliance', $checkResult->getStatus(), 
'check should comply' );
        }
 
+       public function testRangeConstraintTimeWithinYearRange() {
+               $min = '1960';
+               $max = '1980';
+               $statement = new Statement( new PropertyValueSnak( new 
PropertyId( 'P1457' ), $this->timeValue ) );
+               $constraintParameters = array(
+                       'minimum_date' => $min,
+                       'maximum_date' => $max
+               );
+               $checkResult = $this->checker->checkConstraint( $statement, 
$this->getConstraintMock( $constraintParameters ), $this->getEntity() );
+               $this->assertEquals( 'compliance', $checkResult->getStatus(), 
'check should comply' );
+       }
+
+       public function testRangeConstraintTimeWithinYearMonthDayRange() {
+               $min = '1969-12-31';
+               $max = '1970-01-02';
+               $statement = new Statement( new PropertyValueSnak( new 
PropertyId( 'P1457' ), $this->timeValue ) );
+               $constraintParameters = array(
+                       'minimum_date' => $min,
+                       'maximum_date' => $max
+               );
+               $checkResult = $this->checker->checkConstraint( $statement, 
$this->getConstraintMock( $constraintParameters ), $this->getEntity() );
+               $this->assertEquals( 'compliance', $checkResult->getStatus(), 
'check should comply' );
+       }
+
        public function testRangeConstraintTimeTooSmall() {
                $min = '+00000001975-01-01T00:00:00Z';
                $max = '+00000001980-01-01T00:00:00Z';

-- 
To view, visit https://gerrit.wikimedia.org/r/351628
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I902156e4e013e6c5f3c9c73bf35919de9264650a
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/WikibaseQualityConstraints
Gerrit-Branch: master
Gerrit-Owner: Lucas Werkmeister (WMDE) <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to