mirror of
				https://github.com/diocloid/LinkTitles.git
				synced 2025-10-22 05:42:32 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			353 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * Unit tests for the Linker class, i.e. the core functionality
 | 
						|
 *
 | 
						|
 * Copyright 2012-2024 Daniel Kraus <bovender@bovender.de> ('bovender')
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation; either version 2 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | 
						|
 * MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * @author Daniel Kraus <bovender@bovender.de>
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Unit tests for the LinkTitles\Linker class.
 | 
						|
 *
 | 
						|
 * The test class is prefixed with 'LinkTitles' to avoid a naming collision
 | 
						|
 * with a class that exists in the MediaWiki core.
 | 
						|
 *
 | 
						|
 * (Ideally the test classes should be namespaced, but when you do that, they
 | 
						|
 * will no longer be automatically discovered.)
 | 
						|
 *
 | 
						|
 * @group bovender
 | 
						|
 * @group Database
 | 
						|
 */
 | 
						|
 | 
						|
use MediaWiki\MediaWikiServices;
 | 
						|
 | 
						|
class LinkTitlesLinkerTest extends LinkTitles\TestCase {
 | 
						|
	protected $title;
 | 
						|
 | 
						|
	protected function setUp(): void
 | 
						|
	{
 | 
						|
		parent::setUp(); // call last to have the Targets object invalidated after inserting the page
 | 
						|
	}
 | 
						|
 | 
						|
	public function addDBData() {
 | 
						|
		$this->title = $this->insertPage( 'source page', 'This page is the test page' )['title'];
 | 
						|
		$this->insertPage( 'link target', 'This page serves as a link target' );
 | 
						|
		parent::addDBDataOnce(); // call parent after adding page to have targets invalidated
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideTestTitleWithNumberData
 | 
						|
	 */
 | 
						|
	public function testTitleWithNumber( $input, $expectedOutput ) {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->wordStartOnly = true;
 | 
						|
		$config->wordEndOnly = true;
 | 
						|
		$this->insertPage( 'numbered-1', 'This page serves as a link target with a numbered title' );
 | 
						|
		$this->insertPage( 'numbered-101', 'This page serves as a link target with a numbered title' );
 | 
						|
		parent::addDBDataOnce(); // call parent after adding page to have targets invalidated
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideTestTitleWithNumberData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				"Page text with numbered-1 in it.",
 | 
						|
				"Page text with [[numbered-1]] in it.",
 | 
						|
			],
 | 
						|
			[
 | 
						|
				"Page text with numbered-101 in it.",
 | 
						|
				"Page text with [[numbered-101]] in it.",
 | 
						|
			],
 | 
						|
			[
 | 
						|
				"Page text with numbered-1010 in it.",
 | 
						|
				"Page text with numbered-1010 in it.",
 | 
						|
			],
 | 
						|
			[
 | 
						|
				"Page text with link target1 in it.",
 | 
						|
				"Page text with link target1 in it.",
 | 
						|
			],
 | 
						|
		];
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Test issue #39, https://github.com/bovender/LinkTitles/issues/39
 | 
						|
	 */
 | 
						|
	public function testNoautolinks() {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->firstOnly = false;
 | 
						|
		LinkTitles\Splitter::invalidate();
 | 
						|
		$input = 'This is a text with <noautolinks><nowiki>link target</nowiki></noautolinks>';
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $input, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideLinkContentTemplatesData
 | 
						|
	 */
 | 
						|
	public function testLinkContentTemplates( $skipTemplates, $input, $expectedOutput ) {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->firstOnly = false;
 | 
						|
		$config->skipTemplates = $skipTemplates;
 | 
						|
		LinkTitles\Splitter::invalidate();
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideLinkContentTemplatesData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				true, // skipTemplates
 | 
						|
				'With skipTemplates = true, a {{template|with=link target}} in it should not be linked',
 | 
						|
				'With skipTemplates = true, a {{template|with=link target}} in it should not be linked',
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // skipTemplates
 | 
						|
				'With skipTemplates = false, a {{template|with=link target}} in it should be linked',
 | 
						|
				'With skipTemplates = false, a {{template|with=[[link target]]}} in it should be linked',
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // skipTemplates
 | 
						|
				'With skipTemplates = false, a {{template|with=already linked [[link target]]}} in it should not be linked again',
 | 
						|
				'With skipTemplates = false, a {{template|with=already linked [[link target]]}} in it should not be linked again',
 | 
						|
			]
 | 
						|
		];
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideLinkContentSmartModeData
 | 
						|
	 */
 | 
						|
	public function testLinkContentSmartMode( $capitalLinks, $smartMode, $input, $expectedOutput ) {
 | 
						|
		$this->setMwGlobals( 'wgCapitalLinks', $capitalLinks );
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->firstOnly = false;
 | 
						|
		$config->smartMode = $smartMode;
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideLinkContentSmartModeData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				true, // wgCapitalLinks
 | 
						|
				true, // smartMode
 | 
						|
				'With smart mode on and $wgCapitalLinks = true, this page should link to link target',
 | 
						|
				'With smart mode on and $wgCapitalLinks = true, this page should link to [[link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // wgCapitalLinks
 | 
						|
				false, // smartMode
 | 
						|
				'With smart mode off and $wgCapitalLinks = true, this page should link to link target',
 | 
						|
				'With smart mode off and $wgCapitalLinks = true, this page should link to [[link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // wgCapitalLinks
 | 
						|
				true, // smartMode
 | 
						|
				'With smart mode on and $wgCapitalLinks = true, this page should link to Link target',
 | 
						|
				'With smart mode on and $wgCapitalLinks = true, this page should link to [[Link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // wgCapitalLinks
 | 
						|
				false, // smartMode
 | 
						|
				'With smart mode off and $wgCapitalLinks = true, this page should not link to Link Target',
 | 
						|
				'With smart mode off and $wgCapitalLinks = true, this page should not link to Link Target'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				true, // smartMode
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to Link target',
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to [[Link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				true, // smartMode
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to link target',
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to [[Link target|link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				false, // smartMode
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to link target',
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to link target'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				false, // smartMode
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to Link target',
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to [[Link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				true, // smartMode
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to Link target',
 | 
						|
				'With smart mode on and $wgCapitalLinks = false, this page should link to [[Link target]]'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // wgCapitalLinks
 | 
						|
				false, // smartMode
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to Link Target',
 | 
						|
				'With smart mode off and $wgCapitalLinks = false, this page should not link to Link Target'
 | 
						|
			],
 | 
						|
		];
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideLinkContentFirstOnlyData
 | 
						|
	 */
 | 
						|
	public function testLinkContentFirstOnly( $firstOnly, $input, $expectedOutput ) {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->firstOnly = $firstOnly;
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideLinkContentFirstOnlyData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				false, // firstOnly
 | 
						|
				'With firstOnly = false, link target is a link target multiple times',
 | 
						|
				'With firstOnly = false, [[link target]] is a [[link target]] multiple times'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // firstOnly
 | 
						|
				'With firstOnly = false, [[link target]] is a link target multiple times',
 | 
						|
				'With firstOnly = false, [[link target]] is a [[link target]] multiple times'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // firstOnly
 | 
						|
				'With firstOnly = true, link target is a link target only once',
 | 
						|
				'With firstOnly = true, [[link target]] is a link target only once'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // firstOnly
 | 
						|
				'With firstOnly = true, [[link target]] is a link target only once',
 | 
						|
				'With firstOnly = true, [[link target]] is a link target only once'
 | 
						|
			],
 | 
						|
		];
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideLinkContentHeadingsData
 | 
						|
	 */
 | 
						|
	public function testLinkContentHeadings( $parseHeadings, $input, $expectedOutput ) {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->parseHeadings = $parseHeadings;
 | 
						|
		LinkTitles\Splitter::invalidate();
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideLinkContentHeadingsData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				true, // parseHeadings
 | 
						|
				"With parseHeadings = true,\n== a heading with link target in it ==\n should be linked",
 | 
						|
				"With parseHeadings = true,\n== a heading with [[link target]] in it ==\n should be linked",
 | 
						|
			],
 | 
						|
			[
 | 
						|
				true, // parseHeadings
 | 
						|
				"With parseHeadings = true,\n== <span>a heading with link target in ity/span> ==\n should be linked",
 | 
						|
				"With parseHeadings = true,\n== <span>a heading with [[link target]] in ity/span> ==\n should be linked",
 | 
						|
			],
 | 
						|
			[
 | 
						|
				false, // parseHeadings
 | 
						|
				"With parseHeadings = false,\n== a heading with link target in it ==\n should not be linked",
 | 
						|
				"With parseHeadings = false,\n== a heading with link target in it ==\n should not be linked",
 | 
						|
			],
 | 
						|
		];
 | 
						|
	}
 | 
						|
 | 
						|
	public function testLinkContentBlackList() {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->blackList = [ 'Foo', 'Link target', 'Bar' ];
 | 
						|
		LinkTitles\Targets::invalidate();
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$text = 'If the link target is blacklisted, it should not be linked';
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $text, $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $text; }
 | 
						|
		$this->assertSame( $text, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	// Tests for namespace handling are commented out until I find a way to add
 | 
						|
	// a custom namespace during testing. (The assertTrue assertion below fails.)
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @dataProvider provideLinkContentNamespacesData
 | 
						|
	 */
 | 
						|
	public function testLinkContentTargetNamespaces( $namespaces, $input, $expectedOutput ) {
 | 
						|
		$config = new LinkTitles\Config();
 | 
						|
		$config->targetNamespaces = $namespaces;
 | 
						|
 | 
						|
		$ns = 4000;
 | 
						|
		$nsText = 'customnamespace';
 | 
						|
		$this->mergeMwGlobalArrayValue( 'wgExtraNamespaces', [ $ns => $nsText ] );
 | 
						|
 | 
						|
		// Reset namespace caches.
 | 
						|
		// See https://stackoverflow.com/q/45974979/270712
 | 
						|
		$namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
 | 
						|
		$namespaceInfo->getCanonicalNamespaces( true );
 | 
						|
		$wgContLang = \MediaWiki\MediaWikiServices::getInstance()->getContentLanguage();
 | 
						|
		$wgContLang->resetNamespaces();
 | 
						|
		$this->assertTrue( $namespaceInfo->exists( $ns ), "The namespace with id $ns should exist!" );
 | 
						|
 | 
						|
		$this->insertPage( "in custom namespace", 'This is a page in a custom namespace', $ns );
 | 
						|
		LinkTitles\Targets::invalidate();
 | 
						|
		$linker = new LinkTitles\Linker( $config );
 | 
						|
		$source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config );
 | 
						|
		$result = $linker->linkContent( $source );
 | 
						|
		if ( !$result ) { $result = $input; }
 | 
						|
		$this->assertSame( $expectedOutput, $result );
 | 
						|
	}
 | 
						|
 | 
						|
	public function provideLinkContentNamespacesData() {
 | 
						|
		return [
 | 
						|
			[
 | 
						|
				[], // namespaces
 | 
						|
				'With targetNamespaces = [], page in custom namespace should not be linked',
 | 
						|
				'With targetNamespaces = [], page in custom namespace should not be linked'
 | 
						|
			],
 | 
						|
			[
 | 
						|
				[ 4000 ], // namespaces
 | 
						|
				'With targetNamespaces = [ 4000 ], page in custom namespace should be linked',
 | 
						|
				'With targetNamespaces = [ 4000 ], page [[customnamespace:In custom namespace|in custom namespace]] should be linked'
 | 
						|
			],
 | 
						|
		];
 | 
						|
	}
 | 
						|
}
 |