| Four more modules into Nim: members, glyphs, emoji, store 3975b4b nandi 11h ago | 1 | ## What survives a restart. Every case runs against a real directory under a |
| 2 | ## temporary XDG_CONFIG_HOME, because the thing being tested is files. |
| 3 | |
| 4 | import std/[os, tables, unittest] |
| 5 | import frq/[store, model] |
| 6 | |
| 7 | template withTempConfig(body: untyped) = |
| 8 | let dir = getTempDir() / "frq-test-store-" & $getCurrentProcessId() |
| 9 | removeDir(dir) |
| 10 | createDir(dir) |
| 11 | putEnv("XDG_CONFIG_HOME", dir) |
| 12 | defer: |
| 13 | delEnv("XDG_CONFIG_HOME") |
| 14 | removeDir(dir) |
| 15 | body |
| 16 | |
| 17 | suite "the session": |
| 18 | test "absent when nothing was saved": |
| 19 | withTempConfig: |
| 20 | check loadSession()[1] == false |
| 21 | |
| 22 | test "round-trips": |
| 23 | withTempConfig: |
| 24 | check saveSession(SavedSession(brokerToken: "tok", handle: "alice", |
| 25 | did: "did:plc:x", nick: "alice")) |
| 26 | let (s, ok) = loadSession() |
| 27 | check ok |
| 28 | check s.brokerToken == "tok" |
| 29 | check s.handle == "alice" |
| 30 | check s.did == "did:plc:x" |
| 31 | |
| 32 | test "one with no broker token is not a session": |
| 33 | # The token is the whole point of saving one. |
| 34 | withTempConfig: |
| 35 | check saveSession(SavedSession(handle: "alice")) |
| 36 | check loadSession()[1] == false |
| 37 | |
| 38 | test "a file that will not parse is treated as absent": |
| 39 | # A stale credential is not worth an error at startup. |
| 40 | withTempConfig: |
| 41 | createDir(configDir()) |
| 42 | writeFile(sessionFile(), "{ this is not json") |
| 43 | check loadSession()[1] == false |
| 44 | |
| 45 | test "is written so nobody else can read it": |
| 46 | withTempConfig: |
| 47 | check saveSession(SavedSession(brokerToken: "tok")) |
| 48 | let perms = getFilePermissions(sessionFile()) |
| 49 | check fpGroupRead notin perms |
| 50 | check fpOthersRead notin perms |
| 51 | |
| 52 | test "clearing it leaves nothing behind": |
| 53 | withTempConfig: |
| 54 | check saveSession(SavedSession(brokerToken: "tok")) |
| 55 | clearSession() |
| 56 | check loadSession()[1] == false |
| 57 | |
| 58 | test "clearing one that is not there is not an error": |
| 59 | withTempConfig: |
| 60 | clearSession() |
| 61 | |
| 62 | suite "the rooms": |
| 63 | test "none when nothing was saved": |
| 64 | withTempConfig: |
| 65 | check loadRooms().len == 0 |
| 66 | |
| 67 | test "round-trip, with the markers": |
| 68 | # A phone that kept the names and lost the markers comes back to a |
| 69 | # hundred lines it has already read. |
| 70 | withTempConfig: |
| 71 | var rooms = initOrderedTable[string, Room]() |
| 72 | var a = initRoom("#one") |
| 73 | a.accessed = 5 |
| 74 | a.lastReadId = "m1" |
| 75 | a.lastReadAt = 1234 |
| 76 | rooms["#one"] = a |
| 77 | rooms["#two"] = initRoom("#two") |
| 78 | check saveRooms(rooms) |
| 79 | |
| 80 | let got = loadRooms() |
| 81 | check got.len == 2 |
| 82 | check got[0].name == "#one" |
| 83 | check got[0].accessed == 5 |
| 84 | check got[0].lastReadId == "m1" |
| 85 | check got[0].lastReadAt == 1234 |
| 86 | |
| 87 | test "order is kept — most recently used first is the file's own order": |
| 88 | withTempConfig: |
| 89 | var rooms = initOrderedTable[string, Room]() |
| 90 | for n in ["#c", "#a", "#b"]: rooms[n] = initRoom(n) |
| 91 | check saveRooms(rooms) |
| 92 | check loadRooms().len == 3 |
| 93 | check loadRooms()[0].name == "#c" |
| 94 | |
| 95 | test "a record with no name is dropped rather than defaulted": |
| 96 | withTempConfig: |
| 97 | createDir(configDir()) |
| 98 | writeFile(roomsFile(), """[{"name":"#ok"},{"accessed":3}]""") |
| 99 | let got = loadRooms() |
| 100 | check got.len == 1 |
| 101 | check got[0].name == "#ok" |
| 102 | |
| 103 | test "a file that will not parse is no rooms, not an error": |
| 104 | withTempConfig: |
| 105 | createDir(configDir()) |
| 106 | writeFile(roomsFile(), "not json at all") |
| 107 | check loadRooms().len == 0 |
| 108 | |
| 109 | suite "the preferences": |
| 110 | test "round-trip": |
| 111 | withTempConfig: |
| 112 | check savePrefs({"hideJoinPart": true, "showUsers": false}.toTable) |
| 113 | let got = loadPrefs() |
| 114 | check got["hideJoinPart"] == true |
| 115 | check got["showUsers"] == false |
| 116 | |
| 117 | test "absent is empty": |
| 118 | withTempConfig: |
| 119 | check loadPrefs().len == 0 |