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

Change subject: Add ChangeOp, ChangeOpDeserializer and Validator for 
LexicalCategory
......................................................................


Add ChangeOp, ChangeOpDeserializer and Validator for LexicalCategory

Bug: T155703
Bug: T158780
Change-Id: I7ab98d3b7f8844fba6245dd859d7aa87cd0394b6
---
M WikibaseLexeme.entitytypes.php
A src/ChangeOp/ChangeOpLexicalCategory.php
M src/ChangeOp/Deserialization/LexemeChangeOpDeserializer.php
A src/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializer.php
M src/Validators/LexemeValidatorFactory.php
A tests/phpunit/mediawiki/ChangeOp/ChangeOpLexicalCategoryTest.php
M 
tests/phpunit/mediawiki/ChangeOp/Deserialization/LexemeChangeOpDeserializerTest.php
A 
tests/phpunit/mediawiki/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializerTest.php
M tests/phpunit/mediawiki/Validators/LexemeValidatorFactoryTest.php
9 files changed, 592 insertions(+), 4 deletions(-)

Approvals:
  WMDE-leszek: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/WikibaseLexeme.entitytypes.php b/WikibaseLexeme.entitytypes.php
index d1675ad..5623ace 100644
--- a/WikibaseLexeme.entitytypes.php
+++ b/WikibaseLexeme.entitytypes.php
@@ -15,6 +15,7 @@
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\Lexeme\ChangeOp\Deserialization\LemmaChangeOpDeserializer;
 use Wikibase\Lexeme\ChangeOp\Deserialization\LanguageChangeOpDeserializer;
+use 
Wikibase\Lexeme\ChangeOp\Deserialization\LexicalCategoryChangeOpDeserializer;
 use Wikibase\Lexeme\Validators\LexemeValidatorFactory;
 use Wikibase\Repo\ChangeOp\Deserialization\TermChangeOpSerializationValidator;
 use Wikibase\Repo\MediaWikiLanguageDirectionalityLookup;
@@ -137,6 +138,10 @@
                                        $lexemeValidatorFactory,
                                        $wikibaseRepo->getStringNormalizer()
                                ),
