| Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/repo/tests/phpunit/includes/Api/WikibaseApiTestCase.php |
<?php
namespace Wikibase\Test\Repo\Api;
use ApiTestCase;
use OutOfBoundsException;
use Revision;
use TestSites;
use TestUser;
use Title;
use UsageException;
use User;
use Wikibase\Repo\WikibaseRepo;
use WikiPage;
/**
* Base class for test classes that test the API modules that derive from ApiWikibaseModifyItem.
*
* @license GPL-2.0+
* @author John Erling Blad < jeblad@gmail.com >
* @author Daniel Kinzler
* @author Addshore
*/
abstract class WikibaseApiTestCase extends ApiTestCase {
/**
* @var TestUser|null
*/
private static $wbTestUser = null;
protected function setUp() {
parent::setUp();
static $isSetup = false;
$this->setupUser();
if ( !$isSetup ) {
$sitesTable = WikibaseRepo::getDefaultInstance()->getSiteStore();
$sitesTable->clear();
$sitesTable->saveSites( TestSites::getSites() );
$this->doLogin( 'wbeditor' );
$isSetup = true;
}
}
private function setupUser() {
if ( !self::$wbTestUser ) {
self::$wbTestUser = new TestUser(
'Apitesteditor',
'Api Test Editor',
'api_test_editor@example.com',
array( 'wbeditor' )
);
}
ApiTestCase::$users['wbeditor'] = self::$wbTestUser;
$this->setMwGlobals( 'wgUser', self::$users['wbeditor']->getUser() );
$this->setMwGlobals( 'wgGroupPermissions', array( '*' => array(
'property-create' => true,
'createpage' => true,
'bot' => true,
'item-term' => true,
'property-term' => true,
'read' => true,
'edit' => true,
'writeapi' => true
) ) );
}
/**
* Appends an edit token to a request.
*
* @param array $params
* @param array|null $session
* @param User|null $user
*
* @return array( $resultData, $request, $sessionArray )
*/
protected function doApiRequestWithToken( array $params, array $session = null, User $user = null ) {
if ( !$user ) {
$user = $GLOBALS['wgUser'];
}
if ( !array_key_exists( 'token', $params ) ) {
$params['token'] = $user->getEditToken();
}
return $this->doApiRequest( $params, $session, false, $user );
}
/**
* @param string[] $handles
* @param string[] $idMap
*/
protected function initTestEntities( array $handles, array $idMap = array() ) {
$activeHandles = EntityTestHelper::getActiveHandles();
foreach ( $activeHandles as $handle => $id ) {
$title = $this->getTestEntityTitle( $handle );
$page = WikiPage::factory( $title );
$page->doDeleteArticle( 'Test reset' );
EntityTestHelper::unRegisterEntity( $handle );
}
foreach ( $handles as $handle ) {
$params = EntityTestHelper::getEntity( $handle );
$params['action'] = 'wbeditentity';
EntityTestHelper::injectIds( $params, $idMap );
EntityTestHelper::injectIds( $params, EntityTestHelper::$defaultPlaceholderValues );
list( $res, , ) = $this->doApiRequestWithToken( $params );
EntityTestHelper::registerEntity( $handle, $res['entity']['id'], $res['entity'] );
$idMap["%$handle%"] = $res['entity']['id'];
}
}
/**
* @param string $handle
*
* @return null|Title
*/
protected function getTestEntityTitle( $handle ) {
try {
$wikibaseRepo = WikibaseRepo::getDefaultInstance();
$idString = EntityTestHelper::getId( $handle );
$id = $wikibaseRepo->getEntityIdParser()->parse( $idString );
$title = $wikibaseRepo->getEntityTitleLookup()->getTitleForId( $id );
} catch ( OutOfBoundsException $ex ) {
$title = null;
}
return $title;
}
/**
* Loads an entity from the database (via an API call).
*
* @param string $id
*
* @return array
*/
protected function loadEntity( $id ) {
list( $res, , ) = $this->doApiRequest(
array(
'action' => 'wbgetentities',
'format' => 'json', // make sure IDs are used as keys.
'ids' => $id )
);
return $res['entities'][$id];
}
/**
* @see doTestQueryExceptions in IndependentWikibaseApiTestCase
*
* Do the test for exceptions from Api queries.
*
* @param array $params Array of params for the API query.
* @param array $exception Details of the exception to expect (type, code, message).
*/
protected function doTestQueryExceptions( array $params, array $exception ) {
try {
if ( array_key_exists( 'code', $exception )
&& preg_match( '/^(no|bad)token$/', $exception['code'] )
) {
$this->doApiRequest( $params );
} else {
$this->doApiRequestWithToken( $params );
}
$this->fail( "Failed to throw UsageException" );
} catch ( UsageException $e ) {
if ( array_key_exists( 'type', $exception ) ) {
$this->assertInstanceOf( $exception['type'], $e );
}
if ( array_key_exists( 'code', $exception ) ) {
$this->assertEquals( $exception['code'], $e->getCodeString() );
}
if ( array_key_exists( 'message', $exception ) ) {
$this->assertContains( $exception['message'], $e->getMessage() );
}
}
}
/**
* Utility function for converting an array from "deep" (indexed) to "flat" (keyed) structure.
* Arrays that already use a flat structure are left unchanged.
*
* Arrays with a deep structure are expected to be list of entries that are associative arrays,
* where which entry has at least the fields given by $keyField and $valueField.
*
* Arrays with a flat structure are associative and assign values to meaningful keys.
*
* @param array $data the input array.
* @param string $keyField The name of the field in each entry that shall be used as the key in
* the flat structure.
* @param string $valueField The name of the field in each entry that shall be used as the value
* in the flat structure.
* @param bool $multiValue Whether the value in the flat structure shall be an indexed array of
* values instead of a single value.
* @param array $into optional aggregator.
*
* @return array The flat version of $data.
*/
protected function flattenArray( array $data, $keyField, $valueField, $multiValue = false, array &$into = array() ) {
foreach ( $data as $index => $value ) {
if ( is_array( $value ) ) {
if ( isset( $value[$keyField] ) && isset( $value[$valueField] ) ) {
// found "deep" entry in the array
$k = $value[ $keyField ];
$v = $value[ $valueField ];
} elseif ( isset( $value[0] ) && !is_array( $value[0] ) && $multiValue ) {
// found "flat" multi-value entry in the array
$k = $index;
$v = $value;
} else {
// found list, recurse
$this->flattenArray( $value, $keyField, $valueField, $multiValue, $into );
continue;
}
} else {
// found "flat" entry in the array
$k = $index;
$v = $value;
}
if ( $multiValue ) {
if ( is_array( $v ) ) {
$into[$k] = empty( $into[$k] ) ? $v : array_merge( $into[$k], $v );
} else {
$into[$k][] = $v;
}
} else {
$into[$k] = $v;
}
}
return $into;
}
/**
* Compares two entity structures and asserts that they are equal. Only fields present in $expected are considered.
* $expected and $actual can both be either in "flat" or in "deep" form, they are converted as needed before comparison.
*
* @param array $expected
* @param array $actual
* @param bool $expectEmptyArrays Should we expect empty arrays or just ignore them?
*/
protected function assertEntityEquals( array $expected, array $actual, $expectEmptyArrays = true ) {
if ( isset( $expected['id'] ) && !empty( $expected['id'] ) ) {
$this->assertEquals( $expected['id'], $actual['id'], 'id' );
}
if ( isset( $expected['lastrevid'] ) ) {
$this->assertEquals( $expected['lastrevid'], $actual['lastrevid'], 'lastrevid' );
}
if ( isset( $expected['type'] ) ) {
$this->assertEquals( $expected['type'], $actual['type'], 'type' );
}
if ( isset( $expected['labels'] ) ) {
if ( !( $expectEmptyArrays === false && $expected['labels'] === array() ) ) {
$data = $this->flattenArray( $actual['labels'], 'language', 'value' );
$exp = $this->flattenArray( $expected['labels'], 'language', 'value' );
// keys are significant in flat form
$this->assertArrayEquals( $exp, $data, false, true );
}
}
if ( isset( $expected['descriptions'] ) ) {
if ( !( $expectEmptyArrays === false && $expected['descriptions'] === array() ) ) {
$data = $this->flattenArray( $actual['descriptions'], 'language', 'value' );
$exp = $this->flattenArray( $expected['descriptions'], 'language', 'value' );
// keys are significant in flat form
$this->assertArrayEquals( $exp, $data, false, true );
}
}
if ( isset( $expected['sitelinks'] ) ) {
if ( !( $expectEmptyArrays === false && $expected['sitelinks'] === array() ) ) {
$data = $this->flattenArray( isset( $actual['sitelinks'] ) ? $actual['sitelinks'] : array(), 'site', 'title' );
$exp = $this->flattenArray( $expected['sitelinks'], 'site', 'title' );
// keys are significant in flat form
$this->assertArrayEquals( $exp, $data, false, true );
}
}
if ( isset( $expected['aliases'] ) ) {
if ( !( $expectEmptyArrays === false && $expected['aliases'] === array() ) ) {
$data = $this->flattenArray( $actual['aliases'], 'language', 'value', true );
$exp = $this->flattenArray( $expected['aliases'], 'language', 'value', true );
// keys are significant in flat form
$this->assertArrayEquals( $exp, $data, false, true );
}
}
if ( isset( $expected['claims'] ) ) {
if ( !( $expectEmptyArrays === false && $expected['claims'] === array() ) ) {
$data = $this->flattenArray( $actual['claims'], 'mainsnak', 'value', true );
$exp = $this->flattenArray( $expected['claims'], 'language', 'value', true );
$count = count( $expected['claims'] );
for ( $i = 0; $i < $count; $i++ ) {
$this->assertArrayHasKey( $i, $data['id'] );
$this->assertGreaterThanOrEqual( 39, strlen( $data['id'][$i] ) );
}
//unset stuff we dont actually want to compare
if ( isset( $exp['id'] ) ) {
$this->assertArrayHasKey( 'id', $data );
}
unset( $exp['id'] );
unset( $exp['datatype'] );
unset( $data['datatype'] );
unset( $data['id'] );
unset( $data['hash'] );
unset( $data['qualifiers-order'] );
$this->assertArrayEquals( $exp, $data, false, true );
}
}
}
/**
* Asserts that the given API response represents a successful call.
*
* @param array $response
*/
protected function assertResultSuccess( array $response ) {
$this->assertArrayHasKey( 'success', $response, "Missing 'success' marker in response." );
$this->assertResultHasEntityType( $response );
}
/**
* Asserts that the given API response has a valid entity type if the result contains an entity
*
* @param array $response
*/
protected function assertResultHasEntityType( array $response ) {
$wikibaseRepo = WikibaseRepo::getDefaultInstance();
if ( isset( $response['entity'] ) ) {
if ( isset( $response['entity']['type'] ) ) {
$this->assertContains(
$response['entity']['type'],
$wikibaseRepo->getEnabledEntityTypes(),
"Missing valid 'type' in response."
);
}
} elseif ( isset( $response['entities'] ) ) {
foreach ( $response['entities'] as $entity ) {
if ( isset( $entity['type'] ) ) {
$this->assertContains(
$entity['type'],
$wikibaseRepo->getEnabledEntityTypes(),
"Missing valid 'type' in response."
);
}
}
}
}
/**
* Asserts that the revision with the given ID has a summary matching $regex
*
* @param string|string[] $regex The regex to match, or an array to build a regex from.
* @param int $revid
*/
protected function assertRevisionSummary( $regex, $revid ) {
if ( is_array( $regex ) ) {
$r = '';
foreach ( $regex as $s ) {
if ( $r !== '' ) {
$r .= '.*';
}
$r .= preg_quote( $s, '!' );
}
$regex = "!$r!";
}
$rev = Revision::newFromId( $revid );
$this->assertNotNull( $rev, "revision not found: $revid" );
$comment = $rev->getComment();
$this->assertRegExp( $regex, $comment );
}
}