]> git.proxmox.com Git - pve-eslint.git/blame - eslint/tests/lib/linter/code-path-analysis/code-path.js
first commit
[pve-eslint.git] / eslint / tests / lib / linter / code-path-analysis / code-path.js
CommitLineData
eb39fafa
DC
1/**
2 * @fileoverview Tests for CodePath.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const assert = require("assert"),
13 { Linter } = require("../../../../lib/linter");
14const linter = new Linter();
15
16//------------------------------------------------------------------------------
17// Helpers
18//------------------------------------------------------------------------------
19
20/**
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.
24 */
25function parseCodePaths(code) {
26 const retv = [];
27
28 linter.defineRule("test", () => ({
29 onCodePathStart(codePath) {
30 retv.push(codePath);
31 }
32 }));
33 linter.verify(code, { rules: { test: 2 } });
34
35 return retv;
36}
37
38/**
39 * Traverses a given code path then returns the order of traversing.
40 * @param {CodePath} codePath A code path to traverse.
41 * @param {Object|undefined} [options] The option object of
42 * `codePath.traverseSegments()` method.
43 * @param {Function|undefined} [callback] The callback function of
44 * `codePath.traverseSegments()` method.
45 * @returns {string[]} The list of segment's ids in the order traversed.
46 */
47function getOrderOfTraversing(codePath, options, callback) {
48 const retv = [];
49
50 codePath.traverseSegments(options, (segment, controller) => {
51 retv.push(segment.id);
52 if (callback) {
53 callback(segment, controller); // eslint-disable-line callback-return
54 }
55 });
56
57 return retv;
58}
59
60//------------------------------------------------------------------------------
61// Tests
62//------------------------------------------------------------------------------
63
64describe("CodePathAnalyzer", () => {
65 describe(".traverseSegments()", () => {
66 describe("should traverse segments from the first to the end:", () => {
67 /* eslint-disable internal-rules/multiline-comment-style */
68 it("simple", () => {
69 const codePath = parseCodePaths("foo(); bar(); baz();")[0];
70 const order = getOrderOfTraversing(codePath);
71
72 assert.deepStrictEqual(order, ["s1_1"]);
73
74 /*
75 digraph {
76 node[shape=box,style="rounded,filled",fillcolor=white];
77 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
78 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
79 s1_1[label="Program\nExpressionStatement\nCallExpression\nIdentifier (foo)\nExpressionStatement\nCallExpression\nIdentifier (bar)\nExpressionStatement\nCallExpression\nIdentifier (baz)"];
80 initial->s1_1->final;
81 }
82 */
83 });
84
85 it("if", () => {
86 const codePath = parseCodePaths("if (a) foo(); else bar(); baz();")[0];
87 const order = getOrderOfTraversing(codePath);
88
89 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_3", "s1_4"]);
90
91 /*
92 digraph {
93 node[shape=box,style="rounded,filled",fillcolor=white];
94 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
95 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
96 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
97 s1_2[label="ExpressionStatement\nCallExpression\nIdentifier (foo)"];
98 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
99 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
100 initial->s1_1->s1_2->s1_4;
101 s1_1->s1_3->s1_4->final;
102 }
103 */
104 });
105
106 it("switch", () => {
107 const codePath = parseCodePaths("switch (a) { case 0: foo(); break; case 1: bar(); } baz();")[0];
108 const order = getOrderOfTraversing(codePath);
109
110 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_4", "s1_5", "s1_6"]);
111
112 /*
113 digraph {
114 node[shape=box,style="rounded,filled",fillcolor=white];
115 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
116 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
117 s1_1[label="Program\nSwitchStatement\nIdentifier (a)\nSwitchCase\nLiteral (0)"];
118 s1_2[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nBreakStatement"];
119 s1_3[style="rounded,dashed,filled",fillcolor="#FF9800",label="<<unreachable>>\nSwitchCase:exit"];
120 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
121 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
122 s1_4[label="SwitchCase\nLiteral (1)"];
123 initial->s1_1->s1_2->s1_3->s1_5->s1_6;
124 s1_1->s1_4->s1_5;
125 s1_2->s1_6;
126 s1_4->s1_6->final;
127 }
128 */
129 });
130
131 it("while", () => {
132 const codePath = parseCodePaths("while (a) foo(); bar();")[0];
133 const order = getOrderOfTraversing(codePath);
134
135 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_3", "s1_4"]);
136
137 /*
138 digraph {
139 node[shape=box,style="rounded,filled",fillcolor=white];
140 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
141 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
142 s1_1[label="Program\nWhileStatement"];
143 s1_2[label="Identifier (a)"];
144 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (foo)"];
145 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
146 initial->s1_1->s1_2->s1_3->s1_2->s1_4->final;
147 }
148 */
149 });
150
151 it("for", () => {
152 const codePath = parseCodePaths("for (var i = 0; i < 10; ++i) foo(i); bar();")[0];
153 const order = getOrderOfTraversing(codePath);
154
155 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_3", "s1_4", "s1_5"]);
156
157 /*
158 digraph {
159 node[shape=box,style="rounded,filled",fillcolor=white];
160 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
161 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
162 s1_1[label="Program\nForStatement\nVariableDeclaration\nVariableDeclarator\nIdentifier (i)\nLiteral (0)"];
163 s1_2[label="BinaryExpression\nIdentifier (i)\nLiteral (10)"];
164 s1_3[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nIdentifier (i)"];
165 s1_4[label="UpdateExpression\nIdentifier (i)"];
166 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
167 initial->s1_1->s1_2->s1_3->s1_4->s1_2->s1_5->final;
168 }
169 */
170 });
171
172 it("for-in", () => {
173 const codePath = parseCodePaths("for (var key in obj) foo(key); bar();")[0];
174 const order = getOrderOfTraversing(codePath);
175
176 assert.deepStrictEqual(order, ["s1_1", "s1_3", "s1_2", "s1_4", "s1_5"]);
177
178 /*
179 digraph {
180 node[shape=box,style="rounded,filled",fillcolor=white];
181 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
182 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
183 s1_1[label="Program\nForInStatement"];
184 s1_3[label="Identifier (obj)"];
185 s1_2[label="VariableDeclaration\nVariableDeclarator\nIdentifier (key)"];
186 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (foo)\nIdentifier (key)"];
187 s1_5[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
188 initial->s1_1->s1_3->s1_2->s1_4->s1_2;
189 s1_3->s1_5;
190 s1_4->s1_5->final;
191 }
192 */
193 });
194
195 it("try-catch", () => {
196 const codePath = parseCodePaths("try { foo(); } catch (e) { bar(); } baz();")[0];
197 const order = getOrderOfTraversing(codePath);
198
199 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_3", "s1_4"]);
200
201 /*
202 digraph {
203 node[shape=box,style="rounded,filled",fillcolor=white];
204 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
205 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
206 s1_1[label="Program\nTryStatement\nBlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
207 s1_2[label="CallExpression:exit\nExpressionStatement:exit\nBlockStatement:exit"];
208 s1_3[label="CatchClause\nIdentifier (e)\nBlockStatement\nExpressionStatement\nCallExpression\nIdentifier (bar)"];
209 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (baz)"];
210 initial->s1_1->s1_2->s1_3->s1_4;
211 s1_1->s1_3;
212 s1_2->s1_4->final;
213 }
214 */
215 });
216 });
217
218 it("should traverse segments from `options.first` to `options.last`.", () => {
219 const codePath = parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
220 const order = getOrderOfTraversing(codePath, {
221 first: codePath.initialSegment.nextSegments[0],
222 last: codePath.initialSegment.nextSegments[0].nextSegments[1]
223 });
224
225 assert.deepStrictEqual(order, ["s1_2", "s1_3", "s1_4"]);
226
227 /*
228 digraph {
229 node[shape=box,style="rounded,filled",fillcolor=white];
230 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
231 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
232 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
233 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
234 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
235 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
236 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
237 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
238 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
239 s1_1->s1_5->s1_6;
240 s1_2->s1_4;
241 s1_6->final;
242 }
243 */
244 });
245
246 it("should stop immediately when 'controller.break()' was called.", () => {
247 const codePath = parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
248 const order = getOrderOfTraversing(codePath, null, (segment, controller) => {
249 if (segment.id === "s1_2") {
250 controller.break();
251 }
252 });
253
254 assert.deepStrictEqual(order, ["s1_1", "s1_2"]);
255
256 /*
257 digraph {
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\nIfStatement\nIdentifier (a)"];
262 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
263 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
264 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
265 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
266 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
267 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
268 s1_1->s1_5->s1_6;
269 s1_2->s1_4;
270 s1_6->final;
271 }
272 */
273 });
274
275 it("should skip the current branch when 'controller.skip()' was called.", () => {
276 const codePath = parseCodePaths("if (a) { if (b) { foo(); } bar(); } else { out1(); } out2();")[0];
277 const order = getOrderOfTraversing(codePath, null, (segment, controller) => {
278 if (segment.id === "s1_2") {
279 controller.skip();
280 }
281 });
282
283 assert.deepStrictEqual(order, ["s1_1", "s1_2", "s1_5", "s1_6"]);
284
285 /*
286 digraph {
287 node[shape=box,style="rounded,filled",fillcolor=white];
288 initial[label="",shape=circle,style=filled,fillcolor=black,width=0.25,height=0.25];
289 final[label="",shape=doublecircle,style=filled,fillcolor=black,width=0.25,height=0.25];
290 s1_1[label="Program\nIfStatement\nIdentifier (a)"];
291 s1_2[label="BlockStatement\nIfStatement\nIdentifier (b)"];
292 s1_3[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (foo)"];
293 s1_4[label="ExpressionStatement\nCallExpression\nIdentifier (bar)"];
294 s1_6[label="ExpressionStatement\nCallExpression\nIdentifier (out2)"];
295 s1_5[label="BlockStatement\nExpressionStatement\nCallExpression\nIdentifier (out1)"];
296 initial->s1_1->s1_2->s1_3->s1_4->s1_6;
297 s1_1->s1_5->s1_6;
298 s1_2->s1_4;
299 s1_6->final;
300 }
301 */
302 });
303
304 /* eslint-enable internal-rules/multiline-comment-style */
305 });
306});