Source code for tests.family_tests

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

from collections.abc import Mapping
from contextlib import suppress

import pywikibot
from pywikibot.exceptions import UnknownFamilyError
from pywikibot.family import Family, SingleSiteFamily
from tests.aspects import PatchingTestCase, TestCase, unittest
from tests.utils import DrySite


[docs] class TestFamily(TestCase): """Test cases for Family methods.""" net = False
[docs] def test_family_load_valid(self): """Test that a family can be loaded via Family.load.""" for name in pywikibot.config.family_files: with self.subTest(family=name): f = Family.load(name) self.assertIsInstance(f.langs, dict) self.assertTrue(f.langs) self.assertTrue(f.codes) self.assertTrue(iter(f.codes)) self.assertIsInstance(next(iter(f.codes)), str) self.assertTrue(f.domains) self.assertTrue(iter(f.domains)) for domain in f.domains: self.assertIsInstance(domain, str) if not domain.startswith('localhost:'): self.assertIn('.', domain) self.assertEqual(f.name, name) self.assertIsInstance(f.codes, set) self.assertGreaterEqual(set(f.langs), set(f.codes)) if isinstance(f, SingleSiteFamily): self.assertIsNotNone(f.code) self.assertIsNotNone(f.domain) self.assertEqual(set(f.langs), {f.code}) self.assertEqual(set(f.codes), {f.code})
[docs] def test_family_load_invalid(self): """Test that an invalid family raised UnknownFamilyError.""" with self.assertRaisesRegex( UnknownFamilyError, 'Family unknown does not exist'): Family.load('unknown')
[docs] def test_new_same_family_singleton(self): """Test that two same Family are the same object and equal.""" family_1 = Family.load('wikipedia') family_2 = Family.load('wikipedia') self.assertIs(family_1, family_2) self.assertEqual(family_1, family_2)
[docs] def test_new_different_families_ne(self): """Test that two different Family are not same nor equal.""" family_1 = Family.load('wikipedia') family_2 = Family.load('wiktionary') self.assertIsNot(family_1, family_2) self.assertNotEqual(family_1, family_2)
[docs] def test_eq_family_with_string_repr_same_family(self): """Test that Family and string with same name are equal.""" family = Family.load('wikipedia') other = 'wikipedia' self.assertEqual(family, other) self.assertFalse(family != other) # noqa: H204
[docs] def test_ne_family_with_string_repr_different_family(self): """Test that Family and string with different name are not equal.""" family = Family.load('wikipedia') other = 'wikisource' self.assertNotEqual(family, other) self.assertFalse(family == other) # noqa: H204
[docs] def test_eq_family_with_string_repr_not_existing_family(self): """Test that Family and string with different name are not equal.""" family = Family.load('wikipedia') other = 'unknown' with self.assertRaisesRegex( UnknownFamilyError, 'Family unknown does not exist'): family.__eq__(other)
[docs] def test_get_obsolete_wp(self): """Test three types of obsolete codes.""" family = Family.load('wikipedia') self.assertIsInstance(family.obsolete, Mapping) # redirected code (see site tests test_alias_code_site) self.assertEqual(family.code_aliases['dk'], 'da') self.assertEqual(family.interwiki_replacements['dk'], 'da') self.assertEqual(family.obsolete['dk'], 'da') # closed/locked site (see site tests test_locked_site) self.assertIsNone(family.obsolete['mh']) # offline site (see site tests test_removed_site) self.assertIsNone(family.obsolete['ru-sib']) self.assertIn('dk', family.interwiki_replacements)
[docs] def test_obsolete_from_attributes(self): """Test obsolete property for given class attributes.""" # Construct a temporary family and instantiate it family = type('TempFamily', (Family,), {})() self.assertEqual(family.obsolete, {}) self.assertEqual(family.interwiki_replacements, {}) self.assertEqual(family.interwiki_removals, frozenset()) # Construct a temporary family with other attributes and instantiate it family = type('TempFamily', (Family,), {'code_aliases': {'a': 'b'}, 'closed_wikis': ['c']})() self.assertEqual(family.obsolete, {'a': 'b', 'c': None}) self.assertEqual(family.interwiki_replacements, {'a': 'b'}) self.assertEqual(family.interwiki_removals, frozenset('c'))
[docs] def test_obsolete_readonly(self): """Test obsolete result not updatable.""" family = Family.load('wikipedia') with self.assertRaisesRegex( AttributeError, "'mappingproxy' object has no attribute 'update'"): family.obsolete.update({}) with self.assertRaisesRegex( TypeError, "'mappingproxy' object does not support item assignment"): family.obsolete['a'] = 'b' with self.assertRaisesRegex( AttributeError, "property 'obsolete' of 'Family' object has no setter|" "can't set attribute"): family.obsolete = {'a': 'b', 'c': None}
[docs] class TestFamilyUrlRegex(PatchingTestCase): """Test family URL regex.""" net = False
[docs] @PatchingTestCase.patched(pywikibot, 'Site') def Site(self, *args, **kwargs): """Own DrySite creator.""" code, fam, *args = args self.assertEqual(args, []) self.assertEqual(kwargs, {}) self.assertEqual(code, self.current_code) self.assertEqual(fam, self.current_family) site = DrySite(code, fam, None) site._siteinfo._cache['general'] = ({'articlepath': self.articlepath}, True) return site
[docs] def setUp(self): """Setup default article path.""" super().setUp() self.articlepath = '/wiki/$1'
[docs] def test_from_url_wikipedia_extra(self): """Test various URLs against wikipedia regex.""" self.current_code = 'vo' self.current_family = 'wikipedia' f = Family.load('wikipedia') prefix = 'https://vo.wikipedia.org' self.assertEqual(f.from_url(prefix + '/wiki/'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php/'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php?title=$1'), 'vo') self.assertEqual(f.from_url(prefix + '/wiki/$1'), 'vo') self.assertEqual(f.from_url('//vo.wikipedia.org/wiki/$1'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php/$1'), 'vo') self.assertEqual(f.from_url('//vo.wikipedia.org/wiki/$1'), 'vo') # including title self.assertEqual(f.from_url(prefix + '/wiki/Main_page'), 'vo') self.assertEqual(f.from_url(prefix + '/w/index.php?title=Foo'), 'vo') # Text after $1 is allowed self.assertEqual(f.from_url('//vo.wikipedia.org/wiki/$1/foo'), 'vo') # the IWM may contain the wrong protocol, but it's only used to # determine a site so using HTTP or HTTPS is not an issue self.assertEqual(f.from_url('http://vo.wikipedia.org/wiki/$1'), 'vo') # wrong protocol self.assertIsNone(f.from_url('ftp://vo.wikipedia.org/wiki/$1')) # wrong code self.assertIsNone(f.from_url('https://foobar.wikipedia.org/wiki/$1')) # wrong family self.assertIsNone(f.from_url('https://vo.wikibooks.org/wiki/$1')) self.assertIsNone(f.from_url('http://vo.wikibooks.org/wiki/$1')) # invalid path self.assertIsNone(f.from_url('https://vo.wikipedia.org/wik/$1')) self.assertIsNone(f.from_url('https://vo.wikipedia.org/index.php/$1'))
[docs] def test_each_family(self): """Test each family builds a working regex.""" for family in pywikibot.config.family_files: if family == 'wowwiki': self.skipTest( f'Family.from_url() does not work for {family} (T215077)') self.current_family = family family = Family.load(family) for code in family.codes: self.current_code = code url = ('{}://{}{}/$1'.format(family.protocol(code), family.hostname(code), family.path(code))) # Families can switch off if they want to be detected using # URL. This applies for test:test (there is test:wikipedia) with self.subTest(url=url): self.assertEqual(family.from_url(url), code)
if __name__ == '__main__': with suppress(SystemExit): unittest.main()