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

Change subject: Update Wikidata - fix constraint type checks
......................................................................

Update Wikidata - fix constraint type checks

This adds change I2aaf3d6fa6 to the Constraints extension.

Bug: T169326
Change-Id: I49b0f4342b9060bf189f17561e7e3e2e02f536de
---
M composer.lock
M extensions/Constraints/includes/ConstraintCheck/Helper/TypeCheckerHelper.php
M 
extensions/Constraints/tests/phpunit/Checker/TypeChecker/TypeCheckerHelperTest.php
M vendor/composer/installed.json
4 files changed, 113 insertions(+), 30 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata 
refs/changes/55/369555/1

diff --git a/composer.lock b/composer.lock
index 9cd6b13..878c16b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -965,7 +965,7 @@
             "source": {
                 "type": "git",
                 "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints";,
-                "reference": "7b42a909fabb4a2abccdc913cffedd74937a62c4"
+                "reference": "6c32f105be631dcbf876c713bf298381428afea4"
             },
             "require": {
                 "php": ">=5.5.9",
@@ -1026,7 +1026,7 @@
             "support": {
                 "issues": 
"https://phabricator.wikimedia.org/project/profile/1202/";
             },
-            "time": "2017-08-01T11:10:09+00:00"
+            "time": "2017-08-01T14:04:16+00:00"
         },
         {
             "name": "wikibase/data-model",
diff --git 
a/extensions/Constraints/includes/ConstraintCheck/Helper/TypeCheckerHelper.php 
b/extensions/Constraints/includes/ConstraintCheck/Helper/TypeCheckerHelper.php
index d7cb13a..b3b698a 100644
--- 
a/extensions/Constraints/includes/ConstraintCheck/Helper/TypeCheckerHelper.php
+++ 
b/extensions/Constraints/includes/ConstraintCheck/Helper/TypeCheckerHelper.php
@@ -4,6 +4,7 @@
 
 use Config;
 use MediaWiki\MediaWikiServices;
+use OverflowException;
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Entity\EntityIdValue;
 use Wikibase\DataModel\Entity\PropertyId;
@@ -68,31 +69,19 @@
         * of one of the item ID serializations in $classesToCheck.
         * If the class hierarchy is not exhausted before
         * the configured limit (WBQualityConstraintsTypeCheckMaxEntities) is 
reached,
-        * the injected {@link SparqlHelper} is consulted if present,
-        * otherwise the check aborts and returns false.
+        * an OverflowException is thrown.
         *
         * @param EntityId $comparativeClass
         * @param string[] $classesToCheck
         * @param int &$entitiesChecked
         *
         * @return bool
-        *
-        * @throws SparqlHelperException if SPARQL is used and the query times 
out or some other error occurs
+        * @throws OverflowException if $entitiesChecked exceeds the configured 
limit
         */
-       public function isSubclassOf( EntityId $comparativeClass, array 
$classesToCheck, &$entitiesChecked = 0 ) {
+       private function isSubclassOf( EntityId $comparativeClass, array 
$classesToCheck, &$entitiesChecked = 0 ) {
                $maxEntities = $this->config->get( 
'WBQualityConstraintsTypeCheckMaxEntities' );
                if ( ++$entitiesChecked > $maxEntities ) {
-                       if ( $entitiesChecked === $maxEntities + 1 && 
$this->sparqlHelper !== null ) {
-                               
MediaWikiServices::getInstance()->getStatsdDataFactory()
-                                       ->increment( 
'wikibase.quality.constraints.sparql.typeFallback' );
-                               return $this->sparqlHelper->hasType(
-                                       $comparativeClass->getSerialization(),
-                                       $classesToCheck,
-                                       /* withInstance = */ false
-                               );
-                       } else {
-                               return false;
-                       }
+                       throw new OverflowException( 'Too many entities to 
check' );
                }
 
                $item = $this->entityLookup->getEntity( $comparativeClass );
@@ -127,6 +116,39 @@
        }
 
        /**
+        * Checks if $comparativeClass is a subclass
+        * of one of the item ID serializations in $classesToCheck.
+        * If isSubclassOf() aborts due to hitting the configured limit,
+        * the injected {@link SparqlHelper} is consulted if present,
+        * otherwise the check returns false.
+        *
+        * @param EntityId $comparativeClass
+        * @param string[] $classesToCheck
+        * @param int &$entitiesChecked
+        *
+        * @return bool
+        *
+        * @throws SparqlHelperException if SPARQL is used and the query times 
out or some other error occurs
+        */
+       public function isSubclassOfWithSparqlFallback( EntityId 
$comparativeClass, array $classesToCheck ) {
+               try {
+                       return $this->isSubclassOf( $comparativeClass, 
$classesToCheck );
+               } catch ( OverflowException $e ) {
+                       if ( $this->sparqlHelper !== null ) {
+                               
MediaWikiServices::getInstance()->getStatsdDataFactory()
+                                       ->increment( 
'wikibase.quality.constraints.sparql.typeFallback' );
+                               return $this->sparqlHelper->hasType(
+                                       $comparativeClass->getSerialization(),
+                                       $classesToCheck,
+                                       /* withInstance = */ false
+                               );
+                       } else {
+                               return false;
+                       }
+               }
+       }
+
+       /**
         * Checks, if one of the itemId serializations in $classesToCheck
         * is contained in the list of $statements
         * via property $relationId or if it is a subclass of
@@ -158,7 +180,7 @@
                                return true;
                        }
 
-                       if ( $this->isSubclassOf( $comparativeClass, 
$classesToCheck ) ) {
+                       if ( $this->isSubclassOfWithSparqlFallback( 
$comparativeClass, $classesToCheck ) ) {
                                return true;
                        }
                }
diff --git 
a/extensions/Constraints/tests/phpunit/Checker/TypeChecker/TypeCheckerHelperTest.php
 
b/extensions/Constraints/tests/phpunit/Checker/TypeChecker/TypeCheckerHelperTest.php
index c4173a6..746cc8e 100644
--- 
a/extensions/Constraints/tests/phpunit/Checker/TypeChecker/TypeCheckerHelperTest.php
+++ 
b/extensions/Constraints/tests/phpunit/Checker/TypeChecker/TypeCheckerHelperTest.php
@@ -4,12 +4,15 @@
 
 use PHPUnit_Framework_TestCase;
 use Wikibase\DataModel\Services\Lookup\EntityLookup;
+use Wikibase\DataModel\Services\Lookup\InMemoryEntityLookup;
 use Wikibase\DataModel\Statement\Statement;
 use Wikibase\DataModel\Snak\PropertyValueSnak;
 use Wikibase\DataModel\Entity\EntityIdValue;
 use Wikibase\DataModel\Entity\ItemId;
 use Wikibase\DataModel\Entity\PropertyId;
 use Wikibase\DataModel\Statement\StatementList;
+use Wikibase\Repo\Tests\NewItem;
+use Wikibase\Repo\Tests\NewStatement;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\SparqlHelper;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\TypeCheckerHelper;
 use WikibaseQuality\ConstraintReport\Tests\ConstraintParameters;
@@ -46,11 +49,14 @@
        }
 
        /**
+        * @param EntityLookup $lookup The backing lookup of the mock (defaults 
to JsonFileEntityLookup).
         * @return EntityLookup Expects that getEntity is called
         * exactly WBQualityConstraintsTypeCheckMaxEntities times.
         */
-       private function getMaxEntitiesLookup() {
-               $lookup = new JsonFileEntityLookup( __DIR__ );
+       private function getMaxEntitiesLookup( EntityLookup $lookup = null ) {
+               if ( $lookup === null ) {
+                       $lookup = new JsonFileEntityLookup( __DIR__ );
+               }
                $maxEntities = $this->getDefaultConfig()->get( 
'WBQualityConstraintsTypeCheckMaxEntities' );
 
                $spy = $this->getMock( EntityLookup::class );
@@ -63,15 +69,20 @@
 
        /**
         * @param boolean $return
+        * @param array|null $arguments
         * @return SparqlHelper expects that {@link SparqlHelper::hasType}
         * is called exactly once and returns $return.
         */
-       private function getSparqlHelper( $return ) {
+       private function getSparqlHelper( $return, array $arguments = null ) {
+               if ( $arguments === null ) {
+                       $arguments = [ $this->anything(), $this->anything(), 
$this->anything() ];
+               }
                $mock = $this->getMockBuilder( SparqlHelper::class )
                          ->disableOriginalConstructor()
                          ->getMock();
                $mock->expects( $this->once() )
                        ->method( 'hasType' )
+                       ->withConsecutive( $arguments )
                        ->willReturn( $return );
                return $mock;
        }
@@ -98,31 +109,81 @@
        }
 
        public function testCheckIsSubclassOfValidWithIndirection() {
-               $this->assertTrue( $this->getHelper()->isSubclassOf( new 
ItemId( 'Q6' ), [ 'Q100', 'Q101' ] ) );
+               $this->assertTrue( 
$this->getHelper()->isSubclassOfWithSparqlFallback( new ItemId( 'Q6' ), [ 
'Q100', 'Q101' ] ) );
        }
 
        public function testCheckIsSubclassOfInvalid() {
-               $this->assertFalse( $this->getHelper()->isSubclassOf( new 
ItemId( 'Q6' ), [ 'Q200', 'Q201' ] ) );
+               $this->assertFalse( 
$this->getHelper()->isSubclassOfWithSparqlFallback( new ItemId( 'Q6' ), [ 
'Q200', 'Q201' ] ) );
        }
 
        public function testCheckIsSubclassCyclic() {
                $helper = $this->getHelper( $this->getMaxEntitiesLookup() );
-               $this->assertFalse( $helper->isSubclassOf( new ItemId( 'Q7' ), 
[ 'Q100', 'Q101' ] ) );
+               $this->assertFalse( $helper->isSubclassOfWithSparqlFallback( 
new ItemId( 'Q7' ), [ 'Q100', 'Q101' ] ) );
        }
 
        public function testCheckIsSubclassCyclicWide() {
                $helper = $this->getHelper( $this->getMaxEntitiesLookup() );
-               $this->assertFalse( $helper->isSubclassOf( new ItemId( 'Q9' ), 
[ 'Q100', 'Q101' ] ) );
+               $this->assertFalse( $helper->isSubclassOfWithSparqlFallback( 
new ItemId( 'Q9' ), [ 'Q100', 'Q101' ] ) );
        }
 
        public function testCheckIsSubclassCyclicWideWithSparqlTrue() {
                $helper = $this->getHelper( $this->getMaxEntitiesLookup(), 
$this->getSparqlHelper( true ) );
-               $this->assertTrue( $helper->isSubclassOf( new ItemId( 'Q9' ), [ 
'Q100', 'Q101' ] ) );
+               $this->assertTrue( $helper->isSubclassOfWithSparqlFallback( new 
ItemId( 'Q9' ), [ 'Q100', 'Q101' ] ) );
        }
 
        public function testCheckIsSubclassCyclicWideWithSparqlFalse() {
                $helper = $this->getHelper( $this->getMaxEntitiesLookup(), 
$this->getSparqlHelper( false ) );
-               $this->assertFalse( $helper->isSubclassOf( new ItemId( 'Q9' ), 
[ 'Q100', 'Q101' ] ) );
+               $this->assertFalse( $helper->isSubclassOfWithSparqlFallback( 
new ItemId( 'Q9' ), [ 'Q100', 'Q101' ] ) );
+       }
+
+       public function testCheckIsSubclassTree() {
+               $lookup = new InMemoryEntityLookup();
+               $subclassPid = $this->getDefaultConfig()->get( 
'WBQualityConstraintsSubclassOfId' );
+
+               $q1 = NewItem::withId( 'Q1' )
+                       ->andStatement(
+                               NewStatement::forProperty( $subclassPid )
+                                       ->withValue( new ItemId( 'Q2' ) )
+                       )
+                       ->build();
+               $lookup->addEntity( $q1 );
+               $q2 = NewItem::withId( 'Q2' )
+                       ->andStatement(
+                               NewStatement::forProperty( $subclassPid )
+                                       ->withValue( new ItemId( 'Q3' ) )
+                       )
+                       ->andStatement(
+                               NewStatement::forProperty( $subclassPid )
+                                       ->withValue( new ItemId( 'Q5' ) )
+                       )
+                       ->build();
+               $lookup->addEntity( $q2 );
+               $q3 = NewItem::withId( 'Q3' )
+                       ->andStatement(
+                               NewStatement::forProperty( $subclassPid )
+                                       ->withValue( new ItemId( 'Q4' ) )
+                       )
+                       ->build();
+               $lookup->addEntity( $q3 );
+               $q4 = NewItem::withId( 'Q4' )
+                       ->andStatement(
+                               NewStatement::forProperty( $subclassPid )
+                                       ->withValue( new ItemId( 'Q3' ) )
+                       )
+                       ->build();
+               $lookup->addEntity( $q4 );
+
+               $sparqlHelper = $this->getSparqlHelper(
+                       true,
+                       [
+                               $this->identicalTo( 'Q1' ),
+                               $this->identicalTo( [ 'Q5' ] ),
+                               $this->identicalTo( false )
+                       ]
+               );
+               $helper = $this->getHelper( $this->getMaxEntitiesLookup( 
$lookup ), $sparqlHelper );
+
+               $this->assertTrue( $helper->isSubclassOfWithSparqlFallback( new 
ItemId( 'Q1' ), [ 'Q5' ] ) );
        }
 
 }
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 88b7c4e..18dfcf1 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1711,7 +1711,7 @@
         "source": {
             "type": "git",
             "url": 
"https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints";,
-            "reference": "7b42a909fabb4a2abccdc913cffedd74937a62c4"
+            "reference": "6c32f105be631dcbf876c713bf298381428afea4"
         },
         "require": {
             "php": ">=5.5.9",
@@ -1727,7 +1727,7 @@
             "satooshi/php-coveralls": "master-dev",
             "wikibase/wikibase-codesniffer": "^0.1.0"
         },
-        "time": "2017-08-01T11:10:09+00:00",
+        "time": "2017-08-01T14:04:16+00:00",
         "type": "mediawiki-extension",
         "installation-source": "source",
         "autoload": {

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I49b0f4342b9060bf189f17561e7e3e2e02f536de
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikidata
Gerrit-Branch: master
Gerrit-Owner: Lucas Werkmeister (WMDE) <lucas.werkmeis...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to