nandi/freeqsay-nimpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/freeqsay-nim.git
git clone ssh://git@rickub.com/nandi/freeqsay-nim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

test_avatar.nim · 130 lines · 4.4 KBNim Blame HistoryRaw
freeqsay: Nim port of the Clojure implementation fa53aa2 nandi 8h ago1import std/[json, os, sequtils, strutils, tables, unittest]
2import ../src/freeqsay
3
4const didA = "did:plc:ewvi7nmzuoqusbcablsm7c4h"
5
6let fixtures = parseFile(currentSourcePath().parentDir / ".." /
7 "fixtures" / "avatar-conformance.json")
8
9proc stubGet(did: string): HttpGet =
10 ## Test hook standing in for the network: always answers with `did`.
11 result = proc (url: string): HttpResponse {.gcsafe.} =
12 HttpResponse(status: 200, body: %*{"did": did})
13
14suite "sha256":
15 test "vectors":
16 check toHex(digest("")) ==
17 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
18 check toHex(digest("abc")) ==
19 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
20 # RFC 4231 test case 1
21 check toHex(hmac(repeat(0x0b'u8, 20), toBytes("Hi There"))) ==
22 "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
23
24suite "avatar-v1 conformance":
25 test "fixture replays":
26 check fixtures.len > 0
27 for f in fixtures:
28 let
29 did = f["did"].getStr
30 av = deriveAvatar(did)
31 checkpoint did
32 check f["canonical_seed"].getStr == toHex(canonicalSeed(did))
33 for key, want in f["expected_traits"]:
34 check av.traits[key] == want.getStr
35 check f["sprite_hash"].getStr == spriteHash(av)
36
37suite "balloons":
38 test "wraps long lines":
39 let lines = wrapText("one two three four five", 10)
40 check lines.allIt(it.len <= 10)
41 check "one" in lines.join(" ")
42
43 test "single-line speech balloon":
44 let b = makeBalloon("hi")
45 check "< hi" in b
46 let top = b.splitLines[0]
47 check top.startsWith(" ") and top[1 .. ^1].allIt(it == '_')
48
49 test "multi-line balloon":
50 let b = makeBalloon("hello there friend", width = 6)
51 check "/ " in b
52 check "\\ " in b
53
54 test "thought bubble":
55 check "( hmm )" in makeBalloon("hmm", think = true)
56
57suite "balloons preserve ANSI shape":
58 let
59 esc = "\x1b"
60 art = didToAnsi(didA, scale = 1)
61 lines = art.splitLines
62
63 test "escape sequences cost no columns":
64 check visibleWidth(esc & "[38;2;1;2;3mabc" & esc & "[0m") == 3
65 check lines.allIt(visibleWidth(it) == 16)
66
67 test "art lines survive a balloon verbatim":
68 let
69 b = makeBalloon(art, width = 40)
70 body = b.splitLines[1 .. ^2]
71 # every row is padded to one width, so the right border lines up
72 let borders = body.mapIt(it.filterIt(it in {'|', '/', '\\'}).len)
73 check borders.deduplicate.len == 1
74 check body.len == lines.len
75 for i, l in lines:
76 check l in body[i]
77
78 test "indentation is not collapsed":
79 check wrapText(" indented", 40) == @[" indented"]
80
81suite "say":
82 test "balloon + character for handle + message":
83 let said = freeqsay("alice.test", "hello world", scale = 1,
84 resolveOpts = ResolveOpts(httpGet: stubGet(didA)))
85 check said.did == didA
86 check said.text == "hello world"
87 check "< hello world >" in said.output
88 check "\\" in said.output
89 check "\x1b[" in said.output
90
91 test "raw DID needs no network":
92 check "< yo >" in freeqsay(didA, "yo", scale = 1).output
93
94suite "resolving":
95 test "handle normalization":
96 check normalizeHandle("@Jay.Bsky.Team") == "jay.bsky.team"
97 check isDid(didA)
98 check not isDid("jay.bsky.team")
99
100 test "DIDs pass through without a request":
101 check resolveIdentity(didA).did == didA
102
103 test "handles resolve through the endpoint":
104 var seen = ""
105 let get = proc (url: string): HttpResponse {.gcsafe.} =
106 {.cast(gcsafe).}: seen = url
107 HttpResponse(status: 200, body: %*{"did": didA})
108 check resolveHandle("@example.bsky.social", ResolveOpts(httpGet: get)) == didA
109 check "handle=example.bsky.social" in seen
110
111 test "a dead transport says so instead of blaming the handle":
112 let get = proc (url: string): HttpResponse {.gcsafe.} =
113 HttpResponse(status: 0, error: "no TLS here")
114 expect IOError:
115 discard resolveHandle("alice.test", ResolveOpts(httpGet: get))
116
117suite "ansi":
118 test "truecolor escapes":
119 check "\x1b[" in didToAnsi(didA, scale = 1)
120
121 test "handle->ansi matches did->ansi after resolve":
122 let id = resolveIdentity("alice.test", ResolveOpts(httpGet: stubGet(didA)))
123 check didToAnsi(didA, scale = 1) == didToAnsi(id.did, scale = 1)
124
125suite "png":
126 test "signature":
127 let bs = didToPng(didA, scale = 2)
128 check bs[0 .. 1] == @[137'u8, 80'u8]
129 check bs[12 .. 15] == toBytes("IHDR")
130 check bs[^4 .. ^1] == @[0xae'u8, 0x42, 0x60, 0x82] # IEND crc