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