| Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/repo/tests/phpunit/includes/Api/SetReferenceTest.php |
<?php
namespace Wikibase\Test\Repo\Api;
use DataValues\Serializers\DataValueSerializer;
use DataValues\StringValue;
use UsageException;
use Wikibase\DataModel\DeserializerFactory;
use Wikibase\DataModel\Entity\Item;
use Wikibase\DataModel\Entity\ItemId;
use Wikibase\DataModel\Entity\Property;
use Wikibase\DataModel\Entity\PropertyId;
use Wikibase\DataModel\Reference;
use Wikibase\DataModel\SerializerFactory;
use Wikibase\DataModel\Snak\PropertyNoValueSnak;
use Wikibase\DataModel\Snak\PropertySomeValueSnak;
use Wikibase\DataModel\Snak\PropertyValueSnak;
use Wikibase\DataModel\Snak\SnakList;
use Wikibase\DataModel\Statement\Statement;
use Wikibase\Repo\WikibaseRepo;
/**
* @covers Wikibase\Repo\Api\SetReference
*
* @group API
* @group Database
* @group Wikibase
* @group WikibaseAPI
* @group WikibaseRepo
* @group SetReferenceTest
*
* @group medium
*
* @license GPL-2.0+
* @author Jeroen De Dauw < jeroendedauw@gmail.com >
* @author Katie Filbert < aude.wiki@gmail.com >
* @author Daniel Kinzler
* @author H. Snater < mediawiki@snater.com >
* @author Addshore
*/
class SetReferenceTest extends WikibaseApiTestCase {
/**
* @var PropertyId[]
*/
private static $propertyIds;
/**
* @var SerializerFactory
*/
private $serializerFactory;
/**
* @var DeserializerFactory
*/
private $deserializerFactory;
protected function setUp() {
parent::setUp();
$wikibaseRepo = WikibaseRepo::getDefaultInstance();
$store = $wikibaseRepo->getEntityStore();
if ( !self::$propertyIds ) {
self::$propertyIds = array();
for ( $i = 0; $i < 4; $i++ ) {
$property = Property::newFromType( 'string' );
$store->saveEntity( $property, '', $GLOBALS['wgUser'], EDIT_NEW );
self::$propertyIds[] = $property->getId();
}
$this->initTestEntities( array( 'StringProp', 'Berlin' ) );
}
$this->serializerFactory = new SerializerFactory(
new DataValueSerializer(),
SerializerFactory::OPTION_SERIALIZE_REFERENCE_SNAKS_WITHOUT_HASH
);
$this->deserializerFactory = new DeserializerFactory(
$wikibaseRepo->getDataValueDeserializer(),
$wikibaseRepo->getEntityIdParser()
);
}
/**
* @param Reference[] $references references to be created with
*
* @return Statement
*/
private function getNewStatement( array $references = array() ) {
$store = WikibaseRepo::getDefaultInstance()->getEntityStore();
// Create a new empty item
$item = new Item();
$store->saveEntity( $item, '', $GLOBALS['wgUser'], EDIT_NEW );
$statementGuid = $item->getId()->getSerialization() . '$D8505CDA-25E4-4334-AG93-A3290BCD9C0P';
$item->getStatements()->addNewStatement(
new PropertyNoValueSnak( self::$propertyIds[0] ),
null,
$references,
$statementGuid
);
$store->saveEntity( $item, '', $GLOBALS['wgUser'], EDIT_UPDATE );
return $item->getStatements()->getFirstStatementWithGuid( $statementGuid );
}
public function testRequests() {
$reference = new Reference( array( new PropertySomeValueSnak( 100 ) ) );
$referenceHash = $reference->getHash();
$statement = $this->getNewStatement( array( $reference ) );
$guid = $statement->getGuid();
// Replace the reference with this new one
$newReference = new Reference( new SnakList( array(
new PropertyNoValueSnak( self::$propertyIds[1] )
) ) );
$serializedReferenceResult = $this->makeValidRequest(
$guid,
$referenceHash,
$newReference
);
// Since the reference got modified, the hash should no longer match
$propertyIdString = self::$propertyIds[0]->getSerialization();
$this->makeInvalidRequest(
$guid,
$referenceHash,
'{"' . $propertyIdString . '":[{"snaktype":"novalue","property":"' . $propertyIdString . '"}]}',
'["' . $propertyIdString . '"]',
'no-such-reference'
);
// Replace the previous reference with a reference with 2 snaks
$aditionalReference = new Reference( new SnakList(
array(
new PropertyNoValueSnak( self::$propertyIds[0] ),
new PropertyNoValueSnak( self::$propertyIds[1] ),
)
) );
$serializedReferenceResult = $this->makeValidRequest(
$guid,
$serializedReferenceResult['hash'],
$aditionalReference
);
// Reorder reference snaks by moving the last property id to the front:
$firstPropertyId = array_shift( $serializedReferenceResult['snaks-order'] );
array_push( $serializedReferenceResult['snaks-order'], $firstPropertyId );
$this->makeValidRequest(
$guid,
$serializedReferenceResult['hash'],
$serializedReferenceResult
);
}
public function testRequestWithInvalidProperty() {
$reference = new Reference( array( new PropertySomeValueSnak( 100 ) ) );
$statement = $this->getNewStatement( array( $reference ) );
$guid = $statement->getGuid();
$this->makeInvalidRequest(
$guid,
null,
'{"P23728525":[{"snaktype":"somevalue","property":"P23728525"}]}',
'["P23728525"]',
'modification-failed'
);
}
public function testSettingIndex() {
/** @var Reference[] $references */
$references = array(
new Reference( new SnakList( array( new PropertySomeValueSnak( self::$propertyIds[0] ) ) ) ),
new Reference( new SnakList( array( new PropertySomeValueSnak( self::$propertyIds[1] ) ) ) ),
new Reference( new SnakList( array( new PropertySomeValueSnak( self::$propertyIds[2] ) ) ) ),
);
$statement = $this->getNewStatement( $references );
$this->makeValidRequest(
$statement->getGuid(),
$references[2]->getHash(),
$references[2],
0
);
$this->assertEquals( $statement->getReferences()->indexOf( $references[0] ), 0 );
}
/**
* @param string|null $statementGuid
* @param string $referenceHash
* @param Reference|array $reference Reference object or serialized reference
* @param int|null $index
*
* @return array Serialized reference
*/
protected function makeValidRequest( $statementGuid, $referenceHash, $reference, $index = null ) {
$serializedReference = $this->serializeReference( $reference );
$reference = $this->unserializeReference( $reference );
$params = $this->generateRequestParams(
$statementGuid,
json_encode( $serializedReference['snaks'] ),
json_encode( $serializedReference['snaks-order'] ),
$referenceHash,
$index
);
list( $resultArray, ) = $this->doApiRequestWithToken( $params );
$this->assertInternalType( 'array', $resultArray, 'top level element is an array' );
$this->assertArrayHasKey( 'reference', $resultArray, 'top level element has a reference key' );
$serializedReference = $resultArray['reference'];
unset( $serializedReference['lastrevid'] );
foreach ( $serializedReference['snaks'] as &$propertyGroup ) {
foreach ( $propertyGroup as &$snak ) {
$this->assertArrayHasKey( 'datatype', $snak );
unset( $snak['datatype'] );
}
}
$this->assertArrayEquals( $this->serializeReference( $reference ), $serializedReference );
return $serializedReference;
}
protected function makeInvalidRequest(
$statementGuid,
$referenceHash,
$snaksJson,
$snaksOrderJson,
$expectedErrorCode
) {
$params = $this->generateRequestParams(
$statementGuid,
$snaksJson,
$snaksOrderJson,
$referenceHash
);
try {
$this->doApiRequestWithToken( $params );
$this->assertFalse( true, 'Invalid request should raise an exception' );
} catch ( UsageException $e ) {
$this->assertEquals(
$expectedErrorCode,
$e->getCodeString(),
'Invalid request raised correct error'
);
}
}
/**
* Serializes a Reference object (if not serialized already).
*
* @param Reference|array $reference
* @return array
*/
protected function serializeReference( $reference ) {
if ( $reference instanceof Reference ) {
$reference = $this->serializerFactory
->newReferenceSerializer()
->serialize( $reference );
}
return $reference;
}
/**
* Unserializes a serialized Reference object (if not unserialized already).
*
* @param array|Reference $reference
* @return Reference Reference
*/
protected function unserializeReference( $reference ) {
if ( is_array( $reference ) ) {
$reference = $this->deserializerFactory
->newReferenceDeserializer()
->deserialize( $reference );
}
return $reference;
}
/**
* Generates the parameters for a 'wbsetreference' API request.
*
* @param string $statementGuid
* @param string $snaksJson
* @param string|null $snaksOrderJson
* @param string|null $referenceHash
* @param int|null $index
*
* @return array
*/
protected function generateRequestParams(
$statementGuid,
$snaksJson,
$snaksOrderJson = null,
$referenceHash = null,
$index = null
) {
$params = array(
'action' => 'wbsetreference',
'statement' => $statementGuid,
'snaks' => $snaksJson,
);
if ( !is_null( $snaksOrderJson ) ) {
$params['snaks-order'] = $snaksOrderJson;
}
if ( !is_null( $referenceHash ) ) {
$params['reference'] = $referenceHash;
}
if ( !is_null( $index ) ) {
$params['index'] = $index;
}
return $params;
}
/**
* @dataProvider provideInvalidSerializations
*/
public function testInvalidSerialization( $snaksSerialization ) {
$this->setExpectedException( UsageException::class );
$params = array(
'action' => 'wbsetreference',
'statement' => 'Foo$Guid',
'snaks' => $snaksSerialization
);
$this->doApiRequestWithToken( $params );
}
public function provideInvalidSerializations() {
return array(
array( '{
"P813":[
{
"snaktype":"value",
"property":"P813",
"datavalue":{
"value":{
"time":"+00000002013-10-05T00:00:00Z",
"timezone":0,
"before":0,
"after":0,
"precision":11,
"calendarmodel":"FOOBAR :D"
},
"type":"time"
}
}
]
}' ),
array( '{
"P813":[
{
"snaktype":"wubbledubble",
"property":"P813",
"datavalue":{
"value":{
"time":"+00000002013-10-05T00:00:00Z",
"timezone":0,
"before":0,
"after":0,
"precision":11,
"calendarmodel":"http:\/\/www.wikidata.org\/entity\/Q1985727"
},
"type":"time"
}
}
]
}' ),
);
}
/**
* @dataProvider invalidRequestProvider
*/
public function testInvalidRequest( $itemHandle, $guid, $referenceValue, $referenceHash, $error ) {
$itemId = new ItemId( EntityTestHelper::getId( $itemHandle ) );
$item = WikibaseRepo::getDefaultInstance()->getEntityLookup()->getEntity( $itemId );
if ( $guid === null ) {
/** @var Item $item */
$statements = $item->getStatements()->toArray();
/** @var Statement $statement */
$statement = reset( $statements );
$guid = $statement->getGuid();
}
$prop = new PropertyId( EntityTestHelper::getId( 'StringProp' ) );
$snak = new PropertyValueSnak( $prop, new StringValue( $referenceValue ) );
$reference = new Reference( new SnakList( array( $snak ) ) );
$serializedReference = $this->serializeReference( $reference );
$params = array(
'action' => 'wbsetreference',
'statement' => $guid,
'snaks' => json_encode( $serializedReference['snaks'] ),
'snaks-order' => json_encode( $serializedReference['snaks-order'] ),
);
if ( $referenceHash ) {
$params['reference'] = $referenceHash;
}
try {
$this->doApiRequestWithToken( $params );
$this->fail( 'Invalid request did not raise an error' );
} catch ( UsageException $ex ) {
$this->assertEquals( $error, $ex->getCodeString(), 'Invalid request raised correct error' );
}
}
public function invalidRequestProvider() {
return array(
'bad guid 1' =>
array( 'Berlin', 'xyz', 'good', '', 'invalid-guid' ),
'bad guid 2' =>
array( 'Berlin', 'x$y$z', 'good', '', 'invalid-guid' ),
'bad guid 3' =>
array( 'Berlin', 'i1813$358fa2a0-4345-82b6-12a4-7b0fee494a5f', 'good', '', 'invalid-guid' ),
'bad snak value' =>
array( 'Berlin', null, ' ', '', 'modification-failed' ),
);
}
}