eyeling 1.5.16 → 1.5.18
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 +247 -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.18",
|
|
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,247 @@
|
|
|
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 run(cmd, args, opts = {}) {
|
|
19
|
+
return cp.spawnSync(cmd, args, {
|
|
20
|
+
encoding: 'utf8',
|
|
21
|
+
maxBuffer: 200 * 1024 * 1024,
|
|
22
|
+
...opts,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function hasGit() {
|
|
27
|
+
const r = run('git', ['--version']);
|
|
28
|
+
return r.status === 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function inGitWorktree(cwd) {
|
|
32
|
+
if (!hasGit()) return false;
|
|
33
|
+
const r = run('git', ['rev-parse', '--is-inside-work-tree'], { cwd });
|
|
34
|
+
return r.status === 0 && String(r.stdout).trim() === 'true';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Expectation logic:
|
|
38
|
+
// 1) If file contains: # expect-exit: N -> use N
|
|
39
|
+
// 2) Else, if it contains "=> false" -> expect exit 2
|
|
40
|
+
// 3) Else -> expect exit 0
|
|
41
|
+
function expectedExitCode(n3Text) {
|
|
42
|
+
const m = n3Text.match(/^[ \t]*#[: ]*expect-exit:[ \t]*([0-9]+)\b/m);
|
|
43
|
+
if (m) return parseInt(m[1], 10);
|
|
44
|
+
if (/=>\s*false\b/.test(n3Text)) return 2;
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getEyelingVersion(nodePath, eyelingJsPath, cwd) {
|
|
49
|
+
const r = run(nodePath, [eyelingJsPath, '-v'], { cwd });
|
|
50
|
+
const s = (r.stdout || r.stderr || '').trim();
|
|
51
|
+
return s || 'eyeling (unknown version)';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function mkTmpDir() {
|
|
55
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'eyeling-examples-'));
|
|
56
|
+
return dir;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function rmrf(p) {
|
|
60
|
+
try { fs.rmSync(p, { recursive: true, force: true }); } catch {}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function showDiff({ IN_GIT, examplesDir, expectedPath, generatedPath, relExpectedPosix }) {
|
|
64
|
+
if (hasGit()) {
|
|
65
|
+
if (IN_GIT) {
|
|
66
|
+
// Show repo diff for the overwritten golden file
|
|
67
|
+
const d = run('git', ['diff', '--', relExpectedPosix], { cwd: examplesDir });
|
|
68
|
+
if (d.stdout) process.stdout.write(d.stdout);
|
|
69
|
+
if (d.stderr) process.stderr.write(d.stderr);
|
|
70
|
+
} else {
|
|
71
|
+
// Show no-index diff between packaged golden and generated tmp
|
|
72
|
+
const d = run('git', ['diff', '--no-index', expectedPath, generatedPath], { cwd: examplesDir });
|
|
73
|
+
// Replace tmp path in output (nice UX)
|
|
74
|
+
if (d.stdout) process.stdout.write(String(d.stdout).replaceAll(generatedPath, 'generated'));
|
|
75
|
+
if (d.stderr) process.stderr.write(String(d.stderr).replaceAll(generatedPath, 'generated'));
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
// Fallback: diff -u
|
|
79
|
+
const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
|
|
80
|
+
if (d.stdout) process.stdout.write(d.stdout);
|
|
81
|
+
if (d.stderr) process.stderr.write(d.stderr);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function main() {
|
|
86
|
+
const suiteStart = Date.now();
|
|
87
|
+
|
|
88
|
+
// test/examples.test.js -> repo root is one level up
|
|
89
|
+
const root = path.resolve(__dirname, '..');
|
|
90
|
+
const examplesDir = path.join(root, 'examples');
|
|
91
|
+
const outputDir = path.join(examplesDir, 'output');
|
|
92
|
+
const eyelingJsPath = path.join(root, 'eyeling.js');
|
|
93
|
+
const nodePath = process.execPath;
|
|
94
|
+
|
|
95
|
+
if (!fs.existsSync(examplesDir)) {
|
|
96
|
+
fail(`Cannot find examples directory: ${examplesDir}`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
if (!fs.existsSync(eyelingJsPath)) {
|
|
100
|
+
fail(`Cannot find eyeling.js: ${eyelingJsPath}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const IN_GIT = inGitWorktree(root);
|
|
105
|
+
|
|
106
|
+
const files = fs.readdirSync(examplesDir)
|
|
107
|
+
.filter(f => f.endsWith('.n3'))
|
|
108
|
+
.sort((a, b) => a.localeCompare(b));
|
|
109
|
+
|
|
110
|
+
info(
|
|
111
|
+
`Running ${files.length} examples tests (${IN_GIT ? 'git worktree mode' : 'npm-installed mode'})`
|
|
112
|
+
);
|
|
113
|
+
console.log(`${C.dim}${getEyelingVersion(nodePath, eyelingJsPath, root)}; node ${process.version}${C.n}`);
|
|
114
|
+
|
|
115
|
+
if (files.length === 0) {
|
|
116
|
+
ok('No .n3 files found in examples/');
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// In maintainer mode we overwrite tracked goldens in examples/output/
|
|
121
|
+
if (IN_GIT) fs.mkdirSync(outputDir, { recursive: true });
|
|
122
|
+
|
|
123
|
+
let passed = 0;
|
|
124
|
+
let failed = 0;
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < files.length; i++) {
|
|
127
|
+
const idx = String(i + 1).padStart(2, '0');
|
|
128
|
+
const file = files[i];
|
|
129
|
+
|
|
130
|
+
const start = Date.now();
|
|
131
|
+
|
|
132
|
+
const filePath = path.join(examplesDir, file);
|
|
133
|
+
const expectedPath = path.join(outputDir, file);
|
|
134
|
+
const relExpectedPosix = path.posix.join('output', file); // for git diff inside examplesDir
|
|
135
|
+
|
|
136
|
+
let n3Text;
|
|
137
|
+
try {
|
|
138
|
+
n3Text = fs.readFileSync(filePath, 'utf8');
|
|
139
|
+
} catch (e) {
|
|
140
|
+
const ms = Date.now() - start;
|
|
141
|
+
fail(`${idx} ${file} (${ms} ms)`);
|
|
142
|
+
fail(`Cannot read input: ${e.message}`);
|
|
143
|
+
failed++;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const expectedRc = expectedExitCode(n3Text);
|
|
148
|
+
|
|
149
|
+
// Decide where generated output goes
|
|
150
|
+
let tmpDir = null;
|
|
151
|
+
let generatedPath = expectedPath;
|
|
152
|
+
|
|
153
|
+
if (!IN_GIT) {
|
|
154
|
+
// npm-installed / no .git: never modify output/ in node_modules
|
|
155
|
+
if (!fs.existsSync(expectedPath)) {
|
|
156
|
+
const ms = Date.now() - start;
|
|
157
|
+
fail(`${idx} ${file} (${ms} ms)`);
|
|
158
|
+
fail(`Missing expected output/${file}`);
|
|
159
|
+
failed++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
tmpDir = mkTmpDir();
|
|
163
|
+
generatedPath = path.join(tmpDir, 'generated.n3');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Run eyeling on this file (cwd examplesDir so relative behavior matches old script)
|
|
167
|
+
const r = run(nodePath, [eyelingJsPath, file], { cwd: examplesDir });
|
|
168
|
+
const rc = (r.status == null) ? 1 : r.status;
|
|
169
|
+
|
|
170
|
+
// Write stdout to file (expectedPath in git mode; tmp in npm mode)
|
|
171
|
+
try {
|
|
172
|
+
fs.writeFileSync(generatedPath, r.stdout || '', 'utf8');
|
|
173
|
+
} catch (e) {
|
|
174
|
+
const ms = Date.now() - start;
|
|
175
|
+
fail(`${idx} ${file} (${ms} ms)`);
|
|
176
|
+
fail(`Cannot write output: ${e.message}`);
|
|
177
|
+
failed++;
|
|
178
|
+
if (tmpDir) rmrf(tmpDir);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const ms = Date.now() - start;
|
|
183
|
+
|
|
184
|
+
// Compare output
|
|
185
|
+
let diffOk = false;
|
|
186
|
+
if (IN_GIT) {
|
|
187
|
+
const d = run('git', ['diff', '--quiet', '--', relExpectedPosix], { cwd: examplesDir });
|
|
188
|
+
diffOk = (d.status === 0);
|
|
189
|
+
} else {
|
|
190
|
+
if (hasGit()) {
|
|
191
|
+
const d = run('git', ['diff', '--no-index', '--quiet', expectedPath, generatedPath], { cwd: examplesDir });
|
|
192
|
+
diffOk = (d.status === 0);
|
|
193
|
+
} else {
|
|
194
|
+
const d = run('diff', ['-u', expectedPath, generatedPath], { cwd: examplesDir });
|
|
195
|
+
diffOk = (d.status === 0);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const rcOk = (rc === expectedRc);
|
|
200
|
+
|
|
201
|
+
if (diffOk && rcOk) {
|
|
202
|
+
if (expectedRc === 0) {
|
|
203
|
+
ok(`${idx} ${file} (${ms} ms)`);
|
|
204
|
+
} else {
|
|
205
|
+
ok(`${idx} ${file} (expected exit ${expectedRc}, ${ms} ms)`);
|
|
206
|
+
}
|
|
207
|
+
passed++;
|
|
208
|
+
} else {
|
|
209
|
+
fail(`${idx} ${file} (${ms} ms)`);
|
|
210
|
+
if (!rcOk) {
|
|
211
|
+
fail(`Exit code ${rc}, expected ${expectedRc}`);
|
|
212
|
+
}
|
|
213
|
+
if (!diffOk) {
|
|
214
|
+
fail('Output differs');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Show diffs (both modes), because this is a test runner
|
|
218
|
+
showDiff({
|
|
219
|
+
IN_GIT,
|
|
220
|
+
examplesDir,
|
|
221
|
+
expectedPath,
|
|
222
|
+
generatedPath,
|
|
223
|
+
relExpectedPosix,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
failed++;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (tmpDir) rmrf(tmpDir);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log('');
|
|
233
|
+
const suiteMs = Date.now() - suiteStart;
|
|
234
|
+
info(`Total elapsed: ${suiteMs} ms (${(suiteMs / 1000).toFixed(2)} s)`);
|
|
235
|
+
|
|
236
|
+
if (failed === 0) {
|
|
237
|
+
ok(`All examples tests passed (${passed}/${files.length})`);
|
|
238
|
+
process.exit(0);
|
|
239
|
+
} else {
|
|
240
|
+
fail(`Some examples tests failed (${passed}/${files.length})`);
|
|
241
|
+
// keep exit code 2 (matches historical behavior of examples/test)
|
|
242
|
+
process.exit(2);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
main();
|
|
247
|
+
|
|
@@ -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
|
-
|