Compare commits

..

No commits in common. "8fe517f48aadfa55148142a1cfd1e14df907feac" and "1952dae6f7b9ed14231d86bda5ca23f874f231ae" have entirely different histories.

22 changed files with 81 additions and 202 deletions

View File

@ -1,62 +0,0 @@
name: Test
on:
push:
pull_request:
jobs:
build:
runs-on: ${{ matrix.runs-on }}
strategy:
matrix:
python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10.0-beta.4", "pypy-3.6", "pypy-3.7"]
with-opt-deps: [false, true]
runs-on: [ubuntu-latest]
exclude:
# Some of the dependencies don't work on old Python versions
- python-version: "3.4"
with-opt-deps: true
- python-version: "3.5"
with-opt-deps: true
- python-version: "3.6"
with-opt-deps: true
- python-version: "pypy-3.6"
with-opt-deps: true
include:
- python-version: "3.4"
with-opt-deps: false
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Upgrade pip
run: |
python3 -m pip install --upgrade pip
- name: Install optional dependencies
if: ${{ matrix.with-opt-deps }}
run: |
python3 -m pip install --upgrade pip
pip3 install -r requirements.txt
- name: Install
run: |
LIMNORIA_WARN_OLD_PYTHON=0 python3 setup.py install
- name: Test with unittest
run: |
supybot-test test -v --plugins-dir=./plugins/ --no-network
- name: Test with irctest
if: "${{ matrix.with-opt-deps && matrix.python-version != 'pypy-3.7' }}"
run: |
git clone https://github.com/ProgVal/irctest.git
cd irctest
pip3 install -r requirements.txt
make limnoria

54
.travis.yml Normal file
View File

@ -0,0 +1,54 @@
language: python
sudo: true
install:
- if [ "$WITH_OPT_DEPS" = "true" ] ; then pip install -vr requirements.txt pytest; fi
- git clone https://github.com/ProgVal/irctest.git
- echo "y" | pip uninstall limnoria || true
# command to run tests, e.g. python setup.py test
script:
- echo $TRAVIS_PYTHON_VERSION
- python setup.py install
- supybot-test test -v --plugins-dir=./plugins/ --no-network
- if [ "$WITH_OPT_DEPS" = "true" ] -a [[ "$TRAVIS_PYTHON_VERSION" =~ ^3\.[4-9] ]] ; then cd irctest; pytest --controllers irctest.controllers.limnoria; fi
notifications:
email: false
matrix:
include:
- python: "3.4"
env: WITH_OPT_DEPS=false
dist: trusty
- python: "3.5"
env: WITH_OPT_DEPS=false
dist: trusty
- python: "3.6"
env: WITH_OPT_DEPS=false
dist: trusty
- python: "3.7"
env: WITH_OPT_DEPS=false
dist: xenial
- python: "3.7"
env: WITH_OPT_DEPS=true
dist: xenial
- python: "3.8"
env: WITH_OPT_DEPS=true
dist: xenial
- python: "3.9"
env: WITH_OPT_DEPS=true
dist: xenial
- python: "nightly"
env: WITH_OPT_DEPS=true
dist: xenial
- python: "pypy3"
env: WITH_OPT_DEPS=false
dist: trusty
- python: "nightly"
env: WITH_OPT_DEPS=true
dist: xenial
allow_failures:
- python: "pypy3"
env: WITH_OPT_DEPS=true
dist: xenial

View File

@ -13,7 +13,7 @@ Searches for results on DuckDuckGo.
Example:: Example::
<+jlu5> %ddg search eiffel tower <+GLolol> %ddg search eiffel tower
<@Atlas> The Eiffel Tower is an iron lattice tower located on the Champ de Mars in Paris. It was named after the engineer Gustave Eiffel, whose company designed and built the tower. - <https://en.wikipedia.org/wiki/Eiffel_Tower> <@Atlas> The Eiffel Tower is an iron lattice tower located on the Champ de Mars in Paris. It was named after the engineer Gustave Eiffel, whose company designed and built the tower. - <https://en.wikipedia.org/wiki/Eiffel_Tower>
.. _commands-DDG: .. _commands-DDG:

View File

