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