Skip to content

Commit

Permalink
Add PHPUnit tests for more paths in MobilePage::class
Browse files Browse the repository at this point in the history
* createTestTitle() - creates a title object from the Title class.
* mockRevisionStoreReturnNullTitle() - mock Revision store that will
  return a revision by a null title.
* testGetSmallThumbnailHtmlWithNoFile() - covers getSmallThumbnailHtml()
  in cases when no file is provided with or without a background image.
* getGetSmallThumbnailHtmlWithNoFileDataProvider() - data provider for
  the testGetSmallThumbnailHtmlWithNoFile() unit test.
* testLatestTimestamp() - covers the getLatestTimestamp() and also the
  setLatestTimestamp() paths default.
* testLatestTimestampWithNullTitle() - covers the getLatestTimestamp()
  path for when the revision is null.
* testLatestTimestampWhenNoRevision() - for when there is no revision
  at all.
* testGetLatestEdit() - covers the getLatestEdit() method and also the
  getRevision() method too.
* mockRevisionStore() - mocks the RevisionStore class and sets a service
  using MediaWikiServices' RevisionStore service to set a revision mock.
  This enables testing the getLatestEdit() method as it injects $rev into
  the class.
* testGetSmallThumbnailHtmlWithNoThumb() - covers test case for there is
  a file provided but thumb couldn't be generated via calling the transform()
  method. Hence return empty string.

Also, update Revision::newKnownCurrent() call to use the mediawiki service
MediaWikiServices::getInstance()->getRevisionStore()->getRevisionByTitle().
Thanks to @pmiazga for the ideas and guidance for achieving this solution
by using MediaWikiServices.

Bug: T209476
Change-Id: I4234b2b731ccfd3fcce2cc8abf8a823b750ad115
  • Loading branch information
xSavitar committed Nov 23, 2018
1 parent 51d0af7 commit d85ddc2
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 14 deletions.
10 changes: 5 additions & 5 deletions includes/models/MobilePage.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use MediaWiki\MediaWikiServices;

/**
* Retrieves information specific to a mobile page
* Currently this only provides helper functions for creating Page Thumbnail
Expand Down Expand Up @@ -40,11 +42,8 @@ public function __construct( Title $title, $file = false ) {
*/
private function getRevision() {
if ( $this->rev === null ) {
$this->rev = Revision::newKnownCurrent(
wfGetDB( DB_REPLICA ),
$this->title->getArticleID(),
$this->title->getLatestRevID()
);
$this->rev = MediaWikiServices::getInstance()->getRevisionStore()
->getRevisionByTitle( $this->title );
}
return $this->rev;
}
Expand Down Expand Up @@ -167,5 +166,6 @@ private function getPageImageHtml( $size, $useBackgroundImage = false ) {
}
return Html::element( $useBackgroundImage ? 'div' : 'img', $props, $text );
}
return '';
}
}
244 changes: 235 additions & 9 deletions tests/phpunit/models/MobilePageTest.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
<?php

use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\RevisionRecord;

