%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/MobileFrontend/tests/phpunit/api/ |
| Current File : //www/varak.net/wiki.varak.net/extensions/MobileFrontend/tests/phpunit/api/ApiMobileViewTest.php |
<?php
use MediaWiki\MediaWikiServices;
class MockApiMobileView extends ApiMobileView {
/** @var PHPUnit_Framework_MockObject_MockObject */
public $mockFile;
public function __construct( ApiMain $main, $action ) {
parent::__construct( $main, $action );
// Force usePageImages = true
$this->usePageImages = true;
}
protected function makeTitle( $name ) {
$t = Title::newFromText( $name );
$row = new stdClass();
$row->page_id = 1;
$row->page_title = $t->getDBkey();
$row->page_namespace = $t->getNamespace();
return Title::newFromRow( $row );
}
protected function getParserOutput(
WikiPage $wikiPage,
ParserOptions $parserOptions,
$oldid = null
) {
$params = $this->extractRequestParams();
if ( !isset( $params['text'] ) ) {
throw new Exception( 'Must specify page text' );
}
$po = MediaWikiServices::getInstance()->getParser()->getFreshParser()->parse(
$params['text'], $wikiPage->getTitle(), $parserOptions );
if ( !defined( 'ParserOutput::SUPPORTS_STATELESS_TRANSFORMS' ) ) {
$po->setTOCEnabled( false );
}
$po->setText( str_replace( [ "\r", "\n" ], '', $po->getText( [
'allowTOC' => false, 'unwrap' => true,
] ) ) );
return $po;
}
protected function makeWikiPage( Title $title ) {
return new MockWikiPage( $title );
}
protected function makeParserOptions( WikiPage $wikiPage ) {
$popt = new ParserOptions( $this->getUser() );
return $popt;
}
public function getAllowedParams() {
return array_merge( parent::getAllowedParams(), [ 'text' => null ] );
}
protected function findFile( $title, $options = [] ) {
return $this->mockFile;
}
protected function getPageImage( Title $title ) {
return $this->findFile( $title );
}
}
class MockWikiPage extends WikiPage {
public function getLatest() {
return 123;
}
public function isRedirect() {
return $this->getTitle()->getPrefixedText() === 'Redirected';
}
public function getRedirectTarget() {
if ( $this->getTitle()->getPrefixedText() === 'Redirected' ) {
return SpecialPage::getTitleFor( 'Blankpage' );
}
return null;
}
}
/**
* @group MobileFrontend
*/
class ApiMobileViewTest extends MediaWikiTestCase {
public function setUp() {
parent::setUp();
$this->setMwGlobals( 'wgAPIModules', [ 'mobileview' => 'MockApiMobileView' ] );
}
/**
* @dataProvider provideGetRequestedSectionIds
* @covers ApiMobileView::getRequestedSectionIds
*/
public function testGetRequestedSectionIds( $expectedSections, $expectedMissing, $str ) {
$data = [
'sections' => range( 0, 9 ),
'refsections' => [ 5 => 1, 7 => 1 ],
];
$missing = [];
$sections = array_keys(
ApiMobileView::getRequestedSectionIds( $str, $data, $missing )
);
$this->assertEquals( $expectedSections, $sections, 'Check sections' );
$this->assertEquals( $expectedMissing, $missing, 'Check missing' );
}
public function provideGetRequestedSectionIds() {
return [
[ [], [], '' ],
[ [], [], ' ' ],
[ [], [ -1 ], '-1' ],
[ range( 0, 10 ), [], 'all' ],
[ range( 0, 10 ), [], ' all ' ],
[ [], [ 'all!' ], 'all!' ],
[ [], [ 'foo' ], ' foo ' ],
[ [ 0 ], [], '0' ],
[ [ 1 ], [], ' 1 ' ],
[ [ 0, 2 ], [], ' 0 | 2 ' ],
[ range( 3, 10 ), [], '3-' ],
[ [ 3, 4, 5 ], [], '3-5' ],
[ [ 7 ], [], '7-7' ],
[ range( 1, 5 ), [], '5-1' ],
[ [ 5, 7 ], [], 'references ' ],
[ [ 0, 5, 7 ], [], '0|references' ],
[ [ 1, 2 ], [ 11 ], '1|1|2|1|11|2|1' ],
[ [ 1, 3, 4, 5 ], [], '1|3-5|4' ],
[ [ 10 ], [], '10-' ],
# https://bugzilla.wikimedia.org/show_bug.cgi?id=61868
[ [], [ '20-' ], '20-' ],
];
}
private function getMobileViewApi( $input ) {
$request = new FauxRequest( $input );
$context = RequestContext::getMain();
$skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
// to test this is working we force the fallback skin which makes zero changes to the
// parser result. This means tests will reliably pass no matter what the default skin is
// T170624 has the background
$context->setSkin( $skinFactory->makeSkin( 'fallback' ) );
$context->setOutput( new OutputPage( $context ) );
$this->setMwGlobals( 'wgOut', $context->getOutput() );
$context->setRequest( $request );
return new MockApiMobileView( new ApiMain( $context ), 'mobileview' );
}
private function executeMobileViewApi( $api, $expected ) {
$api->execute();
$result = $api->getResult()->getResultData( null, [
'BC' => [],
'Types' => [],
'Strip' => 'all',
] );
$this->assertTrue(
isset( $result['mobileview'] ),
'API output should be encloded in mobileview element'
);
$this->assertArrayEquals( $expected, $result['mobileview'], false, true );
}
/**
* @dataProvider provideView
* @covers ApiMobileView::execute
* @covers ApiMobileView::makeTitle
* @covers ApiMobileView::getPageImage
* @covers ApiMobileView::isMainPage
* @covers ApiMobileView::stringSplitter
* @covers ApiMobileView::prepareSection
* @covers ApiMobileView::getRequestedSectionIds
* @covers ApiMobileView::getParserOutput
* @covers ApiMobileView::parseSectionsData
* @covers ApiMobileView::getData
* @covers ApiMobileView::getFilePage
* @covers ApiMobileView::addPageImage
* @covers ApiMobileView::addProtection
* @covers ApiMobileView::getAllowedParams
* @covers ApiMobileView::getResult
*/
public function testView( array $input, array $expected ) {
$api = $this->getMobileViewApi( $input );
$this->executeMobileViewApi( $api, $expected );
}
/**
* @dataProvider provideViewWithTransforms
* @covers ApiMobileView::execute
* @covers ApiMobileView::makeTitle
* @covers ApiMobileView::getPageImage
* @covers ApiMobileView::isMainPage
* @covers ApiMobileView::stringSplitter
* @covers ApiMobileView::prepareSection
* @covers ApiMobileView::getRequestedSectionIds
* @covers ApiMobileView::getParserOutput
* @covers ApiMobileView::parseSectionsData
* @covers ApiMobileView::getData
* @covers ApiMobileView::getFilePage
* @covers ApiMobileView::addPageImage
* @covers ApiMobileView::addProtection
* @covers ApiMobileView::getAllowedParams
* @covers ApiMobileView::getResult
*/
public function testViewWithTransforms( array $input, array $expected ) {
if ( version_compare(
PHPUnit_Runner_Version::id(),
'4.0.0',
'<'
) ) {
$this->markTestSkipped( 'testViewWithTransforms requires PHPUnit 4.0.0 or greater.' );
}
$api = $this->getMobileViewApi( $input );
$api->mockFile = $this->getMock( 'MockFSFile',
[ 'getWidth', 'getHeight', 'getTitle', 'getMimeType', 'transform' ],
[], '', false
);
$api->mockFile->method( 'getWidth' )->will( $this->returnValue( 640 ) );
$api->mockFile->method( 'getHeight' )->will( $this->returnValue( 480 ) );
$api->mockFile->method( 'getTitle' )
->will( $this->returnValue( Title::newFromText( 'File:Foo.jpg' ) ) );
if ( array_key_exists( 'type', $input ) ) {
$api->mockFile->method( 'getMimeType' )->will( $this->returnValue(
$input[ 'type' ] === 'image/svg' ? 'image/svg' : 'image/png' )
);
}
$api->mockFile->method( 'transform' )
->will( $this->returnCallback( [ $this, 'mockTransform' ] ) );
$this->executeMobileViewApi( $api, $expected );
}
public function mockTransform( array $params ) {
$thumb = $this->getMock( 'MediaTransformOutput' );
$thumb->method( 'getUrl' )->will( $this->returnValue( 'http://dummy' ) );
$thumb->method( 'getWidth' )->will( $this->returnValue( $params['width'] ) );
$thumb->method( 'getHeight' )->will( $this->returnValue( $params['height'] ) );
return $thumb;
}
public function provideView() {
$baseIn = [
'action' => 'mobileview',
'page' => 'Foo',
'sections' => '1-',
'noheadings' => '',
'text' => 'Lead
== Section 1 ==
Text 1
== Section 2 ==
Text 2
',
];
$baseOut = [
'sections' => [
0 => [ 'id' => 0 ],
1 => [
'toclevel' => 1,
'line' => 'Section 1',
'id' => 1,
'*' => '<p>Text 1</p>'
],
2 => [
'toclevel' => 1,
'line' => 'Section 2',
'id' => 2,
'*' => '<p>Text 2</p>'
],
],
];
return [
[
$baseIn,
$baseOut,
],
[
$baseIn + [ 'prop' => 'text' ],
[
'sections' => [
[
'id' => 1,
'*' => '<p>Text 1</p>'
],
[
'id' => 2,
'*' => '<p>Text 2</p>'
],
],
],
],
[
[ 'sections' => 1, 'onlyrequestedsections' => '' ] + $baseIn,
[
'sections' => [
$baseOut['sections'][1],
],
],
],
[
[
'page' => 'Main Page',
'sections' => 1,
'onlyrequestedsections' => ''
] + $baseIn,
[
'mainpage' => '',
'sections' => [],
],
],
[
[
'page' => 'Redirected',
'redirect' => 'yes',
] + $baseIn,
[
'redirected' => 'Special:BlankPage',
'viewable' => 'no',
],
],
[
[
'text' => '__NOTOC__',
'prop' => 'pageprops',
] + $baseIn,
[
'sections' => [],
'pageprops' => [ 'notoc' => '' ],
],
],
// T123580
[
[
'page' => 'Main Page',
'sections' => 1,
'onlyrequestedsections' => true,
// When the namespace is requested...
'prop' => 'namespace',
] + $baseIn,
[
'mainpage' => '',
'sections' => [],
// ... then it is returned.
'ns' => 0,
],
]
];
}
public function provideViewWithTransforms() {
// Note that the dimensions are values passed to #transform, not actual
// thumbnail dimensions.
return [
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 50,
'height' => 50,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbsize' => 55,
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 55,
'height' => 55,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbwidth' => 100,
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 100,
'height' => 480,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbheight' => 200,
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 640,
'height' => 200,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbwidth' => 200,
// contrived but needed for testing
'type' => 'image/svg'
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 200,
'height' => 150,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbheight' => 200,
// contrived but needed for testing
'type' => 'image/svg'
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 267,
'height' => 200,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbwidth' => 800,
// contrived but needed for testing
'type' => 'image/svg'
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 800,
'height' => 600,
]
],
],
[
[
'page' => 'Foo',
'text' => '',
'prop' => 'thumb',
'thumbheight' => 800,
// contrived but needed for testing
'type' => 'image/svg'
],
[
'sections' => [],
'thumb' => [
'url' => 'http://dummy',
'width' => 1067,
'height' => 800,
]
],
],
];
}
/**
* @covers ApiMobileView::execute
* @covers ApiMobileView::getResult
*/
public function testRedirectToSpecialPageDoesntTriggerNotices() {
$props = [
'lastmodified',
'lastmodifiedby',
'revision',
'id',
'languagecount',
'hasvariants',
'displaytitle'
];
$this->setMwGlobals( 'wgAPIModules', [ 'mobileview' => 'MockApiMobileView' ] );
$request = new FauxRequest( [
'action' => 'mobileview',
'page' => 'Foo',
'sections' => '1-',
'noheadings' => '',
'text' => 'Lead
== Section 1 ==
Text 1
== Section 2 ==
Text 2
',
'prop' => implode( '|', $props ),
'page' => 'Redirected',
'redirect' => 'yes',
] );
$context = new RequestContext();
$context->setRequest( $request );
$api = new MockApiMobileView( new ApiMain( $context ), 'mobileview' );
$api->execute();
$result = $api->getResult()->getResultData();
foreach ( $props as $prop ) {
$this->assertFalse(
isset( $result[$prop] ),
"{$prop} isn't included in the response when it can't be fetched."
);
}
}
/**
* @covers ApiMobileView::execute
* @covers ApiMobileView::makeTitle
* @covers ApiMobileView::getPageImage
* @covers ApiMobileView::isMainPage
* @covers ApiMobileView::stringSplitter
* @covers ApiMobileView::prepareSection
* @covers ApiMobileView::getRequestedSectionIds
* @covers ApiMobileView::getParserOutput
* @covers ApiMobileView::parseSectionsData
* @covers ApiMobileView::getData
* @covers ApiMobileView::getFilePage
* @covers ApiMobileView::addPageImage
* @covers ApiMobileView::addProtection
* @covers ApiMobileView::getAllowedParams
* @covers ApiMobileView::getResult
*/
public function testEmptyResultArraysAreAssociative() {
$this->setMwGlobals( 'wgAPIModules', [ 'mobileview' => 'MockApiMobileView' ] );
$request = new FauxRequest( [
'action' => 'mobileview',
'page' => 'Foo',
'text' => 'foo',
'onlyrequestedsections' => '',
'sections' => 1,
'prop' => 'protection|pageprops',
// intentionally nonexistent
'pageprops' => 'foo',
] );
$context = new RequestContext();
$context->setRequest( $request );
$api = new MockApiMobileView( new ApiMain( $context ), 'mobileview' );
$api->execute();
$result = $api->getResult()->getResultData();
$protection = $result['mobileview']['protection'];
$pageprops = $result['mobileview']['pageprops'];
$this->assertTrue( $protection[ApiResult::META_TYPE] === 'assoc' );
// the only element is the array type flag
$this->assertTrue( count( $protection ) === 1 );
$this->assertTrue( $pageprops[ApiResult::META_TYPE] === 'assoc' );
// the only element is the array type flag
$this->assertTrue( count( $pageprops ) === 1 );
}
/**
* @covers ApiMobileView::addDescriptionToResult
*/
public function testLocalDescription() {
$api = new ApiMobileView( new ApiMain( new RequestContext() ), 'mobileview' );
$addDescriptionToResult = $this->getNonPublicMethod(
'ApiMobileView',
'addDescriptionToResult'
);
$resultObj = new ApiResult( false );
$pageprops = [ 'wikibase-shortdesc' => 'my local description' ];
$addDescriptionToResult->invokeArgs( $api, [ $resultObj, $pageprops, 'mobileview' ] );
$mobileview = $resultObj->getResultData( 'mobileview' );
$this->assertEquals( 'my local description', $mobileview[ 'description' ] );
$this->assertEquals( 'local', $mobileview[ 'descriptionsource' ] );
}
/**
* @covers ApiMobileView::addDescriptionToResult
*/
public function testNoDescription() {
$api = new ApiMobileView( new ApiMain( new RequestContext() ), 'mobileview' );
$addDescriptionToResult = $this->getNonPublicMethod(
'ApiMobileView',
'addDescriptionToResult'
);
$resultObj = new ApiResult( false );
$pageprops = [];
$addDescriptionToResult->invokeArgs( $api, [ $resultObj, $pageprops, 'mobileview' ] );
$mobileview = $resultObj->getResultData( 'mobileview' );
$this->assertEmpty( $mobileview[ 'description' ] );
$this->assertEmpty( $mobileview[ 'descriptionsource' ] );
}
/**
* @covers ApiMobileView::getScaledDimen
*/
public function testImageScaling() {
$api = new ApiMobileView( new ApiMain( new RequestContext() ), 'mobileview' );
$scale = $this->getNonPublicMethod( 'ApiMobileView', 'getScaledDimen' );
$this->assertEquals( $scale->invokeArgs( $api, [ 100, 50, 20 ] ), 10, 'Check scaling downward' );
$this->assertEquals( $scale->invokeArgs( $api, [ 50, 100, 20 ] ), 40, 'Check scaling downward' );
$this->assertEquals( $scale->invokeArgs( $api, [ 100, 50, 200 ] ), 100, 'Check scaling upward' );
$this->assertEquals( $scale->invokeArgs( $api, [ 50, 100, 200 ] ), 400, 'Check scaling upward' );
$this->assertEquals( $scale->invokeArgs( $api, [ 0, 1, 2 ] ), 0, 'Check divide by zero' );
}
/**
* @covers ApiMobileView::isSVG
*/
public function testIsSVG() {
$api = new ApiMobileView( new ApiMain( new RequestContext() ), 'mobileview' );
$isSVG = $this->getNonPublicMethod( 'ApiMobileView', 'isSVG' );
$this->assertTrue( $isSVG->invokeArgs( $api, [ 'image/svg' ] ) );
$this->assertTrue( $isSVG->invokeArgs( $api, [ 'image/svg+xml' ] ) );
$this->assertFalse( $isSVG->invokeArgs( $api, [ ' image/svg' ] ) );
$this->assertFalse( $isSVG->invokeArgs( $api, [ 'image/png' ] ) );
$this->assertFalse( $isSVG->invokeArgs( $api, [ null ] ) );
}
public function provideGetMobileViewPageProps() {
return [
// Request all available page properties
[
'*',
[
'pageprops' => [ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
[ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
// Request non-existent property
[
'monkey',
[
'pageprops' => [ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
[],
],
// Filter out available page properties with '|'
[
'wikibase_item|notoc',
[
'pageprops' => [ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
[ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
// Filter out available page properties without '|'
[
'wikibase_item',
[
'pageprops' => [ 'wikibase_item' => 'Q76', 'notoc' => true ],
],
[ 'wikibase_item' => 'Q76' ],
],
// When no page properties available (T161026)
[
'wikibase_item',
[
'title' => 'Foo'
],
[],
],
// Request all from nothing
[
'*',
[],
[],
]
];
}
/**
* @dataProvider provideGetMobileViewPageProps
* @covers ApiMobileView::getMobileViewPageProps
*/
public function testGetMobileViewPageProps( $requested, $available, $returned ) {
$context = new RequestContext();
$api = new ApiMobileView( new ApiMain( $context ), 'mobileview' );
$actual = $api->getMobileViewPageProps( $requested, $available );
$this->assertEquals( $returned, $actual );
}
private static function getNonPublicMethod( $className, $methodName ) {
$reflectionClass = new ReflectionClass( $className );
$method = $reflectionClass->getMethod( $methodName );
$method->setAccessible( true );
return $method;
}
}