From bb8a6b6c3d3e55c1146c3c9f8224983d88a42b17 Mon Sep 17 00:00:00 2001
From: Shivaram Lingamneni <slingamn@cs.stanford.edu>
Date: Mon, 22 May 2023 22:18:40 -0700
Subject: [PATCH] add a test for channel +n / -n (#201)

* add a test for channel +n / -n

* Update irctest/server_tests/chmodes/nooutside.py

Co-authored-by: Val Lorentz <progval+github@progval.net>

* Update irctest/server_tests/chmodes/nooutside.py

Co-authored-by: Val Lorentz <progval+github@progval.net>

* consistently rename to "no external messages"

---------

Co-authored-by: Val Lorentz <progval+github@progval.net>
---
 irctest/server_tests/chmodes/no_external.py | 38 +++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 irctest/server_tests/chmodes/no_external.py

diff --git a/irctest/server_tests/chmodes/no_external.py b/irctest/server_tests/chmodes/no_external.py
new file mode 100644
index 0000000..4858c04
--- /dev/null
+++ b/irctest/server_tests/chmodes/no_external.py
@@ -0,0 +1,38 @@
+"""
+Channel "no external messages" mode (`RFC 1459
+<https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.3.1>`__,
+`Modern <https://modern.ircdocs.horse/#no-external-messages-mode>`__)
+"""
+
+from irctest import cases
+from irctest.numerics import ERR_CANNOTSENDTOCHAN
+
+
+class NoExternalMessagesTestCase(cases.BaseServerTestCase):
+    @cases.mark_specifications("RFC1459", "Modern")
+    def testNoExternalMessagesMode(self):
+        # test the +n channel mode
+        self.connectClient("chanop", name="chanop")
+        self.joinChannel("chanop", "#chan")
+        self.sendLine("chanop", "MODE #chan +n")
+        self.getMessages("chanop")
+
+        self.connectClient("baz", name="baz")
+        # this message should be suppressed completely by +n
+        self.sendLine("baz", "PRIVMSG #chan :hi from baz")
+        replies = self.getMessages("baz")
+        reply_cmds = {reply.command for reply in replies}
+        self.assertIn(ERR_CANNOTSENDTOCHAN, reply_cmds)
+        self.assertEqual(self.getMessages("chanop"), [])
+
+        # set the channel to -n: baz should be able to send now
+        self.sendLine("chanop", "MODE #chan -n")
+        replies = self.getMessages("chanop")
+        modeLines = [line for line in replies if line.command == "MODE"]
+        self.assertMessageMatch(modeLines[0], command="MODE", params=["#chan", "-n"])
+        self.sendLine("baz", "PRIVMSG #chan :hi again from baz")
+        self.getMessages("baz")
+        relays = self.getMessages("chanop")
+        self.assertMessageMatch(
+            relays[0], command="PRIVMSG", params=["#chan", "hi again from baz"]
+        )