+                               new LexicalCategoryChangeOpDeserializer(
+                                       $lexemeValidatorFactory,
+                                       $wikibaseRepo->getStringNormalizer()
+                               ),
                                new LanguageChangeOpDeserializer(
                                        $lexemeValidatorFactory,
                                        $wikibaseRepo->getStringNormalizer()
diff --git a/src/ChangeOp/ChangeOpLexicalCategory.php 
b/src/ChangeOp/ChangeOpLexicalCategory.php
new file mode 100644
index 0000000..653c937
--- /dev/null
+++ b/src/ChangeOp/ChangeOpLexicalCategory.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Wikibase\Lexeme\ChangeOp;
+
+use InvalidArgumentException;
+use ValueValidators\Result;
+use Wikibase\ChangeOp\ChangeOpBase;
+use Wikibase\DataModel\Entity\EntityDocument;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\Lexeme\DataModel\Lexeme;
+use Wikibase\Lexeme\DataModel\Providers\LexicalCategoryProvider;
+use Wikibase\Lexeme\Validators\LexemeValidatorFactory;
+use Wikibase\Summary;
+use Wikimedia\Assert\Assert;
+
+/**
+ * @license GPL-2.0+
+ */
+class ChangeOpLexicalCategory extends ChangeOpBase {
+
+       /**
+        * @var ItemId|null
+        */
+       private $lexicalCategory;
+
+       /**
+        * @var LexemeValidatorFactory
+        */
+       private $lexemeValidatorFactory;
+
+       /**
+        * @param ItemId|null $lexicalCategory
+        * @param LexemeValidatorFactory $lexemeValidatorFactory
+        *
+        * @throws InvalidArgumentException
+        */
+       public function __construct(
+               ItemId $lexicalCategory = null,
+               LexemeValidatorFactory $lexemeValidatorFactory
+       ) {
+               $this->lexicalCategory = $lexicalCategory;
+               $this->lexemeValidatorFactory = $lexemeValidatorFactory;
+       }
+
+       /**
+        * @param EntityDocument $entity
+        *
+        * @return Result
+        *
+        * @throws InvalidArgumentException
+        */
+       public function validate( EntityDocument $entity ) {
+               Assert::parameterType( LexicalCategoryProvider::class, $entity, 
'$entity' );
+
+               $lexicalCategoryValidator = 
$this->lexemeValidatorFactory->getLexicalCategoryValidator();
+
+               return $lexicalCategoryValidator->validate( 
$this->lexicalCategory );
+       }
+
+       /**
+        * @param EntityDocument $entity
+        * @param Summary|null $summary
+        *
+        * @throws InvalidArgumentException
+        */
+       public function apply( EntityDocument $entity, Summary $summary = null 
) {
+               Assert::parameterType( Lexeme::class, $entity, '$entity' );
+
+               /** @var Lexeme $entity */
+               $lexicalCategory = $entity->getLexicalCategory();
+
+               if ( $this->lexicalCategory === null ) {
+                       if ( $lexicalCategory ) {
+                               $this->updateSummary(
+                                       $summary,
+                                       'remove',
+                                       '',
+                                       $lexicalCategory->getSerialization()
+                               );
+                               $entity->setLexicalCategory( null );
+                       }
+
+                       return;
+               }
+
+               $this->updateSummary( $summary, 'set', '', 
$this->lexicalCategory->getSerialization() );
+               $entity->setLexicalCategory( $this->lexicalCategory );
+       }
+
+}
diff --git a/src/ChangeOp/Deserialization/LexemeChangeOpDeserializer.php 
b/src/ChangeOp/Deserialization/LexemeChangeOpDeserializer.php
index 46dc63d..a9edf9b 100644
--- a/src/ChangeOp/Deserialization/LexemeChangeOpDeserializer.php
+++ b/src/ChangeOp/Deserialization/LexemeChangeOpDeserializer.php
@@ -20,15 +20,22 @@
        private $lemmaChangeOpDeserializer;
 
        /**
+        * @var LexicalCategoryChangeOpDeserializer
+        */
+       private $lexicalCategoryChangeOpDeserializer;
+
+       /**
         * @var LanguageChangeOpDeserializer
         */
        private $languageChangeOpDeserializer;
 
        public function __construct(
                LemmaChangeOpDeserializer $lemmaChangeOpDeserializer,
+               LexicalCategoryChangeOpDeserializer 
$lexicalCategoryChangeOpDeserializer,
                LanguageChangeOpDeserializer $languageChangeOpDeserializer
        ) {
                $this->lemmaChangeOpDeserializer = $lemmaChangeOpDeserializer;
+               $this->lexicalCategoryChangeOpDeserializer = 
$lexicalCategoryChangeOpDeserializer;
                $this->languageChangeOpDeserializer = 
$languageChangeOpDeserializer;
        }
 
@@ -45,6 +52,12 @@
                        $changeOps->add( 
$this->lemmaChangeOpDeserializer->createEntityChangeOp( $changeRequest ) );
                }
 
+               if ( array_key_exists( 'lexicalCategory', $changeRequest ) ) {
+                       $changeOps->add(
+                               
$this->lexicalCategoryChangeOpDeserializer->createEntityChangeOp( 
$changeRequest )
+                       );
+               }
+
                if ( array_key_exists( 'language', $changeRequest ) ) {
                        $changeOps->add( 
$this->languageChangeOpDeserializer->createEntityChangeOp( $changeRequest ) );
                }
