Skip to content

Commit 51080eb

Browse files
test: processor service (#20731)
Co-authored-by: fnx <966276+DMartens@users.noreply.github.com>
1 parent 84a19d2 commit 51080eb

1 file changed

Lines changed: 225 additions & 0 deletions

File tree

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/**
2+
* @fileoverview Unit tests for the ProcessorService class.
3+
* @author Kuldeep2822k
4+
*/
5+
6+
"use strict";
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
const { ProcessorService } = require("../../../lib/services/processor-service");
13+
const { VFile } = require("../../../lib/linter/vfile");
14+
const assert = require("node:assert");
15+
const sinon = require("sinon");
16+
17+
//------------------------------------------------------------------------------
18+
// Tests
19+
//------------------------------------------------------------------------------
20+
21+
describe("ProcessorService", () => {
22+
const processorService = new ProcessorService();
23+
24+
describe("preprocessSync()", () => {
25+
it("should call preprocess with the file's raw body and file path", () => {
26+
const file = new VFile("/project/file.js", "const a = 1;");
27+
const processor = {
28+
preprocess: sinon.spy(() => []),
29+
};
30+
const config = { processor };
31+
32+
processorService.preprocessSync(file, config);
33+
34+
assert.ok(
35+
processor.preprocess.calledOnceWithExactly(
36+
file.rawBody,
37+
file.path,
38+
),
39+
"Expected preprocess to be called with file's raw body and path",
40+
);
41+
});
42+
43+
it("should return ok:true with VFile objects when preprocessor returns object blocks", () => {
44+
const file = new VFile("/project/file.md", "Hello world");
45+
const config = {
46+
processor: {
47+
preprocess() {
48+
return [
49+
{ filename: "block.js", text: "const a = 1;" },
50+
{ filename: "extra.js", text: "const b = 2;" },
51+
];
52+
},
53+
},
54+
};
55+
56+
const result = processorService.preprocessSync(file, config);
57+
58+
assert.strictEqual(result.ok, true);
59+
assert.strictEqual(result.files.length, 2);
60+
assert.ok(
61+
result.files[0] instanceof VFile,
62+
"Expected first block to be a VFile instance",
63+
);
64+
assert.ok(
65+
result.files[1] instanceof VFile,
66+
"Expected second block to be a VFile instance",
67+
);
68+
assert.ok(
69+
result.files[0].path.endsWith("0_block.js"),
70+
"Expected first VFile path to end with index-prefixed block filename",
71+
);
72+
assert.ok(
73+
result.files[1].path.endsWith("1_extra.js"),
74+
"Expected second VFile path to end with index-prefixed block filename",
75+
);
76+
assert.strictEqual(
77+
result.files[0].body,
78+
"const a = 1;",
79+
"Expected first VFile body to match block text",
80+
);
81+
assert.strictEqual(
82+
result.files[1].body,
83+
"const b = 2;",
84+
"Expected second VFile body to match block text",
85+
);
86+
});
87+
88+
it("should return ok:true with string values when preprocessor returns legacy string blocks", () => {
89+
const file = new VFile("/project/file.js", "const a = 1;");
90+
const config = {
91+
processor: {
92+
preprocess() {
93+
return ["const a = 1;", "const b = 2;"];
94+
},
95+
},
96+
};
97+
98+
const result = processorService.preprocessSync(file, config);
99+
100+
assert.strictEqual(result.ok, true);
101+
assert.strictEqual(result.files.length, 2);
102+
assert.strictEqual(result.files[0], "const a = 1;");
103+
assert.strictEqual(result.files[1], "const b = 2;");
104+
});
105+
106+
it("should return ok:false with error details when the preprocessor throws", () => {
107+
const file = new VFile("/project/file.js", "const a = 1;");
108+
const config = {
109+
processor: {
110+
preprocess() {
111+
const err = new SyntaxError("Unexpected token");
112+
113+
err.lineNumber = 3;
114+
err.column = 5;
115+
throw err;
116+
},
117+
},
118+
};
119+
120+
const result = processorService.preprocessSync(file, config);
121+
122+
assert.strictEqual(result.ok, false);
123+
assert.strictEqual(result.errors.length, 1);
124+
assert.strictEqual(result.errors[0].fatal, true);
125+
assert.strictEqual(result.errors[0].severity, 2);
126+
assert.strictEqual(result.errors[0].ruleId, null);
127+
assert.strictEqual(
128+
result.errors[0].message,
129+
"Preprocessing error: Unexpected token",
130+
"Expected message to include the original error message",
131+
);
132+
assert.strictEqual(result.errors[0].line, 3);
133+
assert.strictEqual(result.errors[0].column, 5);
134+
});
135+
136+
it("should strip leading 'line N:' prefix from preprocessor error messages", () => {
137+
const file = new VFile("/project/file.js", "const a = 1;");
138+
const config = {
139+
processor: {
140+
preprocess() {
141+
throw new SyntaxError("line 5: Unexpected token");
142+
},
143+
},
144+
};
145+
146+
const result = processorService.preprocessSync(file, config);
147+
148+
assert.strictEqual(result.ok, false);
149+
assert.ok(
150+
!result.errors[0].message.includes("line 5:"),
151+
"Expected 'line N:' prefix to be stripped from the error message",
152+
);
153+
});
154+
155+
it("should throw an error if the preprocessor returns a promise", () => {
156+
const file = new VFile("/project/file.js", "const a = 1;");
157+
const config = {
158+
processor: {
159+
preprocess() {
160+
return Promise.resolve(["const a = 1;"]);
161+
},
162+
},
163+
};
164+
165+
assert.throws(() => {
166+
processorService.preprocessSync(file, config);
167+
}, /Unsupported: Preprocessor returned a promise\./u);
168+
});
169+
});
170+
171+
describe("postprocessSync()", () => {
172+
it("should call postprocess with the messages and file path", () => {
173+
const file = new VFile("/project/file.js", "const a = 1;");
174+
const messages = [
175+
[
176+
{
177+
ruleId: "no-unused-vars",
178+
message: "'a' is defined but never used.",
179+
severity: 2,
180+
line: 1,
181+
column: 7,
182+
},
183+
],
184+
];
185+
const processor = {
186+
postprocess: sinon.spy(msgs => msgs.flat()),
187+
};
188+
const config = { processor };
189+
190+
const result = processorService.postprocessSync(
191+
file,
192+
messages,
193+
config,
194+
);
195+
196+
assert.ok(
197+
processor.postprocess.calledOnceWithExactly(
198+
messages,
199+
file.path,
200+
),
201+
"Expected postprocess to be called with messages and file path",
202+
);
203+
assert.deepStrictEqual(
204+
result,
205+
messages.flat(),
206+
"Expected postprocessed messages to be returned",
207+
);
208+
});
209+
210+
it("should not catch errors thrown by the processor's postprocess method", () => {
211+
const file = new VFile("/project/file.js", "const a = 1;");
212+
const config = {
213+
processor: {
214+
postprocess() {
215+
throw new Error("Postprocessing error");
216+
},
217+
},
218+
};
219+
220+
assert.throws(() => {
221+
processorService.postprocessSync(file, [[]], config);
222+
}, /Postprocessing error/u);
223+
});
224+
});
225+
});

0 commit comments

Comments
 (0)