Suite of AT Protocol TypeScript libraries built on web standards
21
fork

Configure Feed

Select the types of activity you want to include in your feed.

at lex 305 lines 9.1 kB view raw
1import { assertEquals, assertThrows } from "@std/assert"; 2import { 3 ensureValidHandle, 4 ensureValidHandleRegex, 5 InvalidHandleError, 6 normalizeAndEnsureValidHandle, 7} from "../mod.ts"; 8 9Deno.test("validation allows valid handles", () => { 10 const expectValid = (h: string) => { 11 ensureValidHandle(h); 12 ensureValidHandleRegex(h); 13 }; 14 15 expectValid("A.ISI.EDU"); 16 expectValid("XX.LCS.MIT.EDU"); 17 expectValid("SRI-NIC.ARPA"); 18 expectValid("john.test"); 19 expectValid("jan.test"); 20 expectValid("a234567890123456789.test"); 21 expectValid("john2.test"); 22 expectValid("john-john.test"); 23 expectValid("john.bsky.app"); 24 expectValid("jo.hn"); 25 expectValid("a.co"); 26 expectValid("a.org"); 27 expectValid("joh.n"); 28 expectValid("j0.h0"); 29 const longHandle = "shoooort" + ".loooooooooooooooooooooooooong".repeat(8) + 30 ".test"; 31 assertEquals(longHandle.length, 253); 32 expectValid(longHandle); 33 expectValid("short." + "o".repeat(63) + ".test"); 34 expectValid("jaymome-johnber123456.test"); 35 expectValid("jay.mome-johnber123456.test"); 36 expectValid("john.test.bsky.app"); 37 38 // NOTE: this probably isn't ever going to be a real domain, but my read of 39 // the RFC is that it would be possible 40 expectValid("john.t"); 41}); 42 43// NOTE: we may change this at the proto level; currently only disallowed at 44// the registration level 45Deno.test("validation allows .local and .arpa handles (proto-level)", () => { 46 const expectValid = (h: string) => { 47 ensureValidHandle(h); 48 ensureValidHandleRegex(h); 49 }; 50 51 expectValid("laptop.local"); 52 expectValid("laptop.arpa"); 53}); 54 55Deno.test("validation allows punycode handles", () => { 56 const expectValid = (h: string) => { 57 ensureValidHandle(h); 58 ensureValidHandleRegex(h); 59 }; 60 61 expectValid("xn--ls8h.test"); // 💩.test 62 expectValid("xn--bcher-kva.tld"); // bücher.tld 63 expectValid("xn--3jk.com"); 64 expectValid("xn--w3d.com"); 65 expectValid("xn--vqb.com"); 66 expectValid("xn--ppd.com"); 67 expectValid("xn--cs9a.com"); 68 expectValid("xn--8r9a.com"); 69 expectValid("xn--cfd.com"); 70 expectValid("xn--5jk.com"); 71 expectValid("xn--2lb.com"); 72}); 73 74Deno.test("validation allows onion (Tor) handles", () => { 75 const expectValid = (h: string) => { 76 ensureValidHandle(h); 77 ensureValidHandleRegex(h); 78 }; 79 80 expectValid("expyuzz4wqqyqhjn.onion"); 81 expectValid("friend.expyuzz4wqqyqhjn.onion"); 82 expectValid( 83 "g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion", 84 ); 85 expectValid( 86 "friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion", 87 ); 88 expectValid( 89 "friend.g2zyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion", 90 ); 91 expectValid( 92 "2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion", 93 ); 94 expectValid( 95 "friend.2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion", 96 ); 97}); 98 99Deno.test("validation throws on invalid handles", () => { 100 const expectInvalid = (h: string) => { 101 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 102 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 103 }; 104 105 expectInvalid("did:thing.test"); 106 expectInvalid("did:thing"); 107 expectInvalid("john-.test"); 108 expectInvalid("john.0"); 109 expectInvalid("john.-"); 110 expectInvalid("short." + "o".repeat(64) + ".test"); 111 expectInvalid("short" + ".loooooooooooooooooooooooong".repeat(10) + ".test"); 112 const longHandle = "shooooort" + ".loooooooooooooooooooooooooong".repeat(8) + 113 ".test"; 114 assertEquals(longHandle.length, 254); 115 expectInvalid(longHandle); 116 expectInvalid("xn--bcher-.tld"); 117 expectInvalid("john..test"); 118 expectInvalid("jo_hn.test"); 119 expectInvalid("-john.test"); 120 expectInvalid(".john.test"); 121 expectInvalid("jo!hn.test"); 122 expectInvalid("jo%hn.test"); 123 expectInvalid("jo&hn.test"); 124 expectInvalid("jo@hn.test"); 125 expectInvalid("jo*hn.test"); 126 expectInvalid("jo|hn.test"); 127 expectInvalid("jo:hn.test"); 128 expectInvalid("jo/hn.test"); 129 expectInvalid("john💩.test"); 130 expectInvalid("bücher.test"); 131 expectInvalid("john .test"); 132 expectInvalid("john.test."); 133 expectInvalid("john"); 134 expectInvalid("john."); 135 expectInvalid(".john"); 136 expectInvalid("john.test."); 137 expectInvalid(".john.test"); 138 expectInvalid(" john.test"); 139 expectInvalid("john.test "); 140 expectInvalid("joh-.test"); 141 expectInvalid("john.-est"); 142 expectInvalid("john.tes-"); 143}); 144 145Deno.test("validation throws on 'dotless' TLD handles", () => { 146 const expectInvalid = (h: string) => { 147 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 148 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 149 }; 150 151 expectInvalid("org"); 152 expectInvalid("ai"); 153 expectInvalid("gg"); 154 expectInvalid("io"); 155}); 156 157Deno.test("validation correctly validates corner cases (modern vs. old RFCs)", () => { 158 const expectValid = (h: string) => { 159 ensureValidHandle(h); 160 ensureValidHandleRegex(h); 161 }; 162 const expectInvalid = (h: string) => { 163 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 164 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 165 }; 166 167 expectValid("12345.test"); 168 expectValid("8.cn"); 169 expectValid("4chan.org"); 170 expectValid("4chan.o-g"); 171 expectValid("blah.4chan.org"); 172 expectValid("thing.a01"); 173 expectValid("120.0.0.1.com"); 174 expectValid("0john.test"); 175 expectValid("9sta--ck.com"); 176 expectValid("99stack.com"); 177 expectValid("0ohn.test"); 178 expectValid("john.t--t"); 179 expectValid("thing.0aa.thing"); 180 181 expectInvalid("cn.8"); 182 expectInvalid("thing.0aa"); 183 expectInvalid("thing.0aa"); 184}); 185 186Deno.test("validation does not allow IP addresses as handles", () => { 187 const expectInvalid = (h: string) => { 188 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 189 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 190 }; 191 192 expectInvalid("127.0.0.1"); 193 expectInvalid("192.168.0.142"); 194 expectInvalid("fe80::7325:8a97:c100:94b"); 195 expectInvalid("2600:3c03::f03c:9100:feb0:af1f"); 196}); 197 198Deno.test("validation is consistent with examples from stackoverflow", () => { 199 const expectValid = (h: string) => { 200 ensureValidHandle(h); 201 ensureValidHandleRegex(h); 202 }; 203 const expectInvalid = (h: string) => { 204 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 205 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 206 }; 207 208 const okStackoverflow = [ 209 "stack.com", 210 "sta-ck.com", 211 "sta---ck.com", 212 "sta--ck9.com", 213 "stack99.com", 214 "sta99ck.com", 215 "google.com.uk", 216 "google.co.in", 217 "google.com", 218 "maselkowski.pl", 219 "m.maselkowski.pl", 220 "xn--masekowski-d0b.pl", 221 "xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s", 222 "xn--stackoverflow.com", 223 "stackoverflow.xn--com", 224 "stackoverflow.co.uk", 225 "xn--masekowski-d0b.pl", 226 "xn--fiqa61au8b7zsevnm8ak20mc4a87e.xn--fiqs8s", 227 ]; 228 okStackoverflow.forEach(expectValid); 229 230 const badStackoverflow = [ 231 "-notvalid.at-all", 232 "-thing.com", 233 "www.masełkowski.pl.com", 234 ]; 235 badStackoverflow.forEach(expectInvalid); 236}); 237 238Deno.test("validation conforms to interop valid handles", async () => { 239 const expectValid = (h: string) => { 240 ensureValidHandle(h); 241 ensureValidHandleRegex(h); 242 }; 243 244 const filePath = 245 new URL("./interop/handle_syntax_valid.txt", import.meta.url).pathname; 246 const fileContent = await Deno.readTextFile(filePath); 247 const lines = fileContent.split("\n"); 248 249 for (const line of lines) { 250 if (line.startsWith("#") || line.length === 0) { 251 continue; 252 } 253 expectValid(line); 254 } 255}); 256 257Deno.test("validation conforms to interop invalid handles", async () => { 258 const expectInvalid = (h: string) => { 259 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 260 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 261 }; 262 263 const filePath = 264 new URL("./interop/handle_syntax_invalid.txt", import.meta.url).pathname; 265 const fileContent = await Deno.readTextFile(filePath); 266 const lines = fileContent.split("\n"); 267 268 for (const line of lines) { 269 if (line.startsWith("#") || line.length === 0) { 270 continue; 271 } 272 expectInvalid(line); 273 } 274}); 275 276Deno.test("validation conforms to interop invalid handles", async () => { 277 const expectInvalid = (h: string) => { 278 assertThrows(() => ensureValidHandle(h), InvalidHandleError); 279 assertThrows(() => ensureValidHandleRegex(h), InvalidHandleError); 280 }; 281 282 const filePath = 283 new URL("./interop/handle_syntax_invalid.txt", import.meta.url).pathname; 284 const fileContent = await Deno.readTextFile(filePath); 285 const lines = fileContent.split("\n"); 286 287 for (const line of lines) { 288 if (line.startsWith("#") || line.length === 0) { 289 continue; 290 } 291 expectInvalid(line); 292 } 293}); 294 295Deno.test("normalization - normalizes handles", () => { 296 const normalized = normalizeAndEnsureValidHandle("JoHn.TeST"); 297 assertEquals(normalized, "john.test"); 298}); 299 300Deno.test("normalization throws on invalid normalized handles", () => { 301 assertThrows( 302 () => normalizeAndEnsureValidHandle("JoH!n.TeST"), 303 InvalidHandleError, 304 ); 305});