summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2026-04-25 16:05:59 -0300
committerEuAndreh <eu@euandre.org>2026-04-25 16:05:59 -0300
commit5f7d58c81eda3c8de4725a4a0561a10723786d7a (patch)
tree154ff4f0c59e96a728fa05ad9f4c2907d4ceb989 /tests
parentImplement channel modes, labeled-response, chathistory BATCH (diff)
downloadpapod-5f7d58c81eda3c8de4725a4a0561a10723786d7a.tar.gz
papod-5f7d58c81eda3c8de4725a4a0561a10723786d7a.tar.xz
Add NICK validation, voice tracking, multi-prefix, OPER/TIME
NICK now rejects invalid characters with 432, does case-insensitive collision detection, and broadcasts NICK changes to all clients sharing a channel after registration. Voice (+v) is tracked in a new :voiced atom alongside ops, with cleanup on PART/KICK/QUIT/disconnect. NAMES and the on-join NAMES reply honor multi-prefix when the client negotiated the capability. Per-recipient PRIVMSG delivery now sends tagged variants only to clients that negotiated message-tags or server-time, while still echoing tagged messages back to senders with echo-message. TOPIC enforces +t against non-ops with 482. WHO marks opers with *, MODE <nick> reports +o, and WHOIS adds the 313 oper line. OPER and TIME commands are now implemented (381/464 and 391).
Diffstat (limited to 'tests')
-rw-r--r--tests/integration.clj9
-rw-r--r--tests/unit.clj54
2 files changed, 41 insertions, 22 deletions
diff --git a/tests/integration.clj b/tests/integration.clj
index b92f85d..3e12833 100644
--- a/tests/integration.clj
+++ b/tests/integration.clj
@@ -45,6 +45,7 @@
:clients (atom {})
:channels (atom {})
:ops (atom {})
+ :voiced (atom {})
:chan-modes (atom {})}))
(defn- make-client
@@ -168,13 +169,12 @@
;; Alice should see bob's join
(let [alice-out (wait-for alice "JOIN" 2000)]
(is (string/includes? alice-out "bob")))
- ;; Alice sends — bob receives with msgid + time
+ ;; Alice sends — bob receives
(.reset (:client-out bob))
(send! alice "PRIVMSG #test :Hello from Alice!")
(let [bob-out (wait-for bob "Hello from Alice" 2000)]
(is (string/includes? bob-out "PRIVMSG #test"))
- (is (string/includes? bob-out "@msgid="))
- (is (string/includes? bob-out "time=")))
+ (is (string/includes? bob-out "Hello from Alice")))
(finally
((:close! alice))
((:close! bob))))))
@@ -264,8 +264,7 @@
(.reset (:client-out bob))
(send! alice "PRIVMSG bob :hey bob")
(let [bob-out (wait-for bob "hey bob" 2000)]
- (is (string/includes? bob-out "PRIVMSG bob :hey bob"))
- (is (string/includes? bob-out "@msgid=")))
+ (is (string/includes? bob-out "PRIVMSG bob :hey bob")))
(finally
((:close! alice))
((:close! bob))))))
diff --git a/tests/unit.clj b/tests/unit.clj
index d172e2a..c5cabaa 100644
--- a/tests/unit.clj
+++ b/tests/unit.clj
@@ -111,7 +111,8 @@
:papod.process/started-at (java.util.Date.)}])
{:conn conn :cracha cracha-state :process-id proc-id
:clients (atom {}) :channels (atom {})
- :ops (atom {}) :chan-modes (atom {})})))
+ :ops (atom {}) :voiced (atom {})
+ :chan-modes (atom {})})))
(defn test-network!
[conn]
@@ -1441,13 +1442,18 @@
(testing "messages include msgid tags"
(let [alice-out (java.io.ByteArrayOutputStream.)
bob-out (java.io.ByteArrayOutputStream.)
+ bob (registered-client "bob" bob-out)
+ _ (swap! bob assoc
+ :caps #{"message-tags" "server-time"})
{:keys [test-network-id] :as components}
(assoc (test-components-with-network)
:clients (atom {"alice" {:w alice-out}
- "bob" {:w bob-out}})
+ "bob" {:w bob-out
+ :client-atom bob}})
:channels (atom {"#test" #{"alice" "bob"}}))
conn (:conn components)
- alice (registered-client "alice" alice-out test-network-id)]
+ alice (registered-client "alice" alice-out
+ test-network-id)]
;; Create channel in DB
@(d/transact conn
[{:papod.channel/id (java.util.UUID/randomUUID)
@@ -1587,13 +1593,18 @@
(testing "+reply tag on PRIVMSG creates thread"
(let [alice-out (java.io.ByteArrayOutputStream.)
bob-out (java.io.ByteArrayOutputStream.)
+ bob (registered-client "bob" bob-out)
+ _ (swap! bob assoc
+ :caps #{"message-tags" "server-time"})
{:keys [test-network-id] :as components}
(assoc (test-components-with-network)
:clients (atom {"alice" {:w alice-out}
- "bob" {:w bob-out}})
+ "bob" {:w bob-out
+ :client-atom bob}})
:channels (atom {}))
conn (:conn components)
- alice (registered-client "alice" alice-out test-network-id)]
+ alice (registered-client "alice" alice-out
+ test-network-id)]
(handle-join ["#test"] alice components)
(swap! (:channels components) update "#test" conj "bob")
(replies-for! {:command "PRIVMSG" :params ["" "#test" ":parent message"]}
@@ -1626,13 +1637,19 @@
(deftest test_ircv3-capabilities
(testing "server-time tag on outgoing messages"
(let [bob-out (java.io.ByteArrayOutputStream.)
+ bob (registered-client "bob" bob-out)
+ _ (swap! bob assoc
+ :caps #{"message-tags" "server-time"})
{:keys [test-network-id] :as components}
(assoc (test-components-with-network)
- :clients (atom {"alice" {:w (java.io.ByteArrayOutputStream.)}
- "bob" {:w bob-out}})
+ :clients (atom {"alice"
+ {:w (java.io.ByteArrayOutputStream.)}
+ "bob"
+ {:w bob-out :client-atom bob}})
:channels (atom {"#test" #{"alice" "bob"}}))
conn (:conn components)
- alice (registered-client "alice" (java.io.ByteArrayOutputStream.)
+ alice (registered-client "alice"
+ (java.io.ByteArrayOutputStream.)
test-network-id)]
@(d/transact conn
[{:papod.channel/id (java.util.UUID/randomUUID)
@@ -1644,7 +1661,8 @@
(handle-privmsg ["#test" ":hello"] alice components)
(let [delivered (.toString bob-out "UTF-8")]
(is (string/includes? delivered "time="))
- (is (re-find #"time=\d{4}-\d{2}-\d{2}T" delivered)))))
+ (is (re-find #"time=\d{4}-\d{2}-\d{2}T"
+ delivered)))))
(testing "echo-message echoes back to sender"
(let [alice-out (java.io.ByteArrayOutputStream.)
bob-out (java.io.ByteArrayOutputStream.)
@@ -1662,15 +1680,17 @@
:papod.channel/type :papod.channel.type/public
:papod.channel/description ""
:papod.channel/created-at (java.util.Date.)}])
- ;; Without echo-message: sender doesn't receive
- (handle-privmsg ["#test" ":no-echo"] alice components)
- (is (= "" (.toString alice-out "UTF-8")))
- ;; With echo-message: sender receives their own message
+ ;; Without echo-message: no reply
+ (let [replies (handle-privmsg ["#test" ":no-echo"]
+ alice components)]
+ (is (empty? replies)))
+ ;; With echo-message: reply includes the message
(swap! alice assoc :caps #{"echo-message"})
- (handle-privmsg ["#test" ":with-echo"] alice components)
- (let [echoed (.toString alice-out "UTF-8")]
- (is (string/includes? echoed "with-echo"))
- (is (string/includes? echoed "@msgid=")))))
+ (let [replies (handle-privmsg ["#test" ":with-echo"]
+ alice components)]
+ (is (= 1 (count replies)))
+ (is (string/includes? (first replies) "with-echo"))
+ (is (string/includes? (first replies) "@msgid=")))))
(testing "CAP LS advertises all capabilities"
(let [c (client)
replies (handle-cap ["LS" "302"] c no-conn)]