1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
## Membership, modes, and Tab completion.
import std/[sequtils, tables, unittest]
import frq/members
suite "splitPrefix":
test "a mode in front of a nick":
check splitPrefix("@alice") == ("@", "alice")
check splitPrefix("+bob") == ("+", "bob")
test "a bare nick":
check splitPrefix("carol") == ("", "carol")
test "an empty entry":
check splitPrefix("") == ("", "")
suite "withNames":
test "folds a 353 into the pending list":
var acc = initTable[string, string]()
acc.withNames("@alice bob +carol")
check acc["alice"] == "@"
check acc["bob"] == ""
check acc["carol"] == "+"
test "several replies accumulate rather than replace":
# NAMES arrives over as many lines as it takes.
var acc = initTable[string, string]()
acc.withNames("@alice")
acc.withNames("bob")
check acc.len == 2
test "runs of spaces do not become members":
var acc = initTable[string, string]()
acc.withNames("alice bob")
check acc.len == 2
suite "withMode":
setup:
var users = {"alice": "", "bob": "", "carol": ""}.toTable
test "granting op":
users.withMode("+o", @["alice"])
check users["alice"] == "@"
test "taking it away":
users.withMode("+o", @["alice"])
users.withMode("-o", @["alice"])
check users["alice"] == ""
test "several at once, in order":
users.withMode("+ov", @["alice", "bob"])
check users["alice"] == "@"
check users["bob"] == "+"
test "a mode naming nobody still eats its argument":
# The rule this exists for: `+ko secret alice` sets a key and then ops
# alice. Reading the next letter's nick out of the wrong place would put
# the op on whoever `secret` happened to match.
users.withMode("+ko", @["secret", "alice"])
check users["alice"] == "@"
check users["bob"] == ""
test "a mode for somebody who is not here changes nothing":
users.withMode("+o", @["stranger"])
check "stranger" notin users
test "removing a mode takes no argument on some servers, and we do not eat one":
users.withMode("+o", @["alice"])
users.withMode("-l+v", @["bob"])
check users["bob"] == "+"
suite "memberList":
test "ops first, then alphabetically":
let users = {"zoe": "", "alice": "", "bob": "@", "carol": "+"}.toTable
check memberList(users).mapIt(it.nick) == @["bob", "carol", "alice", "zoe"]
test "the prefix order is the server's":
let users = {"v": "+", "o": "@", "q": "~", "plain": ""}.toTable
check memberList(users).mapIt(it.nick) == @["q", "o", "v", "plain"]
test "case does not decide the alphabetical order":
let users = {"Bob": "", "alice": ""}.toTable
check memberList(users).mapIt(it.nick) == @["alice", "Bob"]
suite "completeNick":
let nicks = @["alice", "alison", "bob"]
test "one match is taken whole":
check completeNick("hi bo", nicks) == ("hi bob ", true)
test "at the start of a line it is an address, elsewhere a mention":
# `eve: watch this` reads as talking TO eve; mid-sentence it is just a
# name, so it gets a plain space.
check completeNick("bo", nicks)[0] == "bob: "
check completeNick("hi bo", nicks)[0] == "hi bob "
test "several matches go as far as they agree":
check completeNick("al", nicks) == ("ali", true)
test "no match leaves the draft alone":
check completeNick("zz", nicks) == ("zz", false)
test "nothing to complete":
check completeNick("", nicks)[1] == false
check completeNick("hi ", nicks)[1] == false
test "case is ignored, and the nick's own case lands":
check completeNick("hi BO", nicks) == ("hi bob ", true)
test "a completed word is not completed again":
# "ali" already agrees with both; there is nothing more to add.
check completeNick("ali", nicks)[1] == false
|