Fix warnings and enforce conventions in ContentHandler tests.
authorTimo Tijhof <ttijhof@wikimedia.org>
Sat, 20 Oct 2012 01:51:15 +0000 (03:51 +0200)
committerTimo Tijhof <ttijhof@wikimedia.org>
Thu, 25 Oct 2012 20:37:32 +0000 (22:37 +0200)
Syntax:
* Call parent setUp from setUp.
* Set required globals for the test inside the test class instead
  of assuming the default settings.
* Data providers are called statically and outside setUp/tearDown
  ("public static function")
* Test function names should be prefixed with "test"
  ("testIsRedirect")
* Marked 2 functions as unused. JavascriptContentTest has 2 data
  providers for tests that don't exist in it (nor in TextContentText)
  but do exist in WikitextContentTest.

Style:
* Single quotes
* Remove odd comment "# =====" lines
* Consistent tree wrapping with arrays.
  array(
      array(
          .. ) );
  array(
      array(
          ..
      )
  );
  Some were closing on the previous line instead.
  Made it consistent now.
* Remove odd indentation to make nested arrays line up:
  array( 'foo' => array(  'bar' => true,
                          'baz' => array() ) )
  array( 'foo' => array(
      'bar' => true,
      'baz' => array()
  ) )

  We don't do this kind of indentation because it is fragile
  and becomes outdates when any of the earlier keys ("foo")
  change. Converted to a regular tree instead.

  Also triggered git warnings for mixing spaces with tabs, which
  is almost always an detector for this style.

* Not using @annotations in inline comments, reserved (and only
  parsed/meaningful) for block comments.

Follows-up 8b568be5e2dfb889e1eeedbdca50b304864174f7

Change-Id: Ic55d539b9a58f448b550bcd98894d389764e0694

15 files changed:
includes/AutoLoader.php
includes/DefaultSettings.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/ContentHandlerTest.php [deleted file]
tests/phpunit/includes/CssContentTest.php [deleted file]
tests/phpunit/includes/JavascriptContentTest.php [deleted file]
tests/phpunit/includes/TextContentTest.php [deleted file]
tests/phpunit/includes/WikitextContentHandlerTest.php [deleted file]
tests/phpunit/includes/WikitextContentTest.php [deleted file]
tests/phpunit/includes/content/ContentHandlerTest.php [new file with mode: 0644]
tests/phpunit/includes/content/CssContentTest.php [new file with mode: 0644]
tests/phpunit/includes/content/JavascriptContentTest.php [new file with mode: 0644]
tests/phpunit/includes/content/TextContentTest.php [new file with mode: 0644]
tests/phpunit/includes/content/WikitextContentHandlerTest.php [new file with mode: 0644]
tests/phpunit/includes/content/WikitextContentTest.php [new file with mode: 0644]

