eyeling 1.5.16 → 1.5.17
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/README.md +1 -1
- package/package.json +6 -4
- package/test/api.test.js +3 -0
- package/test/examples.test.js +242 -0
- package/test/package.test.js +132 -0
- package/test/packlist.test.js +0 -1
- package/examples/test +0 -154
- package/test/package-smoke.sh +0 -55
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ npm run test:packlist
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
- `test:api` runs an independent JS API test suite (does not rely on `examples/`).
|
|
103
|
-
- `test:examples` runs the `examples
|
|
103
|
+
- `test:examples` runs the examples in `examples` directory and compares against the golden outputs in `examples/output`.
|
|
104
104
|
- `test:package` does a “real consumer” smoke test: `npm pack` → install tarball into a temp project → run API + CLI + examples.
|
|
105
105
|
- `test:packlist` sanity-checks what will be published in the npm tarball (and the CLI shebang/bin wiring).
|
|
106
106
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyeling",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.17",
|
|
4
4
|
"description": "A minimal Notation3 (N3) reasoner in JavaScript.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -31,8 +31,10 @@
|
|
|
31
31
|
"scripts": {
|
|
32
32
|
"test:packlist": "node test/packlist.test.js",
|
|
33
33
|
"test:api": "node test/api.test.js",
|
|
34
|
-
"test:examples": "
|
|
35
|
-
"test:package": "
|
|
36
|
-
"test": "npm run test:packlist && npm run test:api && npm run test:examples"
|
|
34
|
+
"test:examples": "node test/examples.test.js",
|
|
35
|
+
"test:package": "node test/package.test.js",
|
|
36
|
+
"test": "npm run test:packlist && npm run test:api && npm run test:examples",
|
|
37
|
+
"preversion": "npm test",
|
|
38
|
+
"postversion": "git push origin HEAD --follow-tags"
|
|
37
39
|
}
|
|
38
40
|
}
|
package/test/api.test.js
CHANGED
|
@@ -556,6 +556,7 @@ let passed = 0;
|
|
|
556
556
|
let failed = 0;
|
|
557
557
|
|
|
558
558
|
(async function main() {
|
|
559
|
+
const suiteStart = Date.now();
|
|
559
560
|
info(`Running ${cases.length} API tests (independent of examples/)`);
|
|
560
561
|
|
|
561
562
|
for (const tc of cases) {
|
|
@@ -602,6 +603,8 @@ let failed = 0;
|
|
|
602
603
|
}
|
|
603
604
|
|
|
604
605
|
console.log('');
|
|
606
|
+
const suiteMs = Date.now() - suiteStart;
|
|
607
|
+
console.log(`${C.y}==${C.n} Total elapsed: ${suiteMs} ms`);
|
|
605
608
|
if (failed === 0) {
|
|
606
609
|
ok(`All API tests passed (${passed}/${cases.length})`);
|
|
607
610
|
process.exit(0);
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const cp = require('node:child_process');
|
|
8
|
+
|
|
9
|
+
const TTY = process.stdout.isTTY;
|
|
10
|
+
const C = TTY
|
|
11
|
+
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
12
|
+
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
13
|
+
|
|
14
|
+
function ok(msg) { console.log(`${C.g}OK${C.n} ${msg}`); }
|
|
15
|
+
function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
|
|
16
|
+
function info(msg) { console.log(`${C.y}==${C.n} ${msg}`); }
|
|
17
|
+
|
|
18
|
+
function padRight(s, n) {
|
|
19
|
+
s = String(s);
|
|
20
|
+
return s.length >= n ? s : (s + ' '.repeat(n - s.length));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function padLeft(s, n) {
|
|
24
|
+
s = String(s);
|
|
25
|
+
return s.length >= n ? s : (' '.repeat(n - s.length) + s);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function run(cmd, args, opts = {}) {
|
|
29
|
+
return cp.spawnSync(cmd, args, {
|
|
30
|
+
encoding: 'utf8',
|
|
31
|
+
maxBuffer: 200 * 1024 * 1024,
|
|
32
|
+
...opts,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function hasGit() {
|
|
37
|
+
const r = run('git', ['--version']);
|
|
38
|
+
return r.status === 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function inGitWorktree(cwd) {
|
|
42
|
+
if (!hasGit()) return false;
|
|
43
|
+
const r = run('git', ['rev-parse', '--is-inside-work-tree'], { cwd });
|
|
44
|
+
return r.status === 0 && String(r.stdout).trim() === 'true';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Expectation logic (same as bash version):
|
|
48
|
+
// 1) If file contains a comment like: # expect-exit: 2 -> use that
|
|
49
|
+
// 2) Else, if it contains "=> false" -> expect exit 2
|
|
50
|
+
// 3) Else -> expect exit 0
|
|
51
|
+
function expectedExitCode(n3Text) {
|
|
52
|
+
const m = n3Text.match(/^[ \t]*#[: ]*expect-exit:[ \t]*([0-9]+)\b/m);
|
|
53
|
+
if (m) return parseInt(m[1], 10);
|
|
54
|
+
if (/=>\s*false\b/.test(n3Text)) return 2;
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getEyelingVersion(nodePath, eyelingJsPath, cwd) {
|
|
59
|
+
const r = run(nodePath, [eyelingJsPath, '-v'], { cwd });
|
|
60
|
+
// eyeling prints version to stdout in your CLI
|
|
61
|
+
const s = (r.stdout || r.stderr || '').trim();
|
|
62
|
+
return s || 'eyeling (unknown version)';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function mkTmpFile() {
|
|
66
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-examples-'));
|
|
67
|
+
const file = path.join(dir, 'generated.n3');
|
|
68
|
+
return { dir, file };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function rmrf(p) {
|
|
72
|
+
try { fs.rmSync(p, { recursive: true, force: true }); } catch {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function main() {
|
|
76
|
+
const suiteStart = Date.now();
|
|
77
|
+
|
|
78
|
+
// package root: .../test/examples.test.js -> root is one level up
|
|
79
|
+
const root = path.resolve(__dirname, '..');
|
|
80
|
+
const examplesDir = path.join(root, 'examples');
|
|
81
|
+
const outputDir = path.join(examplesDir, 'output');
|
|
82
|
+
const eyelingJsPath = path.join(root, 'eyeling.js');
|
|
83
|
+
const nodePath = process.execPath;
|
|
84
|
+
|
|
85
|
+
if (!fs.existsSync(examplesDir)) {
|
|
86
|
+
fail(`Missing examples directory: ${examplesDir}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
if (!fs.existsSync(eyelingJsPath)) {
|
|
90
|
+
fail(`Missing eyeling.js: ${eyelingJsPath}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const IN_GIT = inGitWorktree(root);
|
|
95
|
+
|
|
96
|
+
// Header
|
|
97
|
+
console.log(`${C.y}-------------------------------------------------${C.n}`);
|
|
98
|
+
console.log(`${C.y}running eyeling examples${C.n}`);
|
|
99
|
+
console.log(
|
|
100
|
+
`${C.y}using ${getEyelingVersion(nodePath, eyelingJsPath, root)} and node ${process.version}${C.n}`
|
|
101
|
+
);
|
|
102
|
+
console.log(`${C.y}-------------------------------------------------${C.n}`);
|
|
103
|
+
console.log('');
|
|
104
|
+
|
|
105
|
+
// In maintainer mode we write expected outputs (tracked) to examples/output/
|
|
106
|
+
if (IN_GIT) fs.mkdirSync(outputDir, { recursive: true });
|
|
107
|
+
|
|
108
|
+
const files = fs.readdirSync(examplesDir)
|
|
109
|
+
.filter(f => f.endsWith('.n3'))
|
|
110
|
+
.sort((a, b) => a.localeCompare(b));
|
|
111
|
+
|
|
112
|
+
if (files.length === 0) {
|
|
113
|
+
info('No .n3 files found in examples/');
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let OK = 0;
|
|
118
|
+
let DIFF = 0;
|
|
119
|
+
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
const filePath = path.join(examplesDir, file);
|
|
122
|
+
const expectedPath = path.join(outputDir, file); // examples/output/<file>
|
|
123
|
+
|
|
124
|
+
const start = Date.now();
|
|
125
|
+
|
|
126
|
+
let n3Text = '';
|
|
127
|
+
try {
|
|
128
|
+
n3Text = fs.readFileSync(filePath, 'utf8');
|
|
129
|
+
} catch (e) {
|
|
130
|
+
const ms = Date.now() - start;
|
|
131
|
+
process.stdout.write(padRight(file, 36));
|
|
132
|
+
process.stdout.write(`${C.y}${padLeft(`${ms} ms`, 10)}${C.n} `);
|
|
133
|
+
console.log(`${C.r}DIFF${C.n} (cannot read input: ${e.message})`);
|
|
134
|
+
DIFF++;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const expectedRc = expectedExitCode(n3Text);
|
|
139
|
+
|
|
140
|
+
// Decide where to write generated output
|
|
141
|
+
let tmp = null;
|
|
142
|
+
let generatedPath = expectedPath;
|
|
143
|
+
|
|
144
|
+
if (!IN_GIT) {
|
|
145
|
+
// npm-installed / no .git: never modify output/ in node_modules
|
|
146
|
+
if (!fs.existsSync(expectedPath)) {
|
|
147
|
+
const ms = Date.now() - start;
|
|
148
|
+
process.stdout.write(padRight(file, 36));
|
|
149
|
+
process.stdout.write(`${C.y}${padLeft(`${ms} ms`, 10)}${C.n} `);
|
|
150
|
+
console.log(`${C.r}MISSING expected output/${file}${C.n}`);
|
|
151
|
+
DIFF++;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
tmp = mkTmpFile();
|
|
155
|
+
generatedPath = tmp.file;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Run eyeling, capture exit code without aborting the suite
|
|
159
|
+
// We run `node eyeling.js <file>` from examplesDir so relative paths match old behavior.
|
|
160
|
+
const r = run(nodePath, [eyelingJsPath, file], { cwd: examplesDir });
|
|
161
|
+
const rc = (r.status == null) ? 1 : r.status;
|
|
162
|
+
|
|
163
|
+
// Write stdout to the chosen output file (expected in git mode, tmp in npm mode)
|
|
164
|
+
try {
|
|
165
|
+
fs.writeFileSync(generatedPath, r.stdout || '', 'utf8');
|
|
166
|
+
} catch (e) {
|
|
167
|
+
const ms = Date.now() - start;
|
|
168
|
+
process.stdout.write(padRight(file, 36));
|
|
169
|
+
process.stdout.write(`${C.y}${padLeft(`${ms} ms`, 10)}${C.n} `);
|
|
170
|
+
console.log(`${C.r}DIFF${C.n} (cannot write output: ${e.message})`);
|
|
171
|
+
DIFF++;
|
|
172
|
+
if (tmp) rmrf(tmp.dir);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const ms = Date.now() - start;
|
|
177
|
+
|
|
178
|
+
// Compare outputs
|
|
179
|
+
let diffOk = false;
|
|
180
|
+
|
|
181
|
+
if (IN_GIT) {
|
|
182
|
+
// Compare expectedPath against HEAD using git diff
|
|
183
|
+
const d = run('git', ['diff', '--quiet', '--', path.posix.join('output', file)], { cwd: examplesDir });
|
|
184
|
+
diffOk = (d.status === 0);
|
|
185
|
+
} else {
|
|
186
|
+
// Compare expectedPath vs generatedPath without needing a repo
|
|
187
|
+
if (hasGit()) {
|
|
188
|
+
const d = run('git', ['diff', '--no-index', '--quiet', expectedPath, generatedPath], { cwd: examplesDir });
|
|
189
|
+
diffOk = (d.status === 0);
|
|
190
|
+
} else {
|
|
191
|
+
const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
|
|
192
|
+
diffOk = (d.status === 0);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Decide pass/fail
|
|
197
|
+
process.stdout.write(padRight(file, 36));
|
|
198
|
+
process.stdout.write(`${C.y}${padLeft(`${ms} ms`, 10)}${C.n} `);
|
|
199
|
+
|
|
200
|
+
if (diffOk && rc === expectedRc) {
|
|
201
|
+
if (rc === 0) {
|
|
202
|
+
console.log(`${C.g}OK${C.n}`);
|
|
203
|
+
} else {
|
|
204
|
+
console.log(`${C.g}OK${C.n} (exit ${rc})`);
|
|
205
|
+
}
|
|
206
|
+
OK++;
|
|
207
|
+
} else {
|
|
208
|
+
if (rc !== expectedRc) {
|
|
209
|
+
console.log(`${C.r}DIFF${C.n} (exit ${rc}, expected ${expectedRc})`);
|
|
210
|
+
} else {
|
|
211
|
+
console.log(`${C.r}DIFF${C.n}`);
|
|
212
|
+
}
|
|
213
|
+
DIFF++;
|
|
214
|
+
|
|
215
|
+
// In npm mode, show a diff (nice UX) without modifying node_modules
|
|
216
|
+
if (!IN_GIT) {
|
|
217
|
+
if (hasGit()) {
|
|
218
|
+
const d = run('git', ['diff', '--no-index', expectedPath, generatedPath], { cwd: examplesDir });
|
|
219
|
+
if (d.stdout) process.stdout.write(d.stdout);
|
|
220
|
+
if (d.stderr) process.stderr.write(d.stderr);
|
|
221
|
+
} else {
|
|
222
|
+
const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
|
|
223
|
+
if (d.stdout) process.stdout.write(d.stdout);
|
|
224
|
+
if (d.stderr) process.stderr.write(d.stderr);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// cleanup tmp file
|
|
230
|
+
if (tmp) rmrf(tmp.dir);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log('');
|
|
234
|
+
const suiteMs = Date.now() - suiteStart;
|
|
235
|
+
console.log(`${C.y}==${C.n} Total elapsed: ${suiteMs} ms (${(suiteMs / 1000).toFixed(2)} s)`);
|
|
236
|
+
console.log(`${C.y}==${C.n} ${C.g}${OK} OK${C.n} ${C.r}${DIFF} DIFF${C.n}`);
|
|
237
|
+
|
|
238
|
+
process.exit(DIFF === 0 ? 0 : 2);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
main();
|
|
242
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const cp = require('node:child_process');
|
|
8
|
+
|
|
9
|
+
const TTY = process.stdout.isTTY;
|
|
10
|
+
const C = TTY
|
|
11
|
+
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
12
|
+
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
13
|
+
|
|
14
|
+
function info(msg) { console.log(`${C.y}==${C.n} ${msg}`); }
|
|
15
|
+
function ok(msg) { console.log(`${C.g}OK${C.n} ${msg}`); }
|
|
16
|
+
function fail(msg) { console.error(`${C.r}FAIL${C.n} ${msg}`); }
|
|
17
|
+
|
|
18
|
+
function isWin() { return process.platform === 'win32'; }
|
|
19
|
+
function npmCmd() { return isWin() ? 'npm.cmd' : 'npm'; }
|
|
20
|
+
|
|
21
|
+
function rmrf(p) {
|
|
22
|
+
try { fs.rmSync(p, { recursive: true, force: true }); } catch {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function run(cmd, args, opts = {}) {
|
|
26
|
+
const res = cp.spawnSync(cmd, args, {
|
|
27
|
+
encoding: 'utf8',
|
|
28
|
+
maxBuffer: 200 * 1024 * 1024,
|
|
29
|
+
...opts,
|
|
30
|
+
});
|
|
31
|
+
return res;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function runChecked(cmd, args, opts = {}) {
|
|
35
|
+
// Print the command in a dim style
|
|
36
|
+
console.log(`${C.dim}$ ${cmd} ${args.join(' ')}${C.n}`);
|
|
37
|
+
const res = run(cmd, args, opts);
|
|
38
|
+
if (res.error) throw res.error;
|
|
39
|
+
if (res.status !== 0) {
|
|
40
|
+
const err = new Error(`Command failed (${cmd} ${args.join(' ')}), exit ${res.status}`);
|
|
41
|
+
err.code = res.status;
|
|
42
|
+
err.stdout = res.stdout;
|
|
43
|
+
err.stderr = res.stderr;
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
return res;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function packTarball(root) {
|
|
50
|
+
// `npm pack --silent` prints the filename (usually one line)
|
|
51
|
+
const res = runChecked(npmCmd(), ['pack', '--silent'], { cwd: root });
|
|
52
|
+
const out = String(res.stdout || '').trim().split(/\r?\n/).filter(Boolean);
|
|
53
|
+
if (out.length === 0) throw new Error('npm pack produced no output');
|
|
54
|
+
return out[out.length - 1].trim(); // tarball filename in root
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function main() {
|
|
58
|
+
const suiteStart = Date.now();
|
|
59
|
+
const root = path.resolve(__dirname, '..');
|
|
60
|
+
|
|
61
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-smoke-'));
|
|
62
|
+
const cleanup = () => rmrf(tmp);
|
|
63
|
+
|
|
64
|
+
let tgzInRoot = null;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
info('Building tarball (npm pack)');
|
|
68
|
+
tgzInRoot = packTarball(root);
|
|
69
|
+
const srcTgz = path.join(root, tgzInRoot);
|
|
70
|
+
const dstTgz = path.join(tmp, tgzInRoot);
|
|
71
|
+
|
|
72
|
+
fs.renameSync(srcTgz, dstTgz);
|
|
73
|
+
|
|
74
|
+
info('Creating temp project + installing tarball');
|
|
75
|
+
runChecked(npmCmd(), ['init', '-y'], { cwd: tmp, stdio: 'ignore' });
|
|
76
|
+
runChecked(npmCmd(), ['install', `./${tgzInRoot}`, '--no-audit', '--no-fund'], { cwd: tmp, stdio: 'inherit' });
|
|
77
|
+
|
|
78
|
+
info('API smoke test');
|
|
79
|
+
// Run a tiny API check via node -e
|
|
80
|
+
const apiCode = `
|
|
81
|
+
const { reason } = require('eyeling');
|
|
82
|
+
const input = \`
|
|
83
|
+
{ <http://example.org/s> <http://example.org/p> <http://example.org/o>. }
|
|
84
|
+
=> { <http://example.org/s> <http://example.org/q> <http://example.org/o>. }.
|
|
85
|
+
|
|
86
|
+
<http://example.org/s> <http://example.org/p> <http://example.org/o>.
|
|
87
|
+
\`;
|
|
88
|
+
const out = reason({ proofComments: false }, input);
|
|
89
|
+
const re = /<http:\\/\\/example\\.org\\/s>\\s+<http:\\/\\/example\\.org\\/q>\\s+<http:\\/\\/example\\.org\\/o>\\s*\\./;
|
|
90
|
+
if (!re.test(out)) {
|
|
91
|
+
console.error('Unexpected output:\\n' + out);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
console.log('OK: API works');
|
|
95
|
+
`;
|
|
96
|
+
runChecked(process.execPath, ['-e', apiCode], { cwd: tmp, stdio: 'inherit' });
|
|
97
|
+
ok('API works');
|
|
98
|
+
|
|
99
|
+
info('CLI smoke test');
|
|
100
|
+
const bin = isWin()
|
|
101
|
+
? path.join(tmp, 'node_modules', '.bin', 'eyeling.cmd')
|
|
102
|
+
: path.join(tmp, 'node_modules', '.bin', 'eyeling');
|
|
103
|
+
runChecked(bin, ['-v'], { cwd: tmp, stdio: 'inherit' });
|
|
104
|
+
ok('CLI works');
|
|
105
|
+
|
|
106
|
+
info('Examples test (installed package)');
|
|
107
|
+
const examplesRunner = path.join(tmp, 'node_modules', 'eyeling', 'test', 'examples.test.js');
|
|
108
|
+
runChecked(process.execPath, [examplesRunner], { cwd: tmp, stdio: 'inherit' });
|
|
109
|
+
ok('Installed examples test passed');
|
|
110
|
+
|
|
111
|
+
const suiteMs = Date.now() - suiteStart;
|
|
112
|
+
console.log('');
|
|
113
|
+
ok(`Packaged install smoke test passed ${C.dim}(${suiteMs} ms, ${(suiteMs / 1000).toFixed(2)} s)${C.n}`);
|
|
114
|
+
process.exit(0);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.log('');
|
|
117
|
+
fail(e && e.stack ? e.stack : String(e));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
} finally {
|
|
120
|
+
// If rename failed and the tarball still exists in root, try to delete it
|
|
121
|
+
if (tgzInRoot) {
|
|
122
|
+
const maybe = path.join(root, tgzInRoot);
|
|
123
|
+
if (fs.existsSync(maybe)) {
|
|
124
|
+
try { fs.unlinkSync(maybe); } catch {}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
cleanup();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main();
|
|
132
|
+
|
package/test/packlist.test.js
CHANGED
package/examples/test
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
RED="\e[31m"
|
|
5
|
-
GREEN="\e[32m"
|
|
6
|
-
YELLOW="\e[33m"
|
|
7
|
-
NORMAL="\e[0;39m"
|
|
8
|
-
|
|
9
|
-
OK=0
|
|
10
|
-
DIFF=0
|
|
11
|
-
|
|
12
|
-
pad() {
|
|
13
|
-
# pad "text" width
|
|
14
|
-
local s="$1" w="$2"
|
|
15
|
-
printf "%-${w}s" "$s"
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
now_ms() {
|
|
19
|
-
echo $(( $(date +%s%N) / 1000000 ))
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
in_git_worktree() {
|
|
23
|
-
command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
# Expectation logic:
|
|
27
|
-
# 1) If the .n3 contains a comment like: # expect-exit: 2 -> use that
|
|
28
|
-
# 2) Else, if it contains "=> false" -> expect exit 2
|
|
29
|
-
# 3) Else -> expect exit 0
|
|
30
|
-
expected_exit_code() {
|
|
31
|
-
local file="$1"
|
|
32
|
-
local line
|
|
33
|
-
if line=$(grep -Em1 '^[[:space:]]*#[: ]*expect-exit:[[:space:]]*[0-9]+' "$file" 2>/dev/null); then
|
|
34
|
-
if [[ "$line" =~ ([0-9]+) ]]; then
|
|
35
|
-
echo "${BASH_REMATCH[1]}"
|
|
36
|
-
return
|
|
37
|
-
fi
|
|
38
|
-
fi
|
|
39
|
-
if grep -Eq '=>[[:space:]]*false\b' "$file"; then
|
|
40
|
-
echo 2
|
|
41
|
-
else
|
|
42
|
-
echo 0
|
|
43
|
-
fi
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
echo -e "${YELLOW}-------------------------------------------------${NORMAL}"
|
|
47
|
-
echo -e "${YELLOW}running eyeling examples${NORMAL}"
|
|
48
|
-
echo -e "${YELLOW}using $(../eyeling.js -v) and node $(node --version)${NORMAL}"
|
|
49
|
-
echo -e "${YELLOW}-------------------------------------------------${NORMAL}"
|
|
50
|
-
echo ""
|
|
51
|
-
|
|
52
|
-
IN_GIT=0
|
|
53
|
-
if in_git_worktree; then IN_GIT=1; fi
|
|
54
|
-
|
|
55
|
-
# In maintainer mode we write expected outputs (tracked) to output/
|
|
56
|
-
if [[ $IN_GIT -eq 1 ]]; then
|
|
57
|
-
mkdir -p output
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
begin="$(now_ms)"
|
|
61
|
-
|
|
62
|
-
for file in *.n3; do
|
|
63
|
-
printf "%s" "$(pad "$file" 36)"
|
|
64
|
-
start="$(now_ms)"
|
|
65
|
-
|
|
66
|
-
expected_rc="$(expected_exit_code "$file")"
|
|
67
|
-
|
|
68
|
-
# Decide where we write generated output
|
|
69
|
-
tmp=""
|
|
70
|
-
generated=""
|
|
71
|
-
expected="output/${file}"
|
|
72
|
-
|
|
73
|
-
if [[ $IN_GIT -eq 1 ]]; then
|
|
74
|
-
generated="$expected" # overwrite expected output in working tree
|
|
75
|
-
else
|
|
76
|
-
# npm-installed / no .git: never modify output/ in node_modules
|
|
77
|
-
if [[ ! -f "$expected" ]]; then
|
|
78
|
-
end="$(now_ms)"
|
|
79
|
-
ms=$((end-start))
|
|
80
|
-
echo -en "${YELLOW}$(pad "${ms} ms" 10)${NORMAL} "
|
|
81
|
-
echo -e "${RED}MISSING expected ${expected}${NORMAL}"
|
|
82
|
-
((++DIFF))
|
|
83
|
-
continue
|
|
84
|
-
fi
|
|
85
|
-
tmp="$(mktemp)"
|
|
86
|
-
generated="$tmp"
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
# Run eyeling, capture exit code without breaking the loop
|
|
90
|
-
rc=0
|
|
91
|
-
if ../eyeling.js "$file" > "$generated"; then
|
|
92
|
-
rc=0
|
|
93
|
-
else
|
|
94
|
-
rc=$?
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
end="$(now_ms)"
|
|
98
|
-
ms=$((end-start))
|
|
99
|
-
echo -en "${YELLOW}$(pad "${ms} ms" 10)${NORMAL} "
|
|
100
|
-
|
|
101
|
-
# Compare output
|
|
102
|
-
diff_ok=0
|
|
103
|
-
if [[ $IN_GIT -eq 1 ]]; then
|
|
104
|
-
if git diff --quiet -- "$expected"; then diff_ok=1; fi
|
|
105
|
-
else
|
|
106
|
-
if command -v git >/dev/null 2>&1; then
|
|
107
|
-
if git diff --no-index --quiet -- "$expected" "$generated" >/dev/null 2>&1; then diff_ok=1; fi
|
|
108
|
-
else
|
|
109
|
-
if diff -u "$expected" "$generated" >/dev/null 2>&1; then diff_ok=1; fi
|
|
110
|
-
fi
|
|
111
|
-
fi
|
|
112
|
-
|
|
113
|
-
# Decide pass/fail
|
|
114
|
-
if [[ $diff_ok -eq 1 && $rc -eq $expected_rc ]]; then
|
|
115
|
-
if [[ $rc -eq 0 ]]; then
|
|
116
|
-
echo -e "${GREEN}OK${NORMAL}"
|
|
117
|
-
else
|
|
118
|
-
echo -e "${GREEN}OK${NORMAL} (exit ${rc})"
|
|
119
|
-
fi
|
|
120
|
-
((++OK))
|
|
121
|
-
else
|
|
122
|
-
if [[ $rc -ne $expected_rc ]]; then
|
|
123
|
-
echo -e "${RED}DIFF${NORMAL} (exit ${rc}, expected ${expected_rc})"
|
|
124
|
-
else
|
|
125
|
-
echo -e "${RED}DIFF${NORMAL}"
|
|
126
|
-
fi
|
|
127
|
-
((++DIFF))
|
|
128
|
-
|
|
129
|
-
# In npm mode, show a git-style diff when available (nice UX)
|
|
130
|
-
if [[ $IN_GIT -eq 0 ]]; then
|
|
131
|
-
if command -v git >/dev/null 2>&1; then
|
|
132
|
-
git diff --no-index -- "$expected" "$generated" || true
|
|
133
|
-
else
|
|
134
|
-
diff -u "$expected" "$generated" || true
|
|
135
|
-
fi
|
|
136
|
-
fi
|
|
137
|
-
fi
|
|
138
|
-
|
|
139
|
-
# cleanup tmp file
|
|
140
|
-
if [[ -n "$tmp" ]]; then rm -f "$tmp"; fi
|
|
141
|
-
done
|
|
142
|
-
|
|
143
|
-
end="$(now_ms)"
|
|
144
|
-
total=$((end-begin))
|
|
145
|
-
|
|
146
|
-
echo ""
|
|
147
|
-
echo -e "${YELLOW}${total} ms${NORMAL} ${GREEN}${OK} OK${NORMAL} ${RED}${DIFF} DIFF${NORMAL}"
|
|
148
|
-
|
|
149
|
-
if [[ ${DIFF} -eq 0 ]]; then
|
|
150
|
-
exit 0
|
|
151
|
-
else
|
|
152
|
-
exit 2
|
|
153
|
-
fi
|
|
154
|
-
|
package/test/package-smoke.sh
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
if [ -t 1 ]; then
|
|
5
|
-
RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m'; NORMAL=$'\e[0m'
|
|
6
|
-
else
|
|
7
|
-
RED=""; GREEN=""; YELLOW=""; NORMAL=""
|
|
8
|
-
fi
|
|
9
|
-
|
|
10
|
-
say() { echo -e "${YELLOW}== $* ==${NORMAL}"; }
|
|
11
|
-
ok() { echo -e "${GREEN}OK${NORMAL} $*"; }
|
|
12
|
-
|
|
13
|
-
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
14
|
-
TMP="$(mktemp -d)"
|
|
15
|
-
cleanup() { rm -rf "$TMP"; }
|
|
16
|
-
trap cleanup EXIT
|
|
17
|
-
|
|
18
|
-
cd "$ROOT"
|
|
19
|
-
|
|
20
|
-
say "Building tarball"
|
|
21
|
-
TGZ="$(npm pack --silent)"
|
|
22
|
-
mv "$TGZ" "$TMP/"
|
|
23
|
-
cd "$TMP"
|
|
24
|
-
|
|
25
|
-
say "Installing tarball into temp project"
|
|
26
|
-
npm init -y >/dev/null 2>&1
|
|
27
|
-
npm install "./$TGZ" >/dev/null 2>&1
|
|
28
|
-
|
|
29
|
-
say "API smoke test"
|
|
30
|
-
node - <<'NODE'
|
|
31
|
-
const { reason } = require('eyeling');
|
|
32
|
-
const input = `
|
|
33
|
-
{ <http://example.org/s> <http://example.org/p> <http://example.org/o>. }
|
|
34
|
-
=> { <http://example.org/s> <http://example.org/q> <http://example.org/o>. }.
|
|
35
|
-
|
|
36
|
-
<http://example.org/s> <http://example.org/p> <http://example.org/o>.
|
|
37
|
-
`;
|
|
38
|
-
const out = reason({ proofComments: false }, input);
|
|
39
|
-
if (!/<http:\/\/example\.org\/s>\s+<http:\/\/example\.org\/q>\s+<http:\/\/example\.org\/o>\s*\./.test(out)) {
|
|
40
|
-
console.error("Unexpected output:\n" + out);
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
NODE
|
|
44
|
-
ok "API works"
|
|
45
|
-
|
|
46
|
-
say "CLI smoke test"
|
|
47
|
-
./node_modules/.bin/eyeling -v
|
|
48
|
-
ok "CLI works"
|
|
49
|
-
|
|
50
|
-
say "Examples test (installed package)"
|
|
51
|
-
cd node_modules/eyeling/examples
|
|
52
|
-
./test
|
|
53
|
-
|
|
54
|
-
ok "packaged install smoke test passed"
|
|
55
|
-
|