Source code for tests.link_tests

#!/usr/bin/env python3
"""Test Link functionality."""
#
# (C) Pywikibot team, 2014-2024
#
# Distributed under the terms of the MIT license.
#
from __future__ import annotations

import re
from contextlib import suppress

import pywikibot
from pywikibot import Site, config
from pywikibot.exceptions import InvalidTitleError, SiteDefinitionError
from pywikibot.page import Link, Page, SiteLink
from pywikibot.site import Namespace
from tests.aspects import (
    AlteredDefaultSiteTestCase,
    DefaultDrySiteTestCase,
    TestCase,
    WikimediaDefaultSiteTestCase,
    unittest,
)


[docs] class TestCreateSeparated(DefaultDrySiteTestCase): """Test ``Link.create_separated``.""" def _test_link(self, link, page, section, label): """Test the separate contents of the link.""" self.assertIs(link.site, self.site) self.assertEqual(link.title, page) if section is None: self.assertIsNone(link.section) else: self.assertEqual(link.section, section) if label is None: self.assertIsNone(link.anchor) else: self.assertEqual(link.anchor, label)
[docs] def test(self): """Test combinations of parameters.""" self._test_link(Link.create_separated('Foo', self.site), 'Foo', None, None) self._test_link(Link.create_separated('Foo', self.site, section='Bar'), 'Foo', 'Bar', None) self._test_link(Link.create_separated('Foo', self.site, label='Baz'), 'Foo', None, 'Baz') self._test_link(Link.create_separated('Foo', self.site, section='Bar', label='Baz'), 'Foo', 'Bar', 'Baz')
# ---- Tests checking if the parser does (not) accept (in)valid titles
[docs] class Issue10254TestCase(DefaultDrySiteTestCase): """Test T102461 (Python issue 10254)."""
[docs] def test_no_change(self): """Test T102461 (Python issue 10254) is not encountered.""" title = 'Li̍t-sṳ́' link = Link(title, self.site) self.assertEqual(link.title, 'Li̍t-sṳ́')
# ---- The first set of tests are explicit links, starting with a ':'.
[docs] class LinkTestCase(AlteredDefaultSiteTestCase): """Cached API test for link tests.""" cache = True
[docs] class LinkTestWikiEn(LinkTestCase): """Link tests on wikipedia:en.""" family = 'wikipedia' code = 'en'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia'
[docs] class TestPartiallyQualifiedExplicitLinkSameSiteParser(LinkTestWikiEn): """Link tests."""
[docs] def test_partially_qualified_NS0_code(self): """Test ':wikipedia:Main Page' on enwp is namespace 4.""" link = Link(':wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_partially_qualified_NS1_code(self): """Test ':wikipedia:Talk:Main Page' on enwp is namespace 4.""" link = Link(':wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_partially_qualified_NS0_family(self): """Test ':en:Main Page' on enwp is namespace 0.""" link = Link(':en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_family(self): """Test ':en:Talk:Main Page' on enwp is namespace 1.""" link = Link(':en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestPartiallyQualifiedExplicitLinkDifferentCodeParser(LinkTestWikiEn): """Link tests."""
[docs] def test_partially_qualified_NS0_family(self): """Test ':en:Main Page' on dewp is namespace 0.""" link = Link(':en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_family(self): """Test ':en:Talk:Main Page' on dewp is namespace 1.""" link = Link(':en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestPartiallyQualifiedExplicitLinkDifferentFamilyParser(LinkTestCase): """Link tests.""" family = 'wikipedia' code = 'en'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource'
[docs] def test_partially_qualified_NS0_code(self): """Test ':wikipedia:Main Page' on enws is namespace 0.""" link = Link(':wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_code(self): """Test ':wikipedia:Talk:Main Page' on enws is ns 1.""" link = Link(':wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedSameNamespaceFamilyParser(LinkTestCase): """Link tests.""" family = 'wikipedia' code = 'en'
[docs] def test_namespace_vs_family(self): """Test namespace is selected before family.""" config.mylang = 'en' config.family = 'wikipedia' link = Link(':wikipedia:en:Main Page') link.parse() self.assertEqual(link.title, 'En:Main Page') self.assertEqual(link.namespace, 4) link = Link(':wikipedia:en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'En:Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] class TestFullyQualifiedExplicitLinkSameFamilyParser(LinkTestWikiEn): """Link tests."""
[docs] def test_fully_qualified_NS0_code(self): """Test ':en:wikipedia:Main Page' on enwp is namespace 4.""" link = Link(':en:wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS1_code(self): """Test ':en:wikipedia:Talk:Main Page' on enwp is namespace 4.""" link = Link(':en:wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] class TestFullyQualifiedLinkDifferentFamilyParser(LinkTestCase): """Test link to a different family with and without preleading colon.""" family = 'wikipedia' code = 'en' PATTERN = '{colon}{first}:{second}:{title}'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource'
[docs] def test_fully_qualified_NS0(self): """Test that fully qualified link is in namespace 0.""" family, code = 'wikipedia', 'en' for colon in ('', ':'): # with or without preleading colon # switch code:family sequence en:wikipedia or wikipedia:en for first, second in [(family, code), (code, family)]: with self.subTest(colon=colon, site=f'{first}:{second}'): link_title = self.PATTERN.format(colon=colon, first=first, second=second, title='Main Page') link = Link(link_title) link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1(self): """Test that fully qualified link is in namespace 1.""" family, code = 'wikipedia', 'en' for colon in ('', ':'): # with or without preleading colon # switch code:family sequence en:wikipedia or wikipedia:en for first, second in [(family, code), (code, family)]: with self.subTest(colon=colon, site=f'{first}:{second}'): link_title = self.PATTERN.format(colon=colon, first=first, second=second, title='Talk:Main Page') link = Link(link_title) link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedExplicitLinkNoLangConfigFamilyParser(LinkTestCase): """Test link from family without lang code to a different family.""" family = 'wikipedia' code = 'en'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'wikidata' config.family = 'wikidata'
[docs] def test_fully_qualified_NS0_code(self): """Test ':en:wikipedia:Main Page' on wikidata is namespace 4.""" link = Link(':en:wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS1_code(self): """Test ':en:wikipedia:Talk:Main Page' on wikidata is namespace 4.""" link = Link(':en:wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS0_family(self): """Test ':wikipedia:en:Main Page' on wikidata is namespace 0.""" link = Link(':wikipedia:en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_family(self): """Test ':wikipedia:en:Talk:Main Page' on wikidata is namespace 1.""" link = Link(':wikipedia:en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedNoLangFamilyExplicitLinkParser(LinkTestCase): """Test wikibase links.""" sites = { 'wikidata': { 'family': 'wikidata', 'code': 'wikidata' }, 'test': { 'family': 'wikipedia', 'code': 'test' }, }
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia'
[docs] def test_fully_qualified_NS0_code(self): """Test ':testwiki:wikidata:Q6' on enwp is namespace 0.""" link = Link(':testwiki:wikidata:Q6') link.parse() self.assertEqual(link.site, self.get_site('wikidata')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_code(self): """Test ':testwiki:wikidata:Talk:Q6' on enwp is namespace 1.""" link = Link(':testwiki:wikidata:Talk:Q6') link.parse() self.assertEqual(link.site, self.get_site('wikidata')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 1)
[docs] def test_fully_qualified_NS0_family(self): """Test ':wikidata:testwiki:Q6' on enwp is namespace 0.""" config.family = 'wikipedia' link = Link(':wikidata:testwiki:Q6') link.parse() self.assertEqual(link.site, self.get_site('test')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_family(self): """Test ':wikidata:testwiki:Talk:Q6' on enwp is namespace 1.""" link = Link(':wikidata:testwiki:Talk:Q6') link.parse() self.assertEqual(link.site, self.get_site('test')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedOneSiteFamilyExplicitLinkParser(LinkTestCase): """Test links to one site target family.""" family = 'species' code = 'species'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia'
[docs] def test_fully_qualified_NS0_code(self): """Test ':species:species:Main Page' on species is namespace 0.""" link = Link(':species:species:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_code(self): """Test ':species:species:Talk:Main Page' on species is namespace 1.""" link = Link(':species:species:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
# ---- Tests of a Link without colons, which shouldn't be interwikis, follow.
[docs] class TestPartiallyQualifiedImplicitLinkSameSiteParser(LinkTestWikiEn): """Test partially qualified links to same site."""
[docs] def test_partially_qualified_NS0_code(self): """Test 'wikipedia:Main Page' on enwp is namespace 4.""" link = Link('wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_partially_qualified_NS1_code(self): """Test 'wikipedia:Talk:Main Page' on enwp is namespace 4.""" link = Link('wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_partially_qualified_NS0_family(self): """Test 'en:Main Page' on enwp is namespace 0.""" link = Link('en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_family(self): """Test 'en:Talk:Main Page' on enwp is namespace 1.""" link = Link('en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestPartiallyQualifiedImplicitLinkDifferentCodeParser(LinkTestWikiEn): """Test partially qualified links to different code."""
[docs] def test_partially_qualified_NS0_family(self): """Test 'en:Main Page' on dewp is namespace 0.""" link = Link('en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_family(self): """Test 'en:Talk:Main Page' on dewp is namespace 1.""" link = Link('en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestPartiallyQualifiedImplicitLinkDifferentFamilyParser(LinkTestCase): """Test partially qualified links to different family.""" family = 'wikipedia' code = 'en'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource'
[docs] def test_partially_qualified_NS0_code(self): """Test 'wikipedia:Main Page' on enws is namespace 0.""" link = Link('wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_partially_qualified_NS1_code(self): """Test 'wikipedia:Talk:Main Page' on enws is ns 1.""" link = Link('wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedImplicitLinkSameFamilyParser(LinkTestWikiEn): """Link tests."""
[docs] def test_fully_qualified_NS0_code(self): """Test 'en:wikipedia:Main Page' on enwp is namespace 4.""" link = Link('en:wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS1_code(self): """Test 'en:wikipedia:Talk:Main Page' on enwp is namespace 4.""" link = Link('en:wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] class TestFullyQualifiedImplicitLinkNoLangConfigFamilyParser(LinkTestCase): """Test implicit link from family without lang code to other family.""" family = 'wikipedia' code = 'en'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'wikidata' config.family = 'wikidata'
[docs] def test_fully_qualified_NS0_code(self): """Test 'en:wikipedia:Main Page' on wikidata is namespace 4.""" link = Link('en:wikipedia:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS1_code(self): """Test 'en:wikipedia:Talk:Main Page' on wikidata isn't namespace 1.""" link = Link('en:wikipedia:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Talk:Main Page') self.assertEqual(link.namespace, 4)
[docs] def test_fully_qualified_NS0_family(self): """Test 'wikipedia:en:Main Page' on wikidata is namespace 0.""" link = Link('wikipedia:en:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.namespace, 0) self.assertEqual(link.title, 'Main Page')
[docs] def test_fully_qualified_NS1_family(self): """Test 'wikipedia:en:Talk:Main Page' on wikidata is namespace 1.""" link = Link('wikipedia:en:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedNoLangFamilyImplicitLinkParser(LinkTestCase): """Test wikibase links without preleading colon.""" family = 'wikidata' code = 'test'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia'
[docs] def test_fully_qualified_NS0(self): """Test prefixed links with 'Q6' on enwp is namespace 0.""" test = [('testwiki:wikidata', 'wikidata:wikidata'), ('wikidata:testwiki', 'wikipedia:test')] for linkprefix, sitetitle in test: with self.subTest(pattern=linkprefix): link = Link(linkprefix + ':Q6') link.parse() self.assertEqual(link.site, pywikibot.Site(sitetitle)) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1(self): """Test prefixed links with 'Talk:Q6' on enwp is namespace 1.""" test = [('testwiki:wikidata', 'wikidata:wikidata'), ('wikidata:testwiki', 'wikipedia:test')] for linkprefix, sitetitle in test: with self.subTest(pattern=linkprefix): link = Link(linkprefix + ':Talk:Q6') link.parse() self.assertEqual(link.site, pywikibot.Site(sitetitle)) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, 1)
[docs] class TestFullyQualifiedOneSiteFamilyImplicitLinkParser(LinkTestCase): """Test links to one site target family without preleading colon.""" family = 'species' code = 'species'
[docs] def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia'
[docs] def test_fully_qualified_NS0_family_code(self): """Test 'species:species:Main Page' on enwp is namespace 0.""" link = Link('species:species:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_family_code(self): """Test 'species:species:Talk:Main Page' on enwp is namespace 1.""" link = Link('species:species:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] def test_fully_qualified_NS0_code(self): """Test 'species:Main Page' on enwp is namespace 0.""" link = Link('species:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 0)
[docs] def test_fully_qualified_NS1_code(self): """Test 'species:Talk:Main Page' on enwp is namespace 1.""" link = Link('species:Talk:Main Page') link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'Main Page') self.assertEqual(link.namespace, 1)
[docs] class TestEmptyTitle(TestCase): """Test links which contain no title.""" family = 'wikipedia' code = 'en'
[docs] def test_interwiki_mainpage(self): """Test that Link allow links without a title to the main page.""" link = Link('en:', self.site) link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, '') self.assertEqual(link.namespace, 0)
[docs] def test_interwiki_namespace_without_title(self): """Test that Link doesn't allow links without a title.""" link = Link('en:Help:', self.site) with self.assertRaisesRegex( InvalidTitleError, "'en:Help:' has no title."): link.parse()
[docs] def test_no_text(self): """Test that Link doesn't allow empty.""" link = Link('', self.site) with self.assertRaisesRegex( InvalidTitleError, r'The link \[\[.*\]\] does not contain a page title'): link.parse()
[docs] def test_namespace_lookalike(self): """Test that Link does only detect valid namespaces.""" link = Link('CAT:', self.site) link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'CAT:') self.assertEqual(link.namespace, 0) link = Link('en:CAT:', self.site) link.parse() self.assertEqual(link.site, self.site) self.assertEqual(link.title, 'CAT:') self.assertEqual(link.namespace, 0)
if __name__ == '__main__': with suppress(SystemExit): unittest.main()