@ -55,7 +55,7 @@ class DDG(callbacks.Plugin):
Example:: Example::
<+jlu5> %ddg search eiffel tower <+GLolol> %ddg search eiffel tower
<@Atlas> The Eiffel Tower is an iron lattice tower located on the Champ de Mars in Paris. It was named after the engineer Gustave Eiffel, whose company designed and built the tower. - <https://en.wikipedia.org/wiki/Eiffel_Tower> <@Atlas> The Eiffel Tower is an iron lattice tower located on the Champ de Mars in Paris. It was named after the engineer Gustave Eiffel, whose company designed and built the tower. - <https://en.wikipedia.org/wiki/Eiffel_Tower>
""" """

View File

@ -126,7 +126,7 @@ class Google(callbacks.PluginRegexp):
'plugin for your searches, like ' 'plugin for your searches, like '
'<https://github.com/Hoaas/Supybot-plugins/tree/master/DuckDuckGo>, ' '<https://github.com/Hoaas/Supybot-plugins/tree/master/DuckDuckGo>, '
'<https://github.com/joulez/GoogleCSE>, or ' '<https://github.com/joulez/GoogleCSE>, or '
'<https://github.com/jlu5/SupyPlugins/tree/master/DDG>.') '<https://github.com/GLolol/SupyPlugins/tree/master/DDG>.')
ref = self.registryValue('referer') ref = self.registryValue('referer')
if not ref: if not ref:
ref = 'http://%s/%s' % (dynamic.irc.server, ref = 'http://%s/%s' % (dynamic.irc.server,

View File

@ -129,13 +129,8 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
def _runCommandFunction(self, irc, msg, command): def _runCommandFunction(self, irc, msg, command):
"""Run a command from message, as if command was sent over IRC.""" """Run a command from message, as if command was sent over IRC."""
try:
tokens = callbacks.tokenize(command, tokens = callbacks.tokenize(command,
channel=msg.channel, network=irc.network) channel=msg.channel, network=irc.network)
except SyntaxError as e:
# Emulate what callbacks.py does
self.log.debug('Error return: %s', utils.exnToString(e))
irc.error(str(e))
try: try:
self.Proxy(irc.irc, msg, tokens) self.Proxy(irc.irc, msg, tokens)
except Exception as e: except Exception as e:

View File

@ -85,11 +85,6 @@ class MessageParserTestCase(ChannelPluginTestCase):
self.assertResponse(' ', '$1') self.assertResponse(' ', '$1')
self.assertNotError('messageparser remove "this( .+)? a(.*)"') self.assertNotError('messageparser remove "this( .+)? a(.*)"')
def testSyntaxError(self):
self.assertNotError(r'messageparser add "test" "echo foo \" bar"')
self.feedMsg('test')
self.assertResponse(' ', 'Error: No closing quotation')
def testShow(self): def testShow(self):
self.assertNotError('messageparser add "stuff" "echo i saw some stuff"') self.assertNotError('messageparser add "stuff" "echo i saw some stuff"')
self.assertRegexp('messageparser show "nostuff"', 'there is no such regexp trigger') self.assertRegexp('messageparser show "nostuff"', 'there is no such regexp trigger')

View File

@ -37,7 +37,7 @@ Examples
< Mikaela> @load PluginDownloader < Mikaela> @load PluginDownloader
< Limnoria> Ok. < Limnoria> Ok.
< Mikaela> @plugindownloader repolist < Mikaela> @plugindownloader repolist
< Limnoria> Antibody, jlu5, Hoaas, Iota, ProgVal, SpiderDave, boombot, code4lib, code4lib-edsu, code4lib-snapshot, doorbot, frumious, jonimoose, mailed-notifier, mtughan-weather, nanotube-bitcoin, nyuszika7h, nyuszika7h-old, pingdom, quantumlemur, resistivecorpse, scrum, skgsergio, stepnem < Limnoria> Antibody, GLolol, Hoaas, Iota, ProgVal, SpiderDave, boombot, code4lib, code4lib-edsu, code4lib-snapshot, doorbot, frumious, jonimoose, mailed-notifier, mtughan-weather, nanotube-bitcoin, nyuszika7h, nyuszika7h-old, pingdom, quantumlemur, resistivecorpse, scrum, skgsergio, stepnem
< Mikaela> @plugindownloader repolist ProgVal < Mikaela> @plugindownloader repolist ProgVal
< Limnoria> AttackProtector, AutoTrans, Biography, Brainfuck, ChannelStatus, Cleverbot, Coffee, Coinpan, Debian, ERepublik, Eureka, Fortune, GUI, GitHub, Glob2Chan, GoodFrench, I18nPlaceholder, IMDb, IgnoreNonVoice, Iwant, Kickme, LimnoriaChan, LinkRelay, ListEmpty, Listener, Markovgen, MegaHAL, MilleBornes, NoLatin1, NoisyKarma, OEIS, PPP, PingTime, Pinglist, RateLimit, Rbls, Redmine, Scheme, Seeks, (1 more message) < Limnoria> AttackProtector, AutoTrans, Biography, Brainfuck, ChannelStatus, Cleverbot, Coffee, Coinpan, Debian, ERepublik, Eureka, Fortune, GUI, GitHub, Glob2Chan, GoodFrench, I18nPlaceholder, IMDb, IgnoreNonVoice, Iwant, Kickme, LimnoriaChan, LinkRelay, ListEmpty, Listener, Markovgen, MegaHAL, MilleBornes, NoLatin1, NoisyKarma, OEIS, PPP, PingTime, Pinglist, RateLimit, Rbls, Redmine, Scheme, Seeks, (1 more message)
< Mikaela> more < Mikaela> more

View File

@ -348,7 +348,7 @@ class PluginDownloader(callbacks.Plugin):
< Mikaela> @load PluginDownloader < Mikaela> @load PluginDownloader
< Limnoria> Ok. < Limnoria> Ok.
< Mikaela> @plugindownloader repolist < Mikaela> @plugindownloader repolist
< Limnoria> Antibody, jlu5, Hoaas, Iota, ProgVal, SpiderDave, boombot, code4lib, code4lib-edsu, code4lib-snapshot, doorbot, frumious, jonimoose, mailed-notifier, mtughan-weather, nanotube-bitcoin, nyuszika7h, nyuszika7h-old, pingdom, quantumlemur, resistivecorpse, scrum, skgsergio, stepnem < Limnoria> Antibody, GLolol, Hoaas, Iota, ProgVal, SpiderDave, boombot, code4lib, code4lib-edsu, code4lib-snapshot, doorbot, frumious, jonimoose, mailed-notifier, mtughan-weather, nanotube-bitcoin, nyuszika7h, nyuszika7h-old, pingdom, quantumlemur, resistivecorpse, scrum, skgsergio, stepnem
< Mikaela> @plugindownloader repolist ProgVal < Mikaela> @plugindownloader repolist ProgVal
< Limnoria> AttackProtector, AutoTrans, Biography, Brainfuck, ChannelStatus, Cleverbot, Coffee, Coinpan, Debian, ERepublik, Eureka, Fortune, GUI, GitHub, Glob2Chan, GoodFrench, I18nPlaceholder, IMDb, IgnoreNonVoice, Iwant, Kickme, LimnoriaChan, LinkRelay, ListEmpty, Listener, Markovgen, MegaHAL, MilleBornes, NoLatin1, NoisyKarma, OEIS, PPP, PingTime, Pinglist, RateLimit, Rbls, Redmine, Scheme, Seeks, (1 more message) < Limnoria> AttackProtector, AutoTrans, Biography, Brainfuck, ChannelStatus, Cleverbot, Coffee, Coinpan, Debian, ERepublik, Eureka, Fortune, GUI, GitHub, Glob2Chan, GoodFrench, I18nPlaceholder, IMDb, IgnoreNonVoice, Iwant, Kickme, LimnoriaChan, LinkRelay, ListEmpty, Listener, Markovgen, MegaHAL, MilleBornes, NoLatin1, NoisyKarma, OEIS, PPP, PingTime, Pinglist, RateLimit, Rbls, Redmine, Scheme, Seeks, (1 more message)
< Mikaela> more < Mikaela> more

View File

@ -25,7 +25,7 @@ Creates a poll that can be voted on in this way::
And results:: And results::
<admin> @poll results <admin> @poll results
<bot> 2 votes for No, 1 vote for Yes, and 0 votes for Maybe <bot> 2 votes for No, 1 vote for Yes, and 0 votes for Maybe",
Longer answers are possible, and voters only need to use the first Longer answers are possible, and voters only need to use the first
word of each answer to vote. For example, this creates a poll that word of each answer to vote. For example, this creates a poll that

View File

@ -64,7 +64,7 @@ class Poll_(callbacks.Plugin):
And results:: And results::
<admin> @poll results <admin> @poll results
<bot> 2 votes for No, 1 vote for Yes, and 0 votes for Maybe <bot> 2 votes for No, 1 vote for Yes, and 0 votes for Maybe",
Longer answers are possible, and voters only need to use the first Longer answers are possible, and voters only need to use the first
word of each answer to vote. For example, this creates a poll that word of each answer to vote. For example, this creates a poll that

View File

@ -102,7 +102,6 @@ class RSSTestCase(ChannelPluginTestCase):
@mock_urllib @mock_urllib
def testRemoveAliasedFeed(self, mock): def testRemoveAliasedFeed(self, mock):
mock._data = xkcd_new
try: try:
self.assertNotError('rss announce add http://xkcd.com/rss.xml') self.assertNotError('rss announce add http://xkcd.com/rss.xml')
self.assertNotError('rss add xkcd http://xkcd.com/rss.xml') self.assertNotError('rss add xkcd http://xkcd.com/rss.xml')

View File

@ -16,9 +16,9 @@ After enabling SedRegex, typing a regex in the form
:: ::
20:24 <jlu5> helli world 20:24 <~GL> helli world
20:24 <jlu5> s/i/o/ 20:24 <~GL> s/i/o/
20:24 <Limnoria> jlu5 meant to say: hello world 20:24 <@Lily> GL meant to say: hello world
You can also do ``othernick: s/text/replacement/`` to only replace You can also do ``othernick: s/text/replacement/`` to only replace
messages from a certain user. Supybot ignores are respected by the plugin, messages from a certain user. Supybot ignores are respected by the plugin,

View File

@ -69,9 +69,9 @@ class SedRegex(callbacks.PluginRegexp):
:: ::
20:24 <jlu5> helli world 20:24 <~GL> helli world
20:24 <jlu5> s/i/o/ 20:24 <~GL> s/i/o/
20:24 <Limnoria> jlu5 meant to say: hello world 20:24 <@Lily> GL meant to say: hello world
You can also do ``othernick: s/text/replacement/`` to only replace You can also do ``othernick: s/text/replacement/`` to only replace
messages from a certain user. Supybot ignores are respected by the plugin, messages from a certain user. Supybot ignores are respected by the plugin,

View File

@ -146,9 +146,6 @@ class User(callbacks.Plugin):
user.setPassword(password) user.setPassword(password)
if addHostmask: if addHostmask:
user.addHostmask(msg.prefix) user.addHostmask(msg.prefix)
account = msg.server_tags.get('account')
if account:
user.addNick(irc.network, account)
ircdb.users.setUser(user) ircdb.users.setUser(user)
irc.replySuccess() irc.replySuccess()
register = wrap(register, ['private', 'something', 'something']) register = wrap(register, ['private', 'something', 'something'])

View File

@ -82,19 +82,10 @@ if version:
fd.close() fd.close()
if sys.version_info < (3, 4, 0): if sys.version_info < (3, 4, 0):
sys.stderr.write("Limnoria requires Python 3.6 or newer.") sys.stderr.write("Limnoria requires Python 3.4 or newer.")
sys.stderr.write(os.linesep) sys.stderr.write(os.linesep)
sys.exit(-1) sys.exit(-1)
if sys.version_info < (3, 6, 0) \
and os.environ.get('LIMNORIA_WARN_OLD_PYTHON') != '0':
sys.stderr.write('====================================================\n')
sys.stderr.write('Limnoria support for Python versions older than 3.6\n')
sys.stderr.write('is deprecated and may be removed in the near future.\n')
sys.stderr.write('You should upgrade ASAP.\n')
sys.stderr.write('Install will continue in 60s.\n')
sys.stderr.write('====================================================\n')
time.sleep(60)
import textwrap import textwrap

View File

@ -114,13 +114,6 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
except: except:
pass pass
self.connected = False self.connected = False
if self.irc is None:
# This driver is dead already, but we're still running because
# of select() running in an other driver's thread that started
# before this one died and stil holding a reference to this
# instance.
# Just return, and we should never be called again.
return
self.scheduleReconnect() self.scheduleReconnect()
else: else:
log.debug('Got EAGAIN, current count: %s.', self.eagains) log.debug('Got EAGAIN, current count: %s.', self.eagains)
@ -215,8 +208,6 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
msg = drivers.parseMsg(line) msg = drivers.parseMsg(line)
if msg is not None and self.irc is not None: if msg is not None and self.irc is not None:
# self.irc may be None if this driver is already dead,
# see comment in _handleSocketError
self.irc.feedMsg(msg) self.irc.feedMsg(msg)
except socket.timeout: except socket.timeout:
pass pass

View File

@ -389,15 +389,15 @@ class ChannelState(utils.python.Object):
"""Returns whether the given nick is an halfop, or an op.""" """Returns whether the given nick is an halfop, or an op."""
return nick in self.halfops or nick in self.ops return nick in self.halfops or nick in self.ops
def addUser(self, user, prefix_chars='@%+&~!'): def addUser(self, user):
"Adds a given user to the ChannelState. Power prefixes are handled." "Adds a given user to the ChannelState. Power prefixes are handled."
nick = user.lstrip(prefix_chars) nick = user.lstrip('@%+&~!')
if not nick: if not nick:
return return
# & is used to denote protected users in UnrealIRCd # & is used to denote protected users in UnrealIRCd
# ~ is used to denote channel owner in UnrealIRCd # ~ is used to denote channel owner in UnrealIRCd
# ! is used to denote protected users in UltimateIRCd # ! is used to denote protected users in UltimateIRCd
while user and user[0] in prefix_chars: while user and user[0] in '@%+&~!':
(marker, user) = (user[0], user[1:]) (marker, user) = (user[0], user[1:])
assert user, 'Looks like my caller is passing chars, not nicks.' assert user, 'Looks like my caller is passing chars, not nicks.'
if marker in '@&~!': if marker in '@&~!':
@ -963,27 +963,13 @@ class IrcState(IrcCommandDispatcher, log.Firewalled):
if channel not in self.channels: if channel not in self.channels:
self.channels[channel] = ChannelState() self.channels[channel] = ChannelState()
c = self.channels[channel] c = self.channels[channel]
# Set of prefixes servers may append before a NAMES reply when
# the user is op/halfop/voice/...
# https://datatracker.ietf.org/doc/html/draft-hardy-irc-isupport-00#section-4.15
prefix = self.supported.get('PREFIX')
if prefix is None:
prefix_chars = '@%+&~!' # see the comments in addUser
else:
prefix_chars = ''.join(prefix.values())
for item in items.split(): for item in items.split():
stripped_item = item.lstrip(prefix_chars) if ircutils.isUserHostmask(item):
item_prefix = item[0:-len(stripped_item)] name = ircutils.nickFromHostmask(item)
if ircutils.isUserHostmask(stripped_item): self.nicksToHostmasks[name] = name
nick = ircutils.nickFromHostmask(stripped_item)
self.nicksToHostmasks[nick] = stripped_item
name = item_prefix + nick
else: else:
name = item name = item
c.addUser(name, prefix_chars=prefix_chars) c.addUser(name)
if type == '@': if type == '@':
c.modes['s'] = None c.modes['s'] = None

View File

@ -60,11 +60,7 @@ def debug(s, *args):
"""Prints a debug string. Most likely replaced by our logging debug.""" """Prints a debug string. Most likely replaced by our logging debug."""
print('***', s % args) print('***', s % args)
def warning(s, *args): userHostmaskRe = re.compile(r'^\S+!\S+@\S+$')
"""Prints a debug string. Most likely replaced by our logging debug."""
print('###', s % args)
userHostmaskRe = re.compile(r'^(?P<nick>\S+?)!(?P<user>\S+)@(?P<host>\S+?)$')
def isUserHostmask(s): def isUserHostmask(s):
"""Returns whether or not the string s is a valid User hostmask.""" """Returns whether or not the string s is a valid User hostmask."""
return userHostmaskRe.match(s) is not None return userHostmaskRe.match(s) is not None
@ -95,17 +91,9 @@ def hostFromHostmask(hostmask):
def splitHostmask(hostmask): def splitHostmask(hostmask):
"""hostmask => (nick, user, host) """hostmask => (nick, user, host)
Returns the nick, user, host of a user hostmask.""" Returns the nick, user, host of a user hostmask."""
m = userHostmaskRe.match(hostmask) assert isUserHostmask(hostmask)
assert m is not None, hostmask nick, rest = hostmask.rsplit('!', 1)
nick = m.group("nick") user, host = rest.rsplit('@', 1)
user = m.group("user")
host = m.group("host")
if set("!@") & set(nick+user+host):
# There should never be either of these characters in the part.
# As far as I know it never happens in practice aside from networks
# broken by design.
warning("Invalid hostmask format: %s", hostmask)
# TODO: error if strictRfc is True
return (minisix.intern(nick), minisix.intern(user), minisix.intern(host)) return (minisix.intern(nick), minisix.intern(user), minisix.intern(host))
def joinHostmask(nick, ident, host): def joinHostmask(nick, ident, host):

View File

@ -329,7 +329,6 @@ atexit.register(logging.shutdown)
# ircutils will work without this, but it's useful. # ircutils will work without this, but it's useful.
ircutils.debug = debug ircutils.debug = debug
ircutils.warning = warning
def getPluginLogger(name): def getPluginLogger(name):
if not conf.supybot.log.plugins.individualLogfiles(): if not conf.supybot.log.plugins.individualLogfiles():

View File

@ -529,42 +529,6 @@ class IrcStateTestCase(SupyTestCase):
st = irclib.IrcState() st = irclib.IrcState()
self.assert_(st.addMsg(self.irc, ircmsgs.IrcMsg('MODE foo +i')) or 1) self.assert_(st.addMsg(self.irc, ircmsgs.IrcMsg('MODE foo +i')) or 1)
def testNamreply(self):
"""RPL_NAMREPLY / reply to NAMES"""
# Just nicks (à la RFC 1459 + some common prefix chars)
st = irclib.IrcState()
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
args=('*', '=', '#chan', 'nick1 @nick2 ~@nick3')))
chan_st = st.channels['#chan']
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', 'nick3']))
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2', 'nick3']))
self.assertEqual(st.nicksToHostmasks, ircutils.IrcDict({}))
# with userhost-in-names
st = irclib.IrcState()
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
args=('*', '=', '#chan', 'nick1!u1@h1 @nick2!u2@h2 ~@nick3!u3@h3')))
chan_st = st.channels['#chan']
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', 'nick3']))
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2', 'nick3']))
self.assertEqual(st.nicksToHostmasks['nick1'], 'nick1!u1@h1')
self.assertEqual(st.nicksToHostmasks['nick2'], 'nick2!u2@h2')
self.assertEqual(st.nicksToHostmasks['nick3'], 'nick3!u3@h3')
# Prefixed with chars not in ISUPPORT PREFIX
st = irclib.IrcState()
st.addMsg(self.irc, ircmsgs.IrcMsg(command='005',
args=('*', 'PREFIX=(ov)@+', 'are supported')))
st.addMsg(self.irc, ircmsgs.IrcMsg(command='353',
args=('*', '=', '#chan', 'nick1!u1@h1 @nick2!u2@h2 ~@nick3!u3@h3')))
chan_st = st.channels['#chan']
self.assertEqual(chan_st.users, ircutils.IrcSet(['nick1', 'nick2', '~@nick3']))
self.assertEqual(chan_st.ops, ircutils.IrcSet(['nick2']))
self.assertEqual(st.nicksToHostmasks['nick1'], 'nick1!u1@h1')
self.assertEqual(st.nicksToHostmasks['nick2'], 'nick2!u2@h2')
self.assertEqual(st.nicksToHostmasks['~@nick3'], '~@nick3!u3@h3')
class IrcCapsTestCase(SupyTestCase, CapNegMixin): class IrcCapsTestCase(SupyTestCase, CapNegMixin):
def testReqLineLength(self): def testReqLineLength(self):

