9578053 Jan 22 2022 distfiles.gentoo.org/distfiles/gajim-1.3.3-2.tar.gz
This commit is contained in:
parent
a5b3822651
commit
4c1b226bff
1045 changed files with 753037 additions and 18 deletions
46
test/lib/__init__.py
Normal file
46
test/lib/__init__.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
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()
|
77
test/lib/data.py
Executable file
77
test/lib/data.py
Executable file
|
@ -0,0 +1,77 @@
|
|||
# -*- 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}]
|
||||
]
|
139
test/lib/gajim_mocks.py
Normal file
139
test/lib/gajim_mocks.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
'''
|
||||
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
|
466
test/lib/mock.py
Normal file
466
test/lib/mock.py
Normal file
|
@ -0,0 +1,466 @@
|
|||
#
|
||||
# (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
|
28
test/lib/notify.py
Normal file
28
test/lib/notify.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# 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
|
Loading…
Add table
Add a link
Reference in a new issue