-
Notifications
You must be signed in to change notification settings - Fork 107
/
Copy pathmodule-test.ts
87 lines (77 loc) · 2.61 KB
/
module-test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import type { QuickJSContext } from "./context"
import type { ModuleEvalOptions, QuickJSWASMModule } from "./module"
import type { QuickJSRuntime } from "./runtime"
import type { ContextOptions, RuntimeOptions } from "./types"
import { QuickJSMemoryLeakDetected } from "./errors"
import { Lifetime } from "./lifetime"
/**
* A test wrapper of {@link QuickJSWASMModule} that keeps a reference to each
* context or runtime created.
*
* Call {@link disposeAll} to reset these sets and calls `dispose` on any left alive
* (which may throw an error).
*
* Call {@link assertNoMemoryAllocated} at the end of a test, when you expect that you've
* freed all the memory you've ever allocated.
*/
export class TestQuickJSWASMModule implements Pick<QuickJSWASMModule, keyof QuickJSWASMModule> {
contexts = new Set<QuickJSContext>()
runtimes = new Set<QuickJSRuntime>()
constructor(private parent: QuickJSWASMModule) {}
newRuntime(options?: RuntimeOptions): QuickJSRuntime {
const runtime = this.parent.newRuntime({
...options,
ownedLifetimes: [
new Lifetime(undefined, undefined, () => this.runtimes.delete(runtime)),
...(options?.ownedLifetimes ?? []),
],
})
this.runtimes.add(runtime)
return runtime
}
newContext(options?: ContextOptions): QuickJSContext {
const context = this.parent.newContext({
...options,
ownedLifetimes: [
new Lifetime(undefined, undefined, () => this.contexts.delete(context)),
...(options?.ownedLifetimes ?? []),
],
})
this.contexts.add(context)
return context
}
evalCode(code: string, options?: ModuleEvalOptions): unknown {
return this.parent.evalCode(code, options)
}
disposeAll() {
const allDisposables = [...this.contexts, ...this.runtimes]
this.runtimes.clear()
this.contexts.clear()
allDisposables.forEach((d) => {
if (d.alive) {
d.dispose()
}
})
}
assertNoMemoryAllocated() {
const leaksDetected = this.getFFI().QTS_RecoverableLeakCheck()
if (leaksDetected) {
// Note: this is currently only available when building from source
// with debug builds.
throw new QuickJSMemoryLeakDetected("Leak sanitizer detected un-freed memory")
}
if (this.contexts.size > 0) {
throw new QuickJSMemoryLeakDetected(`${this.contexts.size} contexts leaked`)
}
if (this.runtimes.size > 0) {
throw new QuickJSMemoryLeakDetected(`${this.runtimes.size} runtimes leaked`)
}
}
getWasmMemory(): WebAssembly.Memory {
return this.parent.getWasmMemory()
}
/** @private */
getFFI() {
return this.parent.getFFI()
}
}