View File

@ -113,24 +113,6 @@ class FunctionsTestCase(SupyTestCase):
self.assertFalse(ircutils.isUserHostmask('@')) self.assertFalse(ircutils.isUserHostmask('@'))
self.assertFalse(ircutils.isUserHostmask('!bar@baz')) self.assertFalse(ircutils.isUserHostmask('!bar@baz'))
def testSplitHostmask(self):
# This is the only valid case:
self.assertEqual(ircutils.splitHostmask('foo!bar@baz'),
('foo', 'bar', 'baz'))
# This ones are technically allowed by RFC1459, but never happens in
# practice:
self.assertEqual(ircutils.splitHostmask('foo!bar!qux@quux'),
('foo', 'bar!qux', 'quux'))
self.assertEqual(ircutils.splitHostmask('foo!bar@baz@quux'),
('foo', 'bar@baz', 'quux'))
self.assertEqual(ircutils.splitHostmask('foo!bar@baz!qux@quux'),
('foo', 'bar@baz!qux', 'quux'))
# And this one in garbage, let's just make sure we don't crash:
self.assertEqual(ircutils.splitHostmask('foo!bar@baz!qux'),
('foo', 'bar', 'baz!qux'))
def testIsChannel(self): def testIsChannel(self):
self.assertTrue(ircutils.isChannel('#')) self.assertTrue(ircutils.isChannel('#'))
self.assertTrue(ircutils.isChannel('&')) self.assertTrue(ircutils.isChannel('&'))