/**
* @group MobileFrontend
* @coversDefaultClass MobilePage
* @covers ::__construct()
*/
class MobilePageTest extends MediaWikiTestCase {
// Anonymous username is 127.0.0.1 (localhost IP addr)
const ANONYMOUS_USER_NAME = '127.0.0.1';

// Timestamp from MW format to Unix format
// TS_MW is '20181028200709' and to Unix gives
// '1540757229' using the wfTimestamp() function.
const TS_MW_TO_TS_UNIX = '1540757229';

// Example timestamp in MediaWiki format
const TS_MW = '20181028200709';
/**
* Creates an instance of `File`.
* By default, let the picture height be less than it's width.
Expand Down Expand Up @@ -37,22 +51,169 @@ private function mockFileFactory( $height ) {
return $file;
}

/**
* Mock the RevisionStore class
* @return RevisionStore
*/
private function mockRevisionStore( $title ) {
// Create a mock of the RevisionRecord class.
$revisionRecordMock = $this->getMockForAbstractClass(
RevisionRecord::class,
[],
'',
false,
false,
false,
[ 'getTimestamp', 'getUser' ]
);

$revisionRecordMock->expects( $this->any() )
->method( 'getTimestamp' )
->willReturn( self::TS_MW );

$revisionRecordMock->expects( $this->any() )
->method( 'getUser' )
->willReturn( -1 );

// Create a mock of the RevisionStore class that returns the RevisionRecord
// mock when getRevisionByTitle() method is called.
$revisionStoreMock = $this->getMockBuilder( RevisionStore::class )
->disableOriginalConstructor()
->setMethods( [ 'getRevisionByTitle' ] )
->getMock();

$revisionStoreMock->expects( $this->once() )
->method( 'getRevisionByTitle' )
->with( $title )
->willReturn( $revisionRecordMock );

return $revisionStoreMock;
}

/**
* Mock RevisionStore class with title that returns null
* @return RevisionStore
*/
private function mockRevisionStoreWithTitleReturnNullRevision( $title ) {
$mock = $this->getMockBuilder( RevisionStore::class )
->disableOriginalConstructor()
->setMethods( [ 'getRevisionByTitle' ] )
->getMock();

$mock->expects( $this->once() )
->method( 'getRevisionByTitle' )
->with( $title )
->willReturn( null );

return $mock;
}

/**
* Helper function to create object of class MobilePage
* @param $file
* @param Title $title Mobile page title
* @param File|bool $file File object or false if not present
* @return MobilePage
*/
private function makeMobilePageFactory( $file ) {
$mobilePage = new MobilePage( Title::newFromText( 'Image', NS_MAIN ), $file );
private function makeMobilePageFactory( Title $title, $file ) {
return new MobilePage( $title, $file );
}

/**
* Create test title helper function
* @return Title
*/
private function createTestTitle() {
return Title::newFromText( 'Image', NS_MAIN );
}

/**
* @covers ::setLatestTimestamp
* @covers ::getLatestTimestamp
*/
public function testLatestTimestamp() {
$mobilePage = $this->makeMobilePageFactory( $this->createTestTitle(), false );
$tsNow = wfTimestamp( TS_MW );
$mobilePage->setLatestTimestamp( $tsNow );

$actual = $mobilePage->getLatestTimestamp();

return $mobilePage;
$this->assertSame( $tsNow, $actual );
}

/**
* @covers ::getLatestTimestamp
*/
public function testLatestTimestampWithNullTitle() {
$title = $this->createTestTitle();
$mock = $this->mockRevisionStoreWithTitleReturnNullRevision( $title );

$this->setService( 'RevisionStore', $mock );
$mobilePage = $this->makeMobilePageFactory( $title, false );
$actual = $mobilePage->getLatestTimestamp();

$this->assertFalse( $actual );
}

/**
* @covers ::getLatestTimestamp
*/
public function testLatestTimestampWhenNoRevision() {
$title = $this->createTestTitle();

$revMock = $this->mockRevisionStore( $title );

$this->setService( 'RevisionStore', $revMock );
$mobilePage = $this->makeMobilePageFactory( $title, false );
$actual = $mobilePage->getLatestTimestamp();

$this->assertSame( self::TS_MW, $actual );
}

/**
* @covers ::getRevision
* @covers ::getLatestEdit
*/
public function testGetLatestEdit() {
$title = $this->createTestTitle();
$revMock = $this->mockRevisionStore( $title );
$mobilePage = new MobilePage( $title, false );
$this->setService( 'RevisionStore', $revMock );
$actual = $mobilePage->getLatestEdit();

$this->assertInternalType( 'array', $actual );
$this->assertArrayHasKey( 'timestamp', $actual );
$this->assertArrayHasKey( 'name', $actual );
$this->assertArrayHasKey( 'gender', $actual );
$this->assertSame( self::TS_MW_TO_TS_UNIX, $actual['timestamp'] );
$this->assertSame( self::ANONYMOUS_USER_NAME, $actual['name'] );
$this->assertSame( 'unknown', $actual['gender'] );
}

/**
* @covers ::getRevision
* @covers ::getLatestEdit
*/
public function testGetLatestEditWithTitleReturnNullRevision() {
$title = $this->createTestTitle();
$revMock = $this->mockRevisionStoreWithTitleReturnNullRevision( $title );
$mobilePage = new MobilePage( $title, false );
$this->setService( 'RevisionStore', $revMock );
$actual = $mobilePage->getLatestEdit();

$this->assertInternalType( 'array', $actual );
$this->assertArrayHasKey( 'timestamp', $actual );
$this->assertArrayHasKey( 'name', $actual );
$this->assertArrayHasKey( 'gender', $actual );
$this->assertFalse( $actual['timestamp'] );
$this->assertSame( '', $actual['name'] );
$this->assertSame( '', $actual['gender'] );
}

/**
* @covers ::getTitle
*/
public function testGetTitle() {
$title = Title::newMainPage();
$title = $this->createTestTitle();
$mPageWithNoFile = new MobilePage( $title, false );
$actual = $mPageWithNoFile->getTitle();

Expand All @@ -73,7 +234,7 @@ public function testGetPlaceHolderThumbnailHtml( $className, $iconClassName, $ex
* @covers ::hasThumbnail
*/
public function testHasNoThumbnail() {
$mPageWithNoFile = $this->makeMobilePageFactory( false );
$mPageWithNoFile = $this->makeMobilePageFactory( $this->createTestTitle(), false );
$actual = $mPageWithNoFile->hasThumbnail();
$this->assertFalse( $actual );
}
Expand All @@ -88,7 +249,9 @@ public function testHasNoThumbnail() {
public function testHasThumbnail() {
$fileWidthGreatThanHeight = $this->mockFileFactory( 100 );

$mPageWithFile = $this->makeMobilePageFactory( $fileWidthGreatThanHeight );
$mPageWithFile = $this->makeMobilePageFactory(
$this->createTestTitle(), $fileWidthGreatThanHeight
);
$actual = $mPageWithFile->hasThumbnail();
$this->assertTrue( $actual );
}
Expand All @@ -103,7 +266,9 @@ public function testGetSmallThumbnailHtmlWidthLessThanHeight( $useBackgroundImag
// is less than height for generating the appropriate element class.
$fileWidthLessThanHeight = $this->mockFileFactory( 300 );

$mPageWithFile = $this->makeMobilePageFactory( $fileWidthLessThanHeight );
$mPageWithFile = $this->makeMobilePageFactory(
$this->createTestTitle(), $fileWidthLessThanHeight
);

$actual = $mPageWithFile->getSmallThumbnailHtml( $useBackgroundImage );

Expand All @@ -119,12 +284,49 @@ public function testGetSmallThumbnailHtmlWidthGreaterThanHeight(
$useBackgroundImage, $expected
) {
$fileWidthGreatThanHeight = $this->mockFileFactory( 100 );
$mPageWithFile = $this->makeMobilePageFactory( $fileWidthGreatThanHeight );
$mPageWithFile = $this->makeMobilePageFactory(
$this->createTestTitle(), $fileWidthGreatThanHeight
);
$actual = $mPageWithFile->getSmallThumbnailHtml( $useBackgroundImage );

$this->assertSame( $expected, $actual );
}

/**
* When no file is provided, always return an empty string.
* @covers ::getSmallThumbnailHtml
* @covers ::getPageImageHtml
* @dataProvider getSmallThumbnailHtmlWithNoFileDataProvider
*/
public function testGetSmallThumbnailHtmlWithNoFile( $useBackgroundImage, $expected ) {
$mPageWithNoFile = $this->makeMobilePageFactory( $this->createTestTitle(), false );
$actual = $mPageWithNoFile->getSmallThumbnailHtml( $useBackgroundImage );

$this->assertSame( $expected, $actual );
}

/**
* When file is provided but thumb couldn't be generated upon
* calling $thumb->transform(). So we don't have a thumb here.
* @covers ::getSmallThumbnailHtml
* @covers ::getPageImageHtml
* @dataProvider getSmallThumbnailHtmlWithNoThumbDataProvider
*/
public function testGetSmallThumbnailHtmlWithNoThumb( $useBackgroundImage, $expected ) {
$thumb = $this->getMockBuilder( 'File' )
->disableOriginalConstructor()
->setMethods( [ 'transform' ] )
->getMock();

$thumb->method( 'transform' )
->willReturn( null );

$mobilePage = $this->makeMobilePageFactory( $this->createTestTitle(), $thumb );
$actual = $mobilePage->getSmallThumbnailHtml( $useBackgroundImage );

$this->assertSame( $expected, $actual );
}

/**
* Data provider for testGetPlaceHolderThumbnailHtml()
*
Expand All @@ -151,6 +353,30 @@ public function getPlaceHolderThumbnailHtmlDataProvider() {
];
}

/**
* Data provider for testGetSmallThumbnailHtmlWithNoFile()
*
* @return array
*/
public function getSmallThumbnailHtmlWithNoFileDataProvider() {
return [
[ false, '' ],
[ true, '' ]
];
}

/**
* Data provider for testGetSmallThumbnailHtmlWithNoThumb()
*
* @return array
*/
public function getSmallThumbnailHtmlWithNoThumbDataProvider() {
return [
[ false, '' ],
[ true, '' ]
];
}

/**
* Data provider for testGetSmallThumbnailHtmlWidthLessThanHeight()
*
Expand Down

0 comments on commit d85ddc2

Please sign in to comment.