tests/link_tests.py
#!/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 refrom contextlib import suppress import pywikibotfrom pywikibot import Site, configfrom pywikibot.exceptions import InvalidTitleError, SiteDefinitionErrorfrom pywikibot.page import Link, Page, SiteLinkfrom pywikibot.site import Namespacefrom tests.aspects import ( AlteredDefaultSiteTestCase, DefaultDrySiteTestCase, TestCase, WikimediaDefaultSiteTestCase, unittest,) 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) 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 class TestLink(DefaultDrySiteTestCase): """Test parsing links with DrySite. The DrySite is using the builtin namespaces which behaviour is controlled in this repository so namespace aware tests do work, even when the actual default site is using completely different namespaces. """ def replaced(self, iterable): """Replace family specific title delimiter.""" for items in iterable: if isinstance(items, str): items = [items] items = [re.sub(' ', self.site.family.title_delimiter_and_aliases[0], item) for item in items] if len(items) == 1: items = items[0] yield items def test_valid(self): """Test that valid titles are correctly normalized.""" title_tests = ['Sandbox', 'A "B"', "A 'B'", '.com', '~', '"', "'", 'Foo/.../Sandbox', 'Sandbox/...', 'A~~', 'X' * 252] extended_title_tests = [ ('Talk:Sandbox', 'Sandbox'), ('Talk:Foo:Sandbox', 'Foo:Sandbox'), ('File:Example.svg', 'Example.svg'), ('File_talk:Example.svg', 'Example.svg'), (':A', 'A'), # Length is 256 total, but only title part matters ('Category:' + 'X' * 248, 'X' * 248), ('A%20B', 'A B'), ('A é B', 'A é B'), ('A é B', 'A é B'), ('A é B', 'A é B'), ('A B', 'A B'), ('A   B', 'A B'), ] site = self.site for title in self.replaced(title_tests): with self.subTest(title=title): self.assertEqual(Link(title, site).title, title) for link, title in self.replaced(extended_title_tests): with self.subTest(link=link, title=title): self.assertEqual(Link(link, site).title, title) anchor_link = Link('A | B', site) self.assertEqual(anchor_link.title, 'A') self.assertEqual(anchor_link.anchor, ' B') section_link = Link('A%23B', site) self.assertEqual(section_link.title, 'A') self.assertEqual(section_link.section, 'B') def test_invalid(self): """Test that invalid titles raise InvalidTitleError.""" # Bad characters forbidden regardless of wgLegalTitleChars def generate_contains_illegal_chars_exc_regex(text): exc_regex = (rf'^(u|)\'{re.escape(text)}\' contains illegal char' rf'\(s\) (u|)\'{re.escape(text[2])}\'$') return exc_regex # Directory navigation def generate_contains_dot_combinations_exc_regex(text): exc_regex = (rf'^\(contains \. / combinations\): (u|)' rf'\'{re.escape(text)}\'$') return exc_regex # Tilde def generate_contains_tilde_exc_regex(text): exc_regex = rf'^\(contains ~~~\): (u|)\'{re.escape(text)}\'$' return exc_regex # Overlength def generate_overlength_exc_regex(text): exc_regex = rf'^\(over 255 bytes\): (u|)\'{re.escape(text)}\'$' return exc_regex # Namespace prefix without actual title def generate_has_no_title_exc_regex(text): exc_regex = rf'^(u|)\'{re.escape(text.strip())}\' has no title\.$' return exc_regex title_tests = [ # Empty title (['', ':'], r'^The link \[\[.*\]\] does not contain a page title$'), (['A [ B', 'A ] B', 'A { B', 'A } B', 'A < B', 'A > B'], generate_contains_illegal_chars_exc_regex), # URL encoding # %XX is understood by wikimedia but not %XXXX (['A%2523B'], r'^(u|)\'A%23B\' contains illegal char\(s\) (u|)\'%23\'$'), # A link is invalid if their (non-)talk page would be in another # namespace than the link's "other" namespace (['Talk:File:Example.svg'], r"The \(non-\)talk page of 'Talk:File:Example.svg'" r' is a valid title in another namespace.'), (['.', '..', './Sandbox', '../Sandbox', 'Foo/./Sandbox', 'Foo/../Sandbox', 'Sandbox/.', 'Sandbox/..'], generate_contains_dot_combinations_exc_regex), (['A ~~~ Name', 'A ~~~~ Signature', 'A ~~~~~ Timestamp'], generate_contains_tilde_exc_regex), ([('x' * 256), ('Invalid:' + 'X' * 248)], generate_overlength_exc_regex), (['Talk:'], generate_has_no_title_exc_regex), ] # Known issues with wikihow. if self.site.family.name != 'wikihow': title_tests.extend([ (['Category: ', 'Category: #bar'], generate_has_no_title_exc_regex), (['__ __', ' __ '], r'^The link \[\[\]\] does not contain a page title$'), ]) for texts_to_test, exception_regex in title_tests: for text in self.replaced(texts_to_test): with self.subTest(title=text): if callable(exception_regex): regex = exception_regex(text) else: regex = exception_regex with self.assertRaisesRegex(InvalidTitleError, regex): Link(text, self.site).parse() def test_relative(self): """Test that relative links are handled properly.""" # Subpage page = Page(self.site, 'Foo') rel_link = Link('/bar', page) self.assertEqual(rel_link.title, 'Foo/bar') self.assertEqual(rel_link.site, self.site) # Subpage of Page with section page = Page(self.site, 'Foo#Baz') rel_link = Link('/bar', page) self.assertEqual(rel_link.title, 'Foo/bar') self.assertEqual(rel_link.site, self.site) # Non-subpage link text beginning with slash abs_link = Link('/bar', self.site) self.assertEqual(abs_link.title, '/bar') class Issue10254TestCase(DefaultDrySiteTestCase): """Test T102461 (Python issue 10254).""" 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 ':'. class LinkTestCase(AlteredDefaultSiteTestCase): """Cached API test for link tests.""" cache = True class LinkTestWikiEn(LinkTestCase): """Link tests on wikipedia:en.""" family = 'wikipedia' code = 'en' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia' class TestPartiallyQualifiedExplicitLinkSameSiteParser(LinkTestWikiEn): """Link tests.""" 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) 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) 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) 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) Similar blocks of code found in 4 locations. Consider refactoring.class TestPartiallyQualifiedExplicitLinkDifferentCodeParser(LinkTestWikiEn): """Link tests.""" 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) 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) Similar blocks of code found in 3 locations. Consider refactoring.class TestPartiallyQualifiedExplicitLinkDifferentFamilyParser(LinkTestCase): """Link tests.""" family = 'wikipedia' code = 'en' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource' 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) 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) class TestFullyQualifiedSameNamespaceFamilyParser(LinkTestCase): """Link tests.""" family = 'wikipedia' code = 'en' 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) Similar blocks of code found in 4 locations. Consider refactoring.class TestFullyQualifiedExplicitLinkSameFamilyParser(LinkTestWikiEn): """Link tests.""" 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) 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) class TestFullyQualifiedLinkDifferentFamilyParser(LinkTestCase): """Test link to a different family with and without preleading colon.""" family = 'wikipedia' code = 'en' PATTERN = '{colon}{first}:{second}:{title}' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource' 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) 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) class TestFullyQualifiedExplicitLinkNoLangConfigFamilyParser(LinkTestCase): """Test link from family without lang code to a different family.""" family = 'wikipedia' code = 'en' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'wikidata' config.family = 'wikidata' 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) 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) 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) 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) class TestFullyQualifiedNoLangFamilyExplicitLinkParser(LinkTestCase): """Test wikibase links.""" sites = { 'wikidata': { 'family': 'wikidata', 'code': 'wikidata' }, 'test': { 'family': 'wikipedia', 'code': 'test' }, } def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia' def test_fully_qualified_NS_code(self): """Test ':testwiki:wikidata:Q6' on enwp.""" for ns, title in enumerate(['Q6', 'Talk:Q6']): with self.subTest(title=title): link = Link(f':testwiki:wikidata:{title}') link.parse() self.assertEqual(link.site, self.get_site('wikidata')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, ns) def test_fully_qualified_NS_family(self): """Test ':wikidata:testwiki:Q6' on enwp.""" for ns, title in enumerate(['Q6', 'Talk:Q6']): with self.subTest(title=title): link = Link(f':wikidata:testwiki:{title}') link.parse() self.assertEqual(link.site, self.get_site('test')) self.assertEqual(link.title, 'Q6') self.assertEqual(link.namespace, ns) Similar blocks of code found in 3 locations. Consider refactoring.class TestFullyQualifiedOneSiteFamilyExplicitLinkParser(LinkTestCase): """Test links to one site target family.""" family = 'species' code = 'species' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia' 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) 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. class TestPartiallyQualifiedImplicitLinkSameSiteParser(LinkTestWikiEn): """Test partially qualified links to same site.""" 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) 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) 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) 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) Similar blocks of code found in 4 locations. Consider refactoring.class TestPartiallyQualifiedImplicitLinkDifferentCodeParser(LinkTestWikiEn): """Test partially qualified links to different code.""" 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) 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) Similar blocks of code found in 3 locations. Consider refactoring.class TestPartiallyQualifiedImplicitLinkDifferentFamilyParser(LinkTestCase): """Test partially qualified links to different family.""" family = 'wikipedia' code = 'en' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikisource' 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) 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) Similar blocks of code found in 4 locations. Consider refactoring.class TestFullyQualifiedImplicitLinkSameFamilyParser(LinkTestWikiEn): """Link tests.""" 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) 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) class TestFullyQualifiedImplicitLinkNoLangConfigFamilyParser(LinkTestCase): """Test implicit link from family without lang code to other family.""" family = 'wikipedia' code = 'en' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'wikidata' config.family = 'wikidata' 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) 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) 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') 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) class TestFullyQualifiedNoLangFamilyImplicitLinkParser(LinkTestCase): """Test wikibase links without preleading colon.""" family = 'wikidata' code = 'test' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia' 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) 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) class TestFullyQualifiedOneSiteFamilyImplicitLinkParser(LinkTestCase): """Test links to one site target family without preleading colon.""" family = 'species' code = 'species' def setUp(self): """Setup tests.""" super().setUp() config.mylang = 'en' config.family = 'wikipedia' 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) 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) 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) 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) class TestEmptyTitle(TestCase): """Test links which contain no title.""" family = 'wikipedia' code = 'en' 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) 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() 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() 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) class TestForeignInterwikiLinks(WikimediaDefaultSiteTestCase): """Test links to non-wikis.""" family = 'wikipedia' code = 'en' def test_non_wiki_prefix(self): """Test that Link fails if the interwiki prefix is not a wiki. *bugzilla* does not return a json content but redirects to phab. api.Request._json_loads cannot detect this problem and raises a :exc:`exceptions.SiteDefinitionError`. The site is created anyway but the title cannot be parsed: """ link = Link('bugzilla:1337', source=self.site) with self.assertRaises(SiteDefinitionError): link.site self.assertEqual(link.site.sitename, 'wikimedia:wikimedia') self.assertTrue(link._is_interwiki) def test_other_wiki_prefix(self): """Test that Link fails if the interwiki prefix is a unknown family. Sometimes *bulba* does not return a json content but a security script. api.Request._json_loads raises a :exc:`exceptions.SiteDefinitionError` for an invalid :class:`Autofamily('bulbapedia.bulbagarden.net') <family.AutoFamily>`. The site is created anyway but the title cannot be parsed in such case. """ link = Link('bulba:title on auto-generated Site', source=self.site) try: link.site except SiteDefinitionError as e: # pragma: no cover self.assertEqual( str(e), "Invalid AutoFamily('bulbapedia.bulbagarden.net')") else: self.assertEqual(link.title, 'Title on auto-generated Site') self.assertEqual(link.site.sitename, 'bulba:bulba') self.assertTrue(link._is_interwiki) def test_invalid_wiki_prefix(self): """Test that Link with prefix not listed in InterwikiMap.""" title = 'Unknownprefix:This title' link = Link(title, source=self.site) self.assertEqual(link.title, title) self.assertEqual(link.site, self.site) self.assertFalse(link._is_interwiki) class TestSiteLink(WikimediaDefaultSiteTestCase): """Test parsing namespaces when creating SiteLinks.""" def _test_link(self, link, title, namespace, site_code, site_fam): """Test the separate contents of the link.""" self.assertEqual(link.title, title) self.assertEqual(link.namespace, namespace) self.assertEqual(link.site, Site(site_code, site_fam)) self.assertEqual(link.badges, []) def test_site_link(self): """Test parsing of title.""" self._test_link(SiteLink('Foobar', 'enwiki'), 'Foobar', Namespace.MAIN, 'en', 'wikipedia') self._test_link(SiteLink('Mall:!!', 'svwiki'), '!!', Namespace.TEMPLATE, 'sv', 'wikipedia') self._test_link(SiteLink('Vorlage:!!', 'dewikibooks'), '!!', Namespace.TEMPLATE, 'de', 'wikibooks') self._test_link(SiteLink('Ai Weiwei: Never Sorry', 'enwiki'), 'Ai Weiwei: Never Sorry', Namespace.MAIN, 'en', 'wikipedia') if __name__ == '__main__': with suppress(SystemExit): unittest.main()