Ticket #3230: ticket3230.patch

File ticket3230.patch, 10.7 KB (added by Ezio Melotti, 12 years ago)
  • twisted/words/test/test_irc.py

     
    160160        del self.client
    161161        del self.transport
    162162
    163     def testModeChange(self):
    164         message = ":ChanServ!ChanServ@services. MODE #tanstaafl +o exarkun\r\n"
     163
     164    def _sendModeChange(self, msg, args=''):
     165        """
     166        Format the string and send it to the client
     167        """
     168        message = ":Wolf!~wolf@yok.utu.fi MODE #chan %s %s\r\n" % (msg, args)
    165169        self.client.dataReceived(message)
    166         self.assertEquals(
    167             self.client.calls,
    168             [('modeChanged', {'user': "ChanServ!ChanServ@services.",
    169                               'channel': '#tanstaafl',
    170                               'set': True,
    171                               'modes': 'o',
    172                               'args': ('exarkun',)})])
    173170
     171
     172    def _parseModeChange(self, results):
     173        """
     174        Parse the results, do some test and return the data to check
     175        """
     176        for n,result in enumerate(results):
     177            method, data = result
     178            self.assertEquals(method, 'modeChanged')
     179            self.assertEquals(data['user'], 'Wolf!~wolf@yok.utu.fi')
     180            self.assertEquals(data['channel'], '#chan')
     181            results[n] = tuple([data[key] for key in ('set', 'modes', 'args')])
     182        return results
     183
     184
     185    def _checkModeChange(self, expected):
     186        """
     187        Compare the expected result with the one returned by the client
     188        """
     189        result = self._parseModeChange(self.client.calls)
     190        self.assertEquals(result, expected)
     191
     192
     193    def test_modeChangeWithASingleMode(self):
     194        """
     195        A single mode added to a user
     196        """
     197        self._sendModeChange('+o', 'exarkun')
     198        self._checkModeChange([(True, 'o', ('exarkun',))])
     199
     200
     201    def test_modeChangeWithArgsAndDifferentModes(self):
     202        """
     203        Two modes added and one removed, they all accept args
     204        """
     205        self._sendModeChange('-oo+b', 'foo bar baz')
     206        self._checkModeChange([
     207            (True, 'b', ('baz',)),
     208            (False, 'oo', ('foo', 'bar'))
     209        ])
     210
     211
     212    def test_modeChangeWithArgsAndEqualModes(self):
     213        """
     214        Two modes added, they all accept args
     215        """
     216        self._sendModeChange('+xy', 'cow frog')
     217        self._checkModeChange([(True, 'xy', ('cow', 'frog'))])
     218
     219
     220    def test_modeChangeWithArgsAndMixedModes(self):
     221        """
     222        Some modes added and others removed, they all accept args
     223        """
     224        self._sendModeChange('+oo-h+vv-b', 'foo bar baz cow frog bat')
     225        self._checkModeChange([
     226            (True, 'oovv', ('foo','bar','cow','frog')),
     227            (False, 'hb', ('baz', 'bat'))
     228        ])
     229
     230
     231    def test_modeChangeWithNoArgsAndDifferentModes(self):
     232        """
     233        A mode added and another removed, they don't accept any arg
     234        """
     235        self._sendModeChange('-c+U')
     236        self._checkModeChange([(True, 'U', ()), (False, 'c', ())])
     237
     238
     239    def test_modeChangeWithNoArgsAndEqualModes(self):
     240        """
     241        Two modes removed, they don't accept any arg
     242        """
     243        self._sendModeChange('-cU')
     244        self._checkModeChange([(False, 'cU', ())])
     245
     246
     247    def test_modeChangeWithNoArgsAndMixedModes(self):
     248        """
     249        Some modes added and others removed, they don't accept any arg
     250        """
     251        self._sendModeChange('-c+fr-o+og-w')
     252        self._checkModeChange([(True, 'frog', ()), (False, 'cow', ())])
     253
     254
     255    def test_modeChangeWithSomeArgAndDifferentModes(self):
     256        """
     257        Two modes added and two removed, only the last accepts an arg
     258        """
     259        self._sendModeChange('+sU-lv', 'dea7h')
     260        self._checkModeChange([(True, 'sU', ()), (False, 'lv', ('dea7h',))])
     261
     262
     263    def test_modeChangeWithSomeArgAndEqualModes(self):
     264        """
     265        Two modes added, only the last accepts an arg
     266        """
     267        self._sendModeChange('+cl 1337')
     268        self._checkModeChange([(True, 'cl', ('1337',))])
     269
     270
     271    def test_modeChangeWithSomeArgAndMixedModes(self):
     272        """
     273        Some modes added and others removed, only the 2nd, 3rd and 5th
     274        accept an arg
     275        """
     276        self._sendModeChange('-co+l-U+o', 'Wolf 3141592 dea7h')
     277        self._checkModeChange([
     278            (True, 'lo', ('3141592', 'dea7h')),
     279            (False, 'coU', ('Wolf',))
     280        ])
     281
     282
     283    def test_modeChangeWithUnknownModes(self):
     284        """
     285        Some modes added and others removed, only the 3rd is known to
     286        accept an arg, the other modes don't accept anything by default
     287        """
     288        self._sendModeChange('+a-eo+f-g+qz', 'Wolf')
     289        self._checkModeChange([(True, 'afqz', ()), (False, 'eog', ('Wolf',))])
     290
     291
     292    def test_modeChangeWithWrongModesString(self):
     293        """
     294        The modes string is supposed to start with '+' or '-', if they miss
     295        a '+' will be added by default
     296        """
     297        self._sendModeChange('o', 'Wolf')
     298        self._checkModeChange([(True, 'o', ('Wolf',))])
     299
     300
     301    def test_modeChangeWithRepeatedAddedModes(self):
     302        """
     303        Two modes are added repeating the '+'
     304        """
     305        self._sendModeChange('+o+c', 'Wolf')
     306        self._checkModeChange([(True, 'oc', ('Wolf',))])
     307
     308
     309    def test_modeChangeWithRepeatedRemovedModes(self):
     310        """
     311        Two modes are removed repeating the '-'
     312        """
     313        self._sendModeChange('-o-c', 'Wolf')
     314        self._checkModeChange([(False, 'oc', ('Wolf',))])
     315
     316
     317    def test_modeChangeWithRepeatedMixedModes(self):
     318        """
     319        Several modes are added and removed repeating the '+' and the '-'
     320        """
     321        self._sendModeChange('+a+v-h-r+o+c-k-l', 'Wolf dea7h Svadilfari')
     322        self._checkModeChange([
     323            (True, 'avoc', ('Wolf', 'Svadilfari')),
     324            (False, 'hrkl', ('dea7h',))
     325        ])
     326
     327
    174328    def _serverTestImpl(self, code, msg, func, **kw):
    175329        host = pop(kw, 'host', 'server.host')
    176330        nick = pop(kw, 'nick', 'nickname')
  • twisted/words/protocols/irc.py

     
    549549    dcc_destdir = '.'
    550550    dcc_sessions = None
    551551
     552    # 'mode': (added, removed) i.e.:
     553    # 'l': (True, False) accepts an arg when added and no arg when removed
     554    # from http://www.faqs.org/rfcs/rfc1459.html - 4.2.3.1 Channel modes
     555    # if you want other modes to accept args, add them here, by default unknown
     556    # modes won't accept any arg
     557    _modeAcceptsArg = {
     558        'o': (True, True),    # op/deop a user
     559        'h': (True, True),    # hop/dehop (halfop) a user (not defined in RFC)
     560        'v': (True, True),    # voice/devoice a user
     561        'b': (True, True),    # ban/unban a user/mask
     562        'l': (True, False),   # set the user limit to channel
     563        'k': (True, False),   # set a channel key (password)
     564        't': (False, False),  # only ops set topic
     565        's': (False, False),  # secret channel
     566        'p': (False, False),  # private channel
     567        'i': (False, False),  # invite-only channel
     568        'm': (False, False),  # moderated channel
     569        'n': (False, False),  # no external messages
     570    }
     571
    552572    # If this is false, no attempt will be made to identify
    553573    # ourself to the server.
    554574    performLogin = 1
     
    699719        self.privmsg(user, channel, message)
    700720
    701721    def modeChanged(self, user, channel, set, modes, args):
    702         """Called when a channel's modes are changed
     722        """Called when users or channel's modes are changed.
    703723
    704724        @type user: C{str}
    705725        @param user: The user and hostmask which instigated this change.
    706726
    707727        @type channel: C{str}
    708         @param channel: The channel for which the modes are changing.
     728        @param channel: The channel where the modes are changed. If args is
     729        empty the channel for which the modes are changing. If the changes are
     730        at server level it could be equal to C{user}.
    709731
    710732        @type set: C{bool} or C{int}
    711         @param set: true if the mode is being added, false if it is being
    712         removed.
     733        @param set: True if the mode(s) is being added, False if it is being
     734        removed. If some modes are added and others removed at the same time
     735        this function will be called twice, the first time with all the added
     736        modes, the second with the removed ones. (To change this behaviour
     737        override the irc_MODE method)
    713738
    714739        @type modes: C{str}
    715740        @param modes: The mode or modes which are being changed.
     
    10111036        nick = string.split(prefix,'!')[0]
    10121037        self.userQuit(nick, params[0])
    10131038
     1039
    10141040    def irc_MODE(self, prefix, params):
    1015         channel, rest = params[0], params[1:]
    1016         set = rest[0][0] == '+'
    1017         modes = rest[0][1:]
    1018         args = rest[1:]
    1019         self.modeChanged(prefix, channel, set, modes, tuple(args))
     1041        """
     1042        Parse the server message when one or more modes are changed
     1043        """
     1044        user, channel, modes, args = prefix, params[0], params[1], params[2:]
     1045        if modes[0] not in '+-':
     1046            # add a '+' before the modes if it isn't specified (e.g. MODE s)
     1047            modes = '+' + modes
     1048        if ((modes[0] == '+' and '-' not in modes[1:]) or
     1049            (modes[0] == '-' and '+' not in modes[1:])):
     1050            # all modes are added or removed
     1051            set = (modes[0] == '+')
     1052            modes = modes[1:].replace('-+'[set], '')
     1053            self.modeChanged(user, channel, set, modes, tuple(args))
     1054        else:
     1055            # some modes added and other removed
     1056            modes2, args2 = ['', ''], [[], []]
     1057            for c in modes:
     1058                if c == '+':
     1059                    i = 0
     1060                elif c == '-':
     1061                    i = 1
     1062                else:
     1063                    modes2[i] += c
     1064                    # take an arg only if the mode accepts it (e.g. +o nick)
     1065                    if args and self._modeAcceptsArg.get(c, (False, False))[i]:
     1066                        args2[i].append(args.pop(0))
     1067            if args:
     1068                log.msg('Too many args (%s) received for %s. If one or more '
     1069                    'modes are supposed to accept an arg and they are not in '
     1070                    '_modeAcceptsArg, add them.' % (' '.join(args), modes))
    10201071
     1072            self.modeChanged(user, channel, True, modes2[0], tuple(args2[0]))
     1073            self.modeChanged(user, channel, False, modes2[1], tuple(args2[1]))
     1074
     1075
    10211076    def irc_PING(self, prefix, params):
    10221077        self.sendLine("PONG %s" % params[-1])
    10231078