MediaWiki  master
RevisionTest.php
Go to the documentation of this file.
1 <?php
2 
13 
19 
20  public function setUp() {
21  parent::setUp();
22  $this->setMwGlobals(
23  'wgMultiContentRevisionSchemaMigrationStage',
25  );
26  }
27 
28  public function provideConstructFromArray() {
29  yield 'with text' => [
30  [
31  'text' => 'hello world.',
32  'content_model' => CONTENT_MODEL_JAVASCRIPT
33  ],
34  ];
35  yield 'with content' => [
36  [
37  'content' => new JavaScriptContent( 'hellow world.' )
38  ],
39  ];
40  // FIXME: test with and without user ID, and with a user object.
41  // We can't prepare that here though, since we don't yet have a dummy DB
42  }
43 
48  public function getMockTitle( $model = CONTENT_MODEL_WIKITEXT ) {
49  $mock = $this->getMockBuilder( Title::class )
50  ->disableOriginalConstructor()
51  ->getMock();
52  $mock->expects( $this->any() )
53  ->method( 'getNamespace' )
54  ->will( $this->returnValue( $this->getDefaultWikitextNS() ) );
55  $mock->expects( $this->any() )
56  ->method( 'getPrefixedText' )
57  ->will( $this->returnValue( 'RevisionTest' ) );
58  $mock->expects( $this->any() )
59  ->method( 'getDBkey' )
60  ->will( $this->returnValue( 'RevisionTest' ) );
61  $mock->expects( $this->any() )
62  ->method( 'getArticleID' )
63  ->will( $this->returnValue( 23 ) );
64  $mock->expects( $this->any() )
65  ->method( 'getContentModel' )
66  ->will( $this->returnValue( $model ) );
67 
68  return $mock;
69  }
70 
76  public function testConstructFromArray( $rowArray ) {
77  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
78  $this->assertNotNull( $rev->getContent(), 'no content object available' );
79  $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
80  $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
81  }
82 
87  public function testConstructFromEmptyArray() {
88  $rev = new Revision( [], 0, $this->getMockTitle() );
89  $this->assertNull( $rev->getContent(), 'no content object should be available' );
90  }
91 
97  Wikimedia\suppressWarnings();
98  $rev = new Revision( [ 'page' => 77777777 ] );
99  $this->assertSame( 77777777, $rev->getPage() );
100  Wikimedia\restoreWarnings();
101  }
102 
104  yield 'no user defaults to wgUser' => [
105  [
106  'content' => new JavaScriptContent( 'hello world.' ),
107  ],
108  null,
109  null,
110  ];
111  yield 'user text and id' => [
112  [
113  'content' => new JavaScriptContent( 'hello world.' ),
114  'user_text' => 'SomeTextUserName',
115  'user' => 99,
116 
117  ],
118  99,
119  'SomeTextUserName',
120  ];
121  yield 'user text only' => [
122  [
123  'content' => new JavaScriptContent( 'hello world.' ),
124  'user_text' => '111.111.111.111',
125  ],
126  0,
127  '111.111.111.111',
128  ];
129  }
130 
141  array $rowArray,
142  $expectedUserId,
143  $expectedUserName
144  ) {
145  $testUser = $this->getTestUser()->getUser();
146  $this->setMwGlobals( 'wgUser', $testUser );
147  if ( $expectedUserId === null ) {
148  $expectedUserId = $testUser->getId();
149  }
150  if ( $expectedUserName === null ) {
151  $expectedUserName = $testUser->getName();
152  }
153 
154  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
155  $this->assertEquals( $expectedUserId, $rev->getUser() );
156  $this->assertEquals( $expectedUserName, $rev->getUserText() );
157  }
158 
160  yield 'content and text_id both not empty' => [
161  [
162  'content' => new WikitextContent( 'GOAT' ),
163  'text_id' => 'someid',
164  ],
165  new MWException( 'The text_id field is only available in the pre-MCR schema' )
166  ];
167 
168  yield 'with bad content object (class)' => [
169  [ 'content' => new stdClass() ],
170  new MWException( 'content field must contain a Content object' )
171  ];
172  yield 'with bad content object (string)' => [
173  [ 'content' => 'ImAGoat' ],
174  new MWException( 'content field must contain a Content object' )
175  ];
176  yield 'bad row format' => [
177  'imastring, not a row',
179  '$row must be a row object, an associative array, or a RevisionRecord'
180  )
181  ];
182  }
183 
189  public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
190  $this->setExpectedException(
191  get_class( $expectedException ),
192  $expectedException->getMessage(),
193  $expectedException->getCode()
194  );
195  new Revision( $rowArray, 0, $this->getMockTitle() );
196  }
197 
202  public function testConstructFromNothing() {
203  $this->setExpectedException(
205  );
206  new Revision( [] );
207  }
208 
209  public function provideConstructFromRow() {
210  yield 'Full construction' => [
211  [
212  'rev_id' => '42',
213  'rev_page' => '23',
214  'rev_timestamp' => '20171017114835',
215  'rev_user_text' => '127.0.0.1',
216  'rev_user' => '0',
217  'rev_minor_edit' => '0',
218  'rev_deleted' => '0',
219  'rev_len' => '46',
220  'rev_parent_id' => '1',
221  'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
222  'rev_comment_text' => 'Goat Comment!',
223  'rev_comment_data' => null,
224  'rev_comment_cid' => null,
225  ],
226  function ( RevisionTest $testCase, Revision $rev ) {
227  $testCase->assertSame( 42, $rev->getId() );
228  $testCase->assertSame( 23, $rev->getPage() );
229  $testCase->assertSame( '20171017114835', $rev->getTimestamp() );
230  $testCase->assertSame( '127.0.0.1', $rev->getUserText() );
231  $testCase->assertSame( 0, $rev->getUser() );
232  $testCase->assertSame( false, $rev->isMinor() );
233  $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
234  $testCase->assertSame( 46, $rev->getSize() );
235  $testCase->assertSame( 1, $rev->getParentId() );
236  $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() );
237  $testCase->assertSame( 'Goat Comment!', $rev->getComment() );
238  }
239  ];
240  yield 'default field values' => [
241  [
242  'rev_id' => '42',
243  'rev_page' => '23',
244  'rev_timestamp' => '20171017114835',
245  'rev_user_text' => '127.0.0.1',
246  'rev_user' => '0',
247  'rev_minor_edit' => '0',
248  'rev_deleted' => '0',
249  'rev_comment_text' => 'Goat Comment!',
250  'rev_comment_data' => null,
251  'rev_comment_cid' => null,
252  ],
253  function ( RevisionTest $testCase, Revision $rev ) {
254  // parent ID may be null
255  $testCase->assertSame( null, $rev->getParentId(), 'revision id' );
256 
257  // given fields
258  $testCase->assertSame( $rev->getTimestamp(), '20171017114835', 'timestamp' );
259  $testCase->assertSame( $rev->getUserText(), '127.0.0.1', 'user name' );
260  $testCase->assertSame( $rev->getUser(), 0, 'user id' );
261  $testCase->assertSame( $rev->getComment(), 'Goat Comment!' );
262  $testCase->assertSame( false, $rev->isMinor(), 'minor edit' );
263  $testCase->assertSame( 0, $rev->getVisibility(), 'visibility flags' );
264  }
265  ];
266  }
267 
273  public function testConstructFromRow( array $arrayData, callable $assertions ) {
274  $row = (object)$arrayData;
275  $rev = new Revision( $row, 0, $this->getMockTitle() );
276  $assertions( $this, $rev );
277  }
278 
284  $this->overrideMwServices();
285  Wikimedia\suppressWarnings();
286  $rev = new Revision( (object)[
287  'rev_page' => 77777777,
288  'rev_comment_text' => '',
289  'rev_comment_data' => null,
290  ] );
291  $this->assertSame( 77777777, $rev->getPage() );
292  Wikimedia\restoreWarnings();
293  }
294 
295  public function provideGetId() {
296  yield [
297  [],
298  null
299  ];
300  yield [
301  [ 'id' => 998 ],
302  998
303  ];
304  }
305 
310  public function testGetId( $rowArray, $expectedId ) {
311  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
312  $this->assertEquals( $expectedId, $rev->getId() );
313  }
314 
315  public function provideSetId() {
316  yield [ '123', 123 ];
317  yield [ 456, 456 ];
318  }
319 
324  public function testSetId( $input, $expected ) {
325  $rev = new Revision( [], 0, $this->getMockTitle() );
326  $rev->setId( $input );
327  $this->assertSame( $expected, $rev->getId() );
328  }
329 
330  public function provideSetUserIdAndName() {
331  yield [ '123', 123, 'GOaT' ];
332  yield [ 456, 456, 'GOaT' ];
333  }
334 
339  public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
340  $rev = new Revision( [], 0, $this->getMockTitle() );
341  $rev->setUserIdAndName( $inputId, $name );
342  $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
343  $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
344  }
345 
346  public function provideGetParentId() {
347  yield [ [], null ];
348  yield [ [ 'parent_id' => '123' ], 123 ];
349  yield [ [ 'parent_id' => 456 ], 456 ];
350  }
351 
356  public function testGetParentId( $rowArray, $expected ) {
357  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
358  $this->assertSame( $expected, $rev->getParentId() );
359  }
360 
361  public function provideGetRevisionText() {
362  yield 'Generic test' => [
363  'This is a goat of revision text.',
364  (object)[
365  'old_flags' => '',
366  'old_text' => 'This is a goat of revision text.',
367  ],
368  ];
369  yield 'garbage in, garbage out' => [
370  false,
371  false,
372  ];
373  }
374 
379  public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) {
380  $this->assertEquals(
381  $expected,
382  Revision::getRevisionText( $rowData, $prefix, $wiki ) );
383  }
384 
386  yield 'Generic gzip test' => [
387  'This is a small goat of revision text.',
388  (object)[
389  'old_flags' => 'gzip',
390  'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
391  ],
392  ];
393  }
394 
399  public function testGetRevisionWithZlibExtension( $expected, $rowData ) {
400  $this->checkPHPExtension( 'zlib' );
401  $this->testGetRevisionText( $expected, $rowData );
402  }
403 
405  yield 'Generic gzip test' => [
406  'This is a small goat of revision text.',
407  (object)[
408  'old_flags' => 'gzip',
409  'old_text' => 'DEAD BEEF',
410  ],
411  ];
412  }
413 
418  public function testGetRevisionWithZlibExtension_badData( $expected, $rowData ) {
419  $this->checkPHPExtension( 'zlib' );
420  Wikimedia\suppressWarnings();
421  $this->assertFalse(
423  (object)$rowData
424  )
425  );
426  Wikimedia\suppressWarnings( true );
427  }
428 
429  private function getWANObjectCache() {
430  return new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
431  }
432 
436  private function getBlobStore() {
438  $lb = $this->getMockBuilder( LoadBalancer::class )
439  ->disableOriginalConstructor()
440  ->getMock();
441 
442  $cache = $this->getWANObjectCache();
443 
444  $blobStore = new SqlBlobStore( $lb, $cache );
445  return $blobStore;
446  }
447 
448  private function mockBlobStoreFactory( $blobStore ) {
450  $factory = $this->getMockBuilder( BlobStoreFactory::class )
451  ->disableOriginalConstructor()
452  ->getMock();
453  $factory->expects( $this->any() )
454  ->method( 'newBlobStore' )
455  ->willReturn( $blobStore );
456  $factory->expects( $this->any() )
457  ->method( 'newSqlBlobStore' )
458  ->willReturn( $blobStore );
459  return $factory;
460  }
461 
465  private function getRevisionStore() {
467  $lb = $this->getMockBuilder( LoadBalancer::class )
468  ->disableOriginalConstructor()
469  ->getMock();
470 
471  $cache = $this->getWANObjectCache();
472 
473  $blobStore = new RevisionStore(
474  $lb,
475  $this->getBlobStore(),
476  $cache,
477  MediaWikiServices::getInstance()->getCommentStore(),
478  MediaWikiServices::getInstance()->getContentModelStore(),
479  MediaWikiServices::getInstance()->getSlotRoleStore(),
480  MediaWikiServices::getInstance()->getSlotRoleRegistry(),
482  MediaWikiServices::getInstance()->getActorMigration()
483  );
484  return $blobStore;
485  }
486 
488  yield 'Utf8Native' => [
489  "Wiki est l'\xc3\xa9cole superieur !",
490  'fr',
491  'iso-8859-1',
492  (object)[
493  'old_flags' => 'utf-8',
494  'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
495  ]
496  ];
497  yield 'Utf8Legacy' => [
498  "Wiki est l'\xc3\xa9cole superieur !",
499  'fr',
500  'iso-8859-1',
501  (object)[
502  'old_flags' => '',
503  'old_text' => "Wiki est l'\xe9cole superieur !",
504  ]
505  ];
506  }
507 
512  public function testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
513  $blobStore = $this->getBlobStore();
514  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
515  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
516 
517  $this->testGetRevisionText( $expected, $rowData );
518  }
519 
526  yield 'Utf8NativeGzip' => [
527  "Wiki est l'\xc3\xa9cole superieur !",
528  'fr',
529  'iso-8859-1',
530  (object)[
531  'old_flags' => 'gzip,utf-8',
532  'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
533  ]
534  ];
535  yield 'Utf8LegacyGzip' => [
536  "Wiki est l'\xc3\xa9cole superieur !",
537  'fr',
538  'iso-8859-1',
539  (object)[
540  'old_flags' => 'gzip',
541  'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
542  ]
543  ];
544  }
545 
550  public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
551  $this->checkPHPExtension( 'zlib' );
552 
553  $blobStore = $this->getBlobStore();
554  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
555  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
556 
557  $this->testGetRevisionText( $expected, $rowData );
558  }
559 
563  public function testCompressRevisionTextUtf8() {
564  $row = new stdClass;
565  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
566  $row->old_flags = Revision::compressRevisionText( $row->old_text );
567  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
568  "Flags should contain 'utf-8'" );
569  $this->assertFalse( strpos( $row->old_flags, 'gzip' ) !== false,
570  "Flags should not contain 'gzip'" );
571  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
572  $row->old_text, "Direct check" );
573  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
574  Revision::getRevisionText( $row ), "getRevisionText" );
575  }
576 
581  $this->checkPHPExtension( 'zlib' );
582 
583  $blobStore = $this->getBlobStore();
584  $blobStore->setCompressBlobs( true );
585  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
586 
587  $row = new stdClass;
588  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
589  $row->old_flags = Revision::compressRevisionText( $row->old_text );
590  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
591  "Flags should contain 'utf-8'" );
592  $this->assertTrue( strpos( $row->old_flags, 'gzip' ) !== false,
593  "Flags should contain 'gzip'" );
594  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
595  gzinflate( $row->old_text ), "Direct check" );
596  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
597  Revision::getRevisionText( $row ), "getRevisionText" );
598  }
599 
603  public function testLoadFromTitle() {
604  $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
605  $this->overrideMwServices();
606  $title = $this->getMockTitle();
607 
608  $conditions = [
609  'rev_id=page_latest',
610  'page_namespace' => $title->getNamespace(),
611  'page_title' => $title->getDBkey()
612  ];
613 
614  $row = (object)[
615  'rev_id' => '42',
616  'rev_page' => $title->getArticleID(),
617  'rev_timestamp' => '20171017114835',
618  'rev_user_text' => '127.0.0.1',
619  'rev_user' => '0',
620  'rev_minor_edit' => '0',
621  'rev_deleted' => '0',
622  'rev_len' => '46',
623  'rev_parent_id' => '1',
624  'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
625  'rev_comment_text' => 'Goat Comment!',
626  'rev_comment_data' => null,
627  'rev_comment_cid' => null,
628  'rev_content_format' => 'GOATFORMAT',
629  'rev_content_model' => 'GOATMODEL',
630  ];
631 
632  $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
633  $db = $this->getMock( IDatabase::class );
634  $db->expects( $this->any() )
635  ->method( 'getDomainId' )
636  ->will( $this->returnValue( $domain ) );
637  $db->expects( $this->once() )
638  ->method( 'selectRow' )
639  ->with(
640  $this->equalTo( [
641  'revision', 'page', 'user',
642  'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment',
643  'temp_rev_user' => 'revision_actor_temp', 'actor_rev_user' => 'actor',
644  ] ),
645  // We don't really care about the fields are they come from the selectField methods
646  $this->isType( 'array' ),
647  $this->equalTo( $conditions ),
648  // Method name
649  $this->stringContains( 'fetchRevisionRowFromConds' ),
650  // We don't really care about the options here
651  $this->isType( 'array' ),
652  // We don't really care about the join conds are they come from the joinCond methods
653  $this->isType( 'array' )
654  )
655  ->willReturn( $row );
656 
657  $revision = Revision::loadFromTitle( $db, $title );
658 
659  $this->assertEquals( $title->getArticleID(), $revision->getTitle()->getArticleID() );
660  $this->assertEquals( $row->rev_id, $revision->getId() );
661  $this->assertEquals( $row->rev_len, $revision->getSize() );
662  $this->assertEquals( $row->rev_sha1, $revision->getSha1() );
663  $this->assertEquals( $row->rev_parent_id, $revision->getParentId() );
664  $this->assertEquals( $row->rev_timestamp, $revision->getTimestamp() );
665  $this->assertEquals( $row->rev_comment_text, $revision->getComment() );
666  $this->assertEquals( $row->rev_user_text, $revision->getUserText() );
667  }
668 
669  public function provideDecompressRevisionText() {
670  yield '(no legacy encoding), false in false out' => [ false, false, [], false ];
671  yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
672  yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
673  yield '(no legacy encoding), string in with gzip flag returns string' => [
674  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
675  false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
676  ];
677  yield '(no legacy encoding), string in with object flag returns false' => [
678  // gzip string below generated with serialize( 'JOJO' )
679  false, "s:4:\"JOJO\";", [ 'object' ], false,
680  ];
681  yield '(no legacy encoding), serialized object in with object flag returns string' => [
682  false,
683  // Using a TitleValue object as it has a getText method (which is needed)
684  serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
685  [ 'object' ],
686  'HHJJDDFF',
687  ];
688  yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
689  false,
690  // Using a TitleValue object as it has a getText method (which is needed)
691  gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
692  [ 'object', 'gzip' ],
693  '8219JJJ840',
694  ];
695  yield '(ISO-8859-1 encoding), string in string out' => [
696  'ISO-8859-1',
697  iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
698  [],
699  '1®Àþ1',
700  ];
701  yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
702  'ISO-8859-1',
703  gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
704  [ 'gzip' ],
705  '4®Àþ4',
706  ];
707  yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
708  'ISO-8859-1',
709  serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
710  [ 'object' ],
711  '3®Àþ3',
712  ];
713  yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
714  'ISO-8859-1',
715  gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
716  [ 'gzip', 'object' ],
717  '2®Àþ2',
718  ];
719  }
720 
730  public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
731  $blobStore = $this->getBlobStore();
732  if ( $legacyEncoding ) {
733  $blobStore->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
734  }
735 
736  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
737  $this->assertSame(
738  $expected,
739  Revision::decompressRevisionText( $text, $flags )
740  );
741  }
742 
744  yield 'Just text' => [
745  (object)[ 'old_text' => 'SomeText' ],
746  'old_',
747  'SomeText'
748  ];
749  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
750  yield 'gzip text' => [
751  (object)[
752  'old_text' => "sttttr\002\022\000",
753  'old_flags' => 'gzip'
754  ],
755  'old_',
756  'AAAABBAAA'
757  ];
758  yield 'gzip text and different prefix' => [
759  (object)[
760  'jojo_text' => "sttttr\002\022\000",
761  'jojo_flags' => 'gzip'
762  ],
763  'jojo_',
764  'AAAABBAAA'
765  ];
766  }
767 
773  $row,
774  $prefix,
775  $expected
776  ) {
777  $this->assertSame( $expected, Revision::getRevisionText( $row, $prefix ) );
778  }
779 
781  yield 'Just some text' => [ 'someNonUrlText' ];
782  yield 'No second URL part' => [ 'someProtocol://' ];
783  }
784 
790  $text
791  ) {
792  Wikimedia\suppressWarnings();
793  $this->assertFalse(
795  (object)[
796  'old_text' => $text,
797  'old_flags' => 'external',
798  ]
799  )
800  );
801  Wikimedia\suppressWarnings( true );
802  }
803 
808  $this->setService(
809  'ExternalStoreFactory',
810  new ExternalStoreFactory( [ 'ForTesting' ] )
811  );
812  $this->assertSame(
813  'AAAABBAAA',
815  (object)[
816  'old_text' => 'ForTesting://cluster1/12345',
817  'old_flags' => 'external,gzip',
818  ]
819  )
820  );
821  }
822 
827  $cache = $this->getWANObjectCache();
828  $this->setService( 'MainWANObjectCache', $cache );
829 
830  $this->setService(
831  'ExternalStoreFactory',
832  new ExternalStoreFactory( [ 'ForTesting' ] )
833  );
834 
835  $lb = $this->getMockBuilder( LoadBalancer::class )
836  ->disableOriginalConstructor()
837  ->getMock();
838 
839  $blobStore = new SqlBlobStore( $lb, $cache );
840  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
841 
842  $this->assertSame(
843  'AAAABBAAA',
845  (object)[
846  'old_text' => 'ForTesting://cluster1/12345',
847  'old_flags' => 'external,gzip',
848  'old_id' => '7777',
849  ]
850  )
851  );
852 
853  $cacheKey = $cache->makeGlobalKey(
854  'BlobStore',
855  'address',
856  $lb->getLocalDomainID(),
857  'tt:7777'
858  );
859  $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
860  }
861 
865  public function testGetSize() {
866  $title = $this->getMockTitle();
867 
868  $rec = new MutableRevisionRecord( $title );
869  $rev = new Revision( $rec, 0, $title );
870 
871  $this->assertSame( 0, $rev->getSize(), 'Size of no slots is 0' );
872 
873  $rec->setSize( 13 );
874  $this->assertSame( 13, $rev->getSize() );
875  }
876 
880  public function testGetSize_failure() {
881  $title = $this->getMockTitle();
882 
883  $rec = $this->getMockBuilder( RevisionRecord::class )
884  ->disableOriginalConstructor()
885  ->getMock();
886 
887  $rec->method( 'getSize' )
888  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
889 
890  $rev = new Revision( $rec, 0, $title );
891  $this->assertNull( $rev->getSize() );
892  }
893 
897  public function testGetSha1() {
898  $title = $this->getMockTitle();
899 
900  $rec = new MutableRevisionRecord( $title );
901  $rev = new Revision( $rec, 0, $title );
902 
903  $emptyHash = SlotRecord::base36Sha1( '' );
904  $this->assertSame( $emptyHash, $rev->getSha1(), 'Sha1 of no slots is hash of empty string' );
905 
906  $rec->setSha1( 'deadbeef' );
907  $this->assertSame( 'deadbeef', $rev->getSha1() );
908  }
909 
913  public function testGetSha1_failure() {
914  $title = $this->getMockTitle();
915 
916  $rec = $this->getMockBuilder( RevisionRecord::class )
917  ->disableOriginalConstructor()
918  ->getMock();
919 
920  $rec->method( 'getSha1' )
921  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
922 
923  $rev = new Revision( $rec, 0, $title );
924  $this->assertNull( $rev->getSha1() );
925  }
926 
930  public function testGetContent() {
931  $title = $this->getMockTitle();
932 
933  $rec = new MutableRevisionRecord( $title );
934  $rev = new Revision( $rec, 0, $title );
935 
936  $this->assertNull( $rev->getContent(), 'Content of no slots is null' );
937 
938  $content = new TextContent( 'Hello Kittens!' );
939  $rec->setContent( SlotRecord::MAIN, $content );
940  $this->assertSame( $content, $rev->getContent() );
941  }
942 
946  public function testGetContent_failure() {
947  $title = $this->getMockTitle();
948 
949  $rec = $this->getMockBuilder( RevisionRecord::class )
950  ->disableOriginalConstructor()
951  ->getMock();
952 
953  $rec->method( 'getContent' )
954  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
955 
956  $rev = new Revision( $rec, 0, $title );
957  $this->assertNull( $rev->getContent() );
958  }
959 
960 }
Service for storing and loading Content objects.
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal()
testGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts( $text)
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts Revision::getRevisionText ...
testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithLegacyEncoding.
provideGetRevisionTextWithGzipAndLegacyEncoding()
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:231
testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected)
provideDecompressRevisionText Revision::decompressRevisionText
if(is_array( $mode)) switch( $mode) $input
testGetRevisionText_external_oldId()
Revision::getRevisionText.
testGetContent()
Revision::getContent.
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
serialize()
testConstructFromEmptyArray()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
testCompressRevisionTextUtf8Gzip()
Revision::compressRevisionText.
if(!isset( $args[0])) $lang
globals will be eliminated from MediaWiki replaced by an application object which would be passed to constructors Whether that would be an convenient solution remains to be but certainly PHP makes such object oriented programming models easier than they were in previous versions For the time being MediaWiki programmers will have to work in an environment with some global context At the time of globals were initialised on startup by MediaWiki of these were configuration which are documented in DefaultSettings php There is no comprehensive documentation for the remaining however some of the most important ones are listed below They are typically initialised either in index php or in Setup php $wgTitle Title object created from the request URL $wgOut OutputPage object for HTTP response $wgUser User object for the user associated with the current request $wgLang Language object selected by user preferences $wgContLang Language object associated with the wiki being viewed $wgParser Parser object Parser extensions register their hooks here $wgRequest WebRequest object
Definition: globals.txt:25
testConstructFromArrayWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
testGetContent_failure()
Revision::getContent.
testSetId( $input, $expected)
provideSetId Revision::setId
const SCHEMA_COMPAT_READ_NEW
Definition: Defines.php:283
mockBlobStoreFactory( $blobStore)
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
provideConstructFromArray()
testGetSha1_failure()
Revision::getSha1.
Content for JavaScript pages.
provideGetRevisionTextWithLegacyEncoding()
static decompressRevisionText( $text, $flags)
Re-converts revision text according to it&#39;s flags.
Definition: Revision.php:1133
provideConstructFromArrayThrowsExceptions()
testConstructFromArray( $rowArray)
provideConstructFromArray Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevision...
testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException)
provideConstructFromArrayThrowsExceptions Revision::__construct \MediaWiki\Revision\RevisionStore::ne...
testGetParentId( $rowArray, $expected)
provideGetParentId Revision::getParentId()
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row.
Definition: Revision.php:1046
Mutable RevisionRecord implementation, for building new revision entries programmatically.
provideDecompressRevisionText()
getDefaultWikitextNS()
Returns the ID of a namespace that defaults to Wikitext.
provideGetRevisionTextWithZlibExtension()
testGetRevisionWithZlibExtension_badData( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension_badData.
testGetRevisionText_external_noOldId()
Revision::getRevisionText.
testSetUserIdAndName( $inputId, $expectedId, $name)
provideSetUserIdAndName Revision::setUserIdAndName
const MIGRATION_OLD
Definition: Defines.php:311
Service for looking up page revisions.
testCompressRevisionTextUtf8()
Revision::compressRevisionText.
static compressRevisionText(&$text)
If $wgCompressRevisions is enabled, we will compress data.
Definition: Revision.php:1122
$cache
Definition: mcc.php:33
provideConstructFromArray_userSetAsExpected()
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that&#39;s attached to a given page.
Definition: Revision.php:277
testLoadFromTitle()
Revision::loadFromTitle.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
testGetSize_failure()
Revision::getSize.
provideGetRevisionTextWithZlibExtension_badData()
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:216
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1766
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown...
const RAW
Definition: Revision.php:56
testGetRevisionText( $expected, $rowData, $prefix='old_', $wiki=false)
Revision::getRevisionText provideGetRevisionText.
const SCHEMA_COMPAT_WRITE_BOTH
Definition: Defines.php:284
testConstructFromNothing()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
CONTENT_MODEL_JAVASCRIPT
Allow users to upload files.
const DELETED_TEXT
Definition: Revision.php:46
setService( $name, $object)
Sets a service, maintaining a stashed version of the previous service to be restored in tearDown...
testGetSha1()
Revision::getSha1.
checkPHPExtension( $extName)
Check if $extName is a loaded PHP extension, will skip the test whenever it is not loaded...
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
testGetSize()
Revision::getSize.
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
testConstructFromArray_userSetAsExpected(array $rowArray, $expectedUserId, $expectedUserName)
provideConstructFromArray_userSetAsExpected Revision::__construct \MediaWiki\Revision\RevisionStore::...
testGetRevisionText_returnsDecompressedTextFieldWhenNotExternal( $row, $prefix, $expected)
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal Revision::getRevisionText ...
Exception representing a failure to look up a revision.
const SCHEMA_COMPAT_NEW
Definition: Defines.php:287
testGetId( $rowArray, $expectedId)
provideGetId Revision::getId
Database $db
Primary database.
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts()
getMockTitle( $model=CONTENT_MODEL_WIKITEXT)
testConstructFromRowWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
$content
Definition: pageupdater.txt:72
testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithGzipAndLegacyEncoding.
testConstructFromRow(array $arrayData, callable $assertions)
provideConstructFromRow Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFr...
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
testGetRevisionWithZlibExtension( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension.
Test cases in RevisionTest should not interact with the Database.