diff --git 
a/src/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializer.php 
b/src/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializer.php
new file mode 100644
index 0000000..3cddb22
--- /dev/null
+++ b/src/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializer.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Wikibase\Lexeme\ChangeOp\Deserialization;
+
+use InvalidArgumentException;
+use Wikibase\ChangeOp\ChangeOp;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\Lexeme\ChangeOp\ChangeOpLexicalCategory;
+use Wikibase\Lexeme\Validators\LexemeValidatorFactory;
+use Wikibase\Repo\ChangeOp\ChangeOpDeserializer;
+use Wikibase\Repo\ChangeOp\Deserialization\ChangeOpDeserializationException;
+use Wikibase\StringNormalizer;
+
+/**
+ * Deserializer for lexical category change request data.
+ *
+ * @see docs/change-op-serialization.wiki for a description of the 
serialization format.
+ *
+ * @license GPL-2.0+
+ */
+class LexicalCategoryChangeOpDeserializer implements ChangeOpDeserializer {
+
+       /**
+        * @var LexemeValidatorFactory
+        */
+       private $lexemeValidatorFactory;
+
+       /**
+        * @var StringNormalizer
+        */
+       private $stringNormalizer;
+
+       public function __construct(
+               LexemeValidatorFactory $lexemeValidatorFactory,
+               StringNormalizer $stringNormalizer
+       ) {
+               $this->lexemeValidatorFactory = $lexemeValidatorFactory;
+               $this->stringNormalizer = $stringNormalizer;
+       }
+
+       /**
+        * @see ChangeOpDeserializer::createEntityChangeOp
+        *
+        * @param array $changeRequest
+        *
+        * @throws ChangeOpDeserializationException
+        *
+        * @return ChangeOp
+        */
+       public function createEntityChangeOp( array $changeRequest ) {
+
+               $lexicalCategorySerialization = 
$changeRequest['lexicalCategory'];
+               if ( !isset( $lexicalCategorySerialization )
+                       || ( !is_string( $lexicalCategorySerialization ) && 
$lexicalCategorySerialization !== null )
+               ) {
+                       throw new ChangeOpDeserializationException(
+                               'lexicalCategory must be string or null',
+                               'invalid-lexical-category'
+                       );
+               }
+
+               $lexicalCategorySerialization = 
$this->stringNormalizer->cleanupToNFC(
+                       $changeRequest['lexicalCategory'] );
+
+               if ( $lexicalCategorySerialization === '' ) {
+                       return new ChangeOpLexicalCategory(
+                               null,
+                               $this->lexemeValidatorFactory
+                       );
+               }
+
+               $itemId = $this->validateItemId( $lexicalCategorySerialization 
);
+               return new ChangeOpLexicalCategory( $itemId, 
$this->lexemeValidatorFactory );
+       }
+
+       /**
+        * @param string $idSerialization
+        * @return ItemId
+        * @throws ChangeOpDeserializationException
+        */
+       private function validateItemId( $idSerialization ) {
+               try {
+                       return new ItemId( $idSerialization );
+               } catch ( InvalidArgumentException $e ) {
+                       throw new ChangeOpDeserializationException(
+                               'Item id can not be parsed',
+                               'invalid-item-id'
+                       );
+               }
+       }
+
+}
diff --git a/src/Validators/LexemeValidatorFactory.php 
b/src/Validators/LexemeValidatorFactory.php
index 486b920..360140d 100644
--- a/src/Validators/LexemeValidatorFactory.php
+++ b/src/Validators/LexemeValidatorFactory.php
@@ -74,6 +74,13 @@
        /**
         * @return ValueValidator
         */
+       public function getLexicalCategoryValidator() {
+               return new CompositeValidator( $this->itemValidators, true );
+       }
+
+       /**
+        * @return ValueValidator
+        */
        public function getLanguageValidator() {
                return new CompositeValidator( $this->itemValidators, true );
        }
