Thiemo Mättig (WMDE) has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/358525 )

Change subject: Allow empty EntityContent objects with no EntityHolder
......................................................................

Allow empty EntityContent objects with no EntityHolder

This is split from If0c9827.

This also adds a whole bunch of new tests. I wanted to avoid using the
abstract base class as much as I could.

Change-Id: Ifa9e84353a17a8de8cb827aa1522804412748a82
---
M repo/includes/Content/EntityContent.php
M repo/includes/Content/ItemContent.php
M repo/includes/Content/PropertyContent.php
M repo/tests/phpunit/includes/Content/EntityContentTest.php
M repo/tests/phpunit/includes/Content/ItemContentTest.php
M repo/tests/phpunit/includes/Content/PropertyContentTest.php
6 files changed, 152 insertions(+), 28 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/25/358525/1

diff --git a/repo/includes/Content/EntityContent.php 
b/repo/includes/Content/EntityContent.php
index b6e5eda..dfe373b 100644
--- a/repo/includes/Content/EntityContent.php
+++ b/repo/includes/Content/EntityContent.php
@@ -104,29 +104,30 @@
         * Returns a holder for the entity contained in this EntityContent 
object.
         *
         * @throws MWException when it's a redirect (targets will never be 
resolved)
-        * @return EntityHolder
+        * @return EntityHolder|null
         */
        abstract protected function getEntityHolder();
 
        /**
-        * Returns the ID of the entity represented by this EntityContent;
-        *
-        * @throws RuntimeException if no entity ID is set
+        * @throws RuntimeException if the content object is empty or no entity 
ID is set
         * @return EntityId
         */
        public function getEntityId() {
                if ( $this->isRedirect() ) {
                        return $this->getEntityRedirect()->getEntityId();
-               } else {
-                       $id = $this->getEntityHolder()->getEntityId();
-                       if ( !$id ) {
-                               // @todo: Force an ID to be present; Entity 
objects without an ID make sense,
-                               // EntityContent objects with no entity ID 
don't.
-                               throw new RuntimeException( 'EntityContent was 
constructed without an EntityId!' );
-                       }
-
-                       return $id;
                }
+
+               $holder = $this->getEntityHolder();
+               if ( $holder !== null ) {
+                       $id = $holder->getEntityId();
+                       if ( $id !== null ) {
+                               return $id;
+                       }
+               }
+
+               // @todo: Force an ID to be present; Entity objects without an 
ID make sense,
+               // EntityContent objects with no entity ID don't.
+               throw new RuntimeException( 'EntityContent was constructed 
without an EntityId!' );
        }
 
        /**
@@ -503,8 +504,8 @@
                        return false;
                }
 
-               $thisId = $this->getEntityHolder()->getEntityId();
-               $thatId = $that->getEntityHolder()->getEntityId();
+               $thisId = $this->getEntityHolder() ? 
$this->getEntityHolder()->getEntityId() : null;
+               $thatId = $that->getEntityHolder() ? 
$that->getEntityHolder()->getEntityId() : null;
 
                if ( $thisId !== null && $thatId !== null
                        && !$thisId->equals( $thatId )
@@ -627,22 +628,34 @@
         * @return bool True if this is not a redirect and the page is empty.
         */
        public function isEmpty() {
-               return !$this->isRedirect() && parent::isEmpty();
+               if ( $this->isRedirect() ) {
+                       return false;
+               }
+
+               $holder = $this->getEntityHolder();
+               return $holder === null || $holder->getEntity()->isEmpty();
        }
 
        /**
         * @see Content::copy
         *
-        * @return ItemContent
+        * @return EntityContent
         */
        public function copy() {
                /* @var EntityHandler $handler */
                $handler = $this->getContentHandler();
+
                if ( $this->isRedirect() ) {
                        return $handler->makeEntityRedirectContent( 
$this->getEntityRedirect() );
-               } else {
-                       return $handler->makeEntityContent( new 
DeferredCopyEntityHolder( $this->getEntityHolder() ) );
                }
+
+               $holder = $this->getEntityHolder();
+               if ( $holder !== null ) {
+                       return $handler->makeEntityContent( new 
DeferredCopyEntityHolder( $holder ) );
+               }
+
+               // There is nothing mutable on an entirely empty content object.
+               return $this;
        }
 
        /**
diff --git a/repo/includes/Content/ItemContent.php 
b/repo/includes/Content/ItemContent.php
index 5f9d42e..ce51a86 100644
--- a/repo/includes/Content/ItemContent.php
+++ b/repo/includes/Content/ItemContent.php
@@ -55,9 +55,8 @@
        ) {
                parent::__construct( CONTENT_MODEL_WIKIBASE_ITEM );
 
-               if ( is_null( $itemHolder ) === is_null( $entityRedirect ) ) {
-                       throw new InvalidArgumentException(
-                               'Either $item or $entityRedirect and 
$redirectTitle must be provided.' );
+               if ( $itemHolder !== null && $entityRedirect !== null ) {
+                       throw new InvalidArgumentException( 'Can not be an item 
and a redirect the same time' );
                }
 
                if ( $itemHolder !== null && $itemHolder->getEntityType() !== 
Item::ENTITY_TYPE ) {
@@ -159,7 +158,7 @@
        /**
         * @see EntityContent::getEntityHolder
         *
-        * @return EntityHolder
+        * @return EntityHolder|null
         */
        protected function getEntityHolder() {
                return $this->itemHolder;
diff --git a/repo/includes/Content/PropertyContent.php 
b/repo/includes/Content/PropertyContent.php
index 53d8f23..9af16ba 100644
--- a/repo/includes/Content/PropertyContent.php
+++ b/repo/includes/Content/PropertyContent.php
@@ -17,7 +17,7 @@
 class PropertyContent extends EntityContent {
 
        /**
-        * @var EntityHolder
+        * @var EntityHolder|null
         */
        private $propertyHolder;
 
@@ -30,13 +30,15 @@
         *
         * @protected
         *
-        * @param EntityHolder $propertyHolder
+        * @param EntityHolder|null $propertyHolder
         * @throws InvalidArgumentException
         */
-       public function __construct( EntityHolder $propertyHolder ) {
+       public function __construct( EntityHolder $propertyHolder = null ) {
                parent::__construct( CONTENT_MODEL_WIKIBASE_PROPERTY );
 
-               if ( $propertyHolder->getEntityType() !== Property::ENTITY_TYPE 
) {
+               if ( $propertyHolder !== null
+                       && $propertyHolder->getEntityType() !== 
Property::ENTITY_TYPE
+               ) {
                        throw new InvalidArgumentException( '$propertyHolder 
must contain a Property entity!' );
                }
 
@@ -75,7 +77,7 @@
        /**
         * @see EntityContent::getEntityHolder
         *
-        * @return EntityHolder
+        * @return EntityHolder|null
         */
        public function getEntityHolder() {
                return $this->propertyHolder;
diff --git a/repo/tests/phpunit/includes/Content/EntityContentTest.php 
b/repo/tests/phpunit/includes/Content/EntityContentTest.php
index 4b8eb52..e16835f 100644
--- a/repo/tests/phpunit/includes/Content/EntityContentTest.php
+++ b/repo/tests/phpunit/includes/Content/EntityContentTest.php
@@ -7,6 +7,7 @@
 use Diff\Patcher\PatcherException;
 use InvalidArgumentException;
 use ParserOutput;
+use RuntimeException;
 use Title;
 use Wikibase\DataModel\Entity\EntityDocument;
 use Wikibase\DataModel\Entity\EntityId;
@@ -213,6 +214,16 @@
                $this->assertEquals( $expected, $actual );
        }
 
+       abstract public function provideContentObjectsWithoutId();
+
+       /**
+        * @dataProvider provideContentObjectsWithoutId
+        */
+       public function testGetEntityIdExceptions( EntityContent $content ) {
+               $this->setExpectedException( RuntimeException::class );
+               $content->getEntityId();
+       }
+
        public function provideGetEntityPageProperties() {
                $empty = $this->newEmpty();
 
diff --git a/repo/tests/phpunit/includes/Content/ItemContentTest.php 
b/repo/tests/phpunit/includes/Content/ItemContentTest.php
index 86a357b..7526293 100644
--- a/repo/tests/phpunit/includes/Content/ItemContentTest.php
+++ b/repo/tests/phpunit/includes/Content/ItemContentTest.php
@@ -8,11 +8,13 @@
 use Diff\DiffOp\DiffOpRemove;
 use InvalidArgumentException;
 use Title;
+use Wikibase\Content\EntityHolder;
 use Wikibase\Content\EntityInstanceHolder;
 use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Entity\EntityRedirect;
 use Wikibase\DataModel\Entity\Item;
 use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Entity\Property;
 use Wikibase\DataModel\Entity\PropertyId;
 use Wikibase\DataModel\Services\Diff\EntityDiff;
 use Wikibase\DataModel\Services\Lookup\InMemoryDataTypeLookup;
@@ -44,6 +46,66 @@
  * @author Daniel Kinzler
  */
 class ItemContentTest extends EntityContentTest {
+
+       public function provideValidConstructorArguments() {
+               return [
+                       'empty' => [ null, null, null ],
+                       'empty item' => [ new EntityInstanceHolder( new Item() 
), null, null ],
+                       'redirect' => [
+                               null,
+                               new EntityRedirect( new ItemId( 'Q1' ), new 
ItemId( 'Q2' ) ),
+                               $this->getMock( Title::class )
+                       ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideValidConstructorArguments
+        */
+       public function testConstructor(
+               EntityHolder $holder = null,
+               EntityRedirect $redirect = null,
+               Title $title = null
+       ) {
+               $content = new ItemContent( $holder, $redirect, $title );
+               $this->assertInstanceOf( ItemContent::class, $content );
+       }
+
+       public function provideInvalidConstructorArguments() {
+               $holder = new EntityInstanceHolder( new Item() );
+               $redirect = new EntityRedirect( new ItemId( 'Q1' ), new ItemId( 
'Q2' ) );
+               $title = $this->getMock( Title::class );
+
+               $propertyHolder = new EntityInstanceHolder( 
Property::newFromType( 'string' ) );
+
+               $badTitle = $this->getMock( Title::class );
+               $badTitle->method( 'getContentModel' )
+                       ->will( $this->returnValue( 'bad content model' ) );
+               $badTitle->method( 'exists' )
+                       ->will( $this->returnValue( true ) );
+
+               return [
+                       'all' => [ $holder, $redirect, $title ],
+                       'holder and redirect' => [ $holder, $redirect, null ],
+                       'holder and title' => [ $holder, null, $title ],
+                       'redirect only' => [ null, $redirect, null ],
+                       'title only' => [ null, null, $title ],
+                       'bad entity type' => [ $propertyHolder, null, null ],
+                       'bad title' => [ null, $redirect, $badTitle ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideInvalidConstructorArguments
+        */
+       public function testConstructorExceptions(
+               EntityHolder $holder = null,
+               EntityRedirect $redirect = null,
+               Title $title = null
+       ) {
+               $this->setExpectedException( InvalidArgumentException::class );
+               new ItemContent( $holder, $redirect, $title );
+       }
 
        /**
         * @return ItemId
@@ -440,6 +502,13 @@
                return $cases;
        }
 
+       public function provideContentObjectsWithoutId() {
+               return [
+                       'no holder' => [ new ItemContent() ],
+                       'no ID' => [ new ItemContent( new EntityInstanceHolder( 
new Item() ) ) ],
+               ];
+       }
+
        public function entityRedirectProvider() {
                $cases = parent::entityRedirectProvider();
 
diff --git a/repo/tests/phpunit/includes/Content/PropertyContentTest.php 
b/repo/tests/phpunit/includes/Content/PropertyContentTest.php
index 6c9cc5e..156942c 100644
--- a/repo/tests/phpunit/includes/Content/PropertyContentTest.php
+++ b/repo/tests/phpunit/includes/Content/PropertyContentTest.php
@@ -3,8 +3,10 @@
 namespace Wikibase\Repo\Tests\Content;
 
 use InvalidArgumentException;
+use Wikibase\Content\EntityHolder;
 use Wikibase\Content\EntityInstanceHolder;
 use Wikibase\DataModel\Entity\EntityId;
+use Wikibase\DataModel\Entity\Item;
 use Wikibase\DataModel\Entity\Property;
 use Wikibase\DataModel\Entity\PropertyId;
 use Wikibase\PropertyContent;
@@ -22,6 +24,27 @@
  * @author Jeroen De Dauw < jeroended...@gmail.com >
  */
 class PropertyContentTest extends EntityContentTest {
+
+       public function provideValidConstructorArguments() {
+               return [
+                       'empty' => [ null ],
+                       'empty property' => [ new EntityInstanceHolder( 
Property::newFromType( 'string' ) ) ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideValidConstructorArguments
+        */
+       public function testConstructor( EntityHolder $holder = null ) {
+               $content = new PropertyContent( $holder );
+               $this->assertInstanceOf( PropertyContent::class, $content );
+       }
+
+       public function testConstructorExceptions() {
+               $holder = new EntityInstanceHolder( new Item() );
+               $this->setExpectedException( InvalidArgumentException::class );
+               new PropertyContent( $holder );
+       }
 
        /**
         * @return PropertyId
@@ -61,6 +84,13 @@
                );
        }
 
+       public function provideContentObjectsWithoutId() {
+               return [
+                       'no holder' => [ new PropertyContent() ],
+                       'no ID' => [ new PropertyContent( new 
EntityInstanceHolder( Property::newFromType( 'string' ) ) ) ],
+               ];
+       }
+
        public function testIsEmpty_emptyProperty() {
                $content = PropertyContent::newFromProperty( 
Property::newFromType( 'foo' ) );
                $this->assertTrue( $content->isEmpty() );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifa9e84353a17a8de8cb827aa1522804412748a82
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de>

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

Reply via email to