ic-mops 0.15.1 → 0.17.0
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.
- package/commands/mmf1.js +29 -7
- package/commands/test.js +85 -38
- package/package.json +1 -1
- package/templates/mops-test.yml +3 -6
package/commands/mmf1.js
CHANGED
|
@@ -10,6 +10,28 @@ export class MMF1 {
|
|
|
10
10
|
failed = 0;
|
|
11
11
|
passed = 0;
|
|
12
12
|
skipped = 0;
|
|
13
|
+
srategy; // 'store' | 'print'
|
|
14
|
+
output = [];
|
|
15
|
+
|
|
16
|
+
constructor(srategy) {
|
|
17
|
+
this.srategy = srategy;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_log(...args) {
|
|
21
|
+
if (this.srategy === 'store') {
|
|
22
|
+
this.output.push(args.join(' '));
|
|
23
|
+
}
|
|
24
|
+
else if (this.srategy === 'print') {
|
|
25
|
+
console.log(...args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
flush() {
|
|
30
|
+
for (let out of this.output) {
|
|
31
|
+
console.log(out);
|
|
32
|
+
}
|
|
33
|
+
this.store = [];
|
|
34
|
+
}
|
|
13
35
|
|
|
14
36
|
parseLine(line) {
|
|
15
37
|
if (line.startsWith('mops:1:start ')) {
|
|
@@ -22,7 +44,7 @@ export class MMF1 {
|
|
|
22
44
|
this._testSkip(line.split('mops:1:skip ')[1]);
|
|
23
45
|
}
|
|
24
46
|
else {
|
|
25
|
-
|
|
47
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.gray('stdout'), line);
|
|
26
48
|
}
|
|
27
49
|
}
|
|
28
50
|
|
|
@@ -31,7 +53,7 @@ export class MMF1 {
|
|
|
31
53
|
let suite = this.stack[this.stack.length - 1];
|
|
32
54
|
if (this.currSuite !== suite) {
|
|
33
55
|
this.currSuite = suite;
|
|
34
|
-
|
|
56
|
+
this._log(' '.repeat((this.stack.length - 1) * 2), (chalk.gray('•')) + '', suite);
|
|
35
57
|
}
|
|
36
58
|
}
|
|
37
59
|
this.stack.push(name);
|
|
@@ -55,22 +77,22 @@ export class MMF1 {
|
|
|
55
77
|
return;
|
|
56
78
|
}
|
|
57
79
|
this.passed++;
|
|
58
|
-
|
|
80
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.green('✓'), name);
|
|
59
81
|
}
|
|
60
82
|
else if (status === 'fail') {
|
|
61
83
|
this.failed++;
|
|
62
|
-
|
|
84
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.red('×'), name);
|
|
63
85
|
}
|
|
64
86
|
else if (status === 'skip') {
|
|
65
87
|
this.skipped++;
|
|
66
|
-
|
|
88
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.yellow('−'), name);
|
|
67
89
|
}
|
|
68
90
|
}
|
|
69
91
|
|
|
70
92
|
fail(stderr) {
|
|
71
93
|
let name = this.stack.pop() || '';
|
|
72
94
|
this._status(name, 'fail');
|
|
73
|
-
|
|
95
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.red('FAIL'), stderr);
|
|
74
96
|
}
|
|
75
97
|
|
|
76
98
|
pass() {
|
|
@@ -78,6 +100,6 @@ export class MMF1 {
|
|
|
78
100
|
if (name) {
|
|
79
101
|
this._status(name, 'pass');
|
|
80
102
|
}
|
|
81
|
-
|
|
103
|
+
this._log(' '.repeat(this.stack.length * 2), chalk.green('PASS'));
|
|
82
104
|
}
|
|
83
105
|
}
|
package/commands/test.js
CHANGED
|
@@ -4,9 +4,13 @@ import glob from 'glob';
|
|
|
4
4
|
import chokidar from 'chokidar';
|
|
5
5
|
import debounce from 'debounce';
|
|
6
6
|
import path from 'path';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
|
|
7
10
|
import {MMF1} from './mmf1.js';
|
|
8
11
|
import {sources} from './sources.js';
|
|
9
12
|
import {getRootDir} from '../mops.js';
|
|
13
|
+
import {parallel} from '../parallel.js';
|
|
10
14
|
|
|
11
15
|
let ignore = [
|
|
12
16
|
'**/node_modules/**',
|
|
@@ -58,7 +62,6 @@ let mocPath = process.env.DFX_MOC_PATH;
|
|
|
58
62
|
export async function runAll(filter = '') {
|
|
59
63
|
let start = Date.now();
|
|
60
64
|
let rootDir = getRootDir();
|
|
61
|
-
|
|
62
65
|
let files = [];
|
|
63
66
|
let libFiles = glob.sync('**/test?(s)/lib.mo', globConfig);
|
|
64
67
|
if (libFiles.length) {
|
|
@@ -81,8 +84,6 @@ export async function runAll(filter = '') {
|
|
|
81
84
|
return;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
let absToRel = (p) => path.relative(rootDir, path.resolve(p));
|
|
85
|
-
|
|
86
87
|
console.log('Test files:');
|
|
87
88
|
for (let file of files) {
|
|
88
89
|
console.log(chalk.gray(`• ${absToRel(file)}`));
|
|
@@ -98,51 +99,58 @@ export async function runAll(filter = '') {
|
|
|
98
99
|
mocPath = execSync('dfx cache show').toString().trim() + '/moc';
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
let wasmDir = `${getRootDir()}/.mops/.test/`;
|
|
103
|
+
fs.mkdirSync(wasmDir, {recursive: true});
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
file !== files[0] && console.log('-'.repeat(50));
|
|
106
|
-
console.log(`Running ${chalk.gray(absToRel(file))}`);
|
|
105
|
+
let promises = [];
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
await parallel(os.cpus().length, files, async (file) => {
|
|
108
|
+
let mmf = new MMF1('store');
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
proc.stdout.on('data', (data) => {
|
|
112
|
-
for (let line of data.toString().split('\n')) {
|
|
113
|
-
line = line.trim();
|
|
114
|
-
if (line) {
|
|
115
|
-
mmf1.parseLine(line);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
});
|
|
110
|
+
let wasiMode = fs.readFileSync(file, 'utf8').startsWith('// @testmode wasi');
|
|
119
111
|
|
|
120
|
-
|
|
121
|
-
proc.stderr.on('data', (data) => {
|
|
122
|
-
let text = data.toString().trim();
|
|
123
|
-
// change absolute file path to relative
|
|
124
|
-
// change :line:col-line:col to :line:col to work in vscode
|
|
125
|
-
text = text.replace(/([\w+._/-]+):(\d+).(\d+)(-\d+.\d+)/g, (m0, m1, m2, m3) => `${absToRel(m1)}:${m2}:${m3}`);
|
|
126
|
-
mmf1.fail(text);
|
|
127
|
-
});
|
|
112
|
+
let mocArgs = ['--hide-warnings', '--error-detail=2', ...sourcesArr.join(' ').split(' '), file].filter(x => x);
|
|
128
113
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
114
|
+
// build and run wasm
|
|
115
|
+
if (wasiMode) {
|
|
116
|
+
let wasmFile = `${path.join(wasmDir, path.parse(file).name)}.wasm`;
|
|
117
|
+
|
|
118
|
+
// build
|
|
119
|
+
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs]);
|
|
120
|
+
await pipeMMF(buildProc, mmf).then(async () => {
|
|
121
|
+
if (mmf.failed > 0) {
|
|
122
|
+
return;
|
|
136
123
|
}
|
|
137
|
-
|
|
124
|
+
// run
|
|
125
|
+
let proc = spawn('wasmtime', [wasmFile]);
|
|
126
|
+
await pipeMMF(proc, mmf);
|
|
127
|
+
}).finally(() => {
|
|
128
|
+
fs.rmSync(wasmFile);
|
|
138
129
|
});
|
|
139
|
-
}
|
|
130
|
+
}
|
|
131
|
+
// interpret
|
|
132
|
+
else {
|
|
133
|
+
let proc = spawn(mocPath, ['-r', '-ref-system-api', ...mocArgs], {cwd: rootDir});
|
|
134
|
+
await pipeMMF(proc, mmf);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
passed += mmf.passed;
|
|
138
|
+
failed += mmf.failed;
|
|
139
|
+
skipped += mmf.skipped;
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
promises.push([file, mmf]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
let i = 0;
|
|
145
|
+
for (let [file, mmf] of promises) {
|
|
146
|
+
i++ && console.log('-'.repeat(50));
|
|
147
|
+
let wasiMode = fs.readFileSync(file, 'utf8').startsWith('// @testmode wasi');
|
|
148
|
+
console.log(`Running ${chalk.gray(file)} ${wasiMode ? chalk.gray('(wasi)') : ''}`);
|
|
149
|
+
mmf.flush();
|
|
144
150
|
}
|
|
145
151
|
|
|
152
|
+
fs.rmSync(wasmDir, {recursive: true, force: true});
|
|
153
|
+
|
|
146
154
|
console.log('='.repeat(50));
|
|
147
155
|
if (failed) {
|
|
148
156
|
console.log(chalk.redBright('Tests failed'));
|
|
@@ -158,4 +166,43 @@ export async function runAll(filter = '') {
|
|
|
158
166
|
);
|
|
159
167
|
|
|
160
168
|
return failed === 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function absToRel(p) {
|
|
172
|
+
let rootDir = getRootDir();
|
|
173
|
+
return path.relative(rootDir, path.resolve(p));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function pipeMMF(proc, mmf) {
|
|
177
|
+
return new Promise((resolve) => {
|
|
178
|
+
// stdout
|
|
179
|
+
proc.stdout.on('data', (data) => {
|
|
180
|
+
for (let line of data.toString().split('\n')) {
|
|
181
|
+
line = line.trim();
|
|
182
|
+
if (line) {
|
|
183
|
+
mmf.parseLine(line);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// stderr
|
|
189
|
+
proc.stderr.on('data', (data) => {
|
|
190
|
+
let text = data.toString().trim();
|
|
191
|
+
// change absolute file path to relative
|
|
192
|
+
// change :line:col-line:col to :line:col to work in vscode
|
|
193
|
+
text = text.replace(/([\w+._/-]+):(\d+).(\d+)(-\d+.\d+)/g, (m0, m1, m2, m3) => `${absToRel(m1)}:${m2}:${m3}`);
|
|
194
|
+
mmf.fail(text);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// exit
|
|
198
|
+
proc.on('close', (code) => {
|
|
199
|
+
if (code === 0) {
|
|
200
|
+
mmf.pass();
|
|
201
|
+
}
|
|
202
|
+
else if (code !== 1) {
|
|
203
|
+
mmf.fail(`unknown exit code: ${code}`);
|
|
204
|
+
}
|
|
205
|
+
resolve(mmf);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
161
208
|
}
|
package/package.json
CHANGED
package/templates/mops-test.yml
CHANGED
|
@@ -16,15 +16,12 @@ jobs:
|
|
|
16
16
|
- uses: actions/setup-node@v3
|
|
17
17
|
with:
|
|
18
18
|
node-version: 18
|
|
19
|
-
- uses: aviate-labs/setup-dfx@v0.2.3
|
|
20
|
-
with:
|
|
21
|
-
dfx-version: 0.14.1
|
|
22
19
|
|
|
23
|
-
- name: install
|
|
24
|
-
run:
|
|
20
|
+
- name: install moc
|
|
21
|
+
run: npx mocv use 0.9.3
|
|
25
22
|
|
|
26
23
|
- name: install mops
|
|
27
|
-
run: npm i ic-mops -g
|
|
24
|
+
run: npm i ic-mops -g
|
|
28
25
|
|
|
29
26
|
- name: install mops packages
|
|
30
27
|
run: mops install
|