diff --git a/tests/phpunit/mediawiki/ChangeOp/ChangeOpLexicalCategoryTest.php 
b/tests/phpunit/mediawiki/ChangeOp/ChangeOpLexicalCategoryTest.php
new file mode 100644
index 0000000..d11c71b
--- /dev/null
+++ b/tests/phpunit/mediawiki/ChangeOp/ChangeOpLexicalCategoryTest.php
@@ -0,0 +1,146 @@
+<?php
+
+namespace Wikibase\Lexeme\Tests\MediaWiki\ChangeOp;
+
+use InvalidArgumentException;
+use Wikibase\DataModel\Entity\EntityDocument;
+use Wikibase\DataModel\Entity\Item;
+use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\Lexeme\ChangeOp\ChangeOpLexicalCategory;
+use Wikibase\Lexeme\DataModel\Lexeme;
+use 
Wikibase\Lexeme\Tests\MediaWiki\Validators\LexemeValidatorFactoryTestMockProvider;
+use Wikibase\Repo\Tests\ChangeOp\ChangeOpTestMockProvider;
+use Wikibase\Summary;
+
+/**
+ * @covers Wikibase\Lexeme\ChangeOp\ChangeOpLexicalCategory
+ *
+ * @group WikibaseLexeme
+ *
+ * @license GPL-2.0+
+ */
+class ChangeOpLexicalCategoryTest extends \PHPUnit_Framework_TestCase {
+
+       /**
+        * @dataProvider invalidEntityProvider
+        */
+       public function 
testGivenNotALexicalCategoryProvider_validateThrowsException(
+               EntityDocument $entity
+       ) {
+               $this->setExpectedException( InvalidArgumentException::class );
+               $changeOp = new ChangeOpLexicalCategory( new ItemId( 'Q2' ), 
$this->getLexemeValidatorFactory() );
+               $changeOp->validate( $entity );
+       }
+
+       public function invalidEntityProvider() {
+               return [
+                       [ $this->getMock( EntityDocument::class ) ],
+                       [ new Item( new ItemId( 'Q234' ) ) ],
+               ];
+       }
+
+       public function 
testGivenValidLexicalCategory_validateReturnsValidResult() {
+               $lexeme = new Lexeme();
+
+               $changeOp = new ChangeOpLexicalCategory(
+                       new ItemId( 'Q234' ),
+                       $this->getLexemeValidatorFactory()
+               );
+
+               $this->assertTrue( $changeOp->validate( $lexeme )->isValid() );
+       }
+
+       public function 
testGivenLexicalCategoryIsNull_validateReturnsValidResult() {
+               $lexeme = new Lexeme();
+
+               $changeOp = new ChangeOpLexicalCategory( null, 
$this->getLexemeValidatorFactory() );
+
+               $this->assertTrue( $changeOp->validate( $lexeme )->isValid() );
+       }
+
+       /**
+        * @dataProvider invalidEntityProvider
+        */
+       public function 
testGivenNotALexicalCategoryProvider_applyThrowsException(
+               EntityDocument $entity
+       ) {
+               $this->setExpectedException( InvalidArgumentException::class );
+               $changeOp = new ChangeOpLexicalCategory(
+                       new ItemId( 'Q234' ),
+                       $this->getLexemeValidatorFactory()
+               );
+               $changeOp->apply( $entity );
+       }
+
+       public function 
testGivenLexicalCategoryIsNull_applyRemovesLexicalCategoryAndSetsTheSummary() {
+               $lexicalCategory = new ItemId( 'Q234' );
+               $lexeme = new Lexeme( null, null, $lexicalCategory );
+               $summary = new Summary();
+
+               $changeOp = new ChangeOpLexicalCategory( null, 
$this->getLexemeValidatorFactory() );
+               $changeOp->apply( $lexeme, $summary );
+
+               $this->assertNull( $lexeme->getLexicalCategory() );
+
+               $this->assertSame( 'remove', $summary->getActionName() );
+               $this->assertSame( [ 'Q234' ], $summary->getAutoSummaryArgs() );
+       }
+
+       public function 
testGivenLexicalCategoryExists_applySetsLexicalCategoryAndSetsTheSummary() {
+               $lexicalCategory = new ItemId( 'Q234' );
+               $lexeme = new Lexeme( null, null, $lexicalCategory );
+               $summary = new Summary();
+
+               $changeOp = new ChangeOpLexicalCategory(
+                       new ItemId( 'Q432' ),
+                       $this->getLexemeValidatorFactory()
+               );
+
+               $changeOp->apply( $lexeme, $summary );
+
+               $this->assertSame( 'Q432', 
$lexeme->getLexicalCategory()->getSerialization() );
+
+               $this->assertSame( 'set', $summary->getActionName() );
+               $this->assertSame( [ 'Q432' ], $summary->getAutoSummaryArgs() );
+       }
+
+       public function 
testGivenLexicalCategoryIsNull_applySetsLexicalCategoryAndSetsTheSummary() {
+               $lexeme = new Lexeme();
+               $summary = new Summary();
+
+               $changeOp = new ChangeOpLexicalCategory(
+                       new ItemId( 'Q234' ),
+                       $this->getLexemeValidatorFactory()
+               );
+
+               $changeOp->apply( $lexeme, $summary );
+
+               $this->assertSame( 'Q234', 
$lexeme->getLexicalCategory()->getSerialization() );
+
+               $this->assertSame( 'set', $summary->getActionName() );
+               $this->assertSame( [ 'Q234' ], $summary->getAutoSummaryArgs() );
+       }
+
+       public function 
testGivenLexicalCategoryIsNullAndNoLexicalCategoryExists_applyMakesNoChange() {
+               $lexeme = new Lexeme();
+               $summary = new Summary();
+
+               $changeOp = new ChangeOpLexicalCategory( null, 
$this->getLexemeValidatorFactory() );
+               $changeOp->apply( $lexeme, $summary );
+
+               $this->assertNull( $lexeme->getLexicalCategory() );
+               $this->assertNull( $summary->getActionName() );
+       }
+
+       private function getLexemeValidatorFactory() {
+               $mockProvider = new ChangeOpTestMockProvider( $this );
+               $validatorFactoryMockProvider = new 
LexemeValidatorFactoryTestMockProvider();
+               return $validatorFactoryMockProvider->getLexemeValidatorFactory(
+                       $this,
+                       10,
+                       $mockProvider->getMockTermValidatorFactory(),
+                       [ 'Q234', 'Q432' ]
+               );
+       }
+
+}
diff --git 
a/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexemeChangeOpDeserializerTest.php
 