index d98556e..c97c95a 100644 (file)
@@ -1095,13 +1095,15 @@ $wgAutoloadLocalClasses = array(
        'TestRecorder' => 'tests/testHelpers.inc',
 
        # tests/phpunit
-       'DummyContentHandlerForTesting' => 'tests/phpunit/includes/ContentHandlerTest.php',
-       'DummyContentForTesting' => 'tests/phpunit/includes/ContentHandlerTest.php',
-       'JavascriptContentTest' => 'tests/phpunit/includes/JavascriptContentTest.php',
        'RevisionStorageTest' => 'tests/phpunit/includes/RevisionStorageTest.php',
-       'TextContentTest' => 'tests/phpunit/includes/TextContentTest.php',
        'WikiPageTest' => 'tests/phpunit/includes/WikiPageTest.php',
 
+       # tests/phpunit/content
+       'DummyContentHandlerForTesting' => 'tests/phpunit/includes/content/ContentHandlerTest.php',
+       'DummyContentForTesting' => 'tests/phpunit/includes/content/ContentHandlerTest.php',
+       'JavascriptContentTest' => 'tests/phpunit/includes/content/JavascriptContentTest.php',
+       'TextContentTest' => 'tests/phpunit/includes/content/TextContentTest.php',
+
        # tests/phpunit/includes
        'GenericArrayObjectTest' => 'tests/phpunit/includes/libs/GenericArrayObjectTest.php',
 
index cea63e0..c485b16 100644 (file)
@@ -752,10 +752,14 @@ $wgMediaHandlers = array(
  * @since 1.21
  */
 $wgContentHandlers = array(
-       CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler', // the usual case
-       CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler', // dumb version, no syntax highlighting
-       CONTENT_MODEL_CSS => 'CssContentHandler', // dumb version, no syntax highlighting
-       CONTENT_MODEL_TEXT => 'TextContentHandler', // plain text, for use by extensions etc
+       // the usual case
+       CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler',
+       // dumb version, no syntax highlighting
+       CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler',
+       // dumb version, no syntax highlighting
+       CONTENT_MODEL_CSS => 'CssContentHandler',
+       // plain text, for use by extensions etc
+       CONTENT_MODEL_TEXT => 'TextContentHandler',
 );
 
 /**
index 5bc36ed..258dfec 100644 (file)
@@ -250,7 +250,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                                throw new MWException( "MW global $name is not an array." );
                        }
 
-                       //NOTE: do not use array_merge, it screws up for numeric keys.
+                       // NOTE: do not use array_merge, it screws up for numeric keys.
                        $merged = $GLOBALS[$name];
                        foreach ( $values as $k => $v ) {
                                $merged[$k] = $v;
diff --git a/tests/phpunit/includes/ContentHandlerTest.php b/tests/phpunit/includes/ContentHandlerTest.php
deleted file mode 100644 (file)
index 797a3ee..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- *
- * @note: Declare that we are using the database, because otherwise we'll fail in the "databaseless" test run.
- * This is because the LinkHolderArray used by the parser needs database access.
- *
- * @group Database
- */
-class ContentHandlerTest extends MediaWikiTestCase {
-
-       public function setup() {
-               parent::setup();
-
-               global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
-               $wgExtraNamespaces[ 12312 ] = 'Dummy';
-               $wgExtraNamespaces[ 12313 ] = 'Dummy_talk';
-
-               $wgNamespaceContentModels[ 12312 ] = "testing";
-               $wgContentHandlers[ "testing" ] = 'DummyContentHandlerForTesting';
-
-               MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
-               $wgContLang->resetNamespaces(); # reset namespace cache
-       }
-
-       public function teardown() {
-               global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
-               unset( $wgExtraNamespaces[ 12312 ] );
-               unset( $wgExtraNamespaces[ 12313 ] );
-
-               unset( $wgNamespaceContentModels[ 12312 ] );
-               unset( $wgContentHandlers[ "testing" ] );
-
-               MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
-               $wgContLang->resetNamespaces(); # reset namespace cache
-
-               parent::teardown();
-       }
-
-       public function dataGetDefaultModelFor() {
-               //NOTE: assume that the Help namespace default to wikitext content
-               return array(
-                       array( 'Help:Foo', CONTENT_MODEL_WIKITEXT ),
-                       array( 'Help:Foo.js', CONTENT_MODEL_WIKITEXT ),
-                       array( 'Help:Foo/bar.js', CONTENT_MODEL_WIKITEXT ),
-                       array( 'User:Foo', CONTENT_MODEL_WIKITEXT ),
-                       array( 'User:Foo.js', CONTENT_MODEL_WIKITEXT ),
-                       array( 'User:Foo/bar.js', CONTENT_MODEL_JAVASCRIPT ),
-                       array( 'User:Foo/bar.css', CONTENT_MODEL_CSS ),
-                       array( 'User talk:Foo/bar.css', CONTENT_MODEL_WIKITEXT ),
-                       array( 'User:Foo/bar.js.xxx', CONTENT_MODEL_WIKITEXT ),
-                       array( 'User:Foo/bar.xxx', CONTENT_MODEL_WIKITEXT ),
-                       array( 'MediaWiki:Foo.js', CONTENT_MODEL_JAVASCRIPT ),
-                       array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
-                       array( 'MediaWiki:Foo.JS', CONTENT_MODEL_WIKITEXT ),
-                       array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
-                       array( 'MediaWiki:Foo.css.xxx', CONTENT_MODEL_WIKITEXT ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetDefaultModelFor
-        */
-       public function testGetDefaultModelFor( $title, $expectedModelId ) {
-               $title = Title::newFromText( $title );
-               $this->assertEquals( $expectedModelId, ContentHandler::getDefaultModelFor( $title ) );
-       }
-       /**
-        * @dataProvider dataGetDefaultModelFor
-        */
-       public function testGetForTitle( $title, $expectedContentModel ) {
-               $title = Title::newFromText( $title );
-               $handler = ContentHandler::getForTitle( $title );
-               $this->assertEquals( $expectedContentModel, $handler->getModelID() );
-       }
-
-       public function dataGetLocalizedName() {
-               return array(
-                       array( null, null ),
-                       array( "xyzzy", null ),
-
-                       array( CONTENT_MODEL_JAVASCRIPT, '/javascript/i' ), //XXX: depends on content language
-               );
-       }
-
-       /**
-        * @dataProvider dataGetLocalizedName
-        */
-       public function testGetLocalizedName( $id, $expected ) {
-               $name = ContentHandler::getLocalizedName( $id );
-
-               if ( $expected ) {
-                       $this->assertNotNull( $name, "no name found for content model $id" );
-                       $this->assertTrue( preg_match( $expected, $name ) > 0 ,
-                                                               "content model name for #$id did not match pattern $expected" );
-               } else {
-                       $this->assertEquals( $id, $name, "localization of unknown model $id should have "
-                                                                                       . "fallen back to use the model id directly." );
-               }
-       }
-
-       public function dataGetPageLanguage() {
-               global $wgLanguageCode;
-
-               return array(
-                       array( "Main", $wgLanguageCode ),
-                       array( "Dummy:Foo", $wgLanguageCode ),
-                       array( "MediaWiki:common.js", 'en' ),
-                       array( "User:Foo/common.js", 'en' ),
-                       array( "MediaWiki:common.css", 'en' ),
-                       array( "User:Foo/common.css", 'en' ),
-                       array( "User:Foo", $wgLanguageCode ),
-
-                       array( CONTENT_MODEL_JAVASCRIPT, 'javascript' ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetPageLanguage
-        */
-       public function testGetPageLanguage( $title, $expected ) {
-               if ( is_string( $title ) ) {
-                       $title = Title::newFromText( $title );
-               }
-
-               $expected = wfGetLangObj( $expected );
-
-               $handler = ContentHandler::getForTitle( $title );
-               $lang = $handler->getPageLanguage( $title );
-
-               $this->assertEquals( $expected->getCode(), $lang->getCode() );
-       }
-
-       public function testGetContentText_Null( ) {
-               global $wgContentHandlerTextFallback;
-
-               $content = null;
-
-               $wgContentHandlerTextFallback = 'fail';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( '', $text );
-
-               $wgContentHandlerTextFallback = 'serialize';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( '', $text );
-
-               $wgContentHandlerTextFallback = 'ignore';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( '', $text );
-       }
-
-       public function testGetContentText_TextContent( ) {
-               global $wgContentHandlerTextFallback;
-
-               $content = new WikitextContent( "hello world" );
-
-               $wgContentHandlerTextFallback = 'fail';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( $content->getNativeData(), $text );
-
-               $wgContentHandlerTextFallback = 'serialize';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( $content->serialize(), $text );
-
-               $wgContentHandlerTextFallback = 'ignore';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( $content->getNativeData(), $text );
-       }
-
-       public function testGetContentText_NonTextContent( ) {
-               global $wgContentHandlerTextFallback;
-
-               $content = new DummyContentForTesting( "hello world" );
-
-               $wgContentHandlerTextFallback = 'fail';
-
-               try {
-                       $text = ContentHandler::getContentText( $content );
-
-                       $this->fail( "ContentHandler::getContentText should have thrown an exception for non-text Content object" );
-               } catch (MWException $ex) {
-                       // as expected
-               }
-
-               $wgContentHandlerTextFallback = 'serialize';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertEquals( $content->serialize(), $text );
-
-               $wgContentHandlerTextFallback = 'ignore';
-               $text = ContentHandler::getContentText( $content );
-               $this->assertNull( $text );
-       }
-
-       #public static function makeContent( $text, Title $title, $modelId = null, $format = null )
-
-       public function dataMakeContent() {
-               //NOTE: assume the Help namespace defaults to wikitext content
-               return array(
-                       array( 'hallo', 'Help:Test', null, null, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
-                       array( 'hallo', 'MediaWiki:Test.js', null, null, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
-                       array( serialize('hallo'), 'Dummy:Test', null, null, "testing", 'hallo', false ),
-
-                       array( 'hallo', 'Help:Test', null, CONTENT_FORMAT_WIKITEXT, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
-                       array( 'hallo', 'MediaWiki:Test.js', null, CONTENT_FORMAT_JAVASCRIPT, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
-                       array( serialize('hallo'), 'Dummy:Test', null, "testing", "testing", 'hallo', false ),
-
-                       array( 'hallo', 'Help:Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
-                       array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
-                       array( serialize('hallo'), 'Dummy:Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, serialize('hallo'), false ),
-
-                       array( 'hallo', 'Help:Test', CONTENT_MODEL_WIKITEXT, "testing", null, null, true ),
-                       array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, "testing", null, null, true ),
-                       array( 'hallo', 'Dummy:Test', CONTENT_MODEL_JAVASCRIPT, "testing", null, null, true ),
-               );
-       }
-
-       /**
-        * @dataProvider dataMakeContent
-        */
-       public function testMakeContent( $data, $title, $modelId, $format, $expectedModelId, $expectedNativeData, $shouldFail ) {
-               global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers;
-
-               $title = Title::newFromText( $title );
-
-               try {
-                       $content = ContentHandler::makeContent( $data, $title, $modelId, $format );
-
-                       if ( $shouldFail ) $this->fail( "ContentHandler::makeContent should have failed!" );
-
-                       $this->assertEquals( $expectedModelId, $content->getModel(), 'bad model id' );
-                       $this->assertEquals( $expectedNativeData, $content->getNativeData(), 'bads native data' );
-               } catch ( MWException $ex ) {
-                       if ( !$shouldFail ) $this->fail( "ContentHandler::makeContent failed unexpectedly: " . $ex->getMessage() );
-                       else $this->assertTrue( true ); // dummy, so we don't get the "test did not perform any assertions" message.
-               }
-
-       }
-
-       public function testSupportsSections() {
-               $this->markTestIncomplete( "not yet implemented" );
-       }
-
-       public function testRunLegacyHooks() {
-               Hooks::register( 'testRunLegacyHooks', __CLASS__ . '::dummyHookHandler' );
-
-               $content = new WikitextContent( 'test text' );
-               $ok = ContentHandler::runLegacyHooks( 'testRunLegacyHooks', array( 'foo', &$content, 'bar' ), false );
-
-               $this->assertTrue( $ok, "runLegacyHooks should have returned true" );
-               $this->assertEquals( "TEST TEXT", $content->getNativeData() );
-       }
-
-       public static function dummyHookHandler( $foo, &$text, $bar ) {
-               if ( $text === null || $text === false ) {
-                       return false;
-               }
-
-               $text = strtoupper( $text );
-
-               return true;
-       }
-}
-
-class DummyContentHandlerForTesting extends ContentHandler {
-
-       public function __construct( $dataModel ) {
-               parent::__construct( $dataModel, array( "testing" ) );
-       }
-
-       /**
-        * Serializes Content object of the type supported by this ContentHandler.
-        *
-        * @param Content $content the Content object to serialize
-        * @param null $format the desired serialization format
-        * @return String serialized form of the content
-        */
-       public function serializeContent( Content $content, $format = null )
-       {
-          return $content->serialize();
-       }
-
-       /**
-        * Unserializes a Content object of the type supported by this ContentHandler.
-        *
-        * @param $blob String serialized form of the content
-        * @param null $format the format used for serialization
-        * @return Content the Content object created by deserializing $blob
-        */
-       public function unserializeContent( $blob, $format = null )
-       {
-               $d = unserialize( $blob );
-               return new DummyContentForTesting( $d );
-       }
-
-       /**
-        * Creates an empty Content object of the type supported by this ContentHandler.
-        *
-        */
-       public function makeEmptyContent()
-       {
-               return new DummyContentForTesting( '' );
-       }
-}
-
-class DummyContentForTesting extends AbstractContent {
-
-       public function __construct( $data ) {
-               parent::__construct( "testing" );
-
-               $this->data = $data;
-       }
-
-       public function serialize( $format = null ) {
-               return serialize( $this->data );
-       }
-
-       /**
-        * @return String a string representing the content in a way useful for building a full text search index.
-        *         If no useful representation exists, this method returns an empty string.
-        */
-       public function getTextForSearchIndex() {
-               return '';
-       }
-
-       /**
-        * @return String the wikitext to include when another page includes this  content, or false if the content is not
-        *         includable in a wikitext page.
-        */
-       public function getWikitextForTransclusion() {
-               return false;
-       }
-
-       /**
-        * Returns a textual representation of the content suitable for use in edit summaries and log messages.
-        *
-        * @param int $maxlength maximum length of the summary text
-        * @return String the summary text
-        */
-       public function getTextForSummary( $maxlength = 250 ) {
-               return '';
-       }
-
-       /**
-        * Returns native represenation of the data. Interpretation depends on the data model used,
-        * as given by getDataModel().
-        *
-        * @return mixed the native representation of the content. Could be a string, a nested array
-        *         structure, an object, a binary blob... anything, really.
-        */
-       public function getNativeData()
-       {
-               return $this->data;
-       }
-
-       /**
-        * returns the content's nominal size in bogo-bytes.
-        *
-        * @return int
-        */
-       public function getSize() {
-               return strlen( $this->data );
-       }
-
-       /**
-        * Return a copy of this Content object. The following must be true for the object returned
-        * if $copy = $original->copy()
-        *
-        * * get_class($original) === get_class($copy)
-        * * $original->getModel() === $copy->getModel()
-        * * $original->equals( $copy )
-        *
-        * If and only if the Content object is imutable, the copy() method can and should
-        * return $this. That is,  $copy === $original may be true, but only for imutable content
-        * objects.
-        *
-        * @return Content. A copy of this object
-        */
-       public function copy() {
-               return $this;
-       }
-
-       /**
-        * Returns true if this content is countable as a "real" wiki page, provided
-        * that it's also in a countable location (e.g. a current revision in the main namespace).
-        *
-        * @param $hasLinks Bool: if it is known whether this content contains links, provide this information here,
-        *                        to avoid redundant parsing to find out.
-        * @return boolean
-        */
-       public function isCountable( $hasLinks = null ) {
-               return false;
-       }
-
-       /**
-        * @param Title $title
-        * @param null $revId
-        * @param null|ParserOptions $options
-        * @param Boolean $generateHtml whether to generate Html (default: true). If false,
-        *        the result of calling getText() on the ParserOutput object returned by
-        *        this method is undefined.
-        *
-        * @return ParserOutput
-        */
-       public function getParserOutput( Title $title, $revId = null, ParserOptions $options = NULL, $generateHtml = true ) {
-               return new ParserOutput( $this->getNativeData() );
-       }
-}
diff --git a/tests/phpunit/includes/CssContentTest.php b/tests/phpunit/includes/CssContentTest.php
deleted file mode 100644 (file)
index b6e8d29..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- *
- * @group Database
- *        ^--- needed, because we do need the database to test link updates
- */
-class CssContentTest extends JavascriptContentTest {
-
-       public function newContent( $text ) {
-               return new CssContent( $text );
-       }
-
-
-       public function dataGetParserOutput() {
-               return array(
-                       array(
-                               "MediaWiki:Test.css",
-                               null,
-                               "hello <world>\n",
-                               "<pre class=\"mw-code mw-css\" dir=\"ltr\">\nhello &lt;world&gt;\n\n</pre>" ),
-
-                       array(
-                               "MediaWiki:Test.css",
-                               null,
-                               "/* hello [[world]] */\n",
-                               "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n/* hello [[world]] */\n\n</pre>",
-                               array( 'Links' => array( // NOTE: assumes default settings for $wgTextModelsToParse
-                                       array( 'World' => 0 ) ) ) ),
-
-                       // @todo: more...?
-               );
-       }
-
-
-       # =================================================================================================================
-
-       public function testGetModel() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_CSS, $content->getModel() );
-       }
-
-       public function testGetContentHandler() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_CSS, $content->getContentHandler()->getModelID() );
-       }
-
-       public function dataEquals( ) {
-               return array(
-                       array( new CssContent( "hallo" ), null, false ),
-                       array( new CssContent( "hallo" ), new CssContent( "hallo" ), true ),
-                       array( new CssContent( "hallo" ), new WikitextContent( "hallo" ), false ),
-                       array( new CssContent( "hallo" ), new CssContent( "HALLO" ), false ),
-               );
-       }
-
-}
diff --git a/tests/phpunit/includes/JavascriptContentTest.php b/tests/phpunit/includes/JavascriptContentTest.php
deleted file mode 100644 (file)
index d3810af..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- *
- * @group Database
- *        ^--- needed, because we do need the database to test link updates
- */
-class JavascriptContentTest extends TextContentTest {
-
-       public function newContent( $text ) {
-               return new JavascriptContent( $text );
-       }
-
-
-       public function dataGetParserOutput() {
-               return array(
-                       array(
-                               "MediaWiki:Test.js",
-                               null,
-                               "hello <world>\n",
-                               "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello &lt;world&gt;\n\n</pre>" ),
-
-                       array(
-                               "MediaWiki:Test.js",
-                               null,
-                               "hello(); // [[world]]\n",
-                               "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello(); // [[world]]\n\n</pre>",
-                               array( 'Links' => array( // NOTE: assumes default settings for $wgTextModelsToParse
-                                                       array( 'World' => 0 ) ) ) ),
-
-                       // @todo: more...?
-               );
-       }
-
-       public function dataGetSection() {
-               return array(
-                       array( WikitextContentTest::$sections,
-                              "0",
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "2",
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "8",
-                              null
-                       ),
-               );
-       }
-
-       public function dataReplaceSection() {
-               return array(
-                       array( WikitextContentTest::$sections,
-                              "0",
-                              "No more",
-                              null,
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "",
-                              "No more",
-                              null,
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "2",
-                              "== TEST ==\nmore fun",
-                              null,
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "8",
-                              "No more",
-                              null,
-                              null
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "new",
-                              "No more",
-                              "New",
-                              null
-                       ),
-               );
-       }
-
-       public function testAddSectionHeader( ) {
-               $content = $this->newContent( 'hello world' );
-               $c = $content->addSectionHeader( 'test' );
-
-               $this->assertTrue( $content->equals( $c ) );
-       }
-
-       // XXX: currently, preSaveTransform is applied to scripts. this may change or become optional.
-       public function dataPreSaveTransform() {
-               return array(
-                       array( 'hello this is ~~~',
-                               "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
-                       ),
-                       array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
-                               'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
-                       ),
-                       array( " Foo \n ",
-                               " Foo",
-                       ),
-               );
-       }
-
-       public function dataPreloadTransform() {
-               return array(
-                       array( 'hello this is ~~~',
-                              "hello this is ~~~",
-                       ),
-                       array( 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
-                              'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
-                       ),
-               );
-       }
-
-       public function dataGetRedirectTarget() {
-               return array(
-                       array( '#REDIRECT [[Test]]',
-                              null,
-                       ),
-                       array( '#REDIRECT Test',
-                              null,
-                       ),
-                       array( '* #REDIRECT [[Test]]',
-                              null,
-                       ),
-               );
-       }
-
-       /**
-        * @todo: test needs database!
-        */
-       /*
-       public function getRedirectChain() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectArray( $text );
-       }
-       */
-
-       /**
-        * @todo: test needs database!
-        */
-       /*
-       public function getUltimateRedirectTarget() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectRecurse( $text );
-       }
-       */
-
-
-       public function dataIsCountable() {
-               return array(
-                       array( '',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'comma',
-                              false
-                       ),
-                       array( 'Foo, bar',
-                              null,
-                              'comma',
-                              false
-                       ),
-                       array( 'Foo',
-                              null,
-                              'link',
-                              false
-                       ),
-                       array( 'Foo [[bar]]',
-                              null,
-                              'link',
-                              false
-                       ),
-                       array( 'Foo',
-                              true,
-                              'link',
-                              false
-                       ),
-                       array( 'Foo [[bar]]',
-                              false,
-                              'link',
-                              false
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'any',
-                              true
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'comma',
-                              false
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'link',
-                              false
-                       ),
-               );
-       }
-
-       public function dataGetTextForSummary() {
-               return array(
-                       array( "hello\nworld.",
-                              16,
-                              'hello world.',
-                       ),
-                       array( 'hello world.',
-                              8,
-                              'hello...',
-                       ),
-                       array( '[[hello world]].',
-                              8,
-                              '[[hel...',
-                       ),
-               );
-       }
-
-       public function testMatchMagicWord( ) {
-               $mw = MagicWord::get( "staticredirect" );
-
-               $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
-               $this->assertFalse( $content->matchMagicWord( $mw ), "should not have matched magic word, since it's not wikitext" );
-       }
-
-       public function testUpdateRedirect( ) {
-               $target = Title::newFromText( "testUpdateRedirect_target" );
-
-               $content = $this->newContent( "#REDIRECT [[Someplace]]" );
-               $newContent = $content->updateRedirect( $target );
-
-               $this->assertTrue( $content->equals( $newContent ), "content should be unchanged since it's not wikitext" );
-       }
-
-       # =================================================================================================================
-
-       public function testGetModel() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $content->getModel() );
-       }
-
-       public function testGetContentHandler() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $content->getContentHandler()->getModelID() );
-       }
-
-       public function dataEquals( ) {
-               return array(
-                       array( new JavascriptContent( "hallo" ), null, false ),
-                       array( new JavascriptContent( "hallo" ), new JavascriptContent( "hallo" ), true ),
-                       array( new JavascriptContent( "hallo" ), new CssContent( "hallo" ), false ),
-                       array( new JavascriptContent( "hallo" ), new JavascriptContent( "HALLO" ), false ),
-               );
-       }
-
-}
diff --git a/tests/phpunit/includes/TextContentTest.php b/tests/phpunit/includes/TextContentTest.php
deleted file mode 100644 (file)
index b80af29..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- *
- * @group Database
- *        ^--- needed, because we do need the database to test link updates
- */
-class TextContentTest extends MediaWikiTestCase {
-
-       public function setup() {
-               global $wgUser;
-
-               parent::setUp();
-
-               // anon user
-               $wgUser = new User();
-               $wgUser->setName( '127.0.0.1' );
-
-               $this->context = new RequestContext( new FauxRequest() );
-               $this->context->setTitle( Title::newFromText( "Test" ) );
-               $this->context->setUser( $wgUser );
-       }
-
-       public function newContent( $text ) {
-               return new TextContent( $text );
-       }
-
-
-       public function dataGetParserOutput() {
-               return array(
-                       array(
-                               "TextContentTest_testGetParserOutput",
-                               CONTENT_MODEL_TEXT,
-                               "hello ''world'' & [[stuff]]\n", "hello ''world'' &amp; [[stuff]]",
-                               array( 'Links' => array() ) ),
-                       // @todo: more...?
-               );
-       }
-
-       /**
-        * @dataProvider dataGetParserOutput
-        */
-       public function testGetParserOutput( $title, $model, $text, $expectedHtml, $expectedFields = null ) {
-               $title = Title::newFromText( $title );
-               $content = ContentHandler::makeContent( $text, $title, $model );
-
-               $po = $content->getParserOutput( $title );
-
-               $html = $po->getText();
-               $html = preg_replace( '#<!--.*?-->#sm', '', $html ); // strip comments
-
-               $this->assertEquals( $expectedHtml, trim( $html ) );
-
-               if ( $expectedFields ) {
-                       foreach ( $expectedFields as $field => $exp ) {
-                               $f = 'get' . ucfirst( $field );
-                               $v = call_user_func( array( $po, $f ) );
-
-                               if ( is_array( $exp ) ) {
-                                       $this->assertArrayEquals( $exp, $v );
-                               } else {
-                                       $this->assertEquals( $exp, $v );
-                               }
-                       }
-               }
-
-               // @todo: assert more properties
-       }
-
-       public function dataPreSaveTransform() {
-               return array(
-                       array( #0: no signature resolution
-                               "hello this is ~~~",
-                               "hello this is ~~~",
-                       ),
-                       array( #1: rtrim
-                               " Foo \n ",
-                               " Foo",
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataPreSaveTransform
-        */
-       public function testPreSaveTransform( $text, $expected ) {
-               global $wgContLang;
-
-               $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
-
-               $content = $this->newContent( $text );
-               $content = $content->preSaveTransform( $this->context->getTitle(), $this->context->getUser(), $options );
-
-               $this->assertEquals( $expected, $content->getNativeData() );
-       }
-
-       public function dataPreloadTransform() {
-               return array(
-                       array( 'hello this is ~~~',
-                              "hello this is ~~~",
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataPreloadTransform
-        */
-       public function testPreloadTransform( $text, $expected ) {
-               global $wgContLang;
-               $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
-
-               $content = $this->newContent( $text );
-               $content = $content->preloadTransform( $this->context->getTitle(), $options );
-
-               $this->assertEquals( $expected, $content->getNativeData() );
-       }
-
-       public function dataGetRedirectTarget() {
-               return array(
-                       array( '#REDIRECT [[Test]]',
-                               null,
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetRedirectTarget
-        */
-       public function testGetRedirectTarget( $text, $expected ) {
-               $content = $this->newContent( $text );
-               $t = $content->getRedirectTarget( );
-
-               if ( is_null( $expected ) ) {
-                       $this->assertNull( $t, "text should not have generated a redirect target: $text" );
-               } else {
-                       $this->assertEquals( $expected, $t->getPrefixedText() );
-               }
-       }
-
-       /**
-        * @dataProvider dataGetRedirectTarget
-        */
-       public function isRedirect( $text, $expected ) {
-               $content = $this->newContent( $text );
-
-               $this->assertEquals( !is_null($expected), $content->isRedirect() );
-       }
-
-
-       /**
-        * @todo: test needs database! Should be done by a test class in the Database group.
-        */
-       /*
-       public function getRedirectChain() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectArray( $text );
-       }
-       */
-
-       /**
-        * @todo: test needs database! Should be done by a test class in the Database group.
-        */
-       /*
-       public function getUltimateRedirectTarget() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectRecurse( $text );
-       }
-       */
-
-
-       public function dataIsCountable() {
-               return array(
-                       array( '',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'comma',
-                              false
-                       ),
-                       array( 'Foo, bar',
-                              null,
-                              'comma',
-                              false
-                       ),
-               );
-       }
-
-
-       /**
-        * @dataProvider dataIsCountable
-        * @group Database
-        */
-       public function testIsCountable( $text, $hasLinks, $mode, $expected ) {
-               global $wgArticleCountMethod;
-
-               $old = $wgArticleCountMethod;
-               $wgArticleCountMethod = $mode;
-
-               $content = $this->newContent( $text );
-
-               $v = $content->isCountable( $hasLinks, $this->context->getTitle() );
-               $wgArticleCountMethod = $old;
-
-               $this->assertEquals( $expected, $v, "isCountable() returned unexpected value " . var_export( $v, true )
-                                                   . " instead of " . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
-       }
-
-       public function dataGetTextForSummary() {
-               return array(
-                       array( "hello\nworld.",
-                              16,
-                              'hello world.',
-                       ),
-                       array( 'hello world.',
-                              8,
-                              'hello...',
-                       ),
-                       array( '[[hello world]].',
-                              8,
-                              '[[hel...',
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetTextForSummary
-        */
-       public function testGetTextForSummary( $text, $maxlength, $expected ) {
-               $content = $this->newContent( $text );
-
-               $this->assertEquals( $expected, $content->getTextForSummary( $maxlength ) );
-       }
-
-
-       public function testGetTextForSearchIndex( ) {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( "hello world.", $content->getTextForSearchIndex() );
-       }
-
-       public function testCopy() {
-               $content = $this->newContent( "hello world." );
-               $copy = $content->copy();
-
-               $this->assertTrue( $content->equals( $copy ), "copy must be equal to original" );
-               $this->assertEquals( "hello world.", $copy->getNativeData() );
-       }
-
-       public function testGetSize( ) {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( 12, $content->getSize() );
-       }
-
-       public function testGetNativeData( ) {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( "hello world.", $content->getNativeData() );
-       }
-
-       public function testGetWikitextForTransclusion( ) {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( "hello world.", $content->getWikitextForTransclusion() );
-       }
-
-       # =================================================================================================================
-
-       public function testGetModel() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_TEXT, $content->getModel() );
-       }
-
-       public function testGetContentHandler() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_TEXT, $content->getContentHandler()->getModelID() );
-       }
-
-       public function dataIsEmpty( ) {
-               return array(
-                       array( '', true ),
-                       array( '  ', false ),
-                       array( '0', false ),
-                       array( 'hallo welt.', false ),
-               );
-       }
-
-       /**
-        * @dataProvider dataIsEmpty
-        */
-       public function testIsEmpty( $text, $empty ) {
-               $content = $this->newContent( $text );
-
-               $this->assertEquals( $empty, $content->isEmpty() );
-       }
-
-       public function dataEquals( ) {
-               return array(
-                       array( new TextContent( "hallo" ), null, false ),
-                       array( new TextContent( "hallo" ), new TextContent( "hallo" ), true ),
-                       array( new TextContent( "hallo" ), new JavascriptContent( "hallo" ), false ),
-                       array( new TextContent( "hallo" ), new WikitextContent( "hallo" ), false ),
-                       array( new TextContent( "hallo" ), new TextContent( "HALLO" ), false ),
-               );
-       }
-
-       /**
-        * @dataProvider dataEquals
-        */
-       public function testEquals( Content $a, Content $b = null, $equal = false ) {
-               $this->assertEquals( $equal, $a->equals( $b ) );
-       }
-
-       public function dataGetDeletionUpdates() {
-               return array(
-                       array("TextContentTest_testGetSecondaryDataUpdates_1",
-                               CONTENT_MODEL_TEXT, "hello ''world''\n",
-                               array( )
-                       ),
-                       array("TextContentTest_testGetSecondaryDataUpdates_2",
-                               CONTENT_MODEL_TEXT, "hello [[world test 21344]]\n",
-                               array( )
-                       ),
-                       // @todo: more...?
-               );
-       }
-
-       /**
-        * @dataProvider dataGetDeletionUpdates
-        */
-       public function testDeletionUpdates( $title, $model, $text, $expectedStuff ) {
-               $title = Title::newFromText( $title );
-               $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
-
-               $content = ContentHandler::makeContent( $text, $title, $model );
-
-               $updates = $content->getDeletionUpdates( WikiPage::factory( $title ) );
-
-               // make updates accessible by class name
-               foreach ( $updates as $update ) {
-                       $class = get_class( $update );
-                       $updates[ $class ] = $update;
-               }
-
-               if ( !$expectedStuff ) {
-                       $this->assertTrue( true ); // make phpunit happy
-                       return;
-               }
-
-               foreach ( $expectedStuff as $class => $fieldValues ) {
-                       $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
-
-                       $update = $updates[ $class ];
-
-                       foreach ( $fieldValues as $field => $value ) {
-                               $v = $update->$field; #if the field doesn't exist, just crash and burn
-                               $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
-                       }
-               }
-       }
-
-}
diff --git a/tests/phpunit/includes/WikitextContentHandlerTest.php b/tests/phpunit/includes/WikitextContentHandlerTest.php
deleted file mode 100644 (file)
index 8db96d1..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- */
-class WikitextContentHandlerTest extends MediaWikiTestCase {
-
-       /**
-        * @var ContentHandler
-        */
-       var $handler;
-
-       public function setup() {
-               parent::setUp();
-               $this->handler = ContentHandler::getForModelID( CONTENT_MODEL_WIKITEXT );
-       }
-
-       public function testSerializeContent( ) {
-               $content = new WikitextContent( 'hello world' );
-
-               $this->assertEquals( 'hello world', $this->handler->serializeContent( $content ) );
-               $this->assertEquals( 'hello world', $this->handler->serializeContent( $content, CONTENT_FORMAT_WIKITEXT ) );
-
-               try {
-                       $this->handler->serializeContent( $content, 'dummy/foo' );
-                       $this->fail( "serializeContent() should have failed on unknown format" );
-               } catch ( MWException $e ) {
-                       // ok, as expected
-               }
-       }
-
-       public function testUnserializeContent( ) {
-               $content = $this->handler->unserializeContent( 'hello world' );
-               $this->assertEquals( 'hello world', $content->getNativeData() );
-
-               $content = $this->handler->unserializeContent( 'hello world', CONTENT_FORMAT_WIKITEXT );
-               $this->assertEquals( 'hello world', $content->getNativeData() );
-
-               try {
-                       $this->handler->unserializeContent( 'hello world', 'dummy/foo' );
-                       $this->fail( "unserializeContent() should have failed on unknown format" );
-               } catch ( MWException $e ) {
-                       // ok, as expected
-               }
-       }
-
-       public function testMakeEmptyContent() {
-               $content = $this->handler->makeEmptyContent();
-
-               $this->assertTrue( $content->isEmpty() );
-               $this->assertEquals( '', $content->getNativeData() );
-       }
-
-       public function dataIsSupportedFormat( ) {
-               return array(
-                       array( null, true ),
-                       array( CONTENT_FORMAT_WIKITEXT, true ),
-                       array( 99887766, false ),
-               );
-       }
-
-       /**
-        * @dataProvider dataIsSupportedFormat
-        */
-       public function testIsSupportedFormat( $format, $supported ) {
-               $this->assertEquals( $supported, $this->handler->isSupportedFormat( $format ) );
-       }
-
-       public function dataMerge3( ) {
-               return array(
-                       array( "first paragraph
-
-                                       second paragraph\n",
-
-                                       "FIRST paragraph
-
-                                       second paragraph\n",
-
-                                       "first paragraph
-
-                                       SECOND paragraph\n",
-
-                                       "FIRST paragraph
-
-                                       SECOND paragraph\n",
-                       ),
-
-                       array( "first paragraph
-                                       second paragraph\n",
-
-                                  "Bla bla\n",
-
-                                  "Blubberdibla\n",
-
-                                  false,
-                       ),
-
-               );
-       }
-
-       /**
-        * @dataProvider dataMerge3
-        */
-       public function testMerge3( $old, $mine, $yours, $expected ) {
-               global $wgDiff3;
-
-               if ( !$wgDiff3 ) {
-                       $this->markTestSkipped( "Can't test merge3(), since \$wgDiff3 is not configured" );
-               }
-
-               if ( !file_exists( $wgDiff3 ) ) {
-                       #XXX: this sucks, since it uses arcane internal knowledge about TextContentHandler::merge3 and wfMerge.
-                       $this->markTestSkipped( "Can't test merge3(), since \$wgDiff3 is misconfigured: can't find $wgDiff3" );
-               }
-
-               // test merge
-               $oldContent = new WikitextContent( $old );
-               $myContent = new WikitextContent( $mine );
-               $yourContent = new WikitextContent( $yours );
-
-               $merged = $this->handler->merge3( $oldContent, $myContent, $yourContent );
-
-               $this->assertEquals( $expected, $merged ? $merged->getNativeData() : $merged );
-       }
-
-       public function dataGetAutosummary( ) {
-               return array(
-                       array(
-                               'Hello there, world!',
-                               '#REDIRECT [[Foo]]',
-                               0,
-                               '/^Redirected page .*Foo/'
-                       ),
-
-                       array(
-                               null,
-                               'Hello world!',
-                               EDIT_NEW,
-                               '/^Created page .*Hello/'
-                       ),
-
-                       array(
-                               'Hello there, world!',
-                               '',
-                               0,
-                               '/^Blanked/'
-                       ),
-
-                       array(
-                               'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
-                               labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
-                               ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
-                               'Hello world!',
-                               0,
-                               '/^Replaced .*Hello/'
-                       ),
-
-                       array(
-                               'foo',
-                               'bar',
-                               0,
-                               '/^$/'
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetAutoSummary
-        */
-       public function testGetAutosummary( $old, $new, $flags, $expected ) {
-               global $wgLanguageCode, $wgContLang;
-
-               $oldContent = is_null( $old ) ? null : new WikitextContent( $old );
-               $newContent = is_null( $new ) ? null : new WikitextContent( $new );
-
-               $summary = $this->handler->getAutosummary( $oldContent, $newContent, $flags );
-
-               $this->assertTrue( (bool)preg_match( $expected, $summary ), "Autosummary didn't match expected pattern $expected: $summary" );
-       }
-
-       /**
-        * @todo Text case requires database, should be done by a test class in the Database group
-        */
-       /*
-       public function testGetAutoDeleteReason( Title $title, &$hasHistory ) {
-       }
-       */
-
-       /**
-        * @todo Text case requires database, should be done by a test class in the Database group
-        */
-       /*
-       public function testGetUndoContent( Revision $current, Revision $undo, Revision $undoafter = null ) {
-       }
-       */
-
-}
diff --git a/tests/phpunit/includes/WikitextContentTest.php b/tests/phpunit/includes/WikitextContentTest.php
deleted file mode 100644 (file)
index c1332a6..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-<?php
-
-/**
- * @group ContentHandler
- *
- * @group Database
- *        ^--- needed, because we do need the database to test link updates
- */
-class WikitextContentTest extends TextContentTest {
-
-       public function newContent( $text ) {
-               return new WikitextContent( $text );
-       }
-
-       public function dataGetParserOutput() {
-               return array(
-                       array("WikitextContentTest_testGetParserOutput", CONTENT_MODEL_WIKITEXT, "hello ''world''\n", "<p>hello <i>world</i>\n</p>"),
-                       // @todo: more...?
-               );
-       }
-
-       public function dataGetSecondaryDataUpdates() {
-               return array(
-                       array( "WikitextContentTest_testGetSecondaryDataUpdates_1",
-                               CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
-                               array( 'LinksUpdate' => array(  'mRecursive' => true,
-                                                               'mLinks' => array() ) )
-                       ),
-                       array( "WikitextContentTest_testGetSecondaryDataUpdates_2",
-                               CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
-                               array( 'LinksUpdate' => array(  'mRecursive' => true,
-                                                               'mLinks' => array( array( 'World_test_21344' => 0 ) ) ) )
-                       ),
-                       // @todo: more...?
-               );
-       }
-
-       /**
-        * @dataProvider dataGetSecondaryDataUpdates
-        * @group Database
-        */
-       public function testGetSecondaryDataUpdates( $title, $model, $text, $expectedStuff ) {
-               $title = Title::newFromText( $title );
-               $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
-
-               $content = ContentHandler::makeContent( $text, $title, $model );
-
-               $updates = $content->getSecondaryDataUpdates( $title );
-
-               // make updates accessible by class name
-               foreach ( $updates as $update ) {
-                       $class = get_class( $update );
-                       $updates[$class] = $update;
-               }
-
-               foreach ( $expectedStuff as $class => $fieldValues ) {
-                       $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
-
-                       $update = $updates[$class];
-
-                       foreach ( $fieldValues as $field => $value ) {
-                               $v = $update->$field; #if the field doesn't exist, just crash and burn
-                               $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
-                       }
-               }
-       }
-
-
-       static $sections =
-
-"Intro
-
-== stuff ==
-hello world
-
-== test ==
-just a test
-
-== foo ==
-more stuff
-";
-
-       public function dataGetSection() {
-               return array(
-                       array( WikitextContentTest::$sections,
-                                       "0",
-                                       "Intro"
-                       ),
-                       array( WikitextContentTest::$sections,
-                                       "2",
-"== test ==
-just a test"
-                       ),
-                       array( WikitextContentTest::$sections,
-                                       "8",
-                                       false
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataGetSection
-        */
-       public function testGetSection( $text, $sectionId, $expectedText ) {
-               $content = $this->newContent( $text );
-
-               $sectionContent = $content->getSection( $sectionId );
-               if ( is_object( $sectionContent ) ) {
-                       $sectionText = $sectionContent->getNativeData();
-               } else {
-                       $sectionText = $sectionContent;
-               }
-
-               $this->assertEquals( $expectedText, $sectionText );
-       }
-
-       public function dataReplaceSection() {
-               return array(
-                       array( WikitextContentTest::$sections,
-                              "0",
-                              "No more",
-                              null,
-                              trim( preg_replace( '/^Intro/sm', 'No more', WikitextContentTest::$sections ) )
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "",
-                              "No more",
-                              null,
-                              "No more"
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "2",
-                              "== TEST ==\nmore fun",
-                              null,
-                              trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikitextContentTest::$sections ) )
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "8",
-                              "No more",
-                              null,
-                              WikitextContentTest::$sections
-                       ),
-                       array( WikitextContentTest::$sections,
-                              "new",
-                              "No more",
-                              "New",
-                              trim( WikitextContentTest::$sections ) . "\n\n\n== New ==\n\nNo more"
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider dataReplaceSection
-        */
-       public function testReplaceSection( $text, $section, $with, $sectionTitle, $expected ) {
-               $content = $this->newContent( $text );
-               $c = $content->replaceSection( $section, $this->newContent( $with ), $sectionTitle );
-
-               $this->assertEquals( $expected, is_null( $c ) ? null : $c->getNativeData() );
-       }
-
-       public function testAddSectionHeader( ) {
-               $content = $this->newContent( 'hello world' );
-               $content = $content->addSectionHeader( 'test' );
-
-               $this->assertEquals( "== test ==\n\nhello world", $content->getNativeData() );
-       }
-
-       public function dataPreSaveTransform() {
-               return array(
-                       array( 'hello this is ~~~',
-                              "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
-                       ),
-                       array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
-                              'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
-                       ),
-                       array( // rtrim
-                               " Foo \n ",
-                               " Foo",
-                       ),
-               );
-       }
-
-       public function dataPreloadTransform() {
-               return array(
-                       array( 'hello this is ~~~',
-                              "hello this is ~~~",
-                       ),
-                       array( 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
-                              'hello \'\'this\'\' is bar',
-                       ),
-               );
-       }
-
-       public function dataGetRedirectTarget() {
-               return array(
-                       array( '#REDIRECT [[Test]]',
-                              'Test',
-                       ),
-                       array( '#REDIRECT Test',
-                              null,
-                       ),
-                       array( '* #REDIRECT [[Test]]',
-                              null,
-                       ),
-               );
-       }
-
-       public function dataGetTextForSummary() {
-               return array(
-                       array( "hello\nworld.",
-                               16,
-                               'hello world.',
-                       ),
-                       array( 'hello world.',
-                               8,
-                               'hello...',
-                       ),
-                       array( '[[hello world]].',
-                               8,
-                               'hel...',
-                       ),
-               );
-       }
-
-       /**
-        * @todo: test needs database! Should be done by a test class in the Database group.
-        */
-       /*
-       public function getRedirectChain() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectArray( $text );
-       }
-       */
-
-       /**
-        * @todo: test needs database! Should be done by a test class in the Database group.
-        */
-       /*
-       public function getUltimateRedirectTarget() {
-               $text = $this->getNativeData();
-               return Title::newFromRedirectRecurse( $text );
-       }
-       */
-
-
-       public function dataIsCountable() {
-               return array(
-                       array( '',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'any',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'comma',
-                              false
-                       ),
-                       array( 'Foo, bar',
-                              null,
-                              'comma',
-                              true
-                       ),
-                       array( 'Foo',
-                              null,
-                              'link',
-                              false
-                       ),
-                       array( 'Foo [[bar]]',
-                              null,
-                              'link',
-                              true
-                       ),
-                       array( 'Foo',
-                              true,
-                              'link',
-                              true
-                       ),
-                       array( 'Foo [[bar]]',
-                              false,
-                              'link',
-                              false
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'any',
-                              false
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'comma',
-                              false
-                       ),
-                       array( '#REDIRECT [[bar]]',
-                              true,
-                              'link',
-                              false
-                       ),
-               );
-       }
-
-       public function testMatchMagicWord( ) {
-               $mw = MagicWord::get( "staticredirect" );
-
-               $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
-               $this->assertTrue( $content->matchMagicWord( $mw ), "should have matched magic word" );
-
-               $content = $this->newContent( "#REDIRECT [[FOO]]" );
-               $this->assertFalse( $content->matchMagicWord( $mw ), "should not have matched magic word" );
-       }
-
-       public function testUpdateRedirect( ) {
-               $target = Title::newFromText( "testUpdateRedirect_target" );
-
-               // test with non-redirect page
-               $content = $this->newContent( "hello world." );
-               $newContent = $content->updateRedirect( $target );
-
-               $this->assertTrue( $content->equals( $newContent ), "content should be unchanged" );
-
-               // test with actual redirect
-               $content = $this->newContent( "#REDIRECT [[Someplace]]" );
-               $newContent = $content->updateRedirect( $target );
-
-               $this->assertFalse( $content->equals( $newContent ), "content should have changed" );
-               $this->assertTrue( $newContent->isRedirect(), "new content should be a redirect" );
-
-               $this->assertEquals( $target->getFullText(), $newContent->getRedirectTarget()->getFullText() );
-       }
-
-       # =================================================================================================================
-
-       public function testGetModel() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getModel() );
-       }
-
-       public function testGetContentHandler() {
-               $content = $this->newContent( "hello world." );
-
-               $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
-       }
-
-       public function dataEquals( ) {
-               return array(
-                       array( new WikitextContent( "hallo" ), null, false ),
-                       array( new WikitextContent( "hallo" ), new WikitextContent( "hallo" ), true ),
-                       array( new WikitextContent( "hallo" ), new JavascriptContent( "hallo" ), false ),
-                       array( new WikitextContent( "hallo" ), new TextContent( "hallo" ), false ),
-                       array( new WikitextContent( "hallo" ), new WikitextContent( "HALLO" ), false ),
-               );
-       }
-
-       public function dataGetDeletionUpdates() {
-               return array(
-                       array("WikitextContentTest_testGetSecondaryDataUpdates_1",
-                               CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
-                               array( 'LinksDeletionUpdate' => array( ) )
-                       ),
-                       array("WikitextContentTest_testGetSecondaryDataUpdates_2",
-                               CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
-                               array( 'LinksDeletionUpdate' => array( ) )
-                       ),
-                       // @todo: more...?
-               );
-       }
-
-}
diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php
new file mode 100644 (file)
index 0000000..60baedc
--- /dev/null
@@ -0,0 +1,423 @@
+<?php
+
+/**
+ * @group ContentHandler
+ * @group Database
+ *
+ * @note Declare that we are using the database, because otherwise we'll fail in the "databaseless" test run.
+ * This is because the LinkHolderArray used by the parser needs database access.
+ *
+ */
+class ContentHandlerTest extends MediaWikiTestCase {
+
+       public function setup() {
+               global $wgContLang;
+               parent::setup();
+
+               $this->setMwGlobals( array(
+                       'wgExtraNamespaces' => array(
+                               12312 => 'Dummy',
+                               12313 => 'Dummy_talk',
+                       ),
+                       // The below tests assume that namespaces not mentioned here (Help, User, MediaWiki, ..)
+                       // default to CONTENT_MODEL_WIKITEXT.
+                       'wgNamespaceContentModels' => array(
+                               12312 => 'testing',
+                       ),
+                       'wgContentHandlers' => array(
+                               CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler',
+                               CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler',
+                               CONTENT_MODEL_CSS => 'CssContentHandler',
+                               CONTENT_MODEL_TEXT => 'TextContentHandler',
+                               'testing' => 'DummyContentHandlerForTesting',
+                       ),
+               ) );
+
+               // Reset namespace cache
+               MWNamespace::getCanonicalNamespaces( true );
+               $wgContLang->resetNamespaces();
+       }
+
+       public function tearDown() {
+               global $wgContLang;
+
+               // Reset namespace cache
+               MWNamespace::getCanonicalNamespaces( true );
+               $wgContLang->resetNamespaces();
+
+               parent::tearDown();
+       }
+
+       public static function dataGetDefaultModelFor() {
+               return array(
+                       array( 'Help:Foo', CONTENT_MODEL_WIKITEXT ),
+                       array( 'Help:Foo.js', CONTENT_MODEL_WIKITEXT ),
+                       array( 'Help:Foo/bar.js', CONTENT_MODEL_WIKITEXT ),
+                       array( 'User:Foo', CONTENT_MODEL_WIKITEXT ),
+                       array( 'User:Foo.js', CONTENT_MODEL_WIKITEXT ),
+                       array( 'User:Foo/bar.js', CONTENT_MODEL_JAVASCRIPT ),
+                       array( 'User:Foo/bar.css', CONTENT_MODEL_CSS ),
+                       array( 'User talk:Foo/bar.css', CONTENT_MODEL_WIKITEXT ),
+                       array( 'User:Foo/bar.js.xxx', CONTENT_MODEL_WIKITEXT ),
+                       array( 'User:Foo/bar.xxx', CONTENT_MODEL_WIKITEXT ),
+                       array( 'MediaWiki:Foo.js', CONTENT_MODEL_JAVASCRIPT ),
+                       array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
+                       array( 'MediaWiki:Foo.JS', CONTENT_MODEL_WIKITEXT ),
+                       array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
+                       array( 'MediaWiki:Foo.css.xxx', CONTENT_MODEL_WIKITEXT ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetDefaultModelFor
+        */
+       public function testGetDefaultModelFor( $title, $expectedModelId ) {
+               $title = Title::newFromText( $title );
+               $this->assertEquals( $expectedModelId, ContentHandler::getDefaultModelFor( $title ) );
+       }
+
+       /**
+        * @dataProvider dataGetDefaultModelFor
+        */
+       public function testGetForTitle( $title, $expectedContentModel ) {
+               $title = Title::newFromText( $title );
+               $handler = ContentHandler::getForTitle( $title );
+               $this->assertEquals( $expectedContentModel, $handler->getModelID() );
+       }
+
+       public static function dataGetLocalizedName() {
+               return array(
+                       array( null, null ),
+                       array( "xyzzy", null ),
+
+                       // XXX: depends on content language
+                       array( CONTENT_MODEL_JAVASCRIPT, '/javascript/i' ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetLocalizedName
+        */
+       public function testGetLocalizedName( $id, $expected ) {
+               $name = ContentHandler::getLocalizedName( $id );
+
+               if ( $expected ) {
+                       $this->assertNotNull( $name, "no name found for content model $id" );
+                       $this->assertTrue( preg_match( $expected, $name ) > 0 ,
+                               "content model name for #$id did not match pattern $expected"
+                       );
+               } else {
+                       $this->assertEquals( $id, $name, "localization of unknown model $id should have "
+                               . "fallen back to use the model id directly."
+                       );
+               }
+       }
+
+       public static function dataGetPageLanguage() {
+               global $wgLanguageCode;
+
+               return array(
+                       array( "Main", $wgLanguageCode ),
+                       array( "Dummy:Foo", $wgLanguageCode ),
+                       array( "MediaWiki:common.js", 'en' ),
+                       array( "User:Foo/common.js", 'en' ),
+                       array( "MediaWiki:common.css", 'en' ),
+                       array( "User:Foo/common.css", 'en' ),
+                       array( "User:Foo", $wgLanguageCode ),
+
+                       array( CONTENT_MODEL_JAVASCRIPT, 'javascript' ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetPageLanguage
+        */
+       public function testGetPageLanguage( $title, $expected ) {
+               if ( is_string( $title ) ) {
+                       $title = Title::newFromText( $title );
+               }
+
+               $expected = wfGetLangObj( $expected );
+
+               $handler = ContentHandler::getForTitle( $title );
+               $lang = $handler->getPageLanguage( $title );
+
+               $this->assertEquals( $expected->getCode(), $lang->getCode() );
+       }
+
+       public function testGetContentText_Null( ) {
+               global $wgContentHandlerTextFallback;
+
+               $content = null;
+
+               $wgContentHandlerTextFallback = 'fail';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( '', $text );
+
+               $wgContentHandlerTextFallback = 'serialize';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( '', $text );
+
+               $wgContentHandlerTextFallback = 'ignore';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( '', $text );
+       }
+
+       public function testGetContentText_TextContent( ) {
+               global $wgContentHandlerTextFallback;
+
+               $content = new WikitextContent( "hello world" );
+
+               $wgContentHandlerTextFallback = 'fail';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( $content->getNativeData(), $text );
+
+               $wgContentHandlerTextFallback = 'serialize';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( $content->serialize(), $text );
+
+               $wgContentHandlerTextFallback = 'ignore';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( $content->getNativeData(), $text );
+       }
+
+       public function testGetContentText_NonTextContent( ) {
+               global $wgContentHandlerTextFallback;
+
+               $content = new DummyContentForTesting( "hello world" );
+
+               $wgContentHandlerTextFallback = 'fail';
+
+               try {
+                       $text = ContentHandler::getContentText( $content );
+
+                       $this->fail( "ContentHandler::getContentText should have thrown an exception for non-text Content object" );
+               } catch ( MWException $ex ) {
+                       // as expected
+               }
+
+               $wgContentHandlerTextFallback = 'serialize';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertEquals( $content->serialize(), $text );
+
+               $wgContentHandlerTextFallback = 'ignore';
+               $text = ContentHandler::getContentText( $content );
+               $this->assertNull( $text );
+       }
+
+       /*
+       public static function makeContent( $text, Title $title, $modelId = null, $format = null ) {}
+       */
+
+       public static function dataMakeContent() {
+               return array(
+                       array( 'hallo', 'Help:Test', null, null, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
+                       array( 'hallo', 'MediaWiki:Test.js', null, null, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
+                       array( serialize('hallo'), 'Dummy:Test', null, null, "testing", 'hallo', false ),
+
+                       array( 'hallo', 'Help:Test', null, CONTENT_FORMAT_WIKITEXT, CONTENT_MODEL_WIKITEXT, 'hallo', false ),
+                       array( 'hallo', 'MediaWiki:Test.js', null, CONTENT_FORMAT_JAVASCRIPT, CONTENT_MODEL_JAVASCRIPT, 'hallo', false ),
+                       array( serialize('hallo'), 'Dummy:Test', null, "testing", "testing", 'hallo', false ),
+
+                       array( 'hallo', 'Help:Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
+                       array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, 'hallo', false ),
+                       array( serialize('hallo'), 'Dummy:Test', CONTENT_MODEL_CSS, null, CONTENT_MODEL_CSS, serialize('hallo'), false ),
+
+                       array( 'hallo', 'Help:Test', CONTENT_MODEL_WIKITEXT, "testing", null, null, true ),
+                       array( 'hallo', 'MediaWiki:Test.js', CONTENT_MODEL_CSS, "testing", null, null, true ),
+                       array( 'hallo', 'Dummy:Test', CONTENT_MODEL_JAVASCRIPT, "testing", null, null, true ),
+               );
+       }
+
+       /**
+        * @dataProvider dataMakeContent
+        */
+       public function testMakeContent( $data, $title, $modelId, $format, $expectedModelId, $expectedNativeData, $shouldFail ) {
+               global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers;
+
+               $title = Title::newFromText( $title );
+
+               try {
+                       $content = ContentHandler::makeContent( $data, $title, $modelId, $format );
+
+                       if ( $shouldFail ) {
+                               $this->fail( "ContentHandler::makeContent should have failed!" );
+                       }
+
+                       $this->assertEquals( $expectedModelId, $content->getModel(), 'bad model id' );
+                       $this->assertEquals( $expectedNativeData, $content->getNativeData(), 'bads native data' );
+               } catch ( MWException $ex ) {
+                       if ( !$shouldFail ) $this->fail( "ContentHandler::makeContent failed unexpectedly: " . $ex->getMessage() );
+                       else $this->assertTrue( true ); // dummy, so we don't get the "test did not perform any assertions" message.
+               }
+
+       }
+
+       /*
+       public function testSupportsSections() {
+               $this->markTestIncomplete( "not yet implemented" );
+       }
+       */
+
+       public function testRunLegacyHooks() {
+               Hooks::register( 'testRunLegacyHooks', __CLASS__ . '::dummyHookHandler' );
+
+               $content = new WikitextContent( 'test text' );
+               $ok = ContentHandler::runLegacyHooks( 'testRunLegacyHooks', array( 'foo', &$content, 'bar' ), false );
+
+               $this->assertTrue( $ok, "runLegacyHooks should have returned true" );
+               $this->assertEquals( "TEST TEXT", $content->getNativeData() );
+       }
+
+       public static function dummyHookHandler( $foo, &$text, $bar ) {
+               if ( $text === null || $text === false ) {
+                       return false;
+               }
+
+               $text = strtoupper( $text );
+
+               return true;
+       }
+}
+
+class DummyContentHandlerForTesting extends ContentHandler {
+
+       public function __construct( $dataModel ) {
+               parent::__construct( $dataModel, array( "testing" ) );
+       }
+
+       /**
+        * Serializes Content object of the type supported by this ContentHandler.
+        *
+        * @param Content $content the Content object to serialize
+        * @param null $format the desired serialization format
+        * @return String serialized form of the content
+        */
+       public function serializeContent( Content $content, $format = null ) {
+          return $content->serialize();
+       }
+
+       /**
+        * Unserializes a Content object of the type supported by this ContentHandler.
+        *
+        * @param $blob String serialized form of the content
+        * @param null $format the format used for serialization
+        * @return Content the Content object created by deserializing $blob
+        */
+       public function unserializeContent( $blob, $format = null ) {
+               $d = unserialize( $blob );
+               return new DummyContentForTesting( $d );
+       }
+
+       /**
+        * Creates an empty Content object of the type supported by this ContentHandler.
+        *
+        */
+       public function makeEmptyContent() {
+               return new DummyContentForTesting( '' );
+       }
+}
+
+class DummyContentForTesting extends AbstractContent {
+
+       public function __construct( $data ) {
+               parent::__construct( "testing" );
+
+               $this->data = $data;
+       }
+
+       public function serialize( $format = null ) {
+               return serialize( $this->data );
+       }
+
+       /**
+        * @return String a string representing the content in a way useful for building a full text search index.
+        *         If no useful representation exists, this method returns an empty string.
+        */
+       public function getTextForSearchIndex() {
+               return '';
+       }
+
+       /**
+        * @return String the wikitext to include when another page includes this  content, or false if the content is not
+        *  includable in a wikitext page.
+        */
+       public function getWikitextForTransclusion() {
+               return false;
+       }
+
+       /**
+        * Returns a textual representation of the content suitable for use in edit summaries and log messages.
+        *
+        * @param int $maxlength Maximum length of the summary text.
+        * @return string The summary text.
+        */
+       public function getTextForSummary( $maxlength = 250 ) {
+               return '';
+       }
+
+       /**
+        * Returns native represenation of the data. Interpretation depends on the data model used,
+        * as given by getDataModel().
+        *
+        * @return mixed the native representation of the content. Could be a string, a nested array
+        *  structure, an object, a binary blob... anything, really.
+        */
+       public function getNativeData()
+       {
+               return $this->data;
+       }
+
+       /**
+        * returns the content's nominal size in bogo-bytes.
+        *
+        * @return int
+        */
+       public function getSize() {
+               return strlen( $this->data );
+       }
+
+       /**
+        * Return a copy of this Content object. The following must be true for the object returned
+        * if $copy = $original->copy()
+        *
+        * * get_class($original) === get_class($copy)
+        * * $original->getModel() === $copy->getModel()
+        * * $original->equals( $copy )
+        *
+        * If and only if the Content object is imutable, the copy() method can and should
+        * return $this. That is,  $copy === $original may be true, but only for imutable content
+        * objects.
+        *
+        * @return Content. A copy of this object.
+        */
+       public function copy() {
+               return $this;
+       }
+
+       /**
+        * Returns true if this content is countable as a "real" wiki page, provided
+        * that it's also in a countable location (e.g. a current revision in the main namespace).
+        *
+        * @param boolean $hasLinks if it is known whether this content contains links, provide this information here,
+        *  to avoid redundant parsing to find out.
+        * @return boolean
+        */
+       public function isCountable( $hasLinks = null ) {
+               return false;
+       }
+
+       /**
+        * @param Title $title
+        * @param null $revId
+        * @param null|ParserOptions $options
+        * @param boolean $generateHtml whether to generate Html (default: true). If false,
+        *  the result of calling getText() on the ParserOutput object returned by
+        *   this method is undefined.
+        *
+        * @return ParserOutput
+        */
+       public function getParserOutput( Title $title, $revId = null, ParserOptions $options = NULL, $generateHtml = true ) {
+               return new ParserOutput( $this->getNativeData() );
+       }
+}
diff --git a/tests/phpunit/includes/content/CssContentTest.php b/tests/phpunit/includes/content/CssContentTest.php
new file mode 100644 (file)
index 0000000..b08a468
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @group ContentHandler
+ * @group Database
+ *        ^--- needed, because we do need the database to test link updates
+ */
+class CssContentTest extends MediaWikiTestCase {
+
+       protected function setUp() {
+               parent::setUp();
+
+               // Anon user
+               $user = new User();
+               $user->setName( '127.0.0.1' );
+
+               $this->setMwGlobals( array(
+                       'wgUser' => $user,
+                       'wgTextModelsToParse' => array(
+                               CONTENT_MODEL_CSS,
+                       )
+               ) );
+       }
+
+       public function newContent( $text ) {
+               return new CssContent( $text );
+       }
+
+       public static function dataGetParserOutput() {
+               return array(
+                       array(
+                               'MediaWiki:Test.css',
+                               null,
+                               "hello <world>\n",
+                               "<pre class=\"mw-code mw-css\" dir=\"ltr\">\nhello &lt;world&gt;\n\n</pre>"
+                       ),
+                       array(
+                               'MediaWiki:Test.css',
+                               null,
+                               "/* hello [[world]] */\n",
+                               "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n/* hello [[world]] */\n\n</pre>",
+                               array(
+                                       'Links' => array(
+                                               array( 'World' => 0 )
+                                       )
+                               )
+                       ),
+
+                       // TODO: more...?
+               );
+       }
+
+       public function testGetModel() {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( CONTENT_MODEL_CSS, $content->getModel() );
+       }
+
+       public function testGetContentHandler() {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( CONTENT_MODEL_CSS, $content->getContentHandler()->getModelID() );
+       }
+
+       public static function dataEquals( ) {
+               return array(
+                       array( new CssContent( 'hallo' ), null, false ),
+                       array( new CssContent( 'hallo' ), new CssContent( 'hallo' ), true ),
+                       array( new CssContent( 'hallo' ), new WikitextContent( 'hallo' ), false ),
+                       array( new CssContent( 'hallo' ), new CssContent( 'HALLO' ), false ),
+               );
+       }
+
+       /**
+        * @dataProvider dataEquals
+        */
+       public function testEquals( Content $a, Content $b = null, $equal = false ) {
+               $this->assertEquals( $equal, $a->equals( $b ) );
+       }
+
+}
diff --git a/tests/phpunit/includes/content/JavascriptContentTest.php b/tests/phpunit/includes/content/JavascriptContentTest.php
new file mode 100644 (file)
index 0000000..e08252c
--- /dev/null
@@ -0,0 +1,273 @@
+<?php
+
+/**
+ * @group ContentHandler
+ * @group Database
+ *        ^--- needed, because we do need the database to test link updates
+ */
+class JavascriptContentTest extends TextContentTest {
+
+       public function newContent( $text ) {
+               return new JavascriptContent( $text );
+       }
+
+       public static function dataGetParserOutput() {
+               return array(
+                       array(
+                               'MediaWiki:Test.js',
+                               null,
+                               "hello <world>\n",
+                               "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello &lt;world&gt;\n\n</pre>"
+                       ),
+                       array(
+                               'MediaWiki:Test.js',
+                               null,
+                               "hello(); // [[world]]\n",
+                               "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello(); // [[world]]\n\n</pre>",
+                               array(
+                                       'Links' => array(
+                                               array( 'World' => 0 )
+                                       )
+                               )
+                       ),
+
+                       // TODO: more...?
+               );
+       }
+
+       // XXX: Unused function
+       public static function dataGetSection() {
+               return array(
+                       array( WikitextContentTest::$sections,
+                              '0',
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              '2',
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              '8',
+                              null
+                       ),
+               );
+       }
+
+       // XXX: Unused function
+       public static function dataReplaceSection() {
+               return array(
+                       array( WikitextContentTest::$sections,
+                              '0',
+                              'No more',
+                              null,
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              '',
+                              'No more',
+                              null,
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              '2',
+                              "== TEST ==\nmore fun",
+                              null,
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              '8',
+                              'No more',
+                              null,
+                              null
+                       ),
+                       array( WikitextContentTest::$sections,
+                              'new',
+                              'No more',
+                              'New',
+                              null
+                       ),
+               );
+       }
+
+       public function testAddSectionHeader( ) {
+               $content = $this->newContent( 'hello world' );
+               $c = $content->addSectionHeader( 'test' );
+
+               $this->assertTrue( $content->equals( $c ) );
+       }
+
+       // XXX: currently, preSaveTransform is applied to scripts. this may change or become optional.
+       public static function dataPreSaveTransform() {
+               return array(
+                       array( 'hello this is ~~~',
+                               "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
+                       ),
+                       array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
+                               'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
+                       ),
+                       array( " Foo \n ",
+                               " Foo",
+                       ),
+               );
+       }
+
+       public static function dataPreloadTransform() {
+               return array(
+                       array( 'hello this is ~~~',
+                              'hello this is ~~~',
+                       ),
+                       array( 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
+                              'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
+                       ),
+               );
+       }
+
+       public static function dataGetRedirectTarget() {
+               return array(
+                       array( '#REDIRECT [[Test]]',
+                              null,
+                       ),
+                       array( '#REDIRECT Test',
+                              null,
+                       ),
+                       array( '* #REDIRECT [[Test]]',
+                              null,
+                       ),
+               );
+       }
+
+       /**
+        * @todo: test needs database!
+        */
+       /*
+       public function getRedirectChain() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectArray( $text );
+       }
+       */
+
+       /**
+        * @todo: test needs database!
+        */
+       /*
+       public function getUltimateRedirectTarget() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectRecurse( $text );
+       }
+       */
+
+       public static function dataIsCountable() {
+               return array(
+                       array( '',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'comma',
+                              false
+                       ),
+                       array( 'Foo, bar',
+                              null,
+                              'comma',
+                              false
+                       ),
+                       array( 'Foo',
+                              null,
+                              'link',
+                              false
+                       ),
+                       array( 'Foo [[bar]]',
+                              null,
+                              'link',
+                              false
+                       ),
+                       array( 'Foo',
+                              true,
+                              'link',
+                              false
+                       ),
+                       array( 'Foo [[bar]]',
+                              false,
+                              'link',
+                              false
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'any',
+                              true
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'comma',
+                              false
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'link',
+                              false
+                       ),
+               );
+       }
+
+       public static function dataGetTextForSummary() {
+               return array(
+                       array( "hello\nworld.",
+                              16,
+                              'hello world.',
+                       ),
+                       array( 'hello world.',
+                              8,
+                              'hello...',
+                       ),
+                       array( '[[hello world]].',
+                              8,
+                              '[[hel...',
+                       ),
+               );
+       }
+
+       public function testMatchMagicWord( ) {
+               $mw = MagicWord::get( "staticredirect" );
+
+               $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
+               $this->assertFalse( $content->matchMagicWord( $mw ), "should not have matched magic word, since it's not wikitext" );
+       }
+
+       public function testUpdateRedirect( ) {
+               $target = Title::newFromText( "testUpdateRedirect_target" );
+
+               $content = $this->newContent( "#REDIRECT [[Someplace]]" );
+               $newContent = $content->updateRedirect( $target );
+
+               $this->assertTrue( $content->equals( $newContent ), "content should be unchanged since it's not wikitext" );
+       }
+
+       public function testGetModel() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $content->getModel() );
+       }
+
+       public function testGetContentHandler() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $content->getContentHandler()->getModelID() );
+       }
+
+       public static function dataEquals( ) {
+               return array(
+                       array( new JavascriptContent( "hallo" ), null, false ),
+                       array( new JavascriptContent( "hallo" ), new JavascriptContent( "hallo" ), true ),
+                       array( new JavascriptContent( "hallo" ), new CssContent( "hallo" ), false ),
+                       array( new JavascriptContent( "hallo" ), new JavascriptContent( "HALLO" ), false ),
+               );
+       }
+
+}
diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php
new file mode 100644 (file)
index 0000000..c867a83
--- /dev/null
@@ -0,0 +1,381 @@
+<?php
+
+/**
+ * @group ContentHandler
+ * @group Database
+ *        ^--- needed, because we do need the database to test link updates
+ */
+class TextContentTest extends MediaWikiTestCase {
+       protected $context;
+
+       protected function setUp() {
+               parent::setUp();
+
+               // Anon user
+               $user = new User();
+               $user->setName( '127.0.0.1' );
+
+               $this->setMwGlobals( array(
+                       'wgUser' => $user,
+                       'wgTextModelsToParse' => array(
+                               CONTENT_MODEL_WIKITEXT,
+                               CONTENT_MODEL_CSS,
+                               CONTENT_MODEL_JAVASCRIPT,
+                       )
+               ) );
+
+               $this->context = new RequestContext( new FauxRequest() );
+               $this->context->setTitle( Title::newFromText( 'Test' ) );
+               $this->context->setUser( $user );
+       }
+
+       public function newContent( $text ) {
+               return new TextContent( $text );
+       }
+
+       public static function dataGetParserOutput() {
+               return array(
+                       array(
+                               'TextContentTest_testGetParserOutput',
+                               CONTENT_MODEL_TEXT,
+                               "hello ''world'' & [[stuff]]\n", "hello ''world'' &amp; [[stuff]]",
+                               array(
+                                       'Links' => array()
+                               )
+                       ),
+                       // TODO: more...?
+               );
+       }
+
+       /**
+        * @dataProvider dataGetParserOutput
+        */
+       public function testGetParserOutput( $title, $model, $text, $expectedHtml, $expectedFields = null ) {
+               $title = Title::newFromText( $title );
+               $content = ContentHandler::makeContent( $text, $title, $model );
+
+               $po = $content->getParserOutput( $title );
+
+               $html = $po->getText();
+               $html = preg_replace( '#<!--.*?-->#sm', '', $html ); // strip comments
+
+               $this->assertEquals( $expectedHtml, trim( $html ) );
+
+               if ( $expectedFields ) {
+                       foreach ( $expectedFields as $field => $exp ) {
+                               $f = 'get' . ucfirst( $field );
+                               $v = call_user_func( array( $po, $f ) );
+
+                               if ( is_array( $exp ) ) {
+                                       $this->assertArrayEquals( $exp, $v );
+                               } else {
+                                       $this->assertEquals( $exp, $v );
+                               }
+                       }
+               }
+
+               // TODO: assert more properties
+       }
+
+       public static function dataPreSaveTransform() {
+               return array(
+                       array(
+                               #0: no signature resolution
+                               'hello this is ~~~',
+                               'hello this is ~~~',
+                       ),
+                       array(
+                               #1: rtrim
+                               " Foo \n ",
+                               ' Foo',
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataPreSaveTransform
+        */
+       public function testPreSaveTransform( $text, $expected ) {
+               global $wgContLang;
+
+               $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
+
+               $content = $this->newContent( $text );
+               $content = $content->preSaveTransform( $this->context->getTitle(), $this->context->getUser(), $options );
+
+               $this->assertEquals( $expected, $content->getNativeData() );
+       }
+
+       public static function dataPreloadTransform() {
+               return array(
+                       array(
+                               'hello this is ~~~',
+                               'hello this is ~~~',
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataPreloadTransform
+        */
+       public function testPreloadTransform( $text, $expected ) {
+               global $wgContLang;
+               $options = ParserOptions::newFromUserAndLang( $this->context->getUser(), $wgContLang );
+
+               $content = $this->newContent( $text );
+               $content = $content->preloadTransform( $this->context->getTitle(), $options );
+
+               $this->assertEquals( $expected, $content->getNativeData() );
+       }
+
+       public static function dataGetRedirectTarget() {
+               return array(
+                       array( '#REDIRECT [[Test]]',
+                               null,
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetRedirectTarget
+        */
+       public function testGetRedirectTarget( $text, $expected ) {
+               $content = $this->newContent( $text );
+               $t = $content->getRedirectTarget( );
+
+               if ( is_null( $expected ) ) {
+                       $this->assertNull( $t, "text should not have generated a redirect target: $text" );
+               } else {
+                       $this->assertEquals( $expected, $t->getPrefixedText() );
+               }
+       }
+
+       /**
+        * @dataProvider dataGetRedirectTarget
+        */
+       public function testIsRedirect( $text, $expected ) {
+               $content = $this->newContent( $text );
+
+               $this->assertEquals( !is_null($expected), $content->isRedirect() );
+       }
+
+       /**
+        * @todo: test needs database! Should be done by a test class in the Database group.
+        */
+       /*
+       public function getRedirectChain() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectArray( $text );
+       }
+       */
+
+       /**
+        * @todo: test needs database! Should be done by a test class in the Database group.
+        */
+       /*
+       public function getUltimateRedirectTarget() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectRecurse( $text );
+       }
+       */
+
+       public static function dataIsCountable() {
+               return array(
+                       array( '',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'comma',
+                              false
+                       ),
+                       array( 'Foo, bar',
+                              null,
+                              'comma',
+                              false
+                       ),
+               );
+       }
+
+
+       /**
+        * @dataProvider dataIsCountable
+        * @group Database
+        */
+       public function testIsCountable( $text, $hasLinks, $mode, $expected ) {
+               global $wgArticleCountMethod;
+
+               $old = $wgArticleCountMethod;
+               $wgArticleCountMethod = $mode;
+
+               $content = $this->newContent( $text );
+
+               $v = $content->isCountable( $hasLinks, $this->context->getTitle() );
+               $wgArticleCountMethod = $old;
+
+               $this->assertEquals( $expected, $v, 'isCountable() returned unexpected value ' . var_export( $v, true )
+                                                   . ' instead of ' . var_export( $expected, true ) . " in mode `$mode` for text \"$text\"" );
+       }
+
+       public static function dataGetTextForSummary() {
+               return array(
+                       array( "hello\nworld.",
+                              16,
+                              'hello world.',
+                       ),
+                       array( 'hello world.',
+                              8,
+                              'hello...',
+                       ),
+                       array( '[[hello world]].',
+                              8,
+                              '[[hel...',
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetTextForSummary
+        */
+       public function testGetTextForSummary( $text, $maxlength, $expected ) {
+               $content = $this->newContent( $text );
+
+               $this->assertEquals( $expected, $content->getTextForSummary( $maxlength ) );
+       }
+
+
+       public function testGetTextForSearchIndex( ) {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( 'hello world.', $content->getTextForSearchIndex() );
+       }
+
+       public function testCopy() {
+               $content = $this->newContent( 'hello world.' );
+               $copy = $content->copy();
+
+               $this->assertTrue( $content->equals( $copy ), 'copy must be equal to original' );
+               $this->assertEquals( 'hello world.', $copy->getNativeData() );
+       }
+
+       public function testGetSize( ) {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( 12, $content->getSize() );
+       }
+
+       public function testGetNativeData( ) {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( 'hello world.', $content->getNativeData() );
+       }
+
+       public function testGetWikitextForTransclusion( ) {
+               $content = $this->newContent( 'hello world.' );
+
+               $this->assertEquals( 'hello world.', $content->getWikitextForTransclusion() );
+       }
+
+       public function testGetModel() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_TEXT, $content->getModel() );
+       }
+
+       public function testGetContentHandler() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_TEXT, $content->getContentHandler()->getModelID() );
+       }
+
+       public static function dataIsEmpty( ) {
+               return array(
+                       array( '', true ),
+                       array( '  ', false ),
+                       array( '0', false ),
+                       array( 'hallo welt.', false ),
+               );
+       }
+
+       /**
+        * @dataProvider dataIsEmpty
+        */
+       public function testIsEmpty( $text, $empty ) {
+               $content = $this->newContent( $text );
+
+               $this->assertEquals( $empty, $content->isEmpty() );
+       }
+
+       public static function dataEquals( ) {
+               return array(
+                       array( new TextContent( "hallo" ), null, false ),
+                       array( new TextContent( "hallo" ), new TextContent( "hallo" ), true ),
+                       array( new TextContent( "hallo" ), new JavascriptContent( "hallo" ), false ),
+                       array( new TextContent( "hallo" ), new WikitextContent( "hallo" ), false ),
+                       array( new TextContent( "hallo" ), new TextContent( "HALLO" ), false ),
+               );
+       }
+
+       /**
+        * @dataProvider dataEquals
+        */
+       public function testEquals( Content $a, Content $b = null, $equal = false ) {
+               $this->assertEquals( $equal, $a->equals( $b ) );
+       }
+
+       public static function dataGetDeletionUpdates() {
+               return array(
+                       array("TextContentTest_testGetSecondaryDataUpdates_1",
+                               CONTENT_MODEL_TEXT, "hello ''world''\n",
+                               array( )
+                       ),
+                       array("TextContentTest_testGetSecondaryDataUpdates_2",
+                               CONTENT_MODEL_TEXT, "hello [[world test 21344]]\n",
+                               array( )
+                       ),
+                       // TODO: more...?
+               );
+       }
+
+       /**
+        * @dataProvider dataGetDeletionUpdates
+        */
+       public function testDeletionUpdates( $title, $model, $text, $expectedStuff ) {
+               $title = Title::newFromText( $title );
+               $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
+
+               $content = ContentHandler::makeContent( $text, $title, $model );
+
+               $updates = $content->getDeletionUpdates( WikiPage::factory( $title ) );
+
+               // make updates accessible by class name
+               foreach ( $updates as $update ) {
+                       $class = get_class( $update );
+                       $updates[ $class ] = $update;
+               }
+
+               if ( !$expectedStuff ) {
+                       $this->assertTrue( true ); // make phpunit happy
+                       return;
+               }
+
+               foreach ( $expectedStuff as $class => $fieldValues ) {
+                       $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
+
+                       $update = $updates[ $class ];
+
+                       foreach ( $fieldValues as $field => $value ) {
+                               $v = $update->$field; #if the field doesn't exist, just crash and burn
+                               $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
+                       }
+               }
+       }
+
+}
diff --git a/tests/phpunit/includes/content/WikitextContentHandlerTest.php b/tests/phpunit/includes/content/WikitextContentHandlerTest.php
new file mode 100644 (file)
index 0000000..1ba85a9
--- /dev/null
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * @group ContentHandler
+ */
+class WikitextContentHandlerTest extends MediaWikiTestCase {
+
+       /**
+        * @var ContentHandler
+        */
+       var $handler;
+
+       public function setUp() {
+               parent::setUp();
+
+               $this->handler = ContentHandler::getForModelID( CONTENT_MODEL_WIKITEXT );
+       }
+
+       public function testSerializeContent( ) {
+               $content = new WikitextContent( 'hello world' );
+
+               $this->assertEquals( 'hello world', $this->handler->serializeContent( $content ) );
+               $this->assertEquals( 'hello world', $this->handler->serializeContent( $content, CONTENT_FORMAT_WIKITEXT ) );
+
+               try {
+                       $this->handler->serializeContent( $content, 'dummy/foo' );
+                       $this->fail( "serializeContent() should have failed on unknown format" );
+               } catch ( MWException $e ) {
+                       // ok, as expected
+               }
+       }
+
+       public function testUnserializeContent( ) {
+               $content = $this->handler->unserializeContent( 'hello world' );
+               $this->assertEquals( 'hello world', $content->getNativeData() );
+
+               $content = $this->handler->unserializeContent( 'hello world', CONTENT_FORMAT_WIKITEXT );
+               $this->assertEquals( 'hello world', $content->getNativeData() );
+
+               try {
+                       $this->handler->unserializeContent( 'hello world', 'dummy/foo' );
+                       $this->fail( "unserializeContent() should have failed on unknown format" );
+               } catch ( MWException $e ) {
+                       // ok, as expected
+               }
+       }
+
+       public function testMakeEmptyContent() {
+               $content = $this->handler->makeEmptyContent();
+
+               $this->assertTrue( $content->isEmpty() );
+               $this->assertEquals( '', $content->getNativeData() );
+       }
+
+       public static function dataIsSupportedFormat( ) {
+               return array(
+                       array( null, true ),
+                       array( CONTENT_FORMAT_WIKITEXT, true ),
+                       array( 99887766, false ),
+               );
+       }
+
+       /**
+        * @dataProvider dataIsSupportedFormat
+        */
+       public function testIsSupportedFormat( $format, $supported ) {
+               $this->assertEquals( $supported, $this->handler->isSupportedFormat( $format ) );
+       }
+
+       public static function dataMerge3( ) {
+               return array(
+                       array( "first paragraph
+
+                                       second paragraph\n",
+
+                                       "FIRST paragraph
+
+                                       second paragraph\n",
+
+                                       "first paragraph
+
+                                       SECOND paragraph\n",
+
+                                       "FIRST paragraph
+
+                                       SECOND paragraph\n",
+                       ),
+
+                       array( "first paragraph
+                                       second paragraph\n",
+
+                                  "Bla bla\n",
+
+                                  "Blubberdibla\n",
+
+                                  false,
+                       ),
+
+               );
+       }
+
+       /**
+        * @dataProvider dataMerge3
+        */
+       public function testMerge3( $old, $mine, $yours, $expected ) {
+               global $wgDiff3;
+
+               if ( !$wgDiff3 ) {
+                       $this->markTestSkipped( "Can't test merge3(), since \$wgDiff3 is not configured" );
+               }
+
+               if ( !file_exists( $wgDiff3 ) ) {
+                       #XXX: this sucks, since it uses arcane internal knowledge about TextContentHandler::merge3 and wfMerge.
+                       $this->markTestSkipped( "Can't test merge3(), since \$wgDiff3 is misconfigured: can't find $wgDiff3" );
+               }
+
+               // test merge
+               $oldContent = new WikitextContent( $old );
+               $myContent = new WikitextContent( $mine );
+               $yourContent = new WikitextContent( $yours );
+
+               $merged = $this->handler->merge3( $oldContent, $myContent, $yourContent );
+
+               $this->assertEquals( $expected, $merged ? $merged->getNativeData() : $merged );
+       }
+
+       public static function dataGetAutosummary( ) {
+               return array(
+                       array(
+                               'Hello there, world!',
+                               '#REDIRECT [[Foo]]',
+                               0,
+                               '/^Redirected page .*Foo/'
+                       ),
+
+                       array(
+                               null,
+                               'Hello world!',
+                               EDIT_NEW,
+                               '/^Created page .*Hello/'
+                       ),
+
+                       array(
+                               'Hello there, world!',
+                               '',
+                               0,
+                               '/^Blanked/'
+                       ),
+
+                       array(
+                               'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
+                               labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et
+                               ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
+                               'Hello world!',
+                               0,
+                               '/^Replaced .*Hello/'
+                       ),
+
+                       array(
+                               'foo',
+                               'bar',
+                               0,
+                               '/^$/'
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetAutosummary
+        */
+       public function testGetAutosummary( $old, $new, $flags, $expected ) {
+               global $wgLanguageCode, $wgContLang;
+
+               $oldContent = is_null( $old ) ? null : new WikitextContent( $old );
+               $newContent = is_null( $new ) ? null : new WikitextContent( $new );
+
+               $summary = $this->handler->getAutosummary( $oldContent, $newContent, $flags );
+
+               $this->assertTrue( (bool)preg_match( $expected, $summary ), "Autosummary didn't match expected pattern $expected: $summary" );
+       }
+
+       /**
+        * @todo Text case requires database, should be done by a test class in the Database group
+        */
+       /*
+       public function testGetAutoDeleteReason( Title $title, &$hasHistory ) {}
+       */
+
+       /**
+        * @todo Text case requires database, should be done by a test class in the Database group
+        */
+       /*
+       public function testGetUndoContent( Revision $current, Revision $undo, Revision $undoafter = null ) {}
+       */
+
+}
diff --git a/tests/phpunit/includes/content/WikitextContentTest.php b/tests/phpunit/includes/content/WikitextContentTest.php
new file mode 100644 (file)
index 0000000..ceb6d48
--- /dev/null
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * @group ContentHandler
+ *
+ * @group Database
+ *        ^--- needed, because we do need the database to test link updates
+ */
+class WikitextContentTest extends TextContentTest {
+
+       static $sections =
+
+"Intro
+
+== stuff ==
+hello world
+
+== test ==
+just a test
+
+== foo ==
+more stuff
+";
+
+       public function newContent( $text ) {
+               return new WikitextContent( $text );
+       }
+
+       public static function dataGetParserOutput() {
+               return array(
+                       array(
+                               "WikitextContentTest_testGetParserOutput",
+                               CONTENT_MODEL_WIKITEXT,
+                               "hello ''world''\n",
+                               "<p>hello <i>world</i>\n</p>"
+                       ),
+                       // TODO: more...?
+               );
+       }
+
+       public static function dataGetSecondaryDataUpdates() {
+               return array(
+                       array( "WikitextContentTest_testGetSecondaryDataUpdates_1",
+                               CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
+                               array(
+                                       'LinksUpdate' => array(
+                                               'mRecursive' => true,
+                                               'mLinks' => array()
+                                       )
+                               )
+                       ),
+                       array( "WikitextContentTest_testGetSecondaryDataUpdates_2",
+                               CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
+                               array(
+                                       'LinksUpdate' => array(
+                                               'mRecursive' => true,
+                                               'mLinks' => array(
+                                                       array( 'World_test_21344' => 0 )
+                                               )
+                                       )
+                               )
+                       ),
+                       // TODO: more...?
+               );
+       }
+
+       /**
+        * @dataProvider dataGetSecondaryDataUpdates
+        * @group Database
+        */
+       public function testGetSecondaryDataUpdates( $title, $model, $text, $expectedStuff ) {
+               $title = Title::newFromText( $title );
+               $title->resetArticleID( 2342 ); //dummy id. fine as long as we don't try to execute the updates!
+
+               $content = ContentHandler::makeContent( $text, $title, $model );
+
+               $updates = $content->getSecondaryDataUpdates( $title );
+
+               // make updates accessible by class name
+               foreach ( $updates as $update ) {
+                       $class = get_class( $update );
+                       $updates[$class] = $update;
+               }
+
+               foreach ( $expectedStuff as $class => $fieldValues ) {
+                       $this->assertArrayHasKey( $class, $updates, "missing an update of type $class" );
+
+                       $update = $updates[$class];
+
+                       foreach ( $fieldValues as $field => $value ) {
+                               $v = $update->$field; #if the field doesn't exist, just crash and burn
+                               $this->assertEquals( $value, $v, "unexpected value for field $field in instance of $class" );
+                       }
+               }
+       }
+
+       public static function dataGetSection() {
+               return array(
+                       array( WikitextContentTest::$sections,
+                                       "0",
+                                       "Intro"
+                       ),
+                       array( WikitextContentTest::$sections,
+                                       "2",
+"== test ==
+just a test"
+                       ),
+                       array( WikitextContentTest::$sections,
+                                       "8",
+                                       false
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataGetSection
+        */
+       public function testGetSection( $text, $sectionId, $expectedText ) {
+               $content = $this->newContent( $text );
+
+               $sectionContent = $content->getSection( $sectionId );
+               if ( is_object( $sectionContent ) ) {
+                       $sectionText = $sectionContent->getNativeData();
+               } else {
+                       $sectionText = $sectionContent;
+               }
+
+               $this->assertEquals( $expectedText, $sectionText );
+       }
+
+       public static function dataReplaceSection() {
+               return array(
+                       array( WikitextContentTest::$sections,
+                              "0",
+                              "No more",
+                              null,
+                              trim( preg_replace( '/^Intro/sm', 'No more', WikitextContentTest::$sections ) )
+                       ),
+                       array( WikitextContentTest::$sections,
+                              "",
+                              "No more",
+                              null,
+                              "No more"
+                       ),
+                       array( WikitextContentTest::$sections,
+                              "2",
+                              "== TEST ==\nmore fun",
+                              null,
+                              trim( preg_replace( '/^== test ==.*== foo ==/sm', "== TEST ==\nmore fun\n\n== foo ==", WikitextContentTest::$sections ) )
+                       ),
+                       array( WikitextContentTest::$sections,
+                              "8",
+                              "No more",
+                              null,
+                              WikitextContentTest::$sections
+                       ),
+                       array( WikitextContentTest::$sections,
+                              "new",
+                              "No more",
+                              "New",
+                              trim( WikitextContentTest::$sections ) . "\n\n\n== New ==\n\nNo more"
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider dataReplaceSection
+        */
+       public function testReplaceSection( $text, $section, $with, $sectionTitle, $expected ) {
+               $content = $this->newContent( $text );
+               $c = $content->replaceSection( $section, $this->newContent( $with ), $sectionTitle );
+
+               $this->assertEquals( $expected, is_null( $c ) ? null : $c->getNativeData() );
+       }
+
+       public function testAddSectionHeader( ) {
+               $content = $this->newContent( 'hello world' );
+               $content = $content->addSectionHeader( 'test' );
+
+               $this->assertEquals( "== test ==\n\nhello world", $content->getNativeData() );
+       }
+
+       public static function dataPreSaveTransform() {
+               return array(
+                       array( 'hello this is ~~~',
+                              "hello this is [[Special:Contributions/127.0.0.1|127.0.0.1]]",
+                       ),
+                       array( 'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
+                              'hello \'\'this\'\' is <nowiki>~~~</nowiki>',
+                       ),
+                       array( // rtrim
+                               " Foo \n ",
+                               " Foo",
+                       ),
+               );
+       }
+
+       public static function dataPreloadTransform() {
+               return array(
+                       array( 'hello this is ~~~',
+                              "hello this is ~~~",
+                       ),
+                       array( 'hello \'\'this\'\' is <noinclude>foo</noinclude><includeonly>bar</includeonly>',
+                              'hello \'\'this\'\' is bar',
+                       ),
+               );
+       }
+
+       public static function dataGetRedirectTarget() {
+               return array(
+                       array( '#REDIRECT [[Test]]',
+                              'Test',
+                       ),
+                       array( '#REDIRECT Test',
+                              null,
+                       ),
+                       array( '* #REDIRECT [[Test]]',
+                              null,
+                       ),
+               );
+       }
+
+       public static function dataGetTextForSummary() {
+               return array(
+                       array( "hello\nworld.",
+                               16,
+                               'hello world.',
+                       ),
+                       array( 'hello world.',
+                               8,
+                               'hello...',
+                       ),
+                       array( '[[hello world]].',
+                               8,
+                               'hel...',
+                       ),
+               );
+       }
+
+       /**
+        * @todo: test needs database! Should be done by a test class in the Database group.
+        */
+       /*
+       public function getRedirectChain() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectArray( $text );
+       }
+       */
+
+       /**
+        * @todo: test needs database! Should be done by a test class in the Database group.
+        */
+       /*
+       public function getUltimateRedirectTarget() {
+               $text = $this->getNativeData();
+               return Title::newFromRedirectRecurse( $text );
+       }
+       */
+
+       public static function dataIsCountable() {
+               return array(
+                       array( '',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'any',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'comma',
+                              false
+                       ),
+                       array( 'Foo, bar',
+                              null,
+                              'comma',
+                              true
+                       ),
+                       array( 'Foo',
+                              null,
+                              'link',
+                              false
+                       ),
+                       array( 'Foo [[bar]]',
+                              null,
+                              'link',
+                              true
+                       ),
+                       array( 'Foo',
+                              true,
+                              'link',
+                              true
+                       ),
+                       array( 'Foo [[bar]]',
+                              false,
+                              'link',
+                              false
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'any',
+                              false
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'comma',
+                              false
+                       ),
+                       array( '#REDIRECT [[bar]]',
+                              true,
+                              'link',
+                              false
+                       ),
+               );
+       }
+
+       public function testMatchMagicWord( ) {
+               $mw = MagicWord::get( "staticredirect" );
+
+               $content = $this->newContent( "#REDIRECT [[FOO]]\n__STATICREDIRECT__" );
+               $this->assertTrue( $content->matchMagicWord( $mw ), "should have matched magic word" );
+
+               $content = $this->newContent( "#REDIRECT [[FOO]]" );
+               $this->assertFalse( $content->matchMagicWord( $mw ), "should not have matched magic word" );
+       }
+
+       public function testUpdateRedirect( ) {
+               $target = Title::newFromText( "testUpdateRedirect_target" );
+
+               // test with non-redirect page
+               $content = $this->newContent( "hello world." );
+               $newContent = $content->updateRedirect( $target );
+
+               $this->assertTrue( $content->equals( $newContent ), "content should be unchanged" );
+
+               // test with actual redirect
+               $content = $this->newContent( "#REDIRECT [[Someplace]]" );
+               $newContent = $content->updateRedirect( $target );
+
+               $this->assertFalse( $content->equals( $newContent ), "content should have changed" );
+               $this->assertTrue( $newContent->isRedirect(), "new content should be a redirect" );
+
+               $this->assertEquals( $target->getFullText(), $newContent->getRedirectTarget()->getFullText() );
+       }
+
+       public function testGetModel() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getModel() );
+       }
+
+       public function testGetContentHandler() {
+               $content = $this->newContent( "hello world." );
+
+               $this->assertEquals( CONTENT_MODEL_WIKITEXT, $content->getContentHandler()->getModelID() );
+       }
+
+       public static function dataEquals( ) {
+               return array(
+                       array( new WikitextContent( "hallo" ), null, false ),
+                       array( new WikitextContent( "hallo" ), new WikitextContent( "hallo" ), true ),
+                       array( new WikitextContent( "hallo" ), new JavascriptContent( "hallo" ), false ),
+                       array( new WikitextContent( "hallo" ), new TextContent( "hallo" ), false ),
+                       array( new WikitextContent( "hallo" ), new WikitextContent( "HALLO" ), false ),
+               );
+       }
+
+       public static function dataGetDeletionUpdates() {
+               return array(
+                       array("WikitextContentTest_testGetSecondaryDataUpdates_1",
+                               CONTENT_MODEL_WIKITEXT, "hello ''world''\n",
+                               array( 'LinksDeletionUpdate' => array( ) )
+                       ),
+                       array("WikitextContentTest_testGetSecondaryDataUpdates_2",
+                               CONTENT_MODEL_WIKITEXT, "hello [[world test 21344]]\n",
+                               array( 'LinksDeletionUpdate' => array( ) )
+                       ),
+                       // @todo: more...?
+               );
+       }
+
+}