sweedworks

← all sources

checkpermalink.py

Round-trips shareable links through a stubbed DOM

272 lines. This is the file the build actually runs, copied verbatim at build time.

  1. 1"""Drive tokens/app.js under QuickJS with a stubbed DOM to test permalinks.
  2. 2 
  3. 3No browser is available here, so this exercises the round trip directly:
  4. 4type text -> click "Copy link" -> feed the resulting URL back in as a fragment
  5. 5-> the text must come back byte-identical. Covers the cases that quietly break
  6. 6URL handling: unicode, emoji, "&", "=", "+", "#", newlines, and malformed
  7. 7escapes that must not throw.
  8. 8"""
  9. 9 
  10. 10import json
  11. 11import os
  12. 12import sys
  13. 13 
  14. 14HERE = os.path.dirname(os.path.abspath(__file__))
  15. 15sys.path.insert(0, os.path.join(HERE, "pylib"))
  16. 16ROOT = os.path.abspath(os.path.join(HERE, ".."))
  17. 17 
  18. 18import quickjs # noqa: E402
  19. 19 
  20. 20from tokenlib import POLYFILL # noqa: E402
  21. 21 
  22. 22DOM_STUB = r"""
  23. 23var globalThis = this;
  24. 24var __handlers = {}; // "id:type" -> [fn]
  25. 25var __els = {};
  26. 26var __lastReplaceUrl = null;
  27. 27 
  28. 28function __mkEl(id) {
  29. 29 return {
  30. 30 id: id, value: "", textContent: "", className: "", hidden: false,
  31. 31 placeholder: "", title: "", src: "",
  32. 32 _attrs: {},
  33. 33 setAttribute: function (k, v) { this._attrs[k] = String(v); },
  34. 34 getAttribute: function (k) { return this._attrs[k] === undefined ? null : this._attrs[k]; },
  35. 35 addEventListener: function (type, fn) {
  36. 36 var key = this.id + ":" + type;
  37. 37 (__handlers[key] = __handlers[key] || []).push(fn);
  38. 38 },
  39. 39 appendChild: function () {},
  40. 40 focus: function () {}, select: function () {},
  41. 41 scrollIntoView: function () {}
  42. 42 };
  43. 43}
  44. 44 
  45. 45["pg-in","pg-tokens","pg-status","pg-tok","pg-chr","pg-rat","pg-ids","pg-ws",
  46. 46 "pg-link","pg-linkwrap","pg-linkurl"].forEach(function (id) {
  47. 47 __els[id] = __mkEl(id);
  48. 48});
  49. 49 
  50. 50// Encoding switch buttons, so setEncoding() and its click wiring are exercised.
  51. 51var __encBtns = ["o200k_base", "cl100k_base"].map(function (name) {
  52. 52 var b = __mkEl("enc-" + name);
  53. 53 b._attrs["data-enc"] = name;
  54. 54 return b;
  55. 55});
  56. 56 
  57. 57var document = {
  58. 58 getElementById: function (id) { return __els[id] || null; },
  59. 59 querySelectorAll: function (sel) { return sel === "[data-enc]" ? __encBtns : []; },
  60. 60 createElement: function () { return __mkEl("_new"); },
  61. 61 createTextNode: function () { return {}; },
  62. 62 createDocumentFragment: function () { return { appendChild: function () {} }; },
  63. 63 head: { appendChild: function () {} }
  64. 64};
  65. 65 
  66. 66var location = { origin: "https://sweedworks.com", pathname: "/tokens/", hash: "" };
  67. 67var history = { replaceState: function (a, b, url) { __lastReplaceUrl = url; } };
  68. 68var __clipboard = null;
  69. 69var navigator = {
  70. 70 clipboard: {
  71. 71 writeText: function (s) {
  72. 72 __clipboard = s;
  73. 73 return { then: function (ok) { ok(); return this; } };
  74. 74 }
  75. 75 }
  76. 76};
  77. 77 
  78. 78var window = {
  79. 79 addEventListener: function (type, fn) {
  80. 80 var key = "window:" + type;
  81. 81 (__handlers[key] = __handlers[key] || []).push(fn);
  82. 82 },
  83. 83 GPTTokenizer_o200k_base: null
  84. 84};
  85. 85// app.js checks `"IntersectionObserver" in window` — leave it absent so it
  86. 86// takes the eager-load path, which is what a permalink visit does anyway.
  87. 87 
  88. 88function requestAnimationFrame(fn) { fn(); return 1; }
  89. 89function cancelAnimationFrame() {}
  90. 90 
  91. 91function __fire(key) {
  92. 92 var fns = __handlers[key] || [];
  93. 93 for (var i = 0; i < fns.length; i++) fns[i]({});
  94. 94}
  95. 95"""
  96. 96 
  97. 97 
  98. 98def harness():
  99. 99 ctx = quickjs.Context()
  100. 100 ctx.set_memory_limit(1 << 29)
  101. 101 ctx.set_max_stack_size(1 << 22)
  102. 102 ctx.eval(POLYFILL)
  103. 103 ctx.eval(DOM_STUB)
  104. 104 src = open(os.path.join(ROOT, "tokens", "app.js"), encoding="utf-8").read()
  105. 105 ctx.eval(src)
  106. 106 return ctx
  107. 107 
  108. 108 
  109. 109CASES = [
  110. 110 "strawberry",
  111. 111 " strawberry",
  112. 112 "How many r's are in strawberry?",
  113. 113 "a & b = c", # & and = are the fragment's own delimiters
  114. 114 "one+two", # + must not silently become a space
  115. 115 "look: #hash", # a second # inside the text
  116. 116 "line one\nline two",
  117. 117 "こんにちは世界",
  118. 118 "🍓👩‍👩‍👧‍👦",
  119. 119 "café",
  120. 120 "100% of the time", # % begins an escape sequence
  121. 121 " leading and trailing ",
  122. 122]
  123. 123 
  124. 124 
  125. 125def main():
  126. 126 failures = []
  127. 127 
  128. 128 for text in CASES:
  129. 129 ctx = harness()
  130. 130 ctx.set("_t", text)
  131. 131 ctx.eval("__els['pg-in'].value = _t;")
  132. 132 ctx.eval("__fire('pg-link:click');")
  133. 133 
  134. 134 url = ctx.eval("String(__lastReplaceUrl)")
  135. 135 copied = ctx.eval("String(__clipboard)")
  136. 136 if url != copied:
  137. 137 failures.append((text, "address bar and clipboard disagree",
  138. 138 url, copied))
  139. 139 continue
  140. 140 
  141. 141 # Now simulate someone opening that link in a fresh page.
  142. 142 frag = url.split("#", 1)[1] if "#" in url else ""
  143. 143 ctx2 = harness()
  144. 144 ctx2.set("_h", "#" + frag)
  145. 145 ctx2.eval("location.hash = _h;")
  146. 146 # Re-run the script against the new location.
  147. 147 src = open(os.path.join(ROOT, "tokens", "app.js"), encoding="utf-8").read()
  148. 148 ctx2.eval(src)
  149. 149 got = ctx2.eval("String(__els['pg-in'].value)")
  150. 150 
  151. 151 if got != text:
  152. 152 failures.append((text, "round trip changed the text", repr(got), repr(text)))
  153. 153 elif "?" in url.split("#")[0]:
  154. 154 failures.append((text, "text leaked into the query string", url, ""))
  155. 155 
  156. 156 # The encoding switch is part of the shared state: a link made while
  157. 157 # comparing GPT-4 must reopen on GPT-4, and the default must stay out of
  158. 158 # the URL so ordinary links keep their readable form.
  159. 159 ctx = harness()
  160. 160 ctx.set("_t", "strawberry")
  161. 161 ctx.eval("__els['pg-in'].value = _t;")
  162. 162 ctx.eval("__fire('enc-cl100k_base:click');")
  163. 163 ctx.eval("__fire('pg-link:click');")
  164. 164 url = ctx.eval("String(__lastReplaceUrl)")
  165. 165 if "enc=cl100k_base" not in url:
  166. 166 failures.append(("enc switch", "encoding missing from link", url, ""))
  167. 167 else:
  168. 168 ctx2 = harness()
  169. 169 ctx2.set("_h", "#" + url.split("#", 1)[1])
  170. 170 ctx2.eval("location.hash = _h;")
  171. 171 ctx2.eval(open(os.path.join(ROOT, "tokens", "app.js"), encoding="utf-8").read())
  172. 172 pressed = ctx2.eval(
  173. 173 "String(__encBtns[1].getAttribute('aria-pressed'))")
  174. 174 if pressed != "true":
  175. 175 failures.append(("enc switch", "reopened on the wrong encoding",
  176. 176 pressed, "true"))
  177. 177 
  178. 178 ctx = harness()
  179. 179 ctx.eval("__els['pg-in'].value = 'strawberry'; __fire('pg-link:click');")
  180. 180 if "enc=" in ctx.eval("String(__lastReplaceUrl)"):
  181. 181 failures.append(("enc default", "default encoding should not appear in URL",
  182. 182 ctx.eval("String(__lastReplaceUrl)"), ""))
  183. 183 
  184. 184 # The shared module, exercised directly — all three interactive pages use it.
  185. 185 shared = quickjs.Context()
  186. 186 shared.eval("var globalThis = this;")
  187. 187 shared.eval("var location = {origin:'https://sweedworks.com', pathname:'/x/', hash:''};"
  188. 188 "var history = {replaceState:function(){}};"
  189. 189 "var navigator = {};")
  190. 190 shared.eval(open(os.path.join(ROOT, "permalink.js"), encoding="utf-8").read())
  191. 191 
  192. 192 SHARED_CASES = [
  193. 193 ({"corpus": "a & b", "n": "30"}, {"n": "30"}), # default dropped
  194. 194 ({"corpus": "🍓 = 100%", "n": "5"}, {"n": "30"}),
  195. 195 ({"corpus": "line\nbreak", "probe": " strawberry"}, {}),
  196. 196 ({"prompt": "it was the", "temp": "18", "topk": "0"},
  197. 197 {"prompt": "it was the", "topk": "0"}), # two defaults
  198. 198 ({"corpus": "plus+and=equals", "n": "1"}, {}),
  199. 199 ]
  200. 200 for params, defaults in SHARED_CASES:
  201. 201 shared.set("_p", json.dumps(params))
  202. 202 shared.set("_d", json.dumps(defaults))
  203. 203 url = shared.eval("Permalink.build(JSON.parse(_p), JSON.parse(_d))")
  204. 204 if "?" in url:
  205. 205 failures.append(("shared", "query string used", url, ""))
  206. 206 continue
  207. 207 frag = url.split("#", 1)[1] if "#" in url else ""
  208. 208 shared.set("_h", "#" + frag)
  209. 209 shared.eval("location.hash = _h;")
  210. 210 got = json.loads(shared.eval("JSON.stringify(Permalink.read())"))
  211. 211 want = {k: v for k, v in params.items()
  212. 212 if str(defaults.get(k)) != str(v)}
  213. 213 if got != want:
  214. 214 failures.append(("shared", "round trip differs", str(got), str(want)))
  215. 215 for k in defaults:
  216. 216 if str(defaults[k]) == str(params.get(k)) and k in got:
  217. 217 failures.append(("shared", f"default {k} leaked into URL", url, ""))
  218. 218 
  219. 219 # num() must clamp and fall back rather than propagate nonsense.
  220. 220 shared.eval("location.hash = '#a=5&b=abc&c=-9&d=999';")
  221. 221 checks = [("a", 1, 0, 10, 5), ("b", 7, 0, 10, 7), ("c", 1, 0, 10, 0),
  222. 222 ("d", 1, 0, 10, 10), ("missing", 3, 0, 10, 3)]
  223. 223 for key, fallback, lo, hi, want in checks:
  224. 224 shared.set("_k", key)
  225. 225 shared.set("_f", fallback)
  226. 226 shared.set("_lo", lo)
  227. 227 shared.set("_hi", hi)
  228. 228 got = float(shared.eval(
  229. 229 "Permalink.num(Permalink.read(), _k, _f, _lo, _hi)"))
  230. 230 if got != want:
  231. 231 failures.append(("shared", f"num({key}) = {got}, expected {want}", "", ""))
  232. 232 
  233. 233 # Malformed fragments must not throw or wipe the page.
  234. 234 for bad in ["#t=%E0%A4", "#t=%", "#t", "#ids=1", "#", "#t=%zz"]:
  235. 235 ctx = harness()
  236. 236 ctx.set("_h", bad)
  237. 237 try:
  238. 238 ctx.eval("location.hash = _h;")
  239. 239 src = open(os.path.join(ROOT, "tokens", "app.js"), encoding="utf-8").read()
  240. 240 ctx.eval(src)
  241. 241 except Exception as e:
  242. 242 failures.append((bad, "malformed fragment threw", str(e)[:120], ""))
  243. 243 
  244. 244 for text, why, a, b in failures:
  245. 245 print(f"FAIL {text!r}: {why}\n {a}\n {b}")
  246. 246 
  247. 247 if failures:
  248. 248 print(f"\n{len(failures)} permalink failure(s)")
  249. 249 return 1
  250. 250 
  251. 251 print(f"PASS permalink round trip — {len(CASES)} strings, encoding switch "
  252. 252 f"carried and restored, default kept out of the URL, "
  253. 253 f"6 malformed fragments handled")
  254. 254 print(f"PASS shared module — {len(SHARED_CASES)} param sets round trip, "
  255. 255 f"defaults omitted, num() clamps and falls back")
  256. 256 
  257. 257 # Show a couple of real links for the record.
  258. 258 ctx = harness()
  259. 259 for sample in ["strawberry", "こんにちは世界"]:
  260. 260 ctx.set("_t", sample)
  261. 261 ctx.eval("__els['pg-in'].value = _t; __fire('pg-link:click');")
  262. 262 print(f" {sample!r} -> {ctx.eval('String(__lastReplaceUrl)')}")
  263. 263 ctx = harness()
  264. 264 ctx.eval("__els['pg-in'].value = 'strawberry';"
  265. 265 "__fire('enc-cl100k_base:click'); __fire('pg-link:click');")
  266. 266 print(f" on cl100k -> {ctx.eval('String(__lastReplaceUrl)')}")
  267. 267 return 0
  268. 268 
  269. 269 
  270. 270if __name__ == "__main__":
  271. 271 sys.exit(main())