jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/341521 )

Change subject: WikibaseQualityConstraints Extension (API)
......................................................................


WikibaseQualityConstraints Extension (API)

Change-Id: Icf4ec91bc0a06435bcf626e2060008d0d88027a8
---
M WikibaseQualityConstraints.php
A api/CheckConstraints.php
M composer.json
M i18n/en.json
M i18n/qqq.json
M includes/ConstraintCheck/DelegatingConstraintChecker.php
A includes/ConstraintParameterRenderer.php
M includes/ConstraintReportFactory.php
M specials/SpecialConstraintReport.php
A tests/phpunit/Api/CheckConstraintsTest.php
M tests/phpunit/DelegatingConstraintCheckerTest.php
A tests/phpunit/Q6.json
12 files changed, 1,031 insertions(+), 90 deletions(-)

Approvals:
  Jonas Kress (WMDE): Looks good to me, approved
  jenkins-bot: Verified



diff --git a/WikibaseQualityConstraints.php b/WikibaseQualityConstraints.php
index bc994f9..70460fa 100644
--- a/WikibaseQualityConstraints.php
+++ b/WikibaseQualityConstraints.php
@@ -29,6 +29,16 @@
        // Initialize special pages
        $GLOBALS['wgSpecialPages']['ConstraintReport'] = 
'WikibaseQuality\ConstraintReport\Specials\SpecialConstraintReport::newFromGlobalState';
 