b/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexemeChangeOpDeserializerTest.php
index 010fb04..4aeae57 100644
--- 
a/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexemeChangeOpDeserializerTest.php
+++ 
b/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexemeChangeOpDeserializerTest.php
@@ -6,6 +6,7 @@
 use Wikibase\Lexeme\ChangeOp\Deserialization\LanguageChangeOpDeserializer;
 use Wikibase\Lexeme\ChangeOp\Deserialization\LemmaChangeOpDeserializer;
 use Wikibase\Lexeme\ChangeOp\Deserialization\LexemeChangeOpDeserializer;
+use 
Wikibase\Lexeme\ChangeOp\Deserialization\LexicalCategoryChangeOpDeserializer;
 
 /**
  * @covers Wikibase\Lexeme\ChangeOp\Deserialization\LexemeChangeOpDeserializer
@@ -34,9 +35,19 @@
                        ->getMock();
        }
 
+       /**
+        * @return LexicalCategoryChangeOpDeserializer
+        */
+       private function getLexicalCategoryChangeOpDeserializer() {
+               return $this->getMockBuilder( 
LexicalCategoryChangeOpDeserializer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+       }
+
        public function testCreateEntityChangeOpReturnsChangeOpInstance() {
                $deserializer = new LexemeChangeOpDeserializer(
                        $this->getLemmaChangeOpDeserializer(),
+                       $this->getLexicalCategoryChangeOpDeserializer(),
                        $this->getLanguageChangeOpDeserializer()
                );
 
@@ -53,7 +64,15 @@
                $languageDeserializer->expects( $this->never() )
                        ->method( $this->anything() );
 
-               $deserializer = new LexemeChangeOpDeserializer( 
$lemmaDeserializer, $languageDeserializer );
+               $lexicalCategoryDeserializer = 
$this->getLexicalCategoryChangeOpDeserializer();
+               $lexicalCategoryDeserializer->expects( $this->never() )
+                       ->method( $this->anything() );
+
+               $deserializer = new LexemeChangeOpDeserializer(
+                       $lemmaDeserializer,
+                       $lexicalCategoryDeserializer,
+                       $languageDeserializer
+               );
 
                $deserializer->createEntityChangeOp(
                        [ 'lemmas' => [ 'en' => [ 'language' => 'en', 'value' 
=> 'rat' ] ] ]
@@ -70,10 +89,43 @@
                        ->method( 'createEntityChangeOp' )
                        ->will( $this->returnValue( $this->getMock( 
ChangeOp::class ) ) );
 
-               $deserializer = new LexemeChangeOpDeserializer( 
$lemmaDeserializer, $languageDeserializer );
+               $lexicalCategoryDeserializer = 
$this->getLexicalCategoryChangeOpDeserializer();
+               $lexicalCategoryDeserializer->expects( $this->never() )
+                       ->method( $this->anything() );
+
+               $deserializer = new LexemeChangeOpDeserializer(
+                       $lemmaDeserializer,
+                       $lexicalCategoryDeserializer,
+                       $languageDeserializer
+               );
 
                $deserializer->createEntityChangeOp(
                        [ 'language' => 'q100' ]
+               );
+       }
+
+       public function 
testGivenLexCatInChangeRequest_lexCatChangeOpDeserializerIsUsed() {
+               $lemmaDeserializer = $this->getLemmaChangeOpDeserializer();
+               $lemmaDeserializer->expects( $this->never() )
+                       ->method( $this->anything() );
+
+               $languageDeserializer = 
$this->getLanguageChangeOpDeserializer();
+               $languageDeserializer->expects( $this->never() )
+                       ->method( $this->anything() );
+
+               $lexicalCategoryDeserializer = 
$this->getLexicalCategoryChangeOpDeserializer();
+               $lexicalCategoryDeserializer->expects( $this->atLeastOnce() )
+                       ->method( 'createEntityChangeOp' )
+                       ->will( $this->returnValue( $this->getMock( 
ChangeOp::class ) ) );
+
+               $deserializer = new LexemeChangeOpDeserializer(
+                       $lemmaDeserializer,
+                       $lexicalCategoryDeserializer,
+                       $languageDeserializer
+               );
+
+               $deserializer->createEntityChangeOp(
+                       [ 'lexicalCategory' => 'q200' ]
                );
        }
 
@@ -86,7 +138,15 @@
                $languageDeserializer->expects( $this->never() )
                        ->method( $this->anything() );
 
-               $deserializer = new LexemeChangeOpDeserializer( 
$lemmaDeserializer, $languageDeserializer );
+               $lexicalCategoryDeserializer = 
$this->getLexicalCategoryChangeOpDeserializer();
+               $lexicalCategoryDeserializer->expects( $this->never() )
+                       ->method( $this->anything() );
+
+               $deserializer = new LexemeChangeOpDeserializer(
+                       $lemmaDeserializer,
+                       $lexicalCategoryDeserializer,
+                       $languageDeserializer
+               );
 
                $deserializer->createEntityChangeOp(
                        [ 'labels' => [ 'en' => [ 'language' => 'en', 'value' 
=> 'rat' ] ] ]
diff --git 
a/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializerTest.php
 
b/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializerTest.php
new file mode 100644
index 0000000..aa84dd5
--- /dev/null
+++ 
b/tests/phpunit/mediawiki/ChangeOp/Deserialization/LexicalCategoryChangeOpDeserializerTest.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace Wikibase\Lexeme\Tests\ChangeOp\Deserialization;
+
+use Wikibase\DataModel\Entity\ItemId;
+use 
Wikibase\Lexeme\ChangeOp\Deserialization\LexicalCategoryChangeOpDeserializer;
+use Wikibase\Lexeme\DataModel\Lexeme;
+use Wikibase\Lexeme\DataModel\LexemeId;
+use 
Wikibase\Lexeme\Tests\MediaWiki\Validators\LexemeValidatorFactoryTestMockProvider;
+use Wikibase\Lexeme\Validators\LexemeValidatorFactory;
+use Wikibase\Repo\ChangeOp\Deserialization\ChangeOpDeserializationException;
+use Wikibase\Repo\Tests\ChangeOp\ChangeOpTestMockProvider;
+use Wikibase\StringNormalizer;
+
+/**
+ * @covers 
Wikibase\Lexeme\ChangeOp\Deserialiazation\LexicalCategoryChangeOpDeserializer
+ *
+ * @group WikibaseLexeme
+ *
+ * @license GPL-2.0+
+ */
+class LexicalCategoryChangeOpDeserializerTest extends 
\PHPUnit_Framework_TestCase {
+
+       private function newLexicalCategoryChangeOpDeserializer() {
+               $mockProvider = new ChangeOpTestMockProvider( $this );
+               $validatorFactoryMockProvider = new 
LexemeValidatorFactoryTestMockProvider();
+               return new LexicalCategoryChangeOpDeserializer(
+                       
$validatorFactoryMockProvider->getLexemeValidatorFactory(
+                               $this,
+                               10,
+                               $mockProvider->getMockTermValidatorFactory()
+                       ),
+                       new StringNormalizer()
+               );
+       }
+
+       public function 
testGivenLexicalCategorySerializationIsNotString_exceptionIsThrown() {
+               $deserializer = $this->newLexicalCategoryChangeOpDeserializer();
+
+               $this->setExpectedException( 
ChangeOpDeserializationException::class );
+
+               $deserializer->createEntityChangeOp( [ 'lexicalCategory' => [] 
] );
+       }
+
+       public function 
testGivenLexicalCategorySerializationIsInvalid_exceptionIsThrown() {
+               $lexemeValidatorFactory = $this->getMockBuilder( 
LexemeValidatorFactory::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $deserializer = new LexicalCategoryChangeOpDeserializer(
+                       $lexemeValidatorFactory,
+                       new StringNormalizer()
+               );
+
+               $this->setExpectedException( 
ChangeOpDeserializationException::class );
+
+               // Invalid ItemId (not a Q###)
+               $deserializer->createEntityChangeOp( [ 'lexicalCategory' => 
'invalid item id' ] );
+       }
+
+       public function 
testGivenRequestLexicalCategoryAndNoLexicalCategory_changeOpAddsLexicalCategory()
 {
+               $lexeme = new Lexeme( new LexemeId( 'L100' ) );
+
+               $deserializer = $this->newLexicalCategoryChangeOpDeserializer();
+
+               $changeOp = $deserializer->createEntityChangeOp(
+                       [ 'lexicalCategory' => 'q100' ]
+               );
+
+               $changeOp->apply( $lexeme );
+               $this->assertSame( 'Q100', 
$lexeme->getLexicalCategory()->getSerialization() );
+       }
+
+       public function 
testGivenRequestWithLexicalCategoryExists_changeOpSetsLexicalCategoryToNewValue()
 {
+               $lexeme = new Lexeme( new LexemeId( 'L100' ), null, null, new 
ItemId( 'Q100' ) );
+
+               $deserializer = $this->newLexicalCategoryChangeOpDeserializer();
+
+               $changeOp = $deserializer->createEntityChangeOp(
+                       [ 'lexicalCategory' => 'q200' ]
+               );
+
+               $changeOp->apply( $lexeme );
+               $this->assertSame( 'Q200', 
$lexeme->getLexicalCategory()->getSerialization() );
+       }
+
+       public function 
testGivenRemoveRequestLexicalCategoryExists_changeOpRemovesLexicalCategory() {
+               $lexeme = new Lexeme( new LexemeId( 'L100' ), null, null, new 
ItemId( 'Q100' ) );
+
+               $deserializer = $this->newLexicalCategoryChangeOpDeserializer();
+
+               $changeOp = $deserializer->createEntityChangeOp(
+                       [ 'lexicalCategory' => '' ]
+               );
+
+               $changeOp->apply( $lexeme );
+               $this->assertNull( $lexeme->getLexicalCategory() );
+       }
+
+       public function 
testRequestRemoveLexicalCategoryDoesNotExist_changeOpDoesNothing() {
+               $lexeme = new Lexeme( new LexemeId( 'L100' ) );
+
+               $deserializer = $this->newLexicalCategoryChangeOpDeserializer();
+
+               $changeOp = $deserializer->createEntityChangeOp(
+                       [ 'lexicalCategory' => '' ]
+               );
+
+               $changeOp->apply( $lexeme );
+               $this->assertNull( $lexeme->getLexicalCategory() );
+       }
+
+}
diff --git a/tests/phpunit/mediawiki/Validators/LexemeValidatorFactoryTest.php 
b/tests/phpunit/mediawiki/Validators/LexemeValidatorFactoryTest.php
index 676a839..090b979 100644
--- a/tests/phpunit/mediawiki/Validators/LexemeValidatorFactoryTest.php
+++ b/tests/phpunit/mediawiki/Validators/LexemeValidatorFactoryTest.php
@@ -129,7 +129,7 @@
        /**
         * @dataProvider invalidLanguageValidatorArgsProvider
         */
-       public function testGiveninputIsInvalid_validatorThrowsException( 
$language ) {
+       public function 
testGivenLanguageInputIsInvalid_validatorThrowsException( $language ) {
                $this->setExpectedException( InvalidArgumentException::class );
                $languageValidator = $this
                        ->getLexemeValidatorFactory( 10, null, [ 'Q123' ] )
@@ -145,6 +145,68 @@
                ];
        }
 
+       public function testGetLexicalCategoryValidatorValid() {
+               $lexicalCategoryValidator = $this
+                       ->getLexemeValidatorFactory( 10, null, [ 'Q234' ] )
+                       ->getLexicalCategoryValidator();
+
+               $this->assertTrue(
+                       $lexicalCategoryValidator->validate( new ItemId( 'Q234' 
) )->isValid()
+               );
+       }
+
+       public function 
testGetLexicalCategoryValidatorEmptyLexicalCategoryValid() {
+               $lexicalCategoryValidator = $this
+                       ->getLexemeValidatorFactory( 10, null, [ 'Q234' ] )
+                       ->getLexicalCategoryValidator();
+
+               $this->assertTrue(
+                       $lexicalCategoryValidator->validate( null )->isValid()
+               );
+       }
+
+       /**
+        * @dataProvider lexicalCategoryProviderInvalid
+        */
+       public function testGetLexicalCategoryValidatorInvalid( 
$lexicalCategory ) {
+               $lexicalCategoryValidator = $this
+                       ->getLexemeValidatorFactory( 10, null, [ 'Q234' ] )
+                       ->getLexicalCategoryValidator();
+
+               $this->assertFalse(
+                       $lexicalCategoryValidator->validate( $lexicalCategory 
)->isValid()
+               );
+       }
+
+       public function lexicalCategoryProviderInvalid() {
+               return [
+                       'not existing item' => [ new ItemId( 'Q432' ) ],
+                       'property' => [ new PropertyId( 'P321' ) ],
+                       'lexeme' => [ new LexemeId( 'L321' ) ],
+               ];
+       }
+
+       /**
+        * @dataProvider invalidLanguageValidatorArgsProvider
+        */
+       public function 
testGivenLexicalCategoryInputIsInvalid_validatorThrowsException(
+               $lexicalCategory
+       ) {
+               $this->setExpectedException( InvalidArgumentException::class );
+               $lexicalCategoryValidator = $this
+                       ->getLexemeValidatorFactory( 10, null, [ 'Q234' ] )
+                       ->getLexicalCategoryValidator();
+               $lexicalCategoryValidator->validate( $lexicalCategory 
)->isValid();
+       }
+
+       public function invalidLexicalCategoryValidatorArgsProvider() {
+               return [
+                       [ false ],
+                       [ '' ],
+                       [ 'Q234' ]
+               ];
+       }
+
        /**
         * @param int $maxLength
         * @param TermValidatorFactory|null $termValidatorFactory

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I7ab98d3b7f8844fba6245dd859d7aa87cd0394b6
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/extensions/WikibaseLexeme
Gerrit-Branch: master
Gerrit-Owner: Ladsgroup <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: WMDE-leszek <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to