quickwin 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +2 -0
  3. package/package.json +2 -3
  4. package/qwin-nowasm-x86.exe +0 -0
  5. package/qwin-nowasm.exe +0 -0
  6. package/qwin-x86.exe +0 -0
  7. package/qwin.exe +0 -0
  8. package/examples/PdfCanvas.js +0 -38
  9. package/examples/PdfCanvas.tsx +0 -54
  10. package/examples/execd/main.js +0 -23379
  11. package/examples/execd/tray.js +0 -192
  12. package/examples/execd/worker.js +0 -122
  13. package/examples/pdf_preview2.js +0 -398
  14. package/examples/pdf_preview2.ts +0 -353
  15. package/examples/pdf_viewer.js +0 -22515
  16. package/examples/pdf_viewer.tsx +0 -228
  17. package/examples/test_gallery.js +0 -18692
  18. package/examples/test_gallery.tsx +0 -291
  19. package/examples/test_react_lazy.js +0 -18560
  20. package/examples/test_react_lazy.tsx +0 -65
  21. package/examples/test_react_listbox.js +0 -18562
  22. package/examples/test_react_listbox.tsx +0 -73
  23. package/examples/test_root_window.js +0 -18532
  24. package/examples/test_root_window.tsx +0 -41
  25. package/examples/test_tab.js +0 -18563
  26. package/examples/test_tab.tsx +0 -77
  27. package/examples/tray_demo.js +0 -86
  28. package/examples/tray_demo.tsx +0 -89
  29. package/test/add.wasm +0 -0
  30. package/test/bench_ffi_callraw.js +0 -235
  31. package/test/bench_ffi_callraw.ts +0 -235
  32. package/test/bench_ffi_overhead.js +0 -139
  33. package/test/bench_ffi_overhead.ts +0 -141
  34. package/test/bench_sendmessage.js +0 -104
  35. package/test/bench_sendmessage.ts +0 -100
  36. package/test/bench_sendmessage_nonnull.js +0 -187
  37. package/test/bench_sendmessage_nonnull.ts +0 -188
  38. package/test/complex.wasm +0 -0
  39. package/test/complex_imports.wasm +0 -0
  40. package/test/debug/http_server_e2e.js +0 -31
  41. package/test/debug/minwasm.js +0 -52
  42. package/test/debug/mupdf_debug.js +0 -86
  43. package/test/debug/wasm.js +0 -122
  44. package/test/debug/wasm_export_debug.js +0 -54
  45. package/test/debug/wasm_names.js +0 -36
  46. package/test/example.pdf +0 -0
  47. package/test/global_imports.wasm +0 -0
  48. package/test/import_func.wasm +0 -0
  49. package/test/imports.wasm +0 -0
  50. package/test/mupdf-cdn.js +0 -40
  51. package/test/mupdf-cdn.ts +0 -43
  52. package/test/run.js +0 -111
  53. package/test/run.ts +0 -116
  54. package/test/sjlj.wasm +0 -0
  55. package/test/test_basic.js +0 -7
  56. package/test/test_basic.ts +0 -9
  57. package/test/test_basic_fetch.js +0 -63
  58. package/test/test_basic_fetch.ts +0 -59
  59. package/test/test_brotli.js +0 -48
  60. package/test/test_brotli.ts +0 -52
  61. package/test/test_fetch_cache.js +0 -169
  62. package/test/test_fetch_cache.ts +0 -187
  63. package/test/test_ffi.js +0 -157
  64. package/test/test_ffi.ts +0 -170
  65. package/test/test_ffi_abi.js +0 -290
  66. package/test/test_ffi_abi.ts +0 -274
  67. package/test/test_ffi_array.js +0 -116
  68. package/test/test_ffi_array.ts +0 -141
  69. package/test/test_ffi_bind.js +0 -656
  70. package/test/test_ffi_bind.ts +0 -670
  71. package/test/test_ffi_struct.js +0 -779
  72. package/test/test_ffi_struct.ts +0 -828
  73. package/test/test_ffi_struct_layout.js +0 -495
  74. package/test/test_ffi_struct_layout.ts +0 -543
  75. package/test/test_ffi_user32.js +0 -103
  76. package/test/test_ffi_user32.ts +0 -113
  77. package/test/test_ffi_windows.js +0 -172
  78. package/test/test_ffi_windows.ts +0 -187
  79. package/test/test_files.js +0 -102
  80. package/test/test_files.ts +0 -121
  81. package/test/test_frame_encoding.js +0 -128
  82. package/test/test_frame_encoding.ts +0 -132
  83. package/test/test_gdi_draw.js +0 -681
  84. package/test/test_gdi_draw.ts +0 -725
  85. package/test/test_helper.js +0 -91
  86. package/test/test_helper.ts +0 -88
  87. package/test/test_http_import.js +0 -96
  88. package/test/test_http_import.ts +0 -93
  89. package/test/test_http_server.js +0 -214
  90. package/test/test_http_server.ts +0 -211
  91. package/test/test_import_dir.js +0 -4
  92. package/test/test_import_dir.ts +0 -5
  93. package/test/test_ipv6.js +0 -134
  94. package/test/test_ipv6.ts +0 -130
  95. package/test/test_jsx.js +0 -1314
  96. package/test/test_meta_url.js +0 -3
  97. package/test/test_meta_url.ts +0 -4
  98. package/test/test_mupdf_render.js +0 -51
  99. package/test/test_mupdf_render.ts +0 -55
  100. package/test/test_mupdf_twice.js +0 -62
  101. package/test/test_mupdf_twice.ts +0 -65
  102. package/test/test_mupdf_wasm.js +0 -39
  103. package/test/test_mupdf_wasm.ts +0 -32
  104. package/test/test_net_event.js +0 -57
  105. package/test/test_net_event.ts +0 -56
  106. package/test/test_net_fetch.js +0 -384
  107. package/test/test_net_fetch.ts +0 -373
  108. package/test/test_net_websocket.js +0 -180
  109. package/test/test_net_websocket.ts +0 -164
  110. package/test/test_polyfill.js +0 -144
  111. package/test/test_polyfill.ts +0 -159
  112. package/test/test_printer.js +0 -137
  113. package/test/test_printer.ts +0 -148
  114. package/test/test_proc.js +0 -141
  115. package/test/test_proc.ts +0 -163
  116. package/test/test_react_complex.js +0 -18678
  117. package/test/test_react_counter.js +0 -18555
  118. package/test/test_react_flex.js +0 -18871
  119. package/test/test_react_hidden.js +0 -18560
  120. package/test/test_react_listview_link.js +0 -18590
  121. package/test/test_react_notify.js +0 -18797
  122. package/test/test_react_render.js +0 -18550
  123. package/test/test_registry.js +0 -74
  124. package/test/test_registry.ts +0 -95
  125. package/test/test_sysinfo.js +0 -122
  126. package/test/test_sysinfo.ts +0 -141
  127. package/test/test_url.js +0 -173
  128. package/test/test_url.ts +0 -183
  129. package/test/test_wasm_basic.js +0 -85
  130. package/test/test_wasm_basic.ts +0 -73
  131. package/test/test_wasm_import_global.js +0 -41
  132. package/test/test_wasm_import_global.ts +0 -45
  133. package/test/test_wasm_sjlj.js +0 -145
  134. package/test/test_wasm_sjlj.ts +0 -125
  135. package/test/test_wasm_types.js +0 -97
  136. package/test/test_wasm_types.ts +0 -124
  137. package/test/test_wolfssl_read.js +0 -203
  138. package/test/test_wolfssl_read.ts +0 -184
  139. package/test/test_worker.js +0 -21
  140. package/test/test_worker.ts +0 -24
  141. package/test/test_worker_concurrent.js +0 -45
  142. package/test/test_worker_concurrent.ts +0 -56
  143. package/test/test_worker_data_url.js +0 -46
  144. package/test/test_worker_data_url.ts +0 -51
  145. package/test/test_worker_fetch.js +0 -26
  146. package/test/test_worker_fetch.ts +0 -27
  147. package/test/test_worker_net.js +0 -69
  148. package/test/test_worker_net.ts +0 -66
  149. package/test/test_worker_wasm_concurrent.js +0 -44
  150. package/test/test_worker_wasm_concurrent.ts +0 -45
  151. package/test/types.wasm +0 -0
  152. package/test/worker_fetch.js +0 -13
  153. package/test/worker_fetch.ts +0 -13
  154. package/test/worker_helper.js +0 -1
  155. package/test/worker_helper.ts +0 -1
  156. package/test/worker_http.js +0 -18
  157. package/test/worker_http.ts +0 -20
  158. package/test/worker_import_lib.js +0 -12
  159. package/test/worker_import_lib.ts +0 -13
  160. package/test/worker_module.js +0 -16
  161. package/test/worker_module.ts +0 -17
  162. package/test/worker_wasm_concurrent.js +0 -22
  163. package/test/worker_wasm_concurrent.ts +0 -22
