Current File : /home/jvzmxxx/wiki/extensions/Wikibase/repo/tests/phpunit/includes/EntityModificationTestHelper.php
<?php

namespace Wikibase\Test;

use Deserializers\Deserializer;
use PHPUnit_Framework_Assert as Assert;
use Serializers\Serializer;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Entity\EntityRedirect;
use Wikibase\DataModel\Entity\EntityIdParser;
use Wikibase\DataModel\Services\Lookup\RedirectResolvingEntityLookup;
use Wikibase\Lib\Tests\MockRepository;
use Wikibase\Repo\WikibaseRepo;

/**
 * EntityModificationTestHelper
 *
 * @license GPL-2.0+
 * @author Daniel Kinzler
 */
class EntityModificationTestHelper {

	/**
	 * @var EntityIdParser
	 */
	private $idParser;

	/**
	 * @var Serializer
	 */
	private $serializer;

	/**
	 * @var Deserializer
	 */
	private $deserializer;

	/**
	 * @var MockRepository
	 */
	private $mockRepository;

	/**
	 * @var RedirectResolvingEntityLookup
	 */
	private $redirectResolvingEntityLookup;

	public function __construct() {
		$wikibaseRepo = WikibaseRepo::getDefaultInstance();
		$this->idParser = $wikibaseRepo->getEntityIdParser();
		$this->serializer = $wikibaseRepo->getEntitySerializer();
		$this->deserializer = $wikibaseRepo->getInternalFormatEntityDeserializer();
		$this->mockRepository = new MockRepository();
		$this->redirectResolvingEntityLookup  = new RedirectResolvingEntityLookup( $this->mockRepository );
	}

	/**
	 * @return MockRepository
	 */
	public function getMockRepository() {
		return $this->mockRepository;
	}

	/**
	 * Adds a list of entities to the test data.
	 *
	 * @param array $entities A list of Entity object or array structures representing entities.
	 *        If the entity does not have an ID and the corresponding array key is a string,
	 *        they key is used as the entity ID.
	 */
	public function putEntities( array $entities ) {
		foreach ( $entities as $key => $entity ) {
			$id = is_string( $key ) ? $key : null;
			$this->putEntity( $entity, $id );
		}
	}

	/**
	 * Adds a list of redirects to the test data.
	 *
	 * @param array $redirects A list of EntityRedirect objects, EntityId objects or strings.
	 *        If a value in the list is not an EntityRedirect, a redirect is constructed from
	 *        the corresponding array key and value; the key is parsed as an EntityId, the value
	 *        is also parsed if it's a string.
	 */
	public function putRedirects( array $redirects ) {
		foreach ( $redirects as $key => $redirect ) {
			if ( !( $redirect instanceof EntityRedirect ) ) {
				$from = $this->idParser->parse( $key );

				if ( $redirect instanceof EntityId ) {
					$target = $redirect;
				} else {
					$target = $this->idParser->parse( $redirect );
				}

				$redirect = new EntityRedirect( $from, $target );
			}

			$this->mockRepository->putRedirect( $redirect );
		}
	}

	/**
	 * @param array|EntityDocument $entity
	 * @param EntityId|string|null $id Overrides any id in $entity
	 */
	public function putEntity( $entity, $id = null ) {
		if ( is_array( $entity ) ) {
			$entity = $this->unserializeEntity( $entity, $id );
		}

		if ( $id !== null ) {
			if ( is_string( $id ) ) {
				$id = $this->idParser->parse( $id );
			}

			$entity->setId( $id );
		}

		$this->mockRepository->putEntity( $entity );
	}

	/**
	 * @param string|EntityId $id
	 * @param bool $resolveRedirects
	 *
	 * @return null|EntityDocument
	 */
	public function getEntity( $id, $resolveRedirects = false ) {
		if ( is_string( $id ) ) {
			$id = $this->idParser->parse( $id );
		}

		if ( $resolveRedirects ) {
			return $this->redirectResolvingEntityLookup->getEntity( $id );
		} else {
			return $this->mockRepository->getEntity( $id );
		}
	}

	/**
	 * @param array $data
	 * @param EntityId|string|null $id
	 *
	 * @return object
	 */
	public function unserializeEntity( array $data, $id = null ) {
		if ( $id !== null ) {
			if ( is_string( $id ) ) {
				$id = $this->idParser->parse( $id );
			}

			$data['id'] = $id->getSerialization();
			$data['type'] = $id->getEntityType();
		}

		$entity = $this->deserializer->deserialize( $data );
		return $entity;
	}

	/**
	 * @param EntityDocument $entity
	 *
	 * @return array
	 */
	public function serializeEntity( EntityDocument $entity ) {
		$data = $this->serializer->serialize( $entity );

		return $data;
	}

	/**
	 * Strip any fields we will likely not have in the arrays that are provided as
	 * expected values. This includes empty fields, and automatic id or hash fields.
	 *
	 * @param array $data
	 */
	private function unsetSpuriousFieldsRecursively( array &$data ) {
		// unset empty fields
		foreach ( $data as $key => &$value ) {
			if ( $key === 'hash' || $key === 'id' ) {
				unset( $data[$key] );
			} elseif ( $value === array() ) {
				unset( $data[$key] );
			} elseif ( is_array( $value ) ) {
				$this->unsetSpuriousFieldsRecursively( $value );
			}
		}
	}

	/**
	 * Compares two entity structures and asserts that they are equal.
	 * Top level keys not present in the $expected structure are ignored.
	 * Some fields ('id' and 'hash') in lower level structures are ignored.
	 *
	 * @param array|EntityDocument $expected
	 * @param array|EntityDocument $actual
	 * @param string $message
	 */
	public function assertEntityEquals( $expected, $actual, $message = '' ) {
		if ( $expected instanceof EntityDocument ) {
			$expected = $this->serializeEntity( $expected );
		}

		if ( $actual instanceof EntityDocument ) {
			$actual = $this->serializeEntity( $actual );
		}

		foreach ( array_keys( $actual ) as $key ) {
			if ( !array_key_exists( $key, $expected ) ) {
				unset( $actual[$key] );
			}
		}

		foreach ( $expected as $key => $value ) {
			Assert::assertArrayHasKey( $key, $actual, $message );

			if ( is_array( $actual[$key] ) ) {
				$this->unsetSpuriousFieldsRecursively( $actual[$key] );
			}

			Assert::assertEquals( $value, $actual[$key], "$message [$key]" );
		}
	}

	/**
	 * 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
	 * @param string $message
	 */
	public function assertRevisionSummary( $regex, $revid, $message = '' ) {
		if ( is_array( $regex ) ) {
			$r = '';

			foreach ( $regex as $s ) {
				if ( strlen( $r ) > 0 ) {
					$r .= '.*';
				}

				$r .= preg_quote( $s, '!' );
			}

			$regex = "!$r!";
		}

		$entry = $this->mockRepository->getLogEntry( $revid );
		Assert::assertNotNull( $entry, "revision not found: $revid" );
		Assert::assertRegExp( $regex, $entry['summary'], $message );
	}

}