]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/linter/code-path-analysis/code-path.js
2 * @fileoverview Tests for CodePath.
3 * @author Toru Nagashima
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const assert
= require("assert"),
13 { Linter
} = require("../../../../lib/linter");
14 const linter
= new Linter();
16 //------------------------------------------------------------------------------
18 //------------------------------------------------------------------------------
21 * Gets the code path of a given source code.
22 * @param {string} code A source code.
23 * @returns {CodePath[]} A list of created code paths.
25 function parseCodePaths(code
) {
28 linter
.defineRule("test", {
30 onCodePathStart(codePath
) {
38 parserOptions
: { ecmaVersion
: "latest" }
45 * Traverses a given code path then returns the order of traversing.
46 * @param {CodePath} codePath A code path to traverse.
47 * @param {Object|undefined} [options] The option object of
48 * `codePath.traverseSegments()` method.
49 * @param {Function|undefined} [callback] The callback function of
50 * `codePath.traverseSegments()` method.
51 * @returns {string[]} The list of segment's ids in the order traversed.
53 function getOrderOfTraversing(codePath
, options
, callback
) {
56 codePath
.traverseSegments(options
, (segment
, controller
) => {
57 retv
.push(segment
.id
);
59 callback(segment
, controller
); // eslint-disable-line n/callback-return -- At end of inner function
66 //------------------------------------------------------------------------------
68 //------------------------------------------------------------------------------
70 describe("CodePathAnalyzer", () => {
73 * If you need to output the code paths and DOT graph information for a
74 * particular piece of code, update and uncomment the following test and
76 * DEBUG=eslint:code-path npx mocha tests/lib/linter/code-path-analysis/
78 * All the information you need will be output to the console.
81 * it.only("test", () => {
82 * const codePaths = parseCodePaths("class Foo { a = () => b }");
86 describe("CodePath#origin", () => {
88 it("should be 'program' when code path starts at root node", () => {
89 const codePath
= parseCodePaths("foo(); bar(); baz();")[0];
91 assert
.strictEqual(codePath
.origin
, "program");
94 it("should be 'function' when code path starts inside a function", () => {
95 const codePath
= parseCodePaths("function foo() {}")[1];
97 assert
.strictEqual(codePath
.origin
, "function");
100 it("should be 'function' when code path starts inside an arrow function", () => {
101 const codePath
= parseCodePaths("let foo = () => {}")[1];
103 assert
.strictEqual(codePath
.origin
, "function");
106 it("should be 'class-field-initializer' when code path starts inside a class field initializer", () => {
107 const codePath
= parseCodePaths("class Foo { a=1; }")[1];
109 assert
.strictEqual(codePath
.origin
, "class-field-initializer");
112 it("should be 'class-static-block' when code path starts inside a class static block", () => {
113 const codePath
= parseCodePaths("class Foo { static { this.a=1; } }")[1];
115 assert
.strictEqual(codePath
.origin
, "class-static-block");
119 describe(".traverseSegments()", () => {
121 describe("should traverse segments from the first to the end:", () => {
122 /* eslint-disable internal-rules/multiline-comment-style -- Commenting out */
124 const codePath = parseCodePaths("foo(); bar(); baz();")[0];
125 const order = getOrderOfTraversing(codePath);
127 assert.deepStrictEqual(order, ["s1_1"]);
131 node[shape=box,style="rounded,filled",fillcolor=white];
132 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
133 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
134 s1_1[label="Program\nExpressionStatement\nCallExpression\nIdentifier (foo)\nExpressionStatement\nCallExpression\nIdentifier (bar)\nExpressionStatement\nCallExpression\nIdentifier (baz)"];
135 initial->s1_1->final;
141 const codePath
= parseCodePaths("if (a) foo(); else bar(); baz();")[0];
142 const order
= getOrderOfTraversing(codePath
);
144 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_3", "s1_4"]);
148 node[shape=box,style="rounded,filled",fillcolor=white];
149 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
150 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
151 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
152 s1_2[label="ExpressionStatement\nCallExpression\nIdentifier (foo)"];
153 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
154 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
155 initial->s1_1->s1_2->s1_4;
156 s1_1->s1_3->s1_4->final;
162 const codePath
= parseCodePaths("switch (a) { case 0: foo(); break; case 1: bar(); } baz();")[0];
163 const order
= getOrderOfTraversing(codePath
);
165 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_4", "s1_5", "s1_6"]);
169 node[shape=box,style="rounded,filled",fillcolor=white];
170 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
171 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
172 s1_1[label="Program\nSwitchStatement\nIdentifier (a)\nSwitchCase\nLiteral (0)"];
173 s1_2[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nBreakStatement"];
174 s1_3[style="rounded,dashed,filled",fillcolor="#FF9800",label="<<unreachable>>\nSwitchCase:exit"];
175 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
176 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
177 s1_4[label="SwitchCase\nLiteral (1)"];
178 initial->s1_1->s1_2->s1_3->s1_5->s1_6;
187 const codePath
= parseCodePaths("while (a) foo(); bar();")[0];
188 const order
= getOrderOfTraversing(codePath
);
190 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_3", "s1_4"]);
194 node[shape=box,style="rounded,filled",fillcolor=white];
195 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
196 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
197 s1_1[label="Program\nWhileStatement"];
198 s1_2[label="Identifier (a)"];
199 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (foo)"];
200 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
201 initial->s1_1->s1_2->s1_3->s1_2->s1_4->final;
207 const codePath
= parseCodePaths("for (var i = 0; i < 10; ++i) foo(i); bar();")[0];
208 const order
= getOrderOfTraversing(codePath
);
210 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_3", "s1_4", "s1_5"]);
214 node[shape=box,style="rounded,filled",fillcolor=white];
215 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
216 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
217 s1_1[label="Program\nForStatement\nVariableDeclaration\nVariableDeclarator\nIdentifier (i)\nLiteral (0)"];
218 s1_2[label="BinaryExpression\nIdentifier (i)\nLiteral (10)"];
219 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nIdentifier (i)"];
220 s1_4[label="UpdateExpression\nIdentifier (i)"];
221 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
222 initial->s1_1->s1_2->s1_3->s1_4->s1_2->s1_5->final;
228 const codePath
= parseCodePaths("for (var key in obj) foo(key); bar();")[0];
229 const order
= getOrderOfTraversing(codePath
);
231 assert
.deepStrictEqual(order
, ["s1_1", "s1_3", "s1_2", "s1_4", "s1_5"]);
235 node[shape=box,style="rounded,filled",fillcolor=white];
236 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
237 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
238 s1_1[label="Program\nForInStatement"];
239 s1_3[label="Identifier (obj)"];
240 s1_2[label="VariableDeclaration\nVariableDeclarator\nIdentifier (key)"];
241 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nIdentifier (key)"];
242 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
243 initial->s1_1->s1_3->s1_2->s1_4->s1_2;
250 it("try-catch", () => {
251 const codePath
= parseCodePaths("try { foo(); } catch (e) { bar(); } baz();")[0];
252 const order
= getOrderOfTraversing(codePath
);
254 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_3", "s1_4"]);
258 node[shape=box,style="rounded,filled",fillcolor=white];
259 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
260 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
261 s1_1[label="Program\nTryStatement\nBlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
262 s1_2[label="CallExpression:exit\nExpressionStatement:exit\nBlockStatement:exit"];
263 s1_3[label="CatchClause\nIdentifier (e)\nBlockStatement\nExpressionStatement\nCallExpression\nIdentifier (bar)"];
264 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
265 initial->s1_1->s1_2->s1_3->s1_4;
273 it("should traverse segments from `options.first` to `options.last`.", () => {
274 const codePath
= parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
275 const order
= getOrderOfTraversing(codePath
, {
276 first
: codePath
.initialSegment
.nextSegments
[0],
277 last
: codePath
.initialSegment
.nextSegments
[0].nextSegments
[1]
280 assert
.deepStrictEqual(order
, ["s1_2", "s1_3", "s1_4"]);
284 node[shape=box,style="rounded,filled",fillcolor=white];
285 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
286 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
287 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
288 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
289 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
290 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
291 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
292 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
293 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
301 it("should stop immediately when 'controller.break()' was called.", () => {
302 const codePath
= parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
303 const order
= getOrderOfTraversing(codePath
, null, (segment
, controller
) => {
304 if (segment
.id
=== "s1_2") {
309 assert
.deepStrictEqual(order
, ["s1_1", "s1_2"]);
313 node[shape=box,style="rounded,filled",fillcolor=white];
314 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
315 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
316 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
317 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
318 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
319 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
320 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
321 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
322 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
330 it("should skip the current branch when 'controller.skip()' was called.", () => {
331 const codePath
= parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
332 const order
= getOrderOfTraversing(codePath
, null, (segment
, controller
) => {
333 if (segment
.id
=== "s1_2") {
338 assert
.deepStrictEqual(order
, ["s1_1", "s1_2", "s1_5", "s1_6"]);
342 node[shape=box,style="rounded,filled",fillcolor=white];
343 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
344 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
345 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
346 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
347 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
348 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
349 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
350 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
351 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
359 /* eslint-enable internal-rules/multiline-comment-style -- Commenting out */