#!/usr/bin/env python3
"""Tests against a fake Site object."""
#
# (C) Pywikibot team, 2012-2023
#
# Distributed under the terms of the MIT license.
#
import unittest
from pywikibot.exceptions import UserRightsError
from pywikibot.site._decorators import must_be, need_right, need_version
from pywikibot.tools import deprecated
from tests.aspects import TestCase, DeprecationTestCase
[docs]
class TestMustBe(TestCase):
"""Test cases for the must_be decorator."""
net = False
# Implemented without setUpClass(cls) and global variables as objects
# were not completely disposed and recreated but retained 'memory'
[docs]
def setUp(self):
"""Creating fake variables to appear as a site."""
self.code = 'test'
self.family = lambda: None
self.family.name = 'test'
self.sitename = self.family.name + ':' + self.code
self._logged_in_as = None
self._userinfo = []
self.obsolete = False
super().setUp()
self.version = lambda: '1.23' # lowest supported release
[docs]
def login(self, group):
"""Fake the log in as required user group."""
self._logged_in_as = group
self._userinfo = [group]
[docs]
def user(self):
"""Fake the logged in user."""
return self._logged_in_as
[docs]
def has_group(self, group):
"""Fake the groups user belongs to."""
return group in self._userinfo
[docs]
def test_mock_in_test(self):
"""Test that setUp and login work."""
self.assertIsNone(self._logged_in_as)
self.login('user')
self.assertEqual(self._logged_in_as, 'user')
# Test that setUp is actually called between each test
test_mock_in_test_reset = test_mock_in_test
[docs]
@must_be('steward')
def call_this_steward_req_function(self, *args, **kwargs):
"""Require a sysop to function."""
return args, kwargs
[docs]
@must_be('sysop')
def call_this_sysop_req_function(self, *args, **kwargs):
"""Require a sysop to function."""
return args, kwargs
[docs]
@must_be('user')
def call_this_user_req_function(self, *args, **kwargs):
"""Require a user to function."""
return args, kwargs
[docs]
def test_must_be_steward(self):
"""Test a function which requires a sysop."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('steward')
retval = self.call_this_steward_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
[docs]
def test_must_be_sysop(self):
"""Test a function which requires a sysop."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('sysop')
retval = self.call_this_sysop_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
with self.assertRaises(UserRightsError):
self.call_this_steward_req_function(args, kwargs)
[docs]
def test_must_be_user(self):
"""Test a function which requires a user."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('user')
retval = self.call_this_user_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
with self.assertRaises(UserRightsError):
self.call_this_sysop_req_function(args, kwargs)
[docs]
def test_override_usertype(self):
"""Test overriding the required group."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('sysop')
retval = self.call_this_user_req_function(
*args, as_group='sysop', **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
[docs]
def test_obsolete_site(self):
"""Test when the site is obsolete and shouldn't be edited."""
self.obsolete = True
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('steward')
retval = self.call_this_user_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
self.login('user')
with self.assertRaises(UserRightsError):
self.call_this_user_req_function(args, kwargs)
[docs]
class TestNeedRight(TestCase):
"""Test cases for the must_be decorator."""
net = False
# Implemented without setUpClass(cls) and global variables as objects
# were not completely disposed and recreated but retained 'memory'
[docs]
def setUp(self):
"""Creating fake variables to appear as a site."""
self.code = 'test'
self.family = lambda: None
self.family.name = 'test'
self.sitename = self.family.name + ':' + self.code
self._logged_in_as = None
self._userinfo = []
self.obsolete = False
super().setUp()
self.version = lambda: '1.23' # lowest supported release
[docs]
def login(self, group, right):
"""Fake the log in as required user group."""
self._logged_in_as = group
self._userinfo = [right]
[docs]
def user(self):
"""Fake the logged in user."""
return self._logged_in_as
[docs]
def has_right(self, right):
"""Fake the groups user belongs to."""
return right in self._userinfo
[docs]
@need_right('edit')
def call_this_edit_req_function(self, *args, **kwargs):
"""Require a sysop to function."""
return args, kwargs
[docs]
@need_right('move')
def call_this_move_req_function(self, *args, **kwargs):
"""Require a sysop to function."""
return args, kwargs
[docs]
def test_need_right_edit(self):
"""Test a function which requires a sysop."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('user', 'edit')
retval = self.call_this_edit_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
[docs]
def test_need_right_move(self):
"""Test a function which requires a sysop."""
args = (1, 2, 'a', 'b')
kwargs = {'i': 'j', 'k': 'l'}
self.login('user', 'move')
retval = self.call_this_move_req_function(*args, **kwargs)
self.assertEqual(retval[0], args)
self.assertEqual(retval[1], kwargs)
with self.assertRaises(UserRightsError):
self.call_this_edit_req_function(args, kwargs)
[docs]
class TestNeedVersion(DeprecationTestCase):
"""Test cases for the need_version decorator."""
net = False
# Implemented without setUpClass(cls) and global variables as objects
# were not completely disposed and recreated but retained 'memory'
[docs]
def setUp(self):
"""Set up test method."""
super().setUp()
self.version = lambda: '1.23'
[docs]
@need_version('1.24')
def too_new(self):
"""Method which is to new."""
return True
[docs]
@need_version('1.23')
def old_enough(self):
"""Method which is as new as the server."""
return True
[docs]
@need_version('1.22')
def older(self):
"""Method which is old enough."""
return True
[docs]
@need_version('1.24')
@deprecated
def deprecated_unavailable_method(self):
"""Method which is to new and then deprecated."""
return True
[docs]
@deprecated
@need_version('1.24')
def deprecated_unavailable_method2(self):
"""Method which is deprecated first and then to new."""
return True
[docs]
@need_version('1.22')
@deprecated
def deprecated_available_method(self):
"""Method which is old enough and then deprecated."""
return True
[docs]
@deprecated
@need_version('1.22')
def deprecated_available_method2(self):
"""Method which is deprecated first and then old enough."""
return True
[docs]
def test_need_version(self):
"""Test need_version when the version is new, exact or old enough."""
with self.assertRaises(NotImplementedError):
self.too_new()
self.assertTrue(self.old_enough())
self.assertTrue(self.older())
[docs]
def test_need_version_fail_with_deprecated(self):
"""Test order of combined version check and deprecation warning."""
# FIXME: The deprecation message should be:
# __name__ + '.TestNeedVersion.deprecated_unavailable_method
# The outermost decorator is the version check, so no
# deprecation message.
with self.assertRaisesRegex(
NotImplementedError,
'deprecated_unavailable_method'):
self.deprecated_unavailable_method()
self.assertNoDeprecation()
# The deprecator is first, but the version check still
# raises exception.
with self.assertRaisesRegex(
NotImplementedError,
'deprecated_unavailable_method2'):
self.deprecated_unavailable_method2()
self.assertOneDeprecationParts(
__name__ + '.TestNeedVersion.deprecated_unavailable_method2')
[docs]
def test_need_version_success_with_deprecated(self):
"""Test order of combined version check and deprecation warning."""
self.deprecated_available_method()
self.assertOneDeprecationParts(
__name__ + '.TestNeedVersion.deprecated_available_method')
self.deprecated_available_method2()
self.assertOneDeprecationParts(
__name__ + '.TestNeedVersion.deprecated_available_method2')
if __name__ == '__main__': # pragma: no cover
unittest.main()