+       $GLOBALS['wgAPIModules']['wbcheckconstraints'] = [
+               'class' => 
'\WikibaseQuality\ConstraintReport\Api\CheckConstraints',
+               'factory' => function ( $main, $name ) {
+                       return 
\WikibaseQuality\ConstraintReport\Api\CheckConstraints::newFromGlobalState(
+                               $main,
+                               $name
+                       );
+               }
+       ];
+
        // Define modules
        $remoteExtPathParts = explode(
                DIRECTORY_SEPARATOR . 'extensions' . DIRECTORY_SEPARATOR, 
__DIR__, 2
diff --git a/api/CheckConstraints.php b/api/CheckConstraints.php
new file mode 100644
index 0000000..00a5f8f
--- /dev/null
+++ b/api/CheckConstraints.php
@@ -0,0 +1,378 @@
+<?php
+
+namespace WikibaseQuality\ConstraintReport\Api;
+
+use ApiBase;
+use ApiMain;
+use ApiResult;
+use DataValues\DataValue;
+use Wikibase\DataModel\Entity\EntityIdValue;
+use Wikibase\DataModel\Services\EntityId\EntityIdFormatter;
+
+use RequestContext;
+
+use Wikibase\DataModel\Entity\EntityId;
+
+use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikibase\DataModel\Entity\EntityIdParsingException;
+use Wikibase\DataModel\Services\Statement\StatementGuidValidator;
+use Wikibase\DataModel\Services\Statement\StatementGuidParser;
+use Wikibase\Repo\Api\ApiErrorReporter;
+use Wikibase\Repo\Api\ApiHelperFactory;
+
+use Wikibase\Repo\WikibaseRepo;
+
+use WikibaseQuality\ConstraintReport\ConstraintReportFactory;
+use 
WikibaseQuality\ConstraintReport\ConstraintCheck\DelegatingConstraintChecker;
+
+use Wikibase\Repo\EntityIdLabelFormatterFactory;
+use ValueFormatters\FormatterOptions;
+use Wikibase\Lib\OutputFormatValueFormatterFactory;
+use Wikibase\Lib\SnakFormatter;
+
+use WikibaseQuality\ConstraintReport\ConstraintParameterRenderer;
+use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory;
+
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\PropertyId;
+
+use Wikibase\ChangeOp\StatementChangeOpFactory;
+use Wikibase\LanguageFallbackChain;
+use Wikibase\LanguageFallbackChainFactory;
+use Wikibase\DataModel\Services\Lookup\TermLookup;
+use Wikibase\DataModel\Services\Term\TermBuffer;
+use Wikimedia\Assert\Assert;
+use Language;
+
+/**
+ * API module that performs constraint check of entities, claims and 
constraint ID
+ *
+ * @author Olga Bode
+ * @license GNU GPL v2+
+ */
+class CheckConstraints extends ApiBase {
+
+       const PARAM_ID = 'id';
+       const PARAM_CLAIM_ID = 'claimid';
+       const PARAM_CONSTRAINT_ID = 'constraintid';
+
+       /**
+        *
+        * @var EntityIdParser
+        */
+       private $entityIdParser;
+
+       /**
+        *
+        * @var StatementGuidValidator
+        */
+       private $statementGuidValidator;
+
+       /**
+        *
+        * @var StatementGuidParser
+        */
+       private $statementGuidParser;
+
+       /**
+        *
+        * @var DelegatingConstraintChecker
+        */
+       private $delegatingConstraintChecker;
+
+       /**
+        *
+        * @var ApiErrorReporter
+        */
+       private $errorReporter;
+
+       /**
+        *
+        * @var EntityIdFormatter
+        */
+       private $entityIdLabelFormatter;
+
+       /**
+        *
+        * @var StatementChangeOpFactory
+        */
+       private $statementChangeOpFactory;
+
+       /**
+        *
+        * @var ConstraintParameterRenderer
+        */
+       private $constraintParameterRenderer;
+
+       /**
+        * @var TermLookup
+        */
+       private $termLookup;
+
+       /**
+        * Creates new instance from global state.
+        *
+        * @param ApiMain $main
+        * @param string $name
+        * @param string $prefix
+        *
+        * @return self
+        */
+       public static function newFromGlobalState( ApiMain $main, $name, 
$prefix = '' ) {
+               $repo = WikibaseRepo::getDefaultInstance();
+               $constraintReportFactory = 
ConstraintReportFactory::getDefaultInstance();
+               $changeOpFactoryProvider = $repo->getChangeOpFactoryProvider();
+               $termLookup = $repo->getTermLookup();
+               $termBuffer = $repo->getTermBuffer();
+               $languageFallbackChainFactory = new 
LanguageFallbackChainFactory();
+               $fallbackLabelDescLookupFactory = new 
LanguageFallbackLabelDescriptionLookupFactory( $languageFallbackChainFactory, 
$termLookup, $termBuffer );
+               $factory = new EntityIdLabelFormatterFactory();
+
+               $language = new Language();
+               $labelLookup = 
$fallbackLabelDescLookupFactory->newLabelDescriptionLookup( $language );
+
+               $formatterOptions = new FormatterOptions();
+               $factoryFunctions = [];
+               Assert::parameterElementType( 'callable', $factoryFunctions, 
'$factoryFunctions' );
+               $formatterOptions->setOption( SnakFormatter::OPT_LANG, 
$language->getCode() );
+               $valueFormatterFactory = new OutputFormatValueFormatterFactory( 
$factoryFunctions, $language,$languageFallbackChainFactory );
+               $valueFormatter = $valueFormatterFactory->getValueFormatter( 
SnakFormatter::FORMAT_HTML, $formatterOptions );
+
+               return new CheckConstraints( $main, $name, $prefix, 
$repo->getEntityIdParser(),
+                       $repo->getStatementGuidValidator(), 
$repo->getStatementGuidParser(), 
$constraintReportFactory->getConstraintChecker(),
+                       new ConstraintParameterRenderer( 
$factory->getEntityIdFormatter( $labelLookup ), $valueFormatter ),
+                       $repo->getApiHelperFactory( RequestContext::getMain() ) 
);
+       }
+
+       /**
+        *
+        * @param ApiMain $main
+        * @param string $name
+        * @param string $prefix
+        * @param EntityIdParser $entityIdParser
+        * @param StatementGuidValidator $statementGuidValidator
+        * @param StatementGuidParser $statementGuidParser
+        * @param DelegatingConstraintChecker $delegatingConstraintChecker
+        * @param ConstraintParameterRenderer $constraintParameterRenderer
+        * @param ApiHelperFactory $apiHelperFactory
+        */
+       public function __construct( ApiMain $main, $name, $prefix = '', 
EntityIdParser $entityIdParser,
+               StatementGuidValidator $statementGuidValidator,
+               StatementGuidParser $statementGuidParser,
+               DelegatingConstraintChecker $delegatingConstraintChecker,
+               ConstraintParameterRenderer $constraintParameterRenderer,
+               ApiHelperFactory $apiHelperFactory ) {
+               parent::__construct( $main, $name, $prefix );
+
+               $repo = WikibaseRepo::getDefaultInstance();
+               $this->statementDeserializer = 
$repo->getExternalFormatStatementDeserializer();
+               $changeOpFactoryProvider = $repo->getChangeOpFactoryProvider();
+
+               $this->statementChangeOpFactory = 
$changeOpFactoryProvider->getStatementChangeOpFactory();
+
+               $this->entityIdParser = $entityIdParser;
+               $this->statementGuidValidator = $statementGuidValidator;
+               $this->statementGuidParser = $statementGuidParser;
+               $this->delegatingConstraintChecker = 
$delegatingConstraintChecker;
+               $this->resultBuilder = $apiHelperFactory->getResultBuilder( 
$this );
+               $this->errorReporter = $apiHelperFactory->getErrorReporter( 
$this );
+
+               $this->constraintParameterRenderer = 
$constraintParameterRenderer;
+       }
+
+       /**
+        * Evaluates the parameters, runs the requested constraint check, and 
sets up the result
+        */
+       public function execute() {
+               $params = $this->extractRequestParams();
+               $output = [];
+
+               $this->validateParameters( $params );
+               $entityIds = $this->parseEntityIds( $params );
+               $claimIds = $this->parseClaimIds( $params );
+
+               $output = array_merge( $output, $this->checkItems( $entityIds, 
$params[self::PARAM_CONSTRAINT_ID] ) );
+               $output = array_merge( $output, $this->checkClaimIds( 
$claimIds, $params[self::PARAM_CONSTRAINT_ID] ) );
+
+               $this->getResult()->addValue( null, $this->getModuleName(), 
$this->buildResult( $output, $params[self::PARAM_ID] ) );
+               $this->resultBuilder->markSuccess( 1 );
+       }
+
+
+       private function checkItems( array $entityIds, $constraintIds ) {
+
+               $checkResults = [];
+               foreach ( $entityIds as $entityId ) {
+                       $currentCheckResults = 
$this->delegatingConstraintChecker->checkAgainstConstraintsOnEntityId(
+                               $entityId, $constraintIds );
+                       if ( $currentCheckResults ) {
+                               $checkResults = array_merge( $checkResults, 
$currentCheckResults );
+                       }
+               }
+
+               return $checkResults;
+       }
+
+       private function checkClaimIds( array $claimIds, $constraintIds ) {
+
+               $checkResults = [];
+               foreach ( $claimIds as $claimId ) {
+                       $currentCheckResults = 
$this->delegatingConstraintChecker->checkAgainstConstraintsOnClaimId(
+                               $claimId, $constraintIds );
+                       if ( $currentCheckResults ) {
+                               $checkResults = array_merge( $checkResults, 
$currentCheckResults );
+                       }
+               }
+
+               return $checkResults;
+       }
+
+       private function parseEntityIds( array $params ) {
+               $ids = $params[self::PARAM_ID];
+               if ( $ids !== null ) {
+                       if ( $ids ) {
+                               foreach ( $ids as $id ) {
+                                       try {
+                                               $entityIds[] = 
$this->entityIdParser->parse( $id );
+                                       } catch ( EntityIdParsingException $e ) 
{
+                                               $this->errorReporter->dieError(
+                                                       "Invalid id: $id", 
'invalid-entity-id', 0, [ self::PARAM_ID => $id ] );
+                                       }
+                               }
+                               return $entityIds;
+                       } else {
+                               $paramId = self::PARAM_ID;
+                               $this->errorReporter->dieError(
+                                       "If $paramId is specified, it must be 
nonempty.", 'no-data' );
+                       }
+               } else {
+                       return [];
+               }
+       }
+
+       private function parseClaimIds( array $params ) {
+               $ids = $params[self::PARAM_CLAIM_ID];
+               if ( $ids !== null ) {
+                       if ( $ids ) {
+                               foreach ( $ids as $id ) {
+                                       try {
+                                               $claimIds[] = 
$this->statementGuidParser->parse( $id );
+                                       } catch ( EntityIdParsingException $e ) 
{
+                                               $this->errorReporter->dieError(
+                                                       "Invalid claim id: 
$id", 'invalid-guid', 0, [ self::PARAM_CLAIM_ID => $id ] );
+                                       }
+                               }
+                               return $claimIds;
+                       } else {
+                               $paramClaimId = self::PARAM_CLAIM_ID;
+                               $this->errorReporter->dieError(
+                                       "If $paramClaimId is specified, it must 
be nonempty.", 'no-data' );
+                       }
+               } else {
+                       return [];
+               }
+       }
+
+       private function validateParameters( array $params ) {
+               if ( $params[self::PARAM_CONSTRAINT_ID] !== null
+                        && empty( $params[self::PARAM_CONSTRAINT_ID] ) ) {
+                       $paramConstraintId = self::PARAM_CONSTRAINT_ID;
+                       $this->errorReporter->dieError(
+                               "If $paramConstraintId is specified, it must be 
nonempty.", 'no-data' );
+               }
+               if ( $params[self::PARAM_ID] === null && 
$params[self::PARAM_CLAIM_ID] === null ) {
+                       $paramId = self::PARAM_ID;
+                       $paramClaimId = self::PARAM_CLAIM_ID;
+                       $this->errorReporter->dieError(
+                               "At least one of $paramId, $paramClaimId must 
be specified.", 'no-data' );
+               }
+               // contents of PARAM_ID and PARAM_CLAIM_ID are validated by 
parse{Entity,Claim}Ids()
+       }
+
+       /**
+        * Converts a flat list of constraint check results
+        * to a nested array structure which can be stored in the ApiResult.
+        * The array is keyed by entity ID, then by property ID,
+        * then by claim ID, and then contains a list of individual results:
+        * { "Q1": { "P1": { "Q1$1a2b...": [ { "status": "compliance", ... }, { 
... } ] } } }
+        *
+        * @param CheckResult[] $checkResults
+        * @param string[]|null $entityIds optionally, a list of entity IDs 
that should be present in the output even if there are no check results for them
+        *
+        * @return array
+        */
+       private function buildResult( array $checkResults, $entityIds = null ) {
+
+               $constraintReport = array();
+               ApiResult::setArrayType( $constraintReport, 'assoc' );
+
+               // ensure that the report contains the given IDs even if there 
are no results for them
+               if ( $entityIds ) {
+                       foreach ( $entityIds as $entityId ) {
+                               $constraintReport[$entityId] = [];
+                               ApiResult::setArrayType( 
$constraintReport[$entityId], 'assoc' );
+                       }
+               }
+
+               foreach ( $checkResults as $checkResult ) {
+
+                       $statement = $checkResult->getStatement();
+
+                       $entityId = 
$checkResult->getEntityId()->getSerialization();
+                       $propertyId = 
$checkResult->getPropertyId()->getSerialization();
+                       $claimId = $statement->getGuid();
+
+                       $result = [
+                               'status' =>  $checkResult->getStatus(),
+                               'property' => 
$checkResult->getPropertyId()->getSerialization(),
+                               'claim' => 
$checkResult->getStatement()->getGuid(),
+                               'constraint' => array(
+                                       'id' => $checkResult->getConstraintId(),
+                                       'type' => 
$checkResult->getConstraintName(),
+                                       'detail' => 
$checkResult->getParameters(),
+                                       'detailHTML' => 
$this->constraintParameterRenderer->formatParameters( 
$checkResult->getParameters() )
+                               )
+                       ];
+                       if ( $checkResult->getMessage() ) {
+                               $result['message-html'] = 
$checkResult->getMessage();
+                       }
+
+                       $constraintReport[$entityId][$propertyId][$claimId][] = 
$result;
+               }
+               return $constraintReport;
+       }
+
+       /**
+        * Returns an array of allowed parameters
+        *
+        * @return array @codeCoverageIgnore
+        */
+       public function getAllowedParams() {
+               return [
+                               self::PARAM_ID => [
+                                               ApiBase::PARAM_TYPE => 'string',
+                                               ApiBase::PARAM_ISMULTI => true
+                               ],
+                               self::PARAM_CLAIM_ID => [
+                                               ApiBase::PARAM_TYPE => 'string',
+                                               ApiBase::PARAM_ISMULTI => true
+                               ],
+                               self::PARAM_CONSTRAINT_ID => [
+                                               ApiBase::PARAM_TYPE => 'string',
+                                               ApiBase::PARAM_ISMULTI => true
+                               ]
+               ];
+       }
+
+       /**
+        * Returns usage examples for this module
+        *
+        * @return array
+        * @codeCoverageIgnore
+        */
+       public function getExamplesMessages() {
+               // TODO Add examples
+               return [];
+       }
+
+}
diff --git a/composer.json b/composer.json
index 073cf85..57d1d21 100644
--- a/composer.json
+++ b/composer.json
@@ -27,6 +27,7 @@
        "autoload": {
                "psr-4": {
                        "WikibaseQuality\\ConstraintReport\\": "includes/",
+                       "WikibaseQuality\\ConstraintReport\\Api\\": "api/",
                        "WikibaseQuality\\ConstraintReport\\Specials\\": 
"specials/",
                        "WikibaseQuality\\ConstraintReport\\Tests\\": 
"tests/phpunit/",
                        "WikibaseQuality\\ConstraintReport\\Maintenance\\": 
"maintenance/"
@@ -41,4 +42,4 @@
                        "parallel-lint . --exclude vendor"
                ]
        }
-}
+}
\ No newline at end of file
diff --git a/i18n/en.json b/i18n/en.json
index fdc12cf..c01e399 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -28,6 +28,11 @@
        "wbqc-constraintreport-result-link-to-constraint": "go to constraint",
        "wbqc-constraintreport-no-parameter": "none",
 
+       "apihelp-wbcheckconstraints-description": "Performs constraint checks 
on any entity you want and returns the result.",
+       "apihelp-wbcheckconstraints-param-id": "ID list of the entities to get 
the data from. Separate values with '|' or alternative.",
+       "apihelp-wbcheckconstraints-param-claimid": "GUID list identifying a 
claim to check a constraint report.  Separate values with '|'.",
+       "apihelp-wbcheckconstraints-param-constraintid": "Optional filter to 
return only the constraints that have the specified constraint ID",
+
        "wbq-subextension-name-wbqc": "Constraints",
        "wbqc-violation-header-parameters": "Parameters:",
        "wbqc-violations-group": "Constraints",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 089b866..5cd91ed 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -64,5 +64,9 @@
        "wbqc-violation-message-type": "Message for violation of Type 
constraint. When entity is not of given type.",
        "wbqc-violation-message-target-required-claim-property": "Message for 
violation of Target required claim constraint. When only a property is given.",
        "wbqc-violation-message-target-required-claim-claim": "Message for 
violation of Target required claim constraint. When property and value are 
given.",
-       "wbqc-violation-message-value-type": "Message for violation of Value 
type constraint. When value is not of given type."
+       "wbqc-violation-message-value-type": "Message for violation of Value 
type constraint. When value is not of given type.",
+       "apihelp-wbcheckconstraints-description": 
"{{doc-apihelp-description|wbcheckconstraints}}",
+       "apihelp-wbcheckconstraints-param-id": 
"{{doc-apihelp-param|wbcheckconstraints|id}}",
+       "apihelp-wbcheckconstraints-param-claimid": 
"{{doc-apihelp-param|wbcheckconstraints|claimid}}",
+       "apihelp-wbcheckconstraints-param-constraintid": 
"{{doc-apihelp-param|wbcheckconstraints|constraintid}}"
 }
diff --git a/includes/ConstraintCheck/DelegatingConstraintChecker.php 
b/includes/ConstraintCheck/DelegatingConstraintChecker.php
index 120d9f1..79c2bed 100644
--- a/includes/ConstraintCheck/DelegatingConstraintChecker.php
+++ b/includes/ConstraintCheck/DelegatingConstraintChecker.php
@@ -7,11 +7,13 @@
 use Wikibase\DataModel\Entity\EntityDocument;
 use Wikibase\DataModel\Services\Lookup\EntityLookup;
 use Wikibase\DataModel\Statement\Statement;
+use Wikibase\DataModel\Statement\StatementGuid;
 use Wikibase\DataModel\Statement\StatementList;
 use Wikibase\DataModel\Statement\StatementListProvider;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
 use WikibaseQuality\ConstraintReport\ConstraintLookup;
 use WikibaseQuality\ConstraintReport\Constraint;
+use Wikibase\DataModel\Entity\EntityId;
 
 /**
  * Used to start the constraint-check process and to delegate
@@ -50,12 +52,16 @@
        /**
         * @param EntityLookup $lookup
         * @param ConstraintChecker[] $checkerMap
-        * @param ConstraintLookup $constraintLookup
+        * @param ConstraintLookup $constraintRepository
         */
-       public function __construct( EntityLookup $lookup, array $checkerMap, 
ConstraintLookup $constraintLookup ) {
+       public function __construct(
+               EntityLookup $lookup,
+               array $checkerMap,
+               ConstraintLookup $constraintRepository
+       ) {
                $this->entityLookup = $lookup;
                $this->checkerMap = $checkerMap;
-               $this->constraintLookup = $constraintLookup;
+               $this->constraintLookup = $constraintRepository;
        }
 
        /**
@@ -79,31 +85,108 @@
        }
 
        /**
+        * Starts the whole constraint-check process for entity or constraint 
ID on entity.
+        * Statements of the entity will be checked against every constraint 
that is defined on the property.
+        *
+        * @param EntityId $entityId
+        * @param array $constraintIds
+        *
+        * @return CheckResult[]
+        *
+        */
+       public function checkAgainstConstraintsOnEntityId( EntityId $entityId, 
$constraintIds = null ) {
+
+               $entity = $this->entityLookup->getEntity( $entityId );
+               if ( $entity instanceof StatementListProvider ) {
+                       $this->statements = $entity->getStatements();
+                       $result = $this->checkEveryStatement( 
$this->entityLookup->getEntity( $entityId ), $constraintIds );
+                       $output = $this->sortResult( $result );
+                       return $output;
+               }
+
+               return [];
+       }
+
+       /**
+        * Starts the whole constraint-check process.
+        * Statements of the entity will be checked against every constraint 
that is defined on the claim.
+        *
+        * @param StatementGuid $guid
+        * @param array $constraintIds
+        * @return CheckResult[]
+        */
+       public function checkAgainstConstraintsOnClaimId( StatementGuid $guid, 
$constraintIds = null ) {
+
+               $entityId = $guid->getEntityId();
+               $entity = $this->entityLookup->getEntity( $entityId );
+               if ( $entity instanceof StatementListProvider ) {
+                       $statement = 
$entity->getStatements()->getFirstStatementWithGuid( $guid->getSerialization() 
);
+                       if ( $statement ) {
+                               $result = $this->checkStatement( $entity, 
$statement, $constraintIds );
+                               $output = $this->sortResult( $result );
+                               return $output;
+                       }
+               }
+
+               return [];
+       }
+
+       /**
         * @param EntityDocument|StatementListProvider $entity
+        * @param string[]|null $constraintIds list of constraints to check (if 
null: all constraints)
         *
         * @return CheckResult[]
         */
-       private function checkEveryStatement( EntityDocument $entity ) {
+       private function checkEveryStatement( EntityDocument $entity, 
$constraintIds = null ) {
                $result = array ();
 
                /** @var Statement $statement */
                foreach ( $this->statements as $statement ) {
-                       if ( $statement->getMainSnak()->getType() !== 'value' ) 
{
-                               // skip 'somevalue' and 'novalue' cases, todo: 
handle in a better way
-                               continue;
-                       }
-
-                       $constraints = 
$this->constraintLookup->queryConstraintsForProperty(
-                               $statement->getPropertyId()
-                       );
-
-                       $result = array_merge( $result, 
$this->checkConstraintsForStatementOnEntity( $constraints, $entity, $statement 
) );
+                       $result = array_merge( $result, $this->checkStatement( 
$entity, $statement, $constraintIds ) );
                }
 
                return $result;
        }
 
        /**
+        *
+        * @param EntityDocument|StatementListProvider $entity
+        * @param Statement $statement
+        * @param string[]|null $constraintIds list of constraints to check (if 
null: all constraints)
+        *
+        *
+        * @return CheckResult[]
+        */
+       private function checkStatement( EntityDocument $entity, Statement 
$statement, $constraintIds = null ) {
+               $result = array();
+
+               if ( $statement->getMainSnak()->getType() !== 'value' ) {
+                       // skip 'somevalue' and 'novalue' cases, todo: handle 
in a better way
+                       return [];
+               }
+
+               $constraints = 
$this->constraintLookup->queryConstraintsForProperty(
+                       $statement->getPropertyId()
+               );
+               if ( $constraintIds !== null ) {
+                       $constraintsToUse = [];
+                       foreach ( $constraints as $constraint ) {
+                               if ( in_array( $constraint->getConstraintId(), 
$constraintIds ) ) {
+                                       $constraintsToUse[] = $constraint;
+                               }
+                       }
+               } else {
+                       $constraintsToUse = $constraints;
+               }
+               $result = array_merge(
+                       $result,
+                       $this->checkConstraintsForStatementOnEntity( 
$constraintsToUse, $entity, $statement )
+               );
+
+               return $result;
+       }
+
+       /**
         * @param Constraint[] $constraints
         * @param EntityDocument|StatementListProvider $entity
         * @param Statement $statement
diff --git a/includes/ConstraintParameterRenderer.php 
b/includes/ConstraintParameterRenderer.php
new file mode 100644
index 0000000..cbb1778
--- /dev/null
+++ b/includes/ConstraintParameterRenderer.php
@@ -0,0 +1,132 @@
+<?php
+namespace WikibaseQuality\ConstraintReport;
+
+use DataValues;
+use DataValues\DataValue;
+use HTMLForm;
+use Html;
+use InvalidArgumentException;
+use SpecialPage;
+use UnexpectedValueException;
+use ValueFormatters\ValueFormatter;
+use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikibase\DataModel\Entity\EntityIdParsingException;
+use Wikibase\DataModel\Entity\EntityIdValue;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\DataModel\Services\EntityId\EntityIdFormatter;
+use Wikibase\DataModel\Services\Lookup\EntityLookup;
+use Wikibase\Lib\OutputFormatValueFormatterFactory;
+use Wikibase\Lib\SnakFormatter;
+use Wikibase\Lib\Store\EntityTitleLookup;
+use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory;
+use Wikibase\Repo\EntityIdHtmlLinkFormatterFactory;
+use Wikibase\Repo\EntityIdLabelFormatterFactory;
+
+/**
+ * Class ConstraintParameterRenderer
+ *
+ * Used to format the constraint values for output.
+ *
+ * @package WikibaseQuality\ConstraintReport
+ * @author BP2014N1
+ * @license GNU GPL v2+
+ */
+
+class ConstraintParameterRenderer{
+
+       /**
+        * Maximum number of displayed values for parameters with multiple ones.
+        *
+        * @var int
+        */
+       const MAX_PARAMETER_ARRAY_LENGTH = 10;
+
+       /**
+        *
+        * @var EntityIdFormatter
+        */
+       private $entityIdLabelFormatter;
+
+       /**
+        * @var ValueFormatter
+        */
+       private $dataValueFormatter;
+
+       /**
+        * @param EntityIdFormatter $entityIdFormatter
+        * @param ValueFormatter $dataValueFormatter
+        */
+       public function __construct( EntityIdFormatter $entityIdFormatter,
+                                                                ValueFormatter 
$dataValueFormatter ) {
+
+               $this->entityIdLabelFormatter = $entityIdFormatter;
+               $this->dataValueFormatter = $dataValueFormatter;
+
+       }
+
+       /**
+        * Formats parameter values of constraints.
+        *
+        * @param string|ItemId|PropertyId|DataValue $value
+        *
+        * @return string HTML
+        */
+       public function formatValue( $value ) {
+               if ( is_string( $value ) ) {
+                       // Cases like 'Format' 'pattern' or 'minimum'/'maximum' 
values, which we have stored as
+                       // strings
+                       return (htmlspecialchars( $value ));
+               } elseif ( $value instanceof EntityId ) {
+                       // Cases like 'Conflicts with' 'property', to which we 
can link
+                       return $this->entityIdLabelFormatter->formatEntityId( 
$value );
+               } else {
+                       // Cases where we format a DataValue
+                       return $this->dataValueFormatter->format( $value );
+               }
+       }
+
+       /**
+        * Formats constraint parameters.
+        *
+        * @param (string|ItemId|PropertyId|DataValue)[]|null $parameters
+        *
+        * @return string HTML
+        */
+       public function formatParameters( $parameters ) {
+               if ( $parameters === null || count( $parameters ) == 0 ) {
+                       return null;
+               }
+
+               $valueFormatter = function ( $value ) {
+                       return $this->formatValue( $value );
+               };
+
+               $formattedParameters = array();
+               foreach ( $parameters as $parameterName => $parameterValue ) {
+                       $formattedParameterValues = implode( ', ',
+                               $this->limitArrayLength( array_map( 
$valueFormatter, $parameterValue ) ) );
+                       $formattedParameters[] = sprintf( '%s: %s', 
$parameterName, $formattedParameterValues );
+               }
+
+               return implode( '; ', $formattedParameters );
+       }
+
+       /**
+        * Cuts an array after n values and appends dots if needed.
+        *
+        * @param array $array
+        *
+        * @return array
+        */
+       private function limitArrayLength( array $array ) {
+               if ( count( $array ) > self::MAX_PARAMETER_ARRAY_LENGTH ) {
+                       $array = array_slice( $array, 0, 
self::MAX_PARAMETER_ARRAY_LENGTH );
+                       array_push( $array, '...' );
+               }
+
+               return $array;
+       }
+
+}
\ No newline at end of file
diff --git a/includes/ConstraintReportFactory.php 
b/includes/ConstraintReportFactory.php
index a2b9c28..270e30e 100644
--- a/includes/ConstraintReportFactory.php
+++ b/includes/ConstraintReportFactory.php
@@ -28,6 +28,7 @@
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConnectionCheckerHelper;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\RangeCheckerHelper;
 use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\TypeCheckerHelper;
+use Wikibase\DataModel\Services\Statement\StatementGuidParser;
 
 class ConstraintReportFactory {
 
@@ -57,6 +58,11 @@
        private $constraintParameterMap;
 
        /**
+        * @var StatementGuidParser
+        */
+       private $statementGuidParser;
+
+       /**
         * Returns the default instance.
         * IMPORTANT: Use only when it is not feasible to inject an instance 
properly.
         *
@@ -66,7 +72,7 @@
                static $instance = null;
 
                if ( $instance === null ) {
-                       $instance = new self( 
WikibaseRepo::getDefaultInstance()->getEntityLookup() );
+                       $instance = new self( 
WikibaseRepo::getDefaultInstance()->getEntityLookup(), 
WikibaseRepo::getDefaultInstance()->getStatementGuidParser() );
                }
 
                return $instance;
@@ -74,9 +80,11 @@
 
        /**
         * @param EntityLookup $lookup
+        * @param StatementGuidParser $statementGuidParser
         */
-       public function __construct( EntityLookup $lookup ) {
+       public function __construct( EntityLookup $lookup, StatementGuidParser 
$statementGuidParser ) {
                $this->lookup = $lookup;
+               $this->statementGuidParser = $statementGuidParser;
        }
 
        /**
diff --git a/specials/SpecialConstraintReport.php 
b/specials/SpecialConstraintReport.php
index 11ec323..6d7c713 100644
--- a/specials/SpecialConstraintReport.php
+++ b/specials/SpecialConstraintReport.php
@@ -13,6 +13,7 @@
 use ValueFormatters\FormatterOptions;
 use ValueFormatters\ValueFormatter;
 use Wikibase\DataModel\Entity\EntityDocument;
+use WikibaseQuality\ConstraintReport\ConstraintParameterRenderer;
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Entity\EntityIdParser;
 use Wikibase\DataModel\Entity\EntityIdParsingException;
@@ -44,13 +45,6 @@
  * @license GNU GPL v2+
  */
 class SpecialConstraintReport extends SpecialPage {
-
-       /**
-        * Maximum number of displayed values for parameters with multiple ones.
-        *
-        * @var int
-        */
-       const MAX_PARAMETER_ARRAY_LENGTH = 5;
 
        /**
         * Id of the property, that is used to specify constraints on entities.
@@ -95,6 +89,11 @@
         * @var DelegatingConstraintChecker
         */
        private $constraintChecker;
+
+       /**
+        * @var ConstraintParameterRenderer
+        */
+       private $constraintParameterRenderer;
 
        public static function newFromGlobalState()     {
                $constraintReportFactory = 
ConstraintReportFactory::getDefaultInstance();
@@ -158,6 +157,8 @@
                );
 
                $this->constraintChecker = $constraintChecker;
+
+               $this->constraintParameterRenderer = new 
ConstraintParameterRenderer( $this->entityIdLabelFormatter, 
$this->dataValueFormatter );
        }
 
        /**
@@ -378,7 +379,7 @@
                // Claim column
                $property = $this->entityIdLabelFormatter->formatEntityId( 
$result->getPropertyId() );
                if ( $result->getMainSnakType() === 'value' ) {
-                       $value = $this->formatValue( $result->getDataValue() );
+                       $value = 
$this->constraintParameterRenderer->formatValue( $result->getDataValue() );
                } else {
                        $value = htmlspecialchars( $result->getMainSnakType() );
                }
@@ -397,7 +398,7 @@
                );
                $constraintColumn = $this->buildExpandableElement(
                        $constraintLink,
-                       $this->formatParameters( $result->getParameters() ),
+                       $this->constraintParameterRenderer->formatParameters( 
$result->getParameters() ),
                        '[...]'
                );
 
@@ -656,67 +657,6 @@
                $entityUrl = sprintf( '%s#%s', $title->getLocalURL(), 
$propertyId->getSerialization() );
 
                return $entityUrl;
-       }
-
-       /**
-        * Formats values of constraints.
-        *
-        * @param string|ItemId|PropertyId|DataValue $value
-        *
-        * @return string HTML
-        */
-       private function formatValue( $value ) {
-               if ( is_string( $value ) ) {
-                       // Cases like 'Format' 'pattern' or 'minimum'/'maximum' 
values, which we have stored as strings
-                       return ( htmlspecialchars ( $value ) );
-               } elseif ( $value instanceof EntityId ) {
-                       // Cases like 'Conflicts with' 'property', to which we 
can link
-                       return $this->entityIdLabelFormatter->formatEntityId( 
$value );
-               } else {
-                       // Cases where we format a DataValue
-                       return $this->formatDataValues( $value );
-               }
-       }
-
-       /**
-        * Formats constraint parameters.
-        *
-        * @param array $parameters
-        *
-        * @return string HTML
-        */
-       private function formatParameters( $parameters ) {
-               if ( $parameters === null || count( $parameters ) == 0 ) {
-                       return null;
-               }
-
-               $valueFormatter = function ( $value ) {
-                       return $this->formatValue( $value );
-               };
-
-               $formattedParameters = array ();
-               foreach ( $parameters as $parameterName => $parameterValue ) {
-                       $formattedParameterValues = implode( ', ', 
$this->limitArrayLength( array_map( $valueFormatter, $parameterValue ) ) );
-                       $formattedParameters[] = sprintf( '%s: %s', 
$parameterName, $formattedParameterValues );
-               }
-
-               return implode( '; ', $formattedParameters );
-       }
-
-       /**
-        * Cuts an array after n values and appends dots if needed.
-        *
-        * @param array $array
-        *
-        * @return array
-        */
-       private function limitArrayLength( $array ) {
-               if ( count( $array ) > self::MAX_PARAMETER_ARRAY_LENGTH ) {
-                       $array = array_slice( $array, 0, 
self::MAX_PARAMETER_ARRAY_LENGTH );
-                       array_push( $array, '...' );
-               }
-
-               return $array;
        }
 
 }
diff --git a/tests/phpunit/Api/CheckConstraintsTest.php 
b/tests/phpunit/Api/CheckConstraintsTest.php
new file mode 100644
index 0000000..c54ad1d
--- /dev/null
+++ b/tests/phpunit/Api/CheckConstraintsTest.php
@@ -0,0 +1,223 @@
+<?php
+
+namespace WikibaseQuality\ConstraintReport\Tests\Api;
+
+use ApiTestCase;
+use DataValues\UnknownValue;
+use RequestContext;
+use Wikibase\DataModel\Entity\Item;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\ItemIdParser;
+use Wikibase\DataModel\Entity\PropertyId;
+use Wikibase\DataModel\Services\Lookup\InMemoryEntityLookup;
+use Wikibase\DataModel\Services\Statement\StatementGuidParser;
+use Wikibase\DataModel\Services\Statement\StatementGuidValidator;
+use Wikibase\DataModel\Snak\PropertyValueSnak;
+use Wikibase\DataModel\Statement\Statement;
+use Wikibase\DataModel\Statement\StatementList;
+use Wikibase\Repo\EntityIdLabelFormatterFactory;
+use Wikibase\Repo\WikibaseRepo;
+use WikibaseQuality\ConstraintReport\Api\CheckConstraints;
+use WikibaseQuality\ConstraintReport\Constraint;
+use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker;
+use 
WikibaseQuality\ConstraintReport\ConstraintCheck\DelegatingConstraintChecker;
+use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
+use WikibaseQuality\ConstraintReport\Tests\Fake\FakeChecker;
+use WikibaseQuality\ConstraintReport\Tests\Fake\InMemoryConstraintLookup;
+use Wikibase\LanguageFallbackChain;
+use Wikibase\LanguageFallbackChainFactory;
+use Wikibase\DataModel\Services\Lookup\TermLookup;
+use Wikibase\DataModel\Services\Term\TermBuffer;
+use Wikibase\Lib\SnakFormatter;
+use Wikibase\Lib\Store\LanguageFallbackLabelDescriptionLookupFactory;
+use Wikibase\Lib\OutputFormatValueFormatterFactory;
+use ValueFormatters\FormatterOptions;
+use Wikimedia\Assert\Assert;
+use Language;
+use WikibaseQuality\ConstraintReport\ConstraintParameterRenderer;
+
+/**
+ * @covers WikibaseQuality\ConstraintReport\Api\CheckConstraints
+ *
+ * @group API
+ * @group Database
+ * @group Wikibase
+ * @group WikibaseAPI
+ *
+ * @group medium
+ *
+ * @license GPL-2.0+
+ */
+class CheckConstraintsTest extends ApiTestCase {
+
+       const NONEXISTENT_ITEM = 'Q99';
+       const NONEXISTENT_CLAIM = 'Q99$does-not-exist';
+
+       private static $oldModuleDeclaration;
+
+       /**
+        * @var InMemoryEntityLookup
+        */
+       private static $entityLookup;
+
+       /**
+        * @var Constraint[]
+        */
+       private static $constraintLookupContents = [];
+
+       /**
+        * @var ConstraintChecker[]
+        */
+       private static $checkerMap = [];
+
+       public static function setUpBeforeClass() {
+               parent::setUpBeforeClass();
+               global $wgAPIModules;
+
+               self::$oldModuleDeclaration = 
$wgAPIModules['wbcheckconstraints'];
+
+               self::$entityLookup = new InMemoryEntityLookup();
+
+               $wgAPIModules['wbcheckconstraints']['factory'] = function ( 
$main, $name ) {
+                       $repo = WikibaseRepo::getDefaultInstance();
+                       $factory = new EntityIdLabelFormatterFactory();
+                       $termLookup = $repo->getTermLookup();
+                       $termBuffer = $repo->getTermBuffer();
+                       $languageFallbackChainFactory = new 
LanguageFallbackChainFactory();
+                       $fallbackLabelDescLookupFactory = new 
LanguageFallbackLabelDescriptionLookupFactory( $languageFallbackChainFactory, 
$termLookup, $termBuffer );
+                       $language = new Language();
+                       $labelLookup = 
$fallbackLabelDescLookupFactory->newLabelDescriptionLookup( $language );
+
+                       $formatterOptions = new FormatterOptions();
+                       $factoryFunctions = [];
+                       Assert::parameterElementType( 'callable', 
$factoryFunctions, '$factoryFunctions' );
+                       $formatterOptions->setOption( SnakFormatter::OPT_LANG, 
$language->getCode() );
+                       $valueFormatterFactory = new 
OutputFormatValueFormatterFactory( $factoryFunctions, 
$language,$languageFallbackChainFactory );
+                       $valueFormatter = 
$valueFormatterFactory->getValueFormatter( SnakFormatter::FORMAT_HTML, 
$formatterOptions );
+
+                       $entityIdParser = new ItemIdParser();
+                       $constraintChecker = new DelegatingConstraintChecker(
+                               self::$entityLookup,
+                               self::$checkerMap,
+                               new InMemoryConstraintLookup( 
self::$constraintLookupContents )
+                       );
+
+                       return new CheckConstraints(
+                               $main,
+                               $name,
+                               '',
+                               $entityIdParser,
+                               new StatementGuidValidator( $entityIdParser ),
+                               new StatementGuidParser( $entityIdParser ),
+                               $constraintChecker,
+                               new ConstraintParameterRenderer( 
$factory->getEntityIdFormatter( $labelLookup ), $valueFormatter ),
+                               $repo->getApiHelperFactory( 
RequestContext::getMain() )
+                       );
+               };
+       }
+
+       protected function tearDown() {
+               self::$constraintLookupContents = [];
+               self::$checkerMap = [];
+               parent::tearDown();
+       }
+
+       public static function tearDownAfterClass() {
+               global $wgAPIModules;
+               $wgAPIModules['wbcheckconstraints'] = 
self::$oldModuleDeclaration;
+
+               parent::tearDownAfterClass();
+       }
+
+       public function testReportForNonexistentItemIsEmpty() {
+               $result = $this->doRequest(
+                       [ CheckConstraints::PARAM_ID => self::NONEXISTENT_ITEM ]
+               );
+
+               $this->assertEmpty( 
$result['wbcheckconstraints'][self::NONEXISTENT_ITEM] );
+       }
+
+       public function testReportForNonexistentClaimIsEmpty() {
+               $result = $this->doRequest(
+                       [ CheckConstraints::PARAM_CLAIM_ID => 
self::NONEXISTENT_CLAIM ]
+               );
+
+               $this->assertEmpty( $result['wbcheckconstraints'] );
+       }
+
+       public function 
testItemExistsAndHasViolation_WillGetOnlyThisViolationInTheResult() {
+               $this->givenItemWithPropertyExists(
+                       new ItemId( 'Q1' ),
+                       new PropertyId( 'P1' ),
+                       'statement-id'
+               );
+               $this->givenPropertyHasViolation( new PropertyId( 'P1' ) );
+
+               $result = $this->doRequest( [ CheckConstraints::PARAM_ID => 
'Q1' ] );
+
+               $this->assertCount( 1, $result['wbcheckconstraints'] );
+               $resultsForItem = 
$result['wbcheckconstraints']['Q1']['P1']['Q1$statement-id'];
+               $this->assertCount( 1, $resultsForItem );
+               $this->assertEquals( CheckResult::STATUS_VIOLATION, 
$resultsForItem[0]['status'] );
+               $this->assertEquals( 'P1', $resultsForItem[0]['property'] );
+       }
+
+       public function 
testItemWithClaimExistsAndHasViolation_WillGetOnlyThisViolationInTheResult() {
+               $this->givenItemWithPropertyExists(
+                       new ItemId( 'Q1' ),
+                       new PropertyId( 'P1' ),
+                       'statement-id'
+               );
+               $this->givenPropertyHasViolation( new PropertyId( 'P1' ) );
+
+               $result = $this->doRequest( [ CheckConstraints::PARAM_CLAIM_ID 
=> 'Q1$statement-id' ] );
+
+               $this->assertCount( 1, $result['wbcheckconstraints'] );
+               $resultsForItem = 
$result['wbcheckconstraints']['Q1']['P1']['Q1$statement-id'];
+               $this->assertCount( 1, $resultsForItem );
+               $this->assertEquals( CheckResult::STATUS_VIOLATION, 
$resultsForItem[0]['status'] );
+               $this->assertEquals( 'P1', $resultsForItem[0]['property'] );
+       }
+
+       /**
+        * @param array $params
+        * @return array Array of violations
+        */
+       private function doRequest( array $params ) {
+               $params['action'] = 'wbcheckconstraints';
+               return $this->doApiRequest( $params, [], false, null )[0];
+       }
+
+       private function givenPropertyHasViolation( PropertyId $propertyId ) {
+               self::$checkerMap['violationConstraint'] = new FakeChecker( 
CheckResult::STATUS_VIOLATION );
+               self::$constraintLookupContents[] = new Constraint(
+                       'some guid',
+                       $propertyId,
+                       'violationConstraint',
+                       []
+               );
+       }
+
+       private function givenItemWithPropertyExists(
+               ItemId $itemId,
+               PropertyId $propertyId,
+               $statementId = 'some-id'
+       ) {
+               $item = new Item(
+                       $itemId,
+                       null,
+                       null,
+                       new StatementList(
+                               [
+                                       new Statement(
+                                               new PropertyValueSnak( 
$propertyId, new UnknownValue( null ) ),
+                                               null,
+                                               null,
+                                               $itemId->getSerialization() . 
'$' . $statementId
+                                       )
+                               ]
+                       )
+               );
+               self::$entityLookup->addEntity( $item );
+       }
+}
diff --git a/tests/phpunit/DelegatingConstraintCheckerTest.php 
b/tests/phpunit/DelegatingConstraintCheckerTest.php
index baba758..6105b20 100644
--- a/tests/phpunit/DelegatingConstraintCheckerTest.php
+++ b/tests/phpunit/DelegatingConstraintCheckerTest.php
@@ -2,8 +2,13 @@
 
 namespace WikibaseQuality\ConstraintReport\Test\ConstraintChecker;
 
+use Wikibase\DataModel\Entity\Item;
 use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\ItemIdParser;
+use Wikibase\DataModel\Services\Statement\StatementGuidParser;
+use Wikibase\DataModel\Statement\Statement;
 use 
WikibaseQuality\ConstraintReport\ConstraintCheck\DelegatingConstraintChecker;
+use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
 use WikibaseQuality\ConstraintReport\ConstraintReportFactory;
 use WikibaseQuality\Tests\Helper\JsonFileEntityLookup;
 
@@ -49,10 +54,19 @@
         */
        private $lookup;
 
+       /**
+        * @var StatementGuidParser
+        */
+       private $statementGuidParser;
+
        protected function setUp() {
                parent::setUp();
-               $this->lookup = new JsonFileEntityLookup( __DIR__ );
-               $factory = new ConstraintReportFactory( $this->lookup );
+               $this->lookup = $this->createEntityLookup();
+               $this->statementGuidParser = new StatementGuidParser( new 
ItemIdParser() );
+               $factory = new ConstraintReportFactory(
+                       $this->lookup,
+                       $this->statementGuidParser
+               );
                $this->constraintChecker = $factory->getConstraintChecker();
 
                // specify database tables used by this test
@@ -275,4 +289,50 @@
                $this->assertEquals( 'exception', $result[ 0 ]->getStatus(), 
'Should be an exception' );
        }
 
+       public function testCheckAgainstConstraints_ByClaims() {
+               $factory = new ConstraintReportFactory(
+                       $this->createEntityLookup(),
+                       $this->statementGuidParser
+               );
+               $constraintChecker = $factory->getConstraintChecker();
+
+               $result = $constraintChecker->checkAgainstConstraintsOnClaimId(
+                       $this->statementGuidParser->parse( 
'Q1$c0f25a6f-9e33-41c8-be34-c86a730ff30b' ) );
+
+               $this->assertCount( 18, $result, 'Every constraint should be 
represented by one result' );
+       }
+
+       public function 
testCheckAgainstConstraintsDoesNotCrashWhenResultIsEmpty_ByClaims() {
+               $factory = new ConstraintReportFactory(
+                       $this->createEntityLookup(),
+                       $this->statementGuidParser
+               );
+               $constraintChecker = $factory->getConstraintChecker();
+
+               $result = $constraintChecker->checkAgainstConstraintsOnClaimId(
+                       $this->statementGuidParser->parse( 
'Q2$c0f25a6f-9e33-41c8-be34-c86a730ff30b' ) );
+
+               $this->assertCount( 0, $result, 'Should be empty' );
+       }
+
+       public function 
testCheckAgainstConstraintsDoesNotCrashWhenClaimDoesNotExist() {
+               $factory = new ConstraintReportFactory(
+                       $this->createEntityLookup(),
+                       $this->statementGuidParser
+               );
+               $constraintChecker = $factory->getConstraintChecker();
+
+               $result = $constraintChecker->checkAgainstConstraintsOnClaimId(
+                       $this->statementGuidParser->parse( 'Q99$does-not-exist' 
) );
+
+               $this->assertCount( 0, $result, 'Should be empty' );
+       }
+
+       /**
+        * @return JsonFileEntityLookup
+        */
+       private function createEntityLookup() {
+               return new JsonFileEntityLookup( __DIR__ );
+       }
+
 }
diff --git a/tests/phpunit/Q6.json b/tests/phpunit/Q6.json
new file mode 100644
index 0000000..7e9acf8
--- /dev/null
+++ b/tests/phpunit/Q6.json
@@ -0,0 +1,97 @@
+{
+  "id": "Q6",
+  "type": "item",
+  "aliases": {},
+  "labels": {},
+  "claims": {
+    "P1": [
+      {
+        "id": "Q6$01015a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "value",
+          "property": "P1",
+          "datatype": "string",
+          "datavalue": {
+            "value": "foo",
+            "type": "string"
+          }
+        },
+        "type": "statement",
+        "rank": "normal"
+      },
+      {
+        "id": "Q6$01025a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "value",
+          "property": "P1",
+          "datatype": "string",
+          "datavalue": {
+            "value": "foo",
+            "type": "string"
+          }
+        },
+        "type": "statement",
+        "rank": "normal"
+      }
+    ],
+    "P2": [
+      {
+        "id": "Q6$02015a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "value",
+          "property": "P2",
+          "datatype": "string",
+          "datavalue": {
+            "value": "foo",
+            "type": "string"
+          }
+        },
+        "type": "statement",
+        "rank": "normal"
+      }
+    ],
+    "P3": [
+      {
+        "id": "Q6$03015a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "value",
+          "property": "P3",
+          "datatype": "string",
+          "datavalue": {
+            "value": "foo",
+            "type": "string"
+          }
+        },
+        "type": "statement",
+        "rank": "normal"
+      }
+    ],
+    "P4": [
+      {
+        "id": "Q6$04015a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "novalue",
+          "property": "P4"
+        },
+        "type": "statement",
+        "rank": "normal"
+      }
+    ],
+    "P10": [
+      {
+        "id": "Q6$10015a6f-9e33-41c8-be34-c86a730ff30b",
+        "mainsnak": {
+          "snaktype": "value",
+          "property": "P10",
+          "datatype": "string",
+          "datavalue": {
+            "value": "foo",
+            "type": "string"
+          }
+        },
+        "type": "statement",
+        "rank": "normal"
+      }
+    ]
+  }
+}

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Icf4ec91bc0a06435bcf626e2060008d0d88027a8
Gerrit-PatchSet: 47
Gerrit-Project: mediawiki/extensions/WikibaseQualityConstraints
Gerrit-Branch: master
Gerrit-Owner: Olga Bode <[email protected]>
Gerrit-Reviewer: Aleksey Bekh-Ivanov (WMDE) <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: Jonas Kress (WMDE) <[email protected]>
Gerrit-Reviewer: Lucas Werkmeister (WMDE) <[email protected]>
Gerrit-Reviewer: Olga Bode <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to