-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathrun-test-unit.mjs
executable file
·168 lines (141 loc) · 4.96 KB
/
run-test-unit.mjs
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/bin/sh
":" //# ; exec /usr/bin/env node --experimental-wasi-unstable-preview1 "$0" "$@"
import * as wasmerWasi from "@wasmer/wasi";
import fs from "fs/promises";
import path from "path";
import * as nodeWasi from "wasi";
import { RubyVM } from "../dist/index.cjs.js";
const deriveRubySetup = () => {
let preopens = {}
let binaryPath;
if (process.env.RUBY_ROOT) {
binaryPath = path.join(process.env.RUBY_ROOT, "./usr/local/bin/ruby");
preopens["/usr"] = path.join(process.env.RUBY_ROOT, "./usr");
} else if (process.env.RUBY_NPM_PACKAGE_ROOT) {
binaryPath = path.join(process.env.RUBY_NPM_PACKAGE_ROOT, "./dist/ruby.debug+stdlib.wasm");
} else {
throw new Error("RUBY_ROOT or RUBY_NPM_PACKAGE_ROOT must be set");
}
return { binaryPath, preopens };
}
const instantiateNodeWasi = async (rootTestFile) => {
const dirname = path.dirname(new URL(import.meta.url).pathname);
const { binaryPath, preopens } = deriveRubySetup();
preopens["__root__"] = path.join(dirname, "..");
const binary = await fs.readFile(binaryPath);
const rubyModule = await WebAssembly.compile(binary);
const wasi = new nodeWasi.WASI({
stdio: "inherit",
args: ["ruby.wasm"].concat(process.argv.slice(2)),
env: {
...process.env,
// Extend fiber stack size to be able to run test-unit
"RUBY_FIBER_MACHINE_STACK_SIZE": String(1024 * 1024 * 20),
},
preopens,
});
const vm = new RubyVM();
const imports = {
wasi_snapshot_preview1: wasi.wasiImport,
};
vm.addToImports(imports);
const instance = await WebAssembly.instantiate(rubyModule, imports);
await vm.setInstance(instance);
wasi.initialize(instance);
vm.initialize(["ruby.wasm", rootTestFile]);
return { instance, vm, wasi };
};
const instantiateWasmerWasi = async (rootTestFile) => {
await wasmerWasi.init();
const memFs = new wasmerWasi.MemFS();
const walk = async (dir) => {
const names = await fs.readdir(dir);
const files = await Promise.all(names.map(async name => {
if ((await fs.stat(path.join(dir, name))).isDirectory()) {
return walk(path.join(dir, name));
} else {
return [path.join(dir, name)];
}
}));
return files.flat();
};
const mkdirpMemFs = (guestPath) => {
const parts = guestPath.split('/');
for (let i = 2; i <= parts.length; i++) {
memFs.createDir(parts.slice(0, i).join('/'));
}
};
const loadToMemFs = async (guestPath, hostPath) => {
const hostFiles = await walk(hostPath);
await Promise.all(hostFiles.map(async hostFile => {
const guestFile = path.join(guestPath, path.relative(hostPath, hostFile));
mkdirpMemFs(path.dirname(guestFile));
const contents = await fs.readFile(hostFile);
memFs.open(guestFile, { write: true, create: true }).write(contents);
}));
};
const dirname = path.dirname(new URL(import.meta.url).pathname);
await loadToMemFs('/__root__/test', path.join(dirname, '../test'));
const { binaryPath, preopens } = deriveRubySetup();
preopens["__root__"] = '/__root__';
if (process.env.RUBY_ROOT) {
console.error('For now, testing with RUBY_ROOT is not supported.');
}
const binary = await fs.readFile(binaryPath);
const rubyModule = await WebAssembly.compile(binary);
const wasi = new wasmerWasi.WASI({
args: ["ruby.wasm"].concat(process.argv.slice(2)),
env: {
...process.env,
// Extend fiber stack size to be able to run test-unit
"RUBY_FIBER_MACHINE_STACK_SIZE": String(1024 * 1024 * 20),
},
preopens,
fs: memFs,
});
const vm = new RubyVM();
const imports = wasi.getImports(rubyModule);
vm.addToImports(imports);
const instance = await WebAssembly.instantiate(rubyModule, imports);
wasi.instantiate(instance);
await vm.setInstance(instance);
instance.exports._initialize();
vm.initialize(["ruby.wasm", rootTestFile]);
return { instance, vm, wasi };
};
const test = async (instantiate) => {
const rootTestFile = "/__root__/test/test_unit.rb";
const { vm, wasi } = await instantiate(rootTestFile);
Error.stackTraceLimit = Infinity;
await vm.evalAsync(`
# HACK: Until we've fixed the issue in the test-unit or power_assert
# See https://github.com/test-unit/test-unit/pull/221
module Kernel
alias test_unit_original_require require
def require(path)
if path == "power_assert"
raise LoadError, "power_assert is not supported in this environment"
end
test_unit_original_require(path)
end
end
require 'test/unit'
require_relative '${rootTestFile}'
Test::Unit::AutoRunner.run
`);
// TODO(makenowjust): override `wasi_snapshot_preview1.fd_write` for output to stdout/stderr.
// See `src/browser.ts`.
if (wasi.getStderrString) {
console.error(wasi.getStderrString());
}
if (wasi.getStdoutString) {
console.log(wasi.getStdoutString());
}
};
const main = async () => {
await test(instantiateNodeWasi);
if (!process.env.RUBY_ROOT) {
await test(instantiateWasmerWasi);
}
};
main();