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 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
- console.log(' '.repeat(this.stack.length * 2), chalk.gray('stdout'), line);
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
- console.log(' '.repeat((this.stack.length - 1) * 2), (chalk.gray('•')) + '', suite);
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
- console.log(' '.repeat(this.stack.length * 2), chalk.green('✓'), name);
80
+ this._log(' '.repeat(this.stack.length * 2), chalk.green('✓'), name);
59
81
  }
60
82
  else if (status === 'fail') {
61
83
  this.failed++;
62
- console.log(' '.repeat(this.stack.length * 2), chalk.red('×'), name);
84
+ this._log(' '.repeat(this.stack.length * 2), chalk.red('×'), name);
63
85
  }
64
86
  else if (status === 'skip') {
65
87
  this.skipped++;
66
- console.log(' '.repeat(this.stack.length * 2), chalk.yellow('−'), name);
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
- console.log(' '.repeat(this.stack.length * 2), chalk.red('FAIL'), stderr);
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
- console.log(' '.repeat(this.stack.length * 2), chalk.green('PASS'));
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
- for (let file of files) {
102
- let mmf1 = new MMF1;
102
+ let wasmDir = `${getRootDir()}/.mops/.test/`;
103
+ fs.mkdirSync(wasmDir, {recursive: true});
103
104
 
104
- await new Promise((resolve) => {
105
- file !== files[0] && console.log('-'.repeat(50));
106
- console.log(`Running ${chalk.gray(absToRel(file))}`);
105
+ let promises = [];
107
106
 
108
- let proc = spawn(mocPath, ['-r', '-wasi-system-api', '-ref-system-api', '--hide-warnings', '--error-detail=2', ...sourcesArr.join(' ').split(' '), file].filter(x => x));
107
+ await parallel(os.cpus().length, files, async (file) => {
108
+ let mmf = new MMF1('store');
109
109
 
110
- // stdout
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
- // stderr
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
- // exit
130
- proc.on('exit', (code) => {
131
- if (code === 0) {
132
- mmf1.pass();
133
- }
134
- else if (code !== 1) {
135
- console.log(chalk.red('unknown code:'), code);
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
- resolve();
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
- passed += mmf1.passed;
142
- failed += mmf1.failed;
143
- skipped += mmf1.skipped;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "cli.js"
@@ -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 dfx
24
- run: dfx cache install
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 --yes
24
+ run: npm i ic-mops -g
28
25
 
29
26
  - name: install mops packages
30
27
  run: mops install