-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathorchestrator.test.ts
More file actions
98 lines (84 loc) · 3.71 KB
/
Copy pathorchestrator.test.ts
File metadata and controls
98 lines (84 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import type { EmitContext, EmittedFile, EmitterStrategy } from '@camunda8/emitter-sdk';
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
import { writeEmitted } from '../../materializer/src/orchestrator.ts';
import type { EndpointScenarioCollection } from '../../path-analyser/src/types.ts';
const FIXTURE: EndpointScenarioCollection = {
endpoint: { operationId: 'createWidget', method: 'POST', path: '/widgets' },
requiredSemanticTypes: [],
optionalSemanticTypes: [],
scenarios: [],
};
function buildEmitter(files: EmittedFile[]): EmitterStrategy {
return {
id: 'stub',
name: 'stub',
supportedConfigs: ['*'],
async emit() {
return files;
},
};
}
let tmp: string;
beforeEach(() => {
tmp = mkdtempSync(path.join(tmpdir(), 'emitter-test-'));
});
afterEach(() => {
rmSync(tmp, { recursive: true, force: true });
});
const ctx = (): EmitContext => ({
outDir: tmp,
suiteName: 'createWidget',
mode: 'feature',
configName: 'test',
emitterConfig: {},
resolveConfigPath: (rel: string) => path.resolve(tmp, rel),
});
describe('orchestrator.writeEmitted', () => {
test('writes a single top-level file', async () => {
const e = buildEmitter([{ relativePath: 'createWidget.spec.ts', content: '// hello' }]);
const written = await writeEmitted(e, FIXTURE, ctx());
expect(written).toHaveLength(1);
expect(readFileSync(path.join(tmp, 'createWidget.spec.ts'), 'utf8')).toBe('// hello');
});
test('creates nested directories on demand', async () => {
const e = buildEmitter([{ relativePath: 'support/env.ts', content: '// env' }]);
await writeEmitted(e, FIXTURE, ctx());
expect(readFileSync(path.join(tmp, 'support/env.ts'), 'utf8')).toBe('// env');
});
test('writes multiple files in emit order', async () => {
const e = buildEmitter([
{ relativePath: 'a.ts', content: '1' },
{ relativePath: 'b.ts', content: '2' },
]);
const written = await writeEmitted(e, FIXTURE, ctx());
expect(written.map((p) => path.basename(p))).toEqual(['a.ts', 'b.ts']);
expect(readdirSync(tmp).sort()).toEqual(['a.ts', 'b.ts']);
});
test('rejects absolute paths returned by an emitter', async () => {
const e = buildEmitter([{ relativePath: '/etc/passwd', content: 'oops' }]);
await expect(writeEmitted(e, FIXTURE, ctx())).rejects.toThrowError(/returned absolute path/);
});
test('rejects paths that escape outDir via ..', async () => {
const e = buildEmitter([{ relativePath: '../escape.ts', content: 'oops' }]);
await expect(writeEmitted(e, FIXTURE, ctx())).rejects.toThrowError(/escapes ctx.outDir/);
});
test('rejects paths that escape outDir via a deeper .. segment', async () => {
const e = buildEmitter([{ relativePath: 'a/b/../../../escape.ts', content: 'oops' }]);
await expect(writeEmitted(e, FIXTURE, ctx())).rejects.toThrowError(/escapes ctx.outDir/);
});
test('allows a filename that contains .. as a substring (not a parent-dir segment)', async () => {
const e = buildEmitter([{ relativePath: 'foo..bar.spec.ts', content: '// ok' }]);
const written = await writeEmitted(e, FIXTURE, ctx());
expect(written).toHaveLength(1);
expect(readFileSync(path.join(tmp, 'foo..bar.spec.ts'), 'utf8')).toBe('// ok');
});
test('allows nested .. segments that resolve to a path inside outDir', async () => {
const e = buildEmitter([{ relativePath: 'a/b/../inside.ts', content: '// ok' }]);
const written = await writeEmitted(e, FIXTURE, ctx());
expect(written).toHaveLength(1);
expect(readFileSync(path.join(tmp, 'a/inside.ts'), 'utf8')).toBe('// ok');
});
});