Philipp Hörist pushed to branch gajim_1.3 at gajim / gajim
Commits: 49553cc4 by lovetox at 2022-03-05T08:47:28+01:00 Remove unused test helpers
- - - - - e83c82d5 by lovetox at 2022-03-05T08:48:21+01:00 Move test to broken
- - - - - 07ab6b91 by lovetox at 2022-03-05T08:48:54+01:00 Move nick completion test to no_gui folder
- - - - - 84c317ca by lovetox at 2022-03-05T08:50:30+01:00 Make sure correct gi libs are loaded
- - - - -
10 changed files:
- test/unit/test_gui_interface.py → test/broken/test_gui_interface.py - − test/lib/__init__.py - − test/lib/data.py - − test/lib/gajim_mocks.py - − test/lib/mock.py - − test/lib/notify.py - test/no_gui/__init__.py - test/no_gui/unit/test_nick_completion.py → test/no_gui/test_nick_completion.py - − test/no_gui/unit/__init__.py - − test/unit/__init__.py
Changes:
===================================== test/unit/test_gui_interface.py → test/broken/test_gui_interface.py =====================================
===================================== test/lib/__init__.py deleted ===================================== @@ -1,46 +0,0 @@ -import os - -from tempfile import gettempdir - -# a temporary version of ~/.gajim for testing -configdir = os.path.join(gettempdir(), 'gajim') -os.makedirs(configdir, exist_ok=True) - -# plugins config dir -pluginsconfigdir = configdir + '/pluginsconfig' -# theme config directory -themedir = configdir + '/theme' - -# define _ for i18n -import builtins -builtins._ = lambda x: x - -from gajim.common.contacts import LegacyContactsAPI - -def setup_env(use_x=True): - # wipe config directory - if os.path.isdir(configdir): - import shutil - shutil.rmtree(configdir) - - os.mkdir(configdir) - os.mkdir(pluginsconfigdir) - os.mkdir(themedir) - - from gajim.common import configpaths - configpaths.set_config_root(configdir) - configpaths.init() - - # for some reason gajim.common.app needs to be imported before xmpppy? - from gajim.common import app - - import logging - logging.basicConfig() - - app.use_x = use_x - app.contacts = LegacyContactsAPI() - app.connections = {} - - if use_x: - from gajim.application import GajimApplication - app.app = GajimApplication()
===================================== test/lib/data.py deleted ===================================== @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -account1 = 'acc1' -account2 = 'Cool"chârßéµö' -account3 = 'dingdong.org' - -contacts = {} -contacts[account1] = { - 'myjid@'+account1: { - 'ask': None, 'groups': [], 'name': None, 'resources': {}, - 'subscription': 'both'}, - 'default1@gajim.org': { - 'ask': None, 'groups': [], 'name': None, 'resources': {}, - 'subscription': 'both'}, - 'default2@gajim.org': { - 'ask': None, 'groups': ['GroupA',], 'name': None, 'resources': {}, - 'subscription': 'both'}, - 'Cool"chârßéµö@gajim.org': { - 'ask': None, 'groups': ['<Cool"chârßéµö', 'GroupB'], - 'name': None, 'resources': {}, 'subscription': 'both'}, - 'samejid@gajim.org': { - 'ask': None, 'groups': ['GroupA',], 'name': None, 'resources': {}, - 'subscription': 'both'} -} -contacts[account2] = { - 'myjid@'+account2: { - 'ask': None, 'groups': [], 'name': None, 'resources': {}, - 'subscription': 'both'}, - 'default3@gajim.org': { - 'ask': None, 'groups': ['GroupC',], 'name': None, 'resources': {}, - 'subscription': 'both'}, - 'asksubfrom@gajim.org': { - 'ask': 'subscribe', 'groups': ['GroupA',], 'name': None, - 'resources': {}, 'subscription': 'from'}, - 'subto@gajim.org': { - 'ask': None, 'groups': ['GroupB'], 'name': None, 'resources': {}, - 'subscription': 'to'}, - 'samejid@gajim.org': { - 'ask': None, 'groups': ['GroupA', 'GroupB'], 'name': None, - 'resources': {}, 'subscription': 'both'} -} -contacts[account3] = { - #'guypsych0\40h.com@msn.dingdong.org': { - # 'ask': None, 'groups': [], 'name': None, 'resources': {}, - # 'subscription': 'both'}, - 'guypsych0%h.com@msn.delx.cjb.net': { - 'ask': 'subscribe', 'groups': [], 'name': None, - 'resources': {}, 'subscription': 'from'}, - #'guypsych0%h.com@msn.jabber.wiretrip.org': { - # 'ask': None, 'groups': [], 'name': None, 'resources': {}, - # 'subscription': 'to'}, - #'guypsycho\40g.com@gtalk.dingdong.org': { - # 'ask': None, 'groups': [], 'name': None, - # 'resources': {}, 'subscription': 'both'} -} - -# We have contacts that are not in roster but only specified in the metadata -metacontact_data = [ - [{'account': account3, - 'jid': 'guypsych0\40h.com@msn.dingdong.org', - 'order': 0}, - {'account': account3, - 'jid': 'guypsych0%h.com@msn.delx.cjb.net', - 'order': 0}, - {'account': account3, - 'jid': 'guypsych0%h.com@msn.jabber.wiretrip.org', - 'order': 0}, - {'account': account3, - 'jid': 'guypsycho\40g.com@gtalk.dingdong.org', - 'order': 0}], - - [{'account': account1, - 'jid': 'samejid@gajim.org', - 'order': 0}, - {'account': account2, - 'jid': 'samejid@gajim.org', - 'order': 0}] - ]
===================================== test/lib/gajim_mocks.py deleted ===================================== @@ -1,139 +0,0 @@ -''' -Module with dummy classes for Gajim specific unit testing -''' - -from .mock import Mock -from gajim.common import app -from gajim.common import ged - -from gajim.common.connection_handlers import ConnectionHandlers - -class MockConnection(Mock, ConnectionHandlers): - def __init__(self, account, *args): - Mock.__init__(self, *args) - - self.connection = Mock() - - self.name = account - - ConnectionHandlers.__init__(self) - - self.connected = 2 - self.pep = {} - self.sessions = {} - self.server_resource = 'Gajim' - - app.interface.instances[account] = {'infos': {}, 'disco': {}, - 'gc_config': {}, 'search': {}, 'sub_request': {}} - app.interface.minimized_controls[account] = {} - app.contacts.add_account(account) - app.groups[account] = {} - app.gc_connected[account] = {} - app.automatic_rooms[account] = {} - app.newly_added[account] = [] - app.to_be_removed[account] = [] - app.nicks[account] = app.settings.get_account_setting(account, 'name') - app.block_signed_in_notifications[account] = True - app.last_message_time[account] = {} - - app.connections[account] = self - -class MockWindow(Mock): - def __init__(self, *args): - Mock.__init__(self, *args) - self.window = Mock() - self._controls = {} - - def get_control(self, jid, account): - try: - return self._controls[account][jid] - except KeyError: - return None - - def has_control(self, jid, acct): - return self.get_control(jid, acct) is not None - - def new_tab(self, ctrl): - account = ctrl.account - jid = ctrl.jid - - if account not in self._controls: - self._controls[account] = {} - - if jid not in self._controls[account]: - self._controls[account][jid] = {} - - self._controls[account][jid] = ctrl - - def __nonzero__(self): - return True - -class MockChatControl(Mock): - def __init__(self, jid, account, *args): - Mock.__init__(self, *args) - - self.jid = jid - self.account = account - - self.parent_win = MockWindow({'get_active_control': self}) - self.session = None - - def set_session(self, sess): - self.session = sess - - def __nonzero__(self): - return True - - def __eq__(self, other): - return self is other - - -class MockInterface(Mock): - def __init__(self, *args): - Mock.__init__(self, *args) - app.interface = self - self.msg_win_mgr = Mock() - self.roster = Mock() - app.ged = ged.GlobalEventsDispatcher() - from gajim import plugins - app.plugin_manager = plugins.PluginManager() - - self.instances = {} - self.minimized_controls = {} - - -class MockLogger(Mock): - def __init__(self): - Mock.__init__(self, {'insert_into_logs': None, - 'get_transports_type': {}}) - self.cur = Mock() - - -class MockContact(Mock): - def __nonzero__(self): - return True - - -import random - -class MockSession(Mock): - def __init__(self, conn, jid, thread_id, type_): - Mock.__init__(self) - - self.conn = conn - self.jid = jid - self.type_ = type_ - self.thread_id = thread_id - self.resource = '' - - if not self.thread_id: - self.thread_id = '%0x' % random.randint(0, 10000) - - def __repr__(self): - return '<MockSession %s>' % self.thread_id - - def __nonzero__(self): - return True - - def __eq__(self, other): - return self is other
===================================== test/lib/mock.py deleted ===================================== @@ -1,466 +0,0 @@ -# -# (c) Dave Kirby 2001 - 2005 -# mock@thedeveloperscoach.com -# -# Original call interceptor and call assertion code by Phil Dawes (pdawes@users.sourceforge.net) -# Call interceptor code enhanced by Bruce Cropley (cropleyb@yahoo.com.au) -# -# This Python module and associated files are released under the FreeBSD -# license. Essentially, you can do what you like with it except pretend you wrote -# it yourself. -# -# -# Copyright (c) 2005, Dave Kirby -# Copyright (c) 2009, Yann Leboulanger -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# * Neither the name of this library nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# mock@thedeveloperscoach.com - - -""" -Mock object library for Python. Mock objects can be used when unit testing -to remove a dependency on another production class. They are typically used -when the dependency would either pull in lots of other classes, or -significantly slow down the execution of the test. -They are also used to create exceptional conditions that cannot otherwise -be easily triggered in the class under test. -""" - -__version__ = "0.1.0" - -# Added in Python 2.1 -import inspect -import re - -class MockInterfaceError(Exception): - pass - -class Mock(object): - """ - The Mock class emulates any other class for testing purposes. - All method calls are stored for later examination. - """ - - def __init__(self, returnValues=None, realClass=None): - """ - The Mock class constructor takes a dictionary of method names and - the values they return. Methods that are not in the returnValues - dictionary will return None. - You may also supply a class whose interface is being mocked. - All calls will be checked to see if they appear in the original - interface. Any calls to methods not appearing in the real class - will raise a MockInterfaceError. Any calls that would fail due to - non-matching parameter lists will also raise a MockInterfaceError. - Both of these help to prevent the Mock class getting out of sync - with the class it is Mocking. - """ - self.mockCalledMethods = {} - self.mockAllCalledMethods = [] - self.mockReturnValues = returnValues or {} - self.mockExpectations = {} - self.realClass = realClass - self.realClassMethods = None - if realClass: - self.realClassMethods = dict(inspect.getmembers(realClass, inspect.isroutine)) - for retMethod in self.mockReturnValues.keys(): - if retMethod not in self.realClassMethods: - raise MockInterfaceError("Return value supplied for method '%s' that was not in the original class" % retMethod) - self._setupSubclassMethodInterceptors() - - def _setupSubclassMethodInterceptors(self): - methods = inspect.getmembers(self.realClass, inspect.isroutine) - baseMethods = dict(inspect.getmembers(Mock, inspect.ismethod)) - for m in methods: - name = m[0] - # Don't record calls to methods of Mock base class. - if not name in baseMethods: - self.__dict__[name] = MockCallable(name, self, handcrafted=True) - - def get_module(self, name): - return Mock() - - def __getattr__(self, name): - return MockCallable(name, self) - - def mockAddReturnValues(self, **methodReturnValues ): - self.mockReturnValues.update(methodReturnValues) - - def mockSetExpectation(self, name, testFn, after=0, until=0): - self.mockExpectations.setdefault(name, []).append((testFn, after, until)) - - def _checkInterfaceCall(self, name, callParams, callKwParams): - """ - Check that a call to a method of the given name to the original - class with the given parameters would not fail. If it would fail, - raise a MockInterfaceError. - Based on the Python 2.3.3 Reference Manual section 5.3.4: Calls. - """ - if self.realClassMethods is None: - return - if name not in self.realClassMethods: - return - - func = self.realClassMethods[name] - try: - args, varargs, varkw, defaults = inspect.getargspec(func) - except TypeError: - # func is not a Python function. It is probably a builtin, - # such as __repr__ or __coerce__. TODO: Checking? - # For now assume params are OK. - return - - # callParams doesn't include self; args does include self. - numPosCallParams = 1 + len(callParams) - - if numPosCallParams > len(args) and not varargs: - raise MockInterfaceError("Original %s() takes at most %s arguments (%s given)" % - (name, len(args), numPosCallParams)) - - # Get the number of positional arguments that appear in the call, - # also check for duplicate parameters and unknown parameters - numPosSeen = _getNumPosSeenAndCheck(numPosCallParams, callKwParams, args, varkw) - - lenArgsNoDefaults = len(args) - len(defaults or []) - if numPosSeen < lenArgsNoDefaults: - raise MockInterfaceError("Original %s() takes at least %s arguments (%s given)" % (name, lenArgsNoDefaults, numPosSeen)) - - def mockGetAllCalls(self): - """ - Return a list of MockCall objects, - representing all the methods in the order they were called. - """ - return self.mockAllCalledMethods - getAllCalls = mockGetAllCalls # deprecated - kept for backward compatibility - - def mockGetNamedCalls(self, methodName): - """ - Return a list of MockCall objects, - representing all the calls to the named method in the order they were called. - """ - return self.mockCalledMethods.get(methodName, []) - getNamedCalls = mockGetNamedCalls # deprecated - kept for backward compatibility - - def mockCheckCall(self, index, name, *args, **kwargs): - '''test that the index-th call had the specified name and parameters''' - call = self.mockAllCalledMethods[index] - assert name == call.getName(), "%r != %r" % (name, call.getName()) - call.checkArgs(*args, **kwargs) - - -def _getNumPosSeenAndCheck(numPosCallParams, callKwParams, args, varkw): - """ - Positional arguments can appear as call parameters either named as - a named (keyword) parameter, or just as a value to be matched by - position. Count the positional arguments that are given by either - keyword or position, and check for duplicate specifications. - Also check for arguments specified by keyword that do not appear - in the method's parameter list. - """ - posSeen = {} - for arg in args[:numPosCallParams]: - posSeen[arg] = True - for kwp in callKwParams: - if kwp in posSeen: - raise MockInterfaceError("%s appears as both a positional and named parameter." % kwp) - if kwp in args: - posSeen[kwp] = True - elif not varkw: - raise MockInterfaceError("Original method does not have a parameter '%s'" % kwp) - return len(posSeen) - -class MockCall: - """ - MockCall records the name and parameters of a call to an instance - of a Mock class. Instances of MockCall are created by the Mock class, - but can be inspected later as part of the test. - """ - def __init__(self, name, params, kwparams ): - self.name = name - self.params = params - self.kwparams = kwparams - - def checkArgs(self, *args, **kwargs): - assert args == self.params, "%r != %r" % (args, self.params) - assert kwargs == self.kwparams, "%r != %r" % (kwargs, self.kwparams) - - def getParam( self, n ): - if isinstance(n, int): - return self.params[n] - elif isinstance(n, str): - return self.kwparams[n] - else: - raise IndexError('illegal index type for getParam') - - def getNumParams(self): - return len(self.params) - - def getNumKwParams(self): - return len(self.kwparams) - - def getName(self): - return self.name - - #pretty-print the method call - def __str__(self): - s = self.name + "(" - sep = '' - for p in self.params: - s = s + sep + repr(p) - sep = ', ' - items = sorted(self.kwparams.items()) - for k, v in items: - s = s + sep + k + '=' + repr(v) - sep = ', ' - s = s + ')' - return s - def __repr__(self): - return self.__str__() - -class MockCallable: - """ - Intercepts the call and records it, then delegates to either the mock's - dictionary of mock return values that was passed in to the constructor, - or a handcrafted method of a Mock subclass. - """ - def __init__(self, name, mock, handcrafted=False): - self.name = name - self.mock = mock - self.handcrafted = handcrafted - - def __call__(self, *params, **kwparams): - self.mock._checkInterfaceCall(self.name, params, kwparams) - thisCall = self.recordCall(params, kwparams) - self.checkExpectations(thisCall, params, kwparams) - return self.makeCall(params, kwparams) - - def recordCall(self, params, kwparams): - """ - Record the MockCall in an ordered list of all calls, and an ordered - list of calls for that method name. - """ - thisCall = MockCall(self.name, params, kwparams) - calls = self.mock.mockCalledMethods.setdefault(self.name, []) - calls.append(thisCall) - self.mock.mockAllCalledMethods.append(thisCall) - return thisCall - - def makeCall(self, params, kwparams): - if self.handcrafted: - allPosParams = (self.mock,) + params - func = _findFunc(self.mock.realClass, self.name) - if not func: - raise NotImplementedError - return func(*allPosParams, **kwparams) - else: - returnVal = self.mock.mockReturnValues.get(self.name) - if isinstance(returnVal, ReturnValuesBase): - returnVal = returnVal.next() - return returnVal - - def checkExpectations(self, thisCall, params, kwparams): - if self.name in self.mock.mockExpectations: - callsMade = len(self.mock.mockCalledMethods[self.name]) - for (expectation, after, until) in self.mock.mockExpectations[self.name]: - if callsMade > after and (until==0 or callsMade < until): - assert expectation(self.mock, thisCall, len(self.mock.mockAllCalledMethods)-1), 'Expectation failed: '+str(thisCall) - - -def _findFunc(cl, name): - """ Depth first search for a method with a given name. """ - if name in cl.__dict__: - return cl.__dict__[name] - for base in cl.__bases__: - func = _findFunc(base, name) - if func: - return func - return None - - - -class ReturnValuesBase: - def next(self): - try: - return self.iter.next() - except StopIteration: - raise AssertionError("No more return values") - def __iter__(self): - return self - -class ReturnValues(ReturnValuesBase): - def __init__(self, *values): - self.iter = iter(values) - - -class ReturnIterator(ReturnValuesBase): - def __init__(self, iterator): - self.iter = iter(iterator) - - -def expectParams(*params, **keywords): - '''check that the callObj is called with specified params and keywords - ''' - def fn(mockObj, callObj, idx): - return callObj.params == params and callObj.kwparams == keywords - return fn - - -def expectAfter(*methods): - '''check that the function is only called after all the functions in 'methods' - ''' - def fn(mockObj, callObj, idx): - calledMethods = [method.getName() for method in mockObj.mockGetAllCalls()] - #skip last entry, since that is the current call - calledMethods = calledMethods[:-1] - for method in methods: - if method not in calledMethods: - return False - return True - return fn - -def expectException(exception, *args, **kwargs): - ''' raise an exception when the method is called - ''' - def fn(mockObj, callObj, idx): - raise exception(*args, **kwargs) - return fn - - -def expectParam(paramIdx, cond): - '''check that the callObj is called with parameter specified by paramIdx (a position index or keyword) - fulfills the condition specified by cond. - cond is a function that takes a single argument, the value to test. - ''' - def fn(mockObj, callObj, idx): - param = callObj.getParam(paramIdx) - return cond(param) - return fn - -def EQ(value): - def testFn(param): - return param == value - return testFn - -def NE(value): - def testFn(param): - return param != value - return testFn - -def GT(value): - def testFn(param): - return param > value - return testFn - -def LT(value): - def testFn(param): - return param < value - return testFn - -def GE(value): - def testFn(param): - return param >= value - return testFn - -def LE(value): - def testFn(param): - return param <= value - return testFn - -def AND(*condlist): - def testFn(param): - for cond in condlist: - if not cond(param): - return False - return True - return testFn - -def OR(*condlist): - def testFn(param): - for cond in condlist: - if cond(param): - return True - return False - return testFn - -def NOT(cond): - def testFn(param): - return not cond(param) - return testFn - -def MATCHES(regex, *args, **kwargs): - compiled_regex = re.compile(regex, *args, **kwargs) - def testFn(param): - return compiled_regex.match(param) is not None - return testFn - -def SEQ(*sequence): - iterator = iter(sequence) - def testFn(param): - try: - cond = iterator.next() - except StopIteration: - raise AssertionError('SEQ exhausted') - return cond(param) - return testFn - -def IS(instance): - def testFn(param): - return param is instance - return testFn - -def ISINSTANCE(class_): - def testFn(param): - return isinstance(param, class_) - return testFn - -def ISSUBCLASS(class_): - def testFn(param): - return issubclass(param, class_) - return testFn - -def CONTAINS(val): - def testFn(param): - return val in param - return testFn - -def IN(container): - def testFn(param): - return param in container - return testFn - -def HASATTR(attr): - def testFn(param): - return hasattr(param, attr) - return testFn - -def HASMETHOD(method): - def testFn(param): - return hasattr(param, method) and callable(getattr(param, method)) - return testFn - -CALLABLE = callable
===================================== test/lib/notify.py deleted ===================================== @@ -1,28 +0,0 @@ -# mock notify module - -from gajim.common import app -from gajim.common import ged - -notifications = [] - -class Notification: - def _nec_notification(self, obj): - global notifications - notifications.append(obj) - - def clean(self): - global notifications - notifications = [] - app.ged.remove_event_handler('notification', ged.GUI2, - self._nec_notification) - - def __init__(self): - app.ged.register_event_handler('notification', ged.GUI2, - self._nec_notification) - - -def notify(event, jid, account, parameters, advanced_notif_num = None): - notifications.append((event, jid, account, parameters, advanced_notif_num)) - -def get_advanced_notification(event, account, contact): - return None
===================================== test/no_gui/__init__.py ===================================== @@ -0,0 +1,11 @@ +import gi + +def require_versions(): + gi.require_versions({'Gdk': '3.0', + 'GLib': '2.0', + 'Gio': '2.0', + 'Gtk': '3.0', + 'GObject': '2.0', + 'Pango': '1.0'}) + +require_versions()
===================================== test/no_gui/unit/test_nick_completion.py → test/no_gui/test_nick_completion.py =====================================
===================================== test/no_gui/unit/__init__.py deleted ===================================== @@ -1,5 +0,0 @@ -''' - -This package just contains plain unit tests - -'''
===================================== test/unit/__init__.py deleted ===================================== @@ -1,5 +0,0 @@ -''' - -This package just contains plain unit tests - -'''
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/e98cf3367c962c8de4345e27ff09e68f...