diff --git a/irctest/server_tests/test_channel_operations.py b/irctest/server_tests/test_channel_operations.py index f98abc2..f651454 100644 --- a/irctest/server_tests/test_channel_operations.py +++ b/irctest/server_tests/test_channel_operations.py @@ -214,7 +214,19 @@ class JoinTestCase(cases.BaseServerTestCase): m = self.getMessage(1) self.assertMessageEqual(m, command='TOPIC', params=['#chan', 'T0P1C']) + @cases.SpecificationSelector.requiredBySpecification('RFC2812') + def testTopicNonexistentChannel(self): + """RFC2812 specifies ERR_NOTONCHANNEL as the correct response to TOPIC + on a nonexistent channel. The modern spec prefers ERR_NOSUCHCHANNEL. + + + """ + self.connectClient('foo') + self.sendLine(1, 'TOPIC #chan') + m = self.getMessage(1) + # either 403 ERR_NOSUCHCHANNEL or 443 ERR_NOTONCHANNEL + self.assertIn(m.command, ('403', '443')) @cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812') def testListEmpty(self): @@ -306,6 +318,15 @@ class JoinTestCase(cases.BaseServerTestCase): self.assertMessageEqual(m, command='KICK', params=['#chan', 'bar', 'bye']) + @cases.SpecificationSelector.requiredBySpecification('RFC2812') + def testKickNonexistentChannel(self): + """“Kick command [...] Numeric replies: [...] ERR_NOSUCHCHANNEL.""" + self.connectClient('foo') + self.sendLine(1, 'KICK #chan nick') + m = self.getMessage(1) + # should return ERR_NOSUCHCHANNEL + self.assertMessageEqual(m, command='403') + @cases.SpecificationSelector.requiredBySpecification('RFC2812') def testDoubleKickMessages(self): """“The server MUST NOT send KICK messages with multiple channels or diff --git a/irctest/server_tests/test_messages.py b/irctest/server_tests/test_messages.py new file mode 100644 index 0000000..d8e705d --- /dev/null +++ b/irctest/server_tests/test_messages.py @@ -0,0 +1,65 @@ +""" +Section 3.2 of RFC 2812 + +""" + +from irctest import cases +from irctest import client_mock +from irctest import runner +from irctest.irc_utils import ambiguities +from irctest.irc_utils.message_parser import Message + +class PrivmsgTestCase(cases.BaseServerTestCase): + @cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812') + def testPrivmsg(self): + """""" + self.connectClient('foo') + self.sendLine(1, 'JOIN #chan') + self.connectClient('bar') + self.sendLine(2, 'JOIN #chan') + self.sendLine(1, 'PRIVMSG #chan :hello there') + self.getMessages(1) # synchronize + pms = [msg for msg in self.getMessages(2) if msg.command == 'PRIVMSG'] + self.assertEqual(len(pms), 1) + self.assertMessageEqual( + pms[0], + command='PRIVMSG', + params=['#chan', 'hello there'] + ) + + @cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812') + def testPrivmsgNonexistentChannel(self): + """""" + self.connectClient('foo') + self.sendLine(1, 'PRIVMSG #nonexistent :hello there') + msg = self.getMessage(1) + # ERR_NOSUCHNICK, ERR_NOSUCHCHANNEL, or ERR_CANNOTSENDTOCHAN + self.assertIn(msg.command, ('401', '403', '404')) + +class NoticeTestCase(cases.BaseServerTestCase): + @cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812') + def testNotice(self): + """""" + self.connectClient('foo') + self.sendLine(1, 'JOIN #chan') + self.connectClient('bar') + self.sendLine(2, 'JOIN #chan') + self.sendLine(1, 'NOTICE #chan :hello there') + self.getMessages(1) # synchronize + notices = [msg for msg in self.getMessages(2) if msg.command == 'NOTICE'] + self.assertEqual(len(notices), 1) + self.assertMessageEqual( + notices[0], + command='NOTICE', + params=['#chan', 'hello there'] + ) + + @cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812') + def testNoticeNonexistentChannel(self): + """ + 'automatic replies MUST NEVER be sent in response to a NOTICE message' + https://tools.ietf.org/html/rfc2812#section-3.3.2> + """ + self.connectClient('foo') + self.sendLine(1, 'NOTICE #nonexistent :hello there') + self.assertEqual(self.getMessages(1), [])