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  $access = MediaWikiServices::getInstance()->getExternalStoreAccess();
442  $cache = $this->getWANObjectCache();
443 
444  $blobStore = new SqlBlobStore( $lb, $access, $cache );
445 
446  return $blobStore;
447  }
448 
449  private function mockBlobStoreFactory( $blobStore ) {
451  $factory = $this->getMockBuilder( BlobStoreFactory::class )
452  ->disableOriginalConstructor()
453  ->getMock();
454  $factory->expects( $this->any() )
455  ->method( 'newBlobStore' )
456  ->willReturn( $blobStore );
457  $factory->expects( $this->any() )
458  ->method( 'newSqlBlobStore' )
459  ->willReturn( $blobStore );
460  return $factory;
461  }
462 
466  private function getRevisionStore() {
468  $lb = $this->getMockBuilder( LoadBalancer::class )
469  ->disableOriginalConstructor()
470  ->getMock();
471 
472  $cache = $this->getWANObjectCache();
473 
474  $blobStore = new RevisionStore(
475  $lb,
476  $this->getBlobStore(),
477  $cache,
478  MediaWikiServices::getInstance()->getCommentStore(),
479  MediaWikiServices::getInstance()->getContentModelStore(),
480  MediaWikiServices::getInstance()->getSlotRoleStore(),
481  MediaWikiServices::getInstance()->getSlotRoleRegistry(),
483  MediaWikiServices::getInstance()->getActorMigration()
484  );
485  return $blobStore;
486  }
487 
489  yield 'Utf8Native' => [
490  "Wiki est l'\xc3\xa9cole superieur !",
491  'fr',
492  'iso-8859-1',
493  (object)[
494  'old_flags' => 'utf-8',
495  'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
496  ]
497  ];
498  yield 'Utf8Legacy' => [
499  "Wiki est l'\xc3\xa9cole superieur !",
500  'fr',
501  'iso-8859-1',
502  (object)[
503  'old_flags' => '',
504  'old_text' => "Wiki est l'\xe9cole superieur !",
505  ]
506  ];
507  }
508 
513  public function testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
514  $blobStore = $this->getBlobStore();
515  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
516  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
517 
518  $this->testGetRevisionText( $expected, $rowData );
519  }
520 
527  yield 'Utf8NativeGzip' => [
528  "Wiki est l'\xc3\xa9cole superieur !",
529  'fr',
530  'iso-8859-1',
531  (object)[
532  'old_flags' => 'gzip,utf-8',
533  'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
534  ]
535  ];
536  yield 'Utf8LegacyGzip' => [
537  "Wiki est l'\xc3\xa9cole superieur !",
538  'fr',
539  'iso-8859-1',
540  (object)[
541  'old_flags' => 'gzip',
542  'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
543  ]
544  ];
545  }
546 
551  public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
552  $this->checkPHPExtension( 'zlib' );
553 
554  $blobStore = $this->getBlobStore();
555  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
556  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
557 
558  $this->testGetRevisionText( $expected, $rowData );
559  }
560 
564  public function testCompressRevisionTextUtf8() {
565  $row = new stdClass;
566  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
567  $row->old_flags = Revision::compressRevisionText( $row->old_text );
568  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
569  "Flags should contain 'utf-8'" );
570  $this->assertFalse( strpos( $row->old_flags, 'gzip' ) !== false,
571  "Flags should not contain 'gzip'" );
572  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
573  $row->old_text, "Direct check" );
574  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
575  Revision::getRevisionText( $row ), "getRevisionText" );
576  }
577 
582  $this->checkPHPExtension( 'zlib' );
583 
584  $blobStore = $this->getBlobStore();
585  $blobStore->setCompressBlobs( true );
586  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
587 
588  $row = new stdClass;
589  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
590  $row->old_flags = Revision::compressRevisionText( $row->old_text );
591  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
592  "Flags should contain 'utf-8'" );
593  $this->assertTrue( strpos( $row->old_flags, 'gzip' ) !== false,
594  "Flags should contain 'gzip'" );
595  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
596  gzinflate( $row->old_text ), "Direct check" );
597  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
598  Revision::getRevisionText( $row ), "getRevisionText" );
599  }
600 
604  public function testLoadFromTitle() {
605  $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
606  $this->overrideMwServices();
607  $title = $this->getMockTitle();
608 
609  $conditions = [
610  'rev_id=page_latest',
611  'page_namespace' => $title->getNamespace(),
612  'page_title' => $title->getDBkey()
613  ];
614 
615  $row = (object)[
616  'rev_id' => '42',
617  'rev_page' => $title->getArticleID(),
618  'rev_timestamp' => '20171017114835',
619  'rev_user_text' => '127.0.0.1',
620  'rev_user' => '0',
621  'rev_minor_edit' => '0',
622  'rev_deleted' => '0',
623  'rev_len' => '46',
624  'rev_parent_id' => '1',
625  'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
626  'rev_comment_text' => 'Goat Comment!',
627  'rev_comment_data' => null,
628  'rev_comment_cid' => null,
629  'rev_content_format' => 'GOATFORMAT',
630  'rev_content_model' => 'GOATMODEL',
631  ];
632 
633  $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
634  $db = $this->getMock( IDatabase::class );
635  $db->expects( $this->any() )
636  ->method( 'getDomainId' )
637  ->will( $this->returnValue( $domain ) );
638  $db->expects( $this->once() )
639  ->method( 'selectRow' )
640  ->with(
641  $this->equalTo( [
642  'revision', 'page', 'user',
643  'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment',
644  'temp_rev_user' => 'revision_actor_temp', 'actor_rev_user' => 'actor',
645  ] ),
646  // We don't really care about the fields are they come from the selectField methods
647  $this->isType( 'array' ),
648  $this->equalTo( $conditions ),
649  // Method name
650  $this->stringContains( 'fetchRevisionRowFromConds' ),
651  // We don't really care about the options here
652  $this->isType( 'array' ),
653  // We don't really care about the join conds are they come from the joinCond methods
654  $this->isType( 'array' )
655  )
656  ->willReturn( $row );
657 
658  $revision = Revision::loadFromTitle( $db, $title );
659 
660  $this->assertEquals( $title->getArticleID(), $revision->getTitle()->getArticleID() );
661  $this->assertEquals( $row->rev_id, $revision->getId() );
662  $this->assertEquals( $row->rev_len, $revision->getSize() );
663  $this->assertEquals( $row->rev_sha1, $revision->getSha1() );
664  $this->assertEquals( $row->rev_parent_id, $revision->getParentId() );
665  $this->assertEquals( $row->rev_timestamp, $revision->getTimestamp() );
666  $this->assertEquals( $row->rev_comment_text, $revision->getComment() );
667  $this->assertEquals( $row->rev_user_text, $revision->getUserText() );
668  }
669 
670  public function provideDecompressRevisionText() {
671  yield '(no legacy encoding), false in false out' => [ false, false, [], false ];
672  yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
673  yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
674  yield '(no legacy encoding), string in with gzip flag returns string' => [
675  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
676  false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
677  ];
678  yield '(no legacy encoding), string in with object flag returns false' => [
679  // gzip string below generated with serialize( 'JOJO' )
680  false, "s:4:\"JOJO\";", [ 'object' ], false,
681  ];
682  yield '(no legacy encoding), serialized object in with object flag returns string' => [
683  false,
684  // Using a TitleValue object as it has a getText method (which is needed)
685  serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
686  [ 'object' ],
687  'HHJJDDFF',
688  ];
689  yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
690  false,
691  // Using a TitleValue object as it has a getText method (which is needed)
692  gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
693  [ 'object', 'gzip' ],
694  '8219JJJ840',
695  ];
696  yield '(ISO-8859-1 encoding), string in string out' => [
697  'ISO-8859-1',
698  iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
699  [],
700  '1®Àþ1',
701  ];
702  yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
703  'ISO-8859-1',
704  gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
705  [ 'gzip' ],
706  '4®Àþ4',
707  ];
708  yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
709  'ISO-8859-1',
710  serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
711  [ 'object' ],
712  '3®Àþ3',
713  ];
714  yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
715  'ISO-8859-1',
716  gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
717  [ 'gzip', 'object' ],
718  '2®Àþ2',
719  ];
720  }
721 
731  public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
732  $blobStore = $this->getBlobStore();
733  if ( $legacyEncoding ) {
734  $blobStore->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
735  }
736 
737  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
738  $this->assertSame(
739  $expected,
740  Revision::decompressRevisionText( $text, $flags )
741  );
742  }
743 
745  yield 'Just text' => [
746  (object)[ 'old_text' => 'SomeText' ],
747  'old_',
748  'SomeText'
749  ];
750  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
751  yield 'gzip text' => [
752  (object)[
753  'old_text' => "sttttr\002\022\000",
754  'old_flags' => 'gzip'
755  ],
756  'old_',
757  'AAAABBAAA'
758  ];
759  yield 'gzip text and different prefix' => [
760  (object)[
761  'jojo_text' => "sttttr\002\022\000",
762  'jojo_flags' => 'gzip'
763  ],
764  'jojo_',
765  'AAAABBAAA'
766  ];
767  }
768 
774  $row,
775  $prefix,
776  $expected
777  ) {
778  $this->assertSame( $expected, Revision::getRevisionText( $row, $prefix ) );
779  }
780 
782  yield 'Just some text' => [ 'someNonUrlText' ];
783  yield 'No second URL part' => [ 'someProtocol://' ];
784  }
785 
791  $text
792  ) {
793  Wikimedia\suppressWarnings();
794  $this->assertFalse(
796  (object)[
797  'old_text' => $text,
798  'old_flags' => 'external',
799  ]
800  )
801  );
802  Wikimedia\suppressWarnings( true );
803  }
804 
809  $this->setService(
810  'ExternalStoreFactory',
811  new ExternalStoreFactory( [ 'ForTesting' ], [ 'ForTesting://cluster1' ], 'test-id' )
812  );
813  $this->assertSame(
814  'AAAABBAAA',
816  (object)[
817  'old_text' => 'ForTesting://cluster1/12345',
818  'old_flags' => 'external,gzip',
819  ]
820  )
821  );
822  }
823 
828  $cache = $this->getWANObjectCache();
829  $this->setService( 'MainWANObjectCache', $cache );
830 
831  $this->setService(
832  'ExternalStoreFactory',
833  new ExternalStoreFactory( [ 'ForTesting' ], [ 'ForTesting://cluster1' ], 'test-id' )
834  );
835 
836  $lb = $this->getMockBuilder( LoadBalancer::class )
837  ->disableOriginalConstructor()
838  ->getMock();
839  $access = MediaWikiServices::getInstance()->getExternalStoreAccess();
840 
841  $blobStore = new SqlBlobStore( $lb, $access, $cache );
842  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
843 
844  $this->assertSame(
845  'AAAABBAAA',
847  (object)[
848  'old_text' => 'ForTesting://cluster1/12345',
849  'old_flags' => 'external,gzip',
850  'old_id' => '7777',
851  ]
852  )
853  );
854 
855  $cacheKey = $cache->makeGlobalKey(
856  'BlobStore',
857  'address',
858  $lb->getLocalDomainID(),
859  'tt:7777'
860  );
861  $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
862  }
863 
867  public function testGetSize() {
868  $title = $this->getMockTitle();
869 
870  $rec = new MutableRevisionRecord( $title );
871  $rev = new Revision( $rec, 0, $title );
872 
873  $this->assertSame( 0, $rev->getSize(), 'Size of no slots is 0' );
874 
875  $rec->setSize( 13 );
876  $this->assertSame( 13, $rev->getSize() );
877  }
878 
882  public function testGetSize_failure() {
883  $title = $this->getMockTitle();
884 
885  $rec = $this->getMockBuilder( RevisionRecord::class )
886  ->disableOriginalConstructor()
887  ->getMock();
888 
889  $rec->method( 'getSize' )
890  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
891 
892  $rev = new Revision( $rec, 0, $title );
893  $this->assertNull( $rev->getSize() );
894  }
895 
899  public function testGetSha1() {
900  $title = $this->getMockTitle();
901 
902  $rec = new MutableRevisionRecord( $title );
903  $rev = new Revision( $rec, 0, $title );
904 
905  $emptyHash = SlotRecord::base36Sha1( '' );
906  $this->assertSame( $emptyHash, $rev->getSha1(), 'Sha1 of no slots is hash of empty string' );
907 
908  $rec->setSha1( 'deadbeef' );
909  $this->assertSame( 'deadbeef', $rev->getSha1() );
910  }
911 
915  public function testGetSha1_failure() {
916  $title = $this->getMockTitle();
917 
918  $rec = $this->getMockBuilder( RevisionRecord::class )
919  ->disableOriginalConstructor()
920  ->getMock();
921 
922  $rec->method( 'getSha1' )
923  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
924 
925  $rev = new Revision( $rec, 0, $title );
926  $this->assertNull( $rev->getSha1() );
927  }
928 
932  public function testGetContent() {
933  $title = $this->getMockTitle();
934 
935  $rec = new MutableRevisionRecord( $title );
936  $rev = new Revision( $rec, 0, $title );
937 
938  $this->assertNull( $rev->getContent(), 'Content of no slots is null' );
939 
940  $content = new TextContent( 'Hello Kittens!' );
941  $rec->setContent( SlotRecord::MAIN, $content );
942  $this->assertSame( $content, $rev->getContent() );
943  }
944 
948  public function testGetContent_failure() {
949  $title = $this->getMockTitle();
950 
951  $rec = $this->getMockBuilder( RevisionRecord::class )
952  ->disableOriginalConstructor()
953  ->getMock();
954 
955  $rec->method( 'getContent' )
956  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
957 
958  $rev = new Revision( $rec, 0, $title );
959  $this->assertNull( $rev->getContent() );
960  }
961 
962 }
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:215
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:267
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()
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:295
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:767
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:912
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:1748
const RAW
Definition: Revision.php:56
testGetRevisionText( $expected, $rowData, $prefix='old_', $wiki=false)
Revision::getRevisionText provideGetRevisionText.
const SCHEMA_COMPAT_WRITE_BOTH
Definition: Defines.php:268
testConstructFromNothing()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
CONTENT_MODEL_JAVASCRIPT
Allow users to upload files.
const DELETED_TEXT
Definition: Revision.php:46
testGetSha1()
Revision::getSha1.
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:271
testGetId( $rowArray, $expectedId)
provideGetId Revision::getId
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...
testGetRevisionWithZlibExtension( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension.
Test cases in RevisionTest should not interact with the Database.