예제 #1
0
class TestServer:
    def setup_method(self, method):
        self.server = Server("TestServer")
        self.user = FakeUser()
        self.user.nick = '*'
        self.user.registered = False
        self.user.realname = None
        
    def register_user(self, user, nick):
        self.server.msg_received(user, 'pass password')
        self.server.msg_received(user, 'nick {}'.format(nick))
        self.server.msg_received(user, 'user {0} 0 * :{0}'.format(nick))

    def setup_channel(self, chan, n):
        users = {}
        for name in ['foo'+str(u) for u in range(n)]:
            users[name] = FakeUser()
            self.register_user(users[name], name)
            self.server.msg_received(users[name], 'join ' + chan)
            users[name].send.reset_mock()
        return users

    # Server methods

    def test_parse(self):
        assert (self.server.parse_msg(':prefix command arg1 arg2 :trailing arg') ==
                ('prefix', 'command', ['arg1', 'arg2', 'trailing arg']))
        assert (self.server.parse_msg('command arg1 arg2 :trailing arg') ==
                ('', 'command', ['arg1', 'arg2', 'trailing arg']))
        assert (self.server.parse_msg(':prefix command :trailing arg') ==
                ('prefix', 'command', ['trailing arg']))
        assert (self.server.parse_msg(':prefix command') ==
                ('prefix', 'command', []))
        assert (self.server.parse_msg(':PREFIX COMMAND ARG1 :TRAILING arg') ==
                ('PREFIX', 'command', ['ARG1', 'TRAILING arg']))

    def test_valid_nick(self):
        assert self.server.valid_nick('s')
        assert self.server.valid_nick('abcdefghi')
        
        letters = map(chr, range(97, 123))
        letters.extend(map(chr, range(65, 91)))
        special = map(chr, range(0x5b, 0x61))
        special.extend(map(chr, range(0x7b, 0x7e)))
        
        non_initial = map(str, range(10))
        non_initial.append('-')

        for c in letters + special:
            assert self.server.valid_nick(c + 'a1[')

        for c in special + non_initial:
            assert self.server.valid_nick('a' + c)

        for c in non_initial:
            assert not self.server.valid_nick(c + 'a')

    def test_valid_chan(self):

        assert self.server.valid_chan('&chan')
        assert not self.server.valid_chan('#chan')
        assert not self.server.valid_chan('!chan')
        assert not self.server.valid_chan('+chan')
        assert not self.server.valid_chan('chan')
        assert not self.server.valid_chan('#')
        assert not self.server.valid_chan('&')
        assert not self.server.valid_chan('+')
        assert not self.server.valid_chan('!')

        assert self.server.valid_chan('&'+'A'*48)
        assert not self.server.valid_chan('&'+'A'*50)

        assert not self.server.valid_chan('&abc def')
        assert not self.server.valid_chan('&abc,def')
        assert not self.server.valid_chan('&abc:def')
        assert not self.server.valid_chan('&abc\x07def')

    # Nick command (before registration)

    def test_nick(self):
        self.server.msg_received(self.user, 'nick shira')
        assert self.user.nick == 'shira'
        assert not self.user.send.called

    def test_nick_alreadytaken(self):
        other = FakeUser()
        self.register_user(other, 'shira')
        
        self.server.msg_received(self.user, 'nick shira')
        assert self.user.nick == '*'
        self.user.send.assert_called_with(':{} {} * shira :Nickname is already '
            'in use'.format(self.server.host, ERR_NICKNAMEINUSE))

    def test_nick_noargs(self):
        self.server.msg_received(self.user, 'nick')
        assert self.user.nick == '*'
        self.user.send.assert_called_with(':{} {} * :No nickname '
            'given'.format(self.server.host, ERR_NONICKNAMEGIVEN))
                                                          
    def test_long_nick(self):
        self.server.msg_received(self.user, 'nick shira6789012345')
        assert self.user.nick == 'shira6789'
        
    def test_long_nick_alreadytaken(self):
        other = FakeUser()
        self.register_user(other, 'shira6789')
        
        self.server.msg_received(self.user, 'nick shira6789012345')
        assert self.user.nick == '*'
        self.user.send.assert_called_with(':{} {} * shira6789 :Nickname is '
            'already in use'.format(self.server.host, ERR_NICKNAMEINUSE))

    def test_invalid_nick(self):
        self.server.msg_received(self.user, 'nick -shira')
        assert self.user.nick == '*'
        self.user.send.assert_called_with(':{} {} * -shira :Erroneous '
            'nickname'.format(self.server.host, ERR_ERRONEUSNICKNAME))

    # Pass command

    def test_pass(self):
        self.server.msg_received(self.user, 'pass password')
        assert not self.user.send.called       

    def test_pass_noargs_before_registration(self):
        self.server.msg_received(self.user, 'pass')
        self.user.send.assert_called_with(':{} {} * PASS :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_pass_noargs_after_registration(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'pass')
        self.user.send.assert_called_with(':{} {} shira :You may not '
            'reregister'.format(self.server.host, ERR_ALREADYREGISTERED))

    def test_second_pass_before_registration(self):
        self.server.msg_received(self.user, 'pass password')
        self.server.msg_received(self.user, 'pass drowssap')
        assert not self.user.send.called
        
    def test_second_pass_after_registration(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'pass drowsapp')
        self.user.send.assert_called_with(':{} {} shira :You may not '
            'reregister'.format(self.server.host, ERR_ALREADYREGISTERED))

    # User command

    def test_user(self):
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        assert not self.user.send.called       

    def test_user_noargs_before_registration(self):
        self.server.msg_received(self.user, 'user')
        self.user.send.assert_called_with(':{} {} * USER :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_user_noargs_after_registration(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'user')
        self.user.send.assert_called_with(':{} {} shira :You may not '
            'reregister'.format(self.server.host, ERR_ALREADYREGISTERED))

    def test_user_1arg(self):
        self.server.msg_received(self.user, 'user shira')
        self.user.send.assert_called_with(':{} {} * USER :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_user_2args(self):
        self.server.msg_received(self.user, 'user shira 0')
        self.user.send.assert_called_with(':{} {} * USER :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_user_3args(self):
        self.server.msg_received(self.user, 'user shira 0 *')
        self.user.send.assert_called_with(':{} {} * USER :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_second_user_before_registration(self):
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.server.msg_received(self.user, 'user arihs 0 * :yecats')
        assert not self.user.send.called

    def test_second_user_after_registration(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.user.send.assert_called_with(':{} {} shira :You may not '
            'reregister'.format(self.server.host, ERR_ALREADYREGISTERED))

    # Registration

    def registration_assertions(self):
        calls = [call(':{} {} shira :Welcome to the IRC Chat Server '
                      'shira'.format(self.server.host, RPL_WELCOME)),
                 call(':{} {} shira :Your host is {}, running version '
                      '{}'.format(self.server.host, RPL_YOURHOST,
                                  self.server.host, self.server.version)),
                 call(':{} {} shira :This server was created '
                      '{}'.format(self.server.host, RPL_CREATED,
                                  self.server.createdate)),
                 call(':{} {} shira {} {}'.format(self.server.host, RPL_MYINFO,
                                                 self.server.host, 
                                                 self.server.version))]

        self.user.send.assert_has_calls(calls)

    def test_register(self):
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        assert self.user.realname == 'Stacey'
                                 
    def test_register_pass_nick_user(self):
        self.server.msg_received(self.user, 'pass password')
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.registration_assertions()

    def test_register_pass_user_nick(self):
        self.server.msg_received(self.user, 'pass password')
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.registration_assertions()

    def test_register_nick_pass_user(self):
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'pass password')
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.registration_assertions()

    def test_register_user_pass_nick(self):
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.server.msg_received(self.user, 'pass password')
        self.server.msg_received(self.user, 'nick shira')
        self.registration_assertions()

    def test_register_nick_user(self):
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.registration_assertions()

    def test_register_user_nick(self):
        self.server.msg_received(self.user, 'user shira 0 * :Stacey')
        self.server.msg_received(self.user, 'nick shira')
        self.registration_assertions()

    # Nick command (after registration)

    def test_change_nick(self):
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick shira')
        assert self.user.nick == 'shira'
        self.user.send.assert_called_wth(':santa NICK shira')

    def test_change_nick_free_old(self):
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick shira')
        self.server.msg_received(self.user, 'nick santa')
        assert self.user.nick == 'santa'

    def test_nick_multiple_channels(self):
        users = self.setup_channel('&chan1', 2).values()
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan1')
        self.server.msg_received(self.user, 'join &chan2')
        for u in users:
            self.server.msg_received(u, 'join &chan2')
        for u in users:
            u.send.reset_mock()
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'nick santa')
        for u in users:
            assert u.send.call_count == 1

    def test_change_nick_alreadytaken(self):
        other = FakeUser()
        self.register_user(other, 'shira')

        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick shira')
        assert self.user.nick == 'santa'
        self.user.send.assert_called_with(':{} {} santa shira :Nickname is '
            'already in use'.format(self.server.host, ERR_NICKNAMEINUSE))

    def test_change_nick_noargs(self):
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick')
        assert self.user.nick == 'santa'
        self.user.send.assert_called_with(':{} {} santa :No nickname '
            'given'.format(self.server.host, ERR_NONICKNAMEGIVEN))
                                                          
    def test_change_long_nick(self):
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick shira6789012345')
        assert self.user.nick == 'shira6789'
        
    def test_change_long_nick_alreadytaken(self):
        other = FakeUser()
        self.register_user(other, 'shira6789')
        
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick shira6789012345')
        assert self.user.nick == 'santa'
        self.user.send.assert_called_with(':{} {} santa shira6789 :Nickname is '
            'already in use'.format(self.server.host, ERR_NICKNAMEINUSE))

    def test_change_invalid_nick(self):
        self.register_user(self.user, 'santa')
        self.server.msg_received(self.user, 'nick -shira')
        assert self.user.nick == 'santa'
        self.user.send.assert_called_with(':{} {} santa -shira :Erroneous '
            'nickname'.format(self.server.host, ERR_ERRONEUSNICKNAME))
        
    # Join command

    def test_join_not_registered(self):
        self.server.msg_received(self.user, 'join &chan')
        self.user.send.assert_called_with(':{} {} * :You have not '
            'registered'.format(self.server.host, ERR_NOTREGISTERED))
    
    def test_join(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'join &chan')
        assert '&chan' in self.server.channels
        assert self.user in self.server.channels['&chan'].users 
        assert self.server.channels['&chan'] in self.user.channels

        calls = [call(':shira JOIN &chan'),
                 call(':{} {} shira @ &chan '
                      ':shira'.format(self.server.host, RPL_NAMREPLY)),
                 call(':{} {} shira &chan :End of NAMES '
                      'list'.format(self.server.host, RPL_ENDOFNAMES))]
        
        self.user.send.assert_has_calls(calls)

        # verify that topic is not being sent
        assert self.user.send.call_count == 3

    def test_join_noargs(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'join')
        self.user.send.assert_called_with(':{} {} shira JOIN :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_invalid_chan(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'join chan')
        self.user.send.assert_called_with(':{} {} shira chan :No such '
            'channel'.format(self.server.host, ERR_NOSUCHCHANNEL))

    def test_join_notification(self):
        users = self.setup_channel('&chan', 2)
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'join &chan')

        names = users.keys()
        names.append('shira')
        names.sort()
        calls = [call(':shira JOIN &chan'),
                 call(':{} {} shira @ &chan :{} {} '
                      '{}'.format(self.server.host, RPL_NAMREPLY,
                                  names[0], names[1], names[2])),
                 call(':{} {} shira &chan :End of NAMES '
                      'list'.format(self.server.host, RPL_ENDOFNAMES))]
        self.user.send.assert_has_calls(calls)

        for user in users.values():
            user.send.assert_called_with(':shira JOIN &chan')

    def test_join_twice(self):
        users = self.setup_channel('&chan', 2)
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'join &chan')
        assert not self.user.send.called
        for user in users:
            assert not self.user.send.called
 
    # Part command

    def test_part_not_registered(self):
        self.server.msg_received(self.user, 'part &chan')
        self.user.send.assert_called_with(':{} {} * :You have not '
            'registered'.format(self.server.host, ERR_NOTREGISTERED))

    def test_part(self):
        users = self.setup_channel('&chan', 2).values()
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'part &chan')
        self.user.send.assert_called_with(':shira PART &chan')
        assert not self.user in self.server.channels['&chan'].users
        assert not self.server.channels['&chan'] in self.user.channels
        for user in users:
            assert self.server.channels['&chan'] in user.channels
            user.send.assert_called_with(':shira PART &chan')

    def test_part_last(self):
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'part &chan')
        assert '&chan' in self.server.channels

    def test_part_noargs(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'part')
        self.user.send.assert_called_with(':{} {} shira PART :Not enough '
            'parameters'.format(self.server.host, ERR_NEEDMOREPARAMS))

    def test_part_non_existent_channel(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'part &chan')
        self.user.send.assert_called_with(":{} {} shira &chan :No "
            'such channel'.format(self.server.host, ERR_NOSUCHCHANNEL))

    def test_part_not_in_channel(self):
        other = FakeUser()
        self.register_user(other,'santa')
        self.server.msg_received(other, 'join &chan')

        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'part &chan')
        self.user.send.assert_called_with(":{} {} shira &chan :You're not "
            'on that channel'.format(self.server.host, ERR_NOTONCHANNEL))

    def test_part_one_of_multiple_channels(self):
        users = self.setup_channel('&chan1', 2).values()
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan1')
        self.server.msg_received(self.user, 'join &chan2')
        for u in users:
            self.server.msg_received(u, 'join &chan2')
        for u in users:
            u.send.reset_mock()
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'part &chan1')
        assert self.user in self.server.channels['&chan2'].users
        assert self.server.channels['&chan2'] in self.user.channels
        for u in users:
            assert u.send.call_count == 1

    def test_join_0(self):
        self.setup_channel('&chan1', 2)
        self.setup_channel('&chan2', 2)
        self.register_user(self.user, 'shira')
        self.server.msg_received(self.user, 'join &chan1')
        self.server.msg_received(self.user, 'join &chan2')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'join 0')
        assert not self.user in self.server.channels['&chan1'].users
        assert not self.user in self.server.channels['&chan2'].users
        assert not self.server.channels['&chan1'] in self.user.channels
        assert not self.server.channels['&chan2'] in self.user.channels

    # Privmsg command

    def test_privmsg_not_registered(self):
        self.server.msg_received(self.user, 'privmsg shira :hi')
        self.user.send.assert_called_with(':{} {} * :You have not '
            'registered'.format(self.server.host, ERR_NOTREGISTERED))
    
    def test_privmsg_to_nick(self):
        other = FakeUser()
        self.register_user(other, 'santa')
        other.send.reset_mock()

        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'privmsg santa :hi')
        other.send.assert_called_with(':shira PRIVMSG santa :hi')

    def test_privmsg_noargs(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        
        self.server.msg_received(self.user, 'privmsg')
        self.user.send.assert_called_with(':{} {} shira :No recipient '
            'given (PRIVMSG)'.format(self.server.host, ERR_NORECIPIENT))

    def test_privmsg_1args(self):
        other = FakeUser()
        self.register_user(other, 'santa')
        other.send.reset_mock()

        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        
        self.server.msg_received(self.user, 'privmsg santa')
        self.user.send.assert_called_with(':{} {} shira :No text to '
            'send'.format(self.server.host, ERR_NOTEXTTOSEND))

        assert not other.send.called

    def test_privmsg_non_existent(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()
        self.server.msg_received(self.user, 'privmsg foo :hi')

        self.user.send.assert_called_with(':{} {} shira foo :No such '
            'nick/channel'.format(self.server.host, ERR_NOSUCHNICK))

    def test_privmsg_to_channel(self):
        users = self.setup_channel('&chan', 2)
        self.register_user(self.user, 'shira')

        self.server.msg_received(self.user, 'join &chan')
        self.user.send.reset_mock()

        for user in users.values():
            user.send.reset_mock()

        self.server.msg_received(self.user, 'privmsg &chan :hi')
        
        for (name, user) in users.items():
            user.send.assert_called_with(':shira PRIVMSG &chan :hi')

        assert not self.user.send.called
 
    # Miscellaneous tests

    def test_invalid_command_before_registration(self):
        self.server.msg_received(self.user, 'qwerty')
        assert not self.user.send.called

    def test_invalid_command_after_registration(self):
        self.register_user(self.user, 'shira')
        self.user.send.reset_mock()

        self.server.msg_received(self.user, 'qwerty')
        assert not self.user.send.called