@@ -1,373 +0,0 @@
1
- import '../lib/fetch.js'
2
- import * as std from 'std'
3
- import * as os from 'os'
4
- import { Tester } from './test_helper.js'
5
-
6
- export const suite = {
7
- name: 'net-fetch',
8
- run: async (t: Tester) => {
9
- function assert(name: string, ok: boolean): void {
10
- if (ok) { t.ok++; std.printf(' PASS: %s\n', name) }
11
- else { t.fail++; std.printf(' FAIL: %s\n', name) }
12
- }
13
-
14
- // Retry: public-site reachability (baidu/jsdelivr/esm.sh) depends on
15
- // CI network conditions, and a single dropped connection must not be
16
- // reported as a certificate regression. The last error is printed so a
17
- // real failure is still diagnosable.
18
- async function safeFetch(url: any, init?: RequestInit) {
19
- let last = 'unknown'
20
- for (let attempt = 0; attempt < 3; attempt++) {
21
- try {
22
- return await fetch(url, init)
23
- } catch (e) {
24
- last = String((e as Error)?.message || e)
25
- if (attempt < 2) os.sleep(500)
26
- }
27
- }
28
- std.printf(' fetch %s failed after 3 attempts: %s\n', String(url), last)
29
- return null
30
- }
31
- const BASE = 'http://localhost:18923'
32
-
33
- // ── Plain HTTP GET (regression: slot 0 + !s bug) ──
34
- t.section('plain HTTP')
35
- const r0 = await safeFetch(BASE + '/', { timeout: 5000 })
36
- if (r0) {
37
- assert('plain HTTP status 200', r0.status === 200)
38
- const body = await r0.text()
39
- assert('plain HTTP body non-empty', body.length > 0)
40
- assert('plain HTTP body matches', body === 'hello from test server')
41
- } else {
42
- assert('plain HTTP endpoint reachable', false)
43
- }
44
-
45
- // ── Basic HTTP GET ──
46
- t.section('HTTP GET')
47
- const r1 = await safeFetch(BASE + '/any')
48
- if (r1) {
49
- assert('status received', r1.status > 0)
50
- const body = await r1.text()
51
- assert('body received', body.length > 0)
52
- } else {
53
- assert('local server reachable', false)
54
- }
55
-
56
- // ── Query string ──
57
- t.section('query string')
58
- const rq = await safeFetch(BASE + '/any?foo=bar&baz=42')
59
- if (rq) {
60
- const body = JSON.parse(await rq.text())
61
- assert('query args received', body.args !== undefined)
62
- assert('?foo=bar preserved', body.args.foo === 'bar')
63
- assert('?baz=42 preserved', body.args.baz === '42')
64
- } else {
65
- assert('query string endpoint reachable', false)
66
- }
67
-
68
- // ── Request constructor ──
69
- t.section('Request constructor')
70
- {
71
- const r = new Request('https://httpbun.com/any?x=1&y=2', { method: 'POST', headers: { 'X-Test': 'val' }, body: 'hello' })
72
- assert('Request.url', r.url === 'https://httpbun.com/any?x=1&y=2')
73
- assert('Request.method', r.method === 'POST')
74
- assert('Request.headers get', r.headers.get('x-test') === 'val')
75
- assert('Request.body is ReadableStream', r.body !== null && typeof r.body.getReader === 'function')
76
- }
77
- {
78
- const r1 = new Request('https://example.com/path')
79
- assert('Request default method GET', r1.method === 'GET')
80
- assert('Request default redirect follow', r1.redirect === 'follow')
81
- }
82
- {
83
- const r2 = new Request('https://httpbun.com/any')
84
- const r3 = new Request(r2, { method: 'PUT' })
85
- assert('Request clone same url', r3.url === r2.url)
86
- assert('Request clone override method', r3.method === 'PUT')
87
- }
88
- {
89
- const r = await safeFetch(new Request(BASE + '/any', { method: 'POST', headers: { 'Content-Type': 'text/plain' }, body: 'req-class' }))
90
- if (r) {
91
- const body = JSON.parse(await r.text())
92
- assert('fetch(Request) status', r.status > 0)
93
- assert('fetch(Request) method POST', body.method === 'POST')
94
- assert('fetch(Request) body received', body.data === 'req-class')
95
- assert('fetch(Request) content-type', body.headers['content-type'] === 'text/plain')
96
- } else {
97
- assert('fetch(Request) endpoint reachable', false)
98
- }
99
- }
100
-
101
- // ── body / bodyUsed / stream ──
102
- t.section('body / bodyUsed / stream')
103
- const r2 = await safeFetch(BASE + '/any')
104
- if (r2) {
105
- assert('r.body exists', typeof r2.body === 'object' && r2.body !== null)
106
- assert('bodyUsed false before read', r2.bodyUsed === false)
107
-
108
- const reader = r2.body!.getReader()
109
- let total = 0
110
- while (true) {
111
- const { done, value } = await reader.read()
112
- if (done) break
113
- total += value.length
114
- }
115
- assert('reader streams all bytes', total > 0)
116
- assert('bodyUsed true after stream', r2.bodyUsed === true)
117
- } else {
118
- assert('body test endpoint reachable', false)
119
- }
120
-
121
- // ── text/json/arrayBuffer ──
122
- t.section('text / json / arrayBuffer')
123
- const r3 = await safeFetch(BASE + '/any')
124
- if (r3) {
125
- const text = await r3.text()
126
- assert('text() returns string', typeof text === 'string' && text.length > 0)
127
- assert('bodyUsed true after text()', r3.bodyUsed === true)
128
-
129
- const r4 = await safeFetch(BASE + '/any')
130
- if (r4) {
131
- const buf = await r4.arrayBuffer()
132
- assert('arrayBuffer() returns bytes', buf.byteLength > 0)
133
- }
134
- } else {
135
- assert('text/json/ab endpoint reachable', false)
136
- }
137
-
138
- // double text() throws
139
- t.section('bodyUsed throws')
140
- const r5 = await safeFetch(BASE + '/any')
141
- if (r5) {
142
- await r5.text()
143
- try { await r5.text(); assert('double text() throws', false) }
144
- catch (e: unknown) { assert('double text() throws TypeError', (e as Error).message === 'Body already used') }
145
- }
146
-
147
- // ── POST ──
148
- t.section('POST')
149
- const r6 = await safeFetch(BASE + '/any', {
150
- method: 'POST',
151
- headers: { 'Content-Type': 'application/json' },
152
- body: JSON.stringify({ msg: 'hello' })
153
- })
154
- if (r6) {
155
- const body = await r6.text()
156
- assert('POST body received', body.length > 0)
157
- } else {
158
- assert('POST endpoint reachable', false)
159
- }
160
-
161
- // ── Headers (local, no network) ──
162
- t.section('Headers (local)')
163
- const h = new Headers({ 'Content-Type': 'text/html', 'X-Custom': 'hello', 'Accept': '*/*' })
164
- let c = 0
165
- for (const [k, v] of h) { c++; if (typeof k !== 'string' || typeof v !== 'string') assert('for...of type', false) }
166
- assert('for...of yields entries', c === 3)
167
- assert('get()', h.get('content-type') === 'text/html')
168
- assert('get() case-insensitive', h.get('Content-Type') === 'text/html')
169
- assert('has()', h.has('x-custom'))
170
- assert('set() overwrites', (h.set('accept', 'application/json'), h.get('accept') === 'application/json'))
171
- assert('append() adds', (h.append('accept', 'text/plain'), h.get('accept') === 'application/json, text/plain'))
172
- assert('delete()', (h.delete('accept'), h.has('accept') === false))
173
-
174
- const h2 = new Headers({ 'a': '1', 'b': '2' })
175
- let ec = 0; for (const _ of h2.entries()) { ec++ }
176
- assert('entries()', ec === 2)
177
- let kc = 0; for (const _ of h2.keys()) { kc++ }
178
- assert('keys()', kc === 2)
179
- let vc = 0; for (const _ of h2.values()) { vc++ }
180
- assert('values()', vc === 2)
181
-
182
- // ── Chunked Transfer-Encoding ──
183
- t.section('chunked transfer encoding')
184
- const r8 = await safeFetch(BASE + '/anything')
185
- if (r8) {
186
- assert('chunked status 200', r8.status === 200)
187
- const body = await r8.json<{ url: string }>()
188
- assert('chunked json has url', typeof body.url === 'string' && body.url.length > 0)
189
- } else {
190
- assert('local server reachable', false)
191
- }
192
-
193
- // ── stream cancel ──
194
- t.section('stream cancel')
195
- const r7 = await safeFetch(BASE + '/any')
196
- if (r7) {
197
- r7.body!.cancel()
198
- assert('cancel() succeeds', true)
199
- // After cancel: buffered chunks still readable, then done
200
- const reader = r7.body!.getReader()
201
- let finalDone = false
202
- while (true) {
203
- const { done } = await reader.read()
204
- if (done) { finalDone = true; break }
205
- }
206
- assert('reader done after cancel', finalDone === true)
207
- } else {
208
- assert('cancel test endpoint reachable', false)
209
- }
210
-
211
- // ── UTF-8 Chinese text body ──
212
- t.section('utf-8 chinese text')
213
- const r9 = await safeFetch(BASE + '/base64/5Lit5paH')
214
- if (r9) {
215
- assert('chinese status 200', r9.status === 200)
216
- const body = await r9.text()
217
- assert('chinese body is 中文', body === '\u4e2d\u6587')
218
- assert('chinese body length=2', body.length === 2)
219
- } else {
220
- assert('local server reachable', false)
221
- }
222
-
223
- // ── POST with Chinese body ──
224
- t.section('post with chinese body')
225
- const r10 = await safeFetch(BASE + '/post', {
226
- method: 'POST',
227
- body: '\u4e2d\u6587',
228
- headers: { 'Content-Type': 'text/plain; charset=utf-8' }
229
- })
230
- if (r10) {
231
- assert('post status 200', r10.status === 200)
232
- const body = await r10.text()
233
- assert('post body contains 中文', body.includes('\u4e2d\u6587'))
234
- } else {
235
- assert('local server reachable', false)
236
- }
237
-
238
- // ── HTTPS fetch ──
239
- t.section('HTTPS fetch')
240
- const r11 = await safeFetch('https://localhost:18924/', { timeout: 5000, rejectUnauthorized: false })
241
- if (r11) {
242
- assert('https status 200', r11.status === 200)
243
- const body = await r11.text()
244
- assert('https body matches', body === 'hello from test server')
245
- } else {
246
- assert('https endpoint reachable', false)
247
- }
248
-
249
- // ── GlobalSign R3 root chain (regression: ASN_SIG_CONFIRM_E -155) ──
250
- // baidu.com and jsdelivr terminate in GlobalSign's 2018 re-keyed R3,
251
- // which reuses the self-signed R3's subject-key-identifier with a
252
- // different public key. Shipping the self-signed R3 in lib/certs.ts
253
- // made wolfSSL match the wrong key and fail the handshake with -155.
254
- // Both are public CDNs: a 500/429 or a dropped connection then counts
255
- // as a retried attempt, not an immediate failure — only a persistent
256
- // failure (cert regression or long-lived outage) should fail CI.
257
- t.section('GlobalSign R3 root chain')
258
- {
259
- async function fetchR3(url: any): Promise<string | null> {
260
- const init = { timeout: 10000 }
261
- for (let attempt = 0; attempt < 3; attempt++) {
262
- try {
263
- const r = await fetch(url, init)
264
- const body = await r.text()
265
- if (r.status === 200 && body.length > 0) return body
266
- std.printf(' fetch %s status=%s len=%d (attempt %d)\n',
267
- String(url), String(r.status), body.length, attempt)
268
- } catch (e) {
269
- std.printf(' fetch %s error: %s (attempt %d)\n',
270
- String(url), String((e as Error)?.message || e), attempt)
271
- }
272
- os.sleep(1000)
273
- }
274
- return null
275
- }
276
-
277
- const bb = await fetchR3('https://www.baidu.com/')
278
- if (bb) {
279
- assert('baidu (GlobalSign R3) status', true)
280
- assert('baidu (GlobalSign R3) body non-empty', bb.length > 0)
281
- } else {
282
- assert('baidu (GlobalSign R3) reachable', false)
283
- }
284
-
285
- const JSDELIVR_HOSTS = ['cdn.jsdelivr.net', 'fastly.jsdelivr.net', 'gcore.jsdelivr.net']
286
- for (const host of JSDELIVR_HOSTS) {
287
- const bj = await fetchR3('https://' + host + '/npm/left-pad@1.3.0')
288
- if (bj) {
289
- assert('jsdelivr (GlobalSign R3) status', true)
290
- assert('jsdelivr (GlobalSign R3) body non-empty', bj.length > 0)
291
- break
292
- }
293
- if (host !== JSDELIVR_HOSTS[JSDELIVR_HOSTS.length - 1]) {
294
- std.printf(' jsdelivr host %s failed, trying next\n', host)
295
- } else {
296
- assert('jsdelivr (GlobalSign R3) reachable', false)
297
- }
298
- }
299
- }
300
-
301
- // ── large HTTPS body (wolfSSL_read int contract) ──
302
- // read returns the raw int; -1/WANT_READ must never leak into
303
- // byte accounting (regression: a leaked -1 made receivedBytes
304
- // NaN → stream never closed → hang).
305
- t.section('large HTTPS body')
306
- {
307
- const LARGE = 200000
308
- try {
309
- const r = await Promise.race([
310
- fetch(`https://localhost:18924/large/${LARGE}`, { timeout: 15000, rejectUnauthorized: false }),
311
- new Promise<never>((_, rej) =>
312
- os.setTimeout(() => rej(new Error('Body hang watchdog 15s')), 15000)
313
- )
314
- ])
315
- assert('large HTTPS status 200', r.status === 200)
316
- const buf = await Promise.race([
317
- r.arrayBuffer(),
318
- new Promise<never>((_, rej) =>
319
- os.setTimeout(() => rej(new Error('arrayBuffer hang watchdog 15s')), 15000)
320
- )
321
- ])
322
- assert('large HTTPS byteLength exact', buf.byteLength === LARGE)
323
- } catch (e: unknown) {
324
- assert('large HTTPS completed without hang (' + String((e as Error).message) + ')', false)
325
- }
326
- }
327
-
328
- // ── large HTTP body (sock.recv path same null contract) ──
329
- t.section('large HTTP body')
330
- {
331
- const LARGE = 200000
332
- try {
333
- const r = await Promise.race([
334
- fetch(`http://localhost:18923/large/${LARGE}`, { timeout: 15000 }),
335
- new Promise<never>((_, rej) =>
336
- os.setTimeout(() => rej(new Error('Body hang watchdog 15s')), 15000)
337
- )
338
- ])
339
- assert('large HTTP status 200', r.status === 200)
340
- const buf = await Promise.race([
341
- r.arrayBuffer(),
342
- new Promise<never>((_, rej) =>
343
- os.setTimeout(() => rej(new Error('arrayBuffer hang watchdog 15s')), 15000)
344
- )
345
- ])
346
- assert('large HTTP byteLength exact', buf.byteLength === LARGE)
347
- } catch (e: unknown) {
348
- assert('large HTTP completed (' + String((e as Error).message) + ')', false)
349
- }
350
- }
351
-
352
- // ── body timeout after headers (armTimeout after doResolve) ──
353
- t.section('HTTPS body timeout')
354
- {
355
- let rejected = false
356
- let msg = ''
357
- try {
358
- const r = await fetch('https://localhost:18924/stall', { timeout: 2000, rejectUnauthorized: false })
359
- await Promise.race([
360
- r.arrayBuffer(),
361
- new Promise<never>((_, rej) =>
362
- os.setTimeout(() => rej(new Error('Body timeout')), 8000)
363
- )
364
- ])
365
- } catch (e: unknown) {
366
- rejected = true
367
- msg = String((e as Error).message)
368
- }
369
- assert('stall body rejects (timeout)', rejected)
370
- assert('stall error mentions timeout', /timeout/i.test(msg))
371
- }
372
- }
373
- }
@@ -1,180 +0,0 @@
1
- import '../lib/websocket.js';
2
- import * as std from 'std';
3
- import * as os from 'os';
4
- export const suite = {
5
- name: 'net-websocket',
6
- run: async (t) => {
7
- function assert(name, ok) {
8
- if (ok) {
9
- t.ok++;
10
- std.printf(' PASS: %s\n', name);
11
- }
12
- else {
13
- t.fail++;
14
- std.printf(' FAIL: %s\n', name);
15
- }
16
- }
17
- let testId = 0;
18
- const resolvers = {};
19
- function waitForTest() {
20
- const id = ++testId;
21
- const promise = new Promise((resolve) => { resolvers[id] = resolve; });
22
- return { promise, id };
23
- }
24
- function finishTest(id) {
25
- const r = resolvers[id];
26
- if (r) {
27
- delete resolvers[id];
28
- r();
29
- }
30
- }
31
- // ── wss basic ──
32
- t.section('wss basic text message');
33
- const p1 = waitForTest();
34
- let opened = false, received = false, closed = false;
35
- const ws1 = new WebSocket("ws://localhost:18923");
36
- ws1.onopen = () => { opened = true; ws1.send("Hello WebSocket!"); };
37
- ws1.onmessage = () => { received = true; ws1.close(1000, "done"); };
38
- ws1.onclose = (e) => {
39
- closed = true;
40
- assert('onopen fired', opened);
41
- assert('onmessage received', received);
42
- assert('close code=1000', e.code === 1000);
43
- assert('wasClean', e.wasClean);
44
- finishTest(p1.id);
45
- };
46
- ws1.onerror = () => { assert('no error', false); finishTest(p1.id); };
47
- const timer1 = os.setTimeout(() => { if (!closed) {
48
- assert('no timeout', false);
49
- finishTest(p1.id);
50
- } }, 10000);
51
- await p1.promise;
52
- os.clearTimeout(timer1);
53
- // ── binary send ──
54
- t.section('binary message (ArrayBuffer)');
55
- const pBin = waitForTest();
56
- const wsBin = new WebSocket("ws://localhost:18923");
57
- let binClose = false;
58
- wsBin.onopen = () => {
59
- const buf = new ArrayBuffer(5);
60
- const v = new Uint8Array(buf);
61
- v[0] = 0x48;
62
- v[1] = 0x65;
63
- v[2] = 0x6C;
64
- v[3] = 0x6C;
65
- v[4] = 0x6F;
66
- wsBin.send(buf);
67
- wsBin.send("binary-send-check");
68
- };
69
- let binMsgCount = 0;
70
- wsBin.onmessage = () => { binMsgCount++; if (binMsgCount >= 2)
71
- wsBin.close(1000, "done"); };
72
- wsBin.onclose = () => { binClose = true; assert('binary send completed', true); finishTest(pBin.id); };
73
- wsBin.onerror = () => { assert('no error', false); finishTest(pBin.id); };
74
- const timerBin = os.setTimeout(() => { if (!binClose)
75
- assert('binary no crash (timeout)', true); finishTest(pBin.id); }, 10000);
76
- await pBin.promise;
77
- os.clearTimeout(timerBin);
78
- // ── extended length frame ──
79
- t.section('extended length frame (>65535 bytes)');
80
- const pExt = waitForTest();
81
- const wsExt = new WebSocket("ws://localhost:18923");
82
- let extClose = false;
83
- wsExt.onopen = () => { wsExt.send("X".repeat(66000)); };
84
- wsExt.onmessage = () => { wsExt.close(1000, "done"); };
85
- wsExt.onclose = () => { extClose = true; assert('extended frame sent', true); finishTest(pExt.id); };
86
- wsExt.onerror = () => { assert('no error', false); finishTest(pExt.id); };
87
- const timerExt = os.setTimeout(() => { if (!extClose)
88
- assert('extended frame timeout', true); finishTest(pExt.id); }, 10000);
89
- await pExt.promise;
90
- os.clearTimeout(timerExt);
91
- // ── large message ──
92
- t.section('large message (>125 bytes)');
93
- const p2 = waitForTest();
94
- const ws2 = new WebSocket("ws://localhost:18923");
95
- let largeOk = false, closed2 = false;
96
- const largeStr = "A".repeat(1000);
97
- ws2.onopen = () => { ws2.send(largeStr); };
98
- ws2.onmessage = (e) => { largeOk = e.data.length === 1000; ws2.close(1000, "done"); };
99
- ws2.onclose = () => { closed2 = true; assert('large msg echo 1000 bytes', largeOk); finishTest(p2.id); };
100
- ws2.onerror = () => { assert('no error', false); finishTest(p2.id); };
101
- const timer2 = os.setTimeout(() => { if (!closed2) {
102
- assert('large msg no timeout', false);
103
- finishTest(p2.id);
104
- } }, 15000);
105
- await p2.promise;
106
- os.clearTimeout(timer2);
107
- // ── multiple messages ──
108
- t.section('multiple messages');
109
- const p3 = waitForTest();
110
- const ws3 = new WebSocket("ws://localhost:18923");
111
- let count = 0, closed3 = false;
112
- ws3.onopen = () => { ws3.send("a"); ws3.send("b"); ws3.send("c"); };
113
- ws3.onmessage = () => { count++; if (count === 3)
114
- ws3.close(1000, "done"); };
115
- ws3.onclose = () => { closed3 = true; assert('received 3 messages', count === 3); finishTest(p3.id); };
116
- ws3.onerror = () => { assert('no error', false); finishTest(p3.id); };
117
- const timer3 = os.setTimeout(() => { if (!closed3) {
118
- assert('no timeout', false);
119
- finishTest(p3.id);
120
- } }, 15000);
121
- await p3.promise;
122
- os.clearTimeout(timer3);
123
- // ── invalid URL ──
124
- t.section('invalid URL');
125
- const p4 = waitForTest();
126
- const ws4 = new WebSocket("not-a-websocket");
127
- let err4 = false;
128
- ws4.onerror = () => { err4 = true; };
129
- ws4.onclose = () => { assert('onerror fired', err4); finishTest(p4.id); };
130
- const timer4 = os.setTimeout(() => { assert('invalid url error', err4); finishTest(p4.id); }, 3000);
131
- await p4.promise;
132
- os.clearTimeout(timer4);
133
- // ── invalid scheme ──
134
- t.section('invalid scheme (http://)');
135
- const p5 = waitForTest();
136
- const ws5 = new WebSocket("http://example.com/ws");
137
- let err5 = false;
138
- ws5.onerror = () => { err5 = true; };
139
- ws5.onclose = () => { assert('http scheme onerror', err5); finishTest(p5.id); };
140
- const timer5 = os.setTimeout(() => { assert('http scheme error guard', err5); finishTest(p5.id); }, 3000);
141
- await p5.promise;
142
- os.clearTimeout(timer5);
143
- // ── early send/close ──
144
- t.section('send/close before onopen');
145
- const p6 = waitForTest();
146
- const ws6 = new WebSocket("ws://localhost:18923");
147
- ws6.send("noop");
148
- ws6.close(1000, "early");
149
- let close6 = false;
150
- ws6.onopen = () => { assert('onopen after early close', false); };
151
- ws6.onclose = () => { close6 = true; assert('early close ok', true); finishTest(p6.id); };
152
- ws6.onerror = () => { };
153
- const timer6 = os.setTimeout(() => { if (!close6)
154
- assert('no crash', true); finishTest(p6.id); }, 5000);
155
- await p6.promise;
156
- os.clearTimeout(timer6);
157
- // ── WSS (Secure WebSocket) ──
158
- t.section('wss basic text message');
159
- const p7 = waitForTest();
160
- let opened7 = false, received7 = false, closed7 = false;
161
- const ws7 = new WebSocket("wss://localhost:18924", { rejectUnauthorized: false });
162
- ws7.onopen = () => { opened7 = true; ws7.send("Hello WSS!"); };
163
- ws7.onmessage = () => { received7 = true; ws7.close(1000, "done"); };
164
- ws7.onclose = (e) => {
165
- closed7 = true;
166
- assert('wss onopen fired', opened7);
167
- assert('wss onmessage received', received7);
168
- assert('wss close code=1000', e.code === 1000);
169
- assert('wss wasClean', e.wasClean);
170
- finishTest(p7.id);
171
- };
172
- ws7.onerror = () => { assert('wss no error', false); finishTest(p7.id); };
173
- const timer7 = os.setTimeout(() => { if (!closed7) {
174
- assert('wss no timeout', false);
175
- finishTest(p7.id);
176
- } }, 10000);
177
- await p7.promise;
178
- os.clearTimeout(timer7);
179
- }
180
- };