]> git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/init/autoconfig.js
1fa2b0476dea016e6676d59f1e76b052da17edeb
[pve-eslint.git] / eslint / tests / lib / init / autoconfig.js
1 /**
2 * @fileoverview Used for creating a suggested configuration based on project code.
3 * @author Ian VanSchooten
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const assert = require("chai").assert,
13 autoconfig = require("../../../lib/init/autoconfig"),
14 sourceCodeUtils = require("../../../lib/init/source-code-utils"),
15 baseDefaultOptions = require("../../../conf/default-cli-options"),
16 recommendedConfig = require("../../conf/eslint-recommended");
17
18 const defaultOptions = Object.assign({}, baseDefaultOptions, { cwd: process.cwd() });
19
20 //------------------------------------------------------------------------------
21 // Data
22 //------------------------------------------------------------------------------
23
24 const SOURCE_CODE_FIXTURE_FILENAME = "./tests/fixtures/autoconfig/source.js";
25 const CONFIG_COMMENTS_FILENAME = "./tests/fixtures/autoconfig/source-with-comments.js";
26 const SEVERITY = 2;
27
28 //------------------------------------------------------------------------------
29 // Tests
30 //------------------------------------------------------------------------------
31
32 const rulesConfig = {
33 semi: [SEVERITY, [SEVERITY, "always"], [SEVERITY, "never"]],
34 "semi-spacing": [SEVERITY,
35 [SEVERITY, { before: true, after: true }],
36 [SEVERITY, { before: true, after: false }],
37 [SEVERITY, { before: false, after: true }],
38 [SEVERITY, { before: false, after: false }]
39 ],
40 quotes: [SEVERITY,
41 [SEVERITY, "single"],
42 [SEVERITY, "double"],
43 [SEVERITY, "backtick"],
44 [SEVERITY, "single", "avoid-escape"],
45 [SEVERITY, "double", "avoid-escape"],
46 [SEVERITY, "backtick", "avoid-escape"]]
47 };
48
49 const errorRulesConfig = {
50 "no-unused-vars": [SEVERITY],
51 "semi-spacing": [SEVERITY,
52 [SEVERITY, { before: true, after: true }],
53 [SEVERITY, { before: true, after: false }],
54 [SEVERITY, { before: false, after: true }],
55 [SEVERITY, { before: false, after: false }]
56 ]
57 };
58
59 describe("autoconfig", () => {
60
61 describe("Registry", () => {
62
63 it("should set up a registry for rules in a provided rulesConfig", () => {
64 const expectedRules = Object.keys(rulesConfig);
65 const registry = new autoconfig.Registry(rulesConfig);
66
67 assert.strictEqual(Object.keys(registry.rules).length, 3);
68 assert.sameMembers(Object.keys(registry.rules), expectedRules);
69 assert.isArray(registry.rules.semi);
70 assert.isArray(registry.rules["semi-spacing"]);
71 assert.isArray(registry.rules.quotes);
72 assert.lengthOf(registry.rules.semi, 3);
73 assert.lengthOf(registry.rules["semi-spacing"], 5);
74 assert.lengthOf(registry.rules.quotes, 7);
75 });
76
77 it("should not have any rules if constructed without a config argument", () => {
78 const registry = new autoconfig.Registry();
79
80 assert.isObject(registry.rules);
81 assert.lengthOf(Object.keys(registry.rules), 0);
82 });
83
84 it("should create registryItems for each rule with the proper keys", () => {
85 const registry = new autoconfig.Registry(rulesConfig);
86
87 assert.isObject(registry.rules.semi[0]);
88 assert.isObject(registry.rules["semi-spacing"][0]);
89 assert.isObject(registry.rules.quotes[0]);
90 assert.property(registry.rules.semi[0], "config");
91 assert.property(registry.rules.semi[0], "specificity");
92 assert.property(registry.rules.semi[0], "errorCount");
93 });
94
95 it("should populate the config property correctly", () => {
96 const registry = new autoconfig.Registry(rulesConfig);
97
98 assert.strictEqual(registry.rules.quotes[0].config, SEVERITY);
99 assert.deepStrictEqual(registry.rules.quotes[1].config, [SEVERITY, "single"]);
100 assert.deepStrictEqual(registry.rules.quotes[2].config, [SEVERITY, "double"]);
101 assert.deepStrictEqual(registry.rules.quotes[3].config, [SEVERITY, "backtick"]);
102 assert.deepStrictEqual(registry.rules.quotes[4].config, [SEVERITY, "single", "avoid-escape"]);
103 assert.deepStrictEqual(registry.rules.quotes[5].config, [SEVERITY, "double", "avoid-escape"]);
104 assert.deepStrictEqual(registry.rules.quotes[6].config, [SEVERITY, "backtick", "avoid-escape"]);
105 });
106
107 it("should assign the correct specificity", () => {
108 const registry = new autoconfig.Registry(rulesConfig);
109
110 assert.strictEqual(registry.rules.quotes[0].specificity, 1);
111 assert.strictEqual(registry.rules.quotes[1].specificity, 2);
112 assert.strictEqual(registry.rules.quotes[6].specificity, 3);
113 });
114
115 it("should initially leave the errorCount as undefined", () => {
116 const registry = new autoconfig.Registry(rulesConfig);
117
118 assert.isUndefined(registry.rules.quotes[0].errorCount);
119 assert.isUndefined(registry.rules.quotes[1].errorCount);
120 assert.isUndefined(registry.rules.quotes[6].errorCount);
121 });
122
123 describe("populateFromCoreRules()", () => {
124
125 it("should add core rules to registry", () => {
126 const registry = new autoconfig.Registry();
127
128 registry.populateFromCoreRules();
129 const finalRuleCount = Object.keys(registry.rules).length;
130
131 assert(finalRuleCount > 0);
132 assert.include(Object.keys(registry.rules), "eqeqeq");
133 });
134
135 it("should not add duplicate rules", () => {
136 const registry = new autoconfig.Registry(rulesConfig);
137
138 registry.populateFromCoreRules();
139 const semiCount = Object.keys(registry.rules).filter(ruleId => ruleId === "semi").length;
140
141 assert.strictEqual(semiCount, 1);
142 });
143 });
144
145 describe("buildRuleSets()", () => {
146 let ruleSets;
147
148 beforeEach(() => {
149 const registry = new autoconfig.Registry(rulesConfig);
150
151 ruleSets = registry.buildRuleSets();
152 });
153
154 it("should create an array of rule configuration sets", () => {
155 assert.isArray(ruleSets);
156 });
157
158 it("should include configs for each rule (at least for the first set)", () => {
159 assert.sameMembers(Object.keys(ruleSets[0]), ["semi", "semi-spacing", "quotes"]);
160 });
161
162 it("should create the first set from default rule configs (severity only)", () => {
163 assert.deepStrictEqual(ruleSets[0], { semi: SEVERITY, "semi-spacing": SEVERITY, quotes: SEVERITY });
164 });
165
166 it("should create as many ruleSets as the highest number of configs in a rule", () => {
167
168 // `quotes` has 7 possible configurations
169 assert.lengthOf(ruleSets, 7);
170 });
171 });
172
173 describe("lintSourceCode()", () => {
174 let registry;
175
176 beforeEach(() => {
177 const config = { ignore: false };
178 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
179
180 registry = new autoconfig.Registry(rulesConfig);
181 registry = registry.lintSourceCode(sourceCode, defaultOptions);
182 });
183
184 it("should populate the errorCount of all registryItems", () => {
185 const expectedRules = ["semi", "semi-spacing", "quotes"];
186
187 assert.sameMembers(Object.keys(registry.rules), expectedRules);
188 expectedRules.forEach(ruleId => {
189 assert(registry.rules[ruleId].length > 0);
190 registry.rules[ruleId].forEach(conf => {
191 assert.isNumber(conf.errorCount);
192 });
193 });
194 });
195
196 it("should correctly set the error count of configurations", () => {
197 assert.strictEqual(registry.rules.semi[0].config, SEVERITY);
198 assert.strictEqual(registry.rules.semi[0].errorCount, 0);
199 assert.deepStrictEqual(registry.rules.semi[2].config, [SEVERITY, "never"]);
200 assert.strictEqual(registry.rules.semi[2].errorCount, 3);
201 });
202
203 it("should respect inline eslint config comments (and not crash when they make linting errors)", () => {
204 const config = { ignore: false };
205 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(CONFIG_COMMENTS_FILENAME, config);
206 const expectedRegistry = [
207 { config: 2, specificity: 1, errorCount: 3 },
208 { config: [2, "always"], specificity: 2, errorCount: 3 },
209 { config: [2, "never"], specificity: 2, errorCount: 3 }
210 ];
211
212 registry = new autoconfig.Registry(rulesConfig);
213 registry = registry.lintSourceCode(sourceCode, defaultOptions);
214
215 assert.deepStrictEqual(registry.rules.semi, expectedRegistry);
216 });
217 });
218
219 describe("stripFailingConfigs()", () => {
220 let registry;
221
222 beforeEach(() => {
223 const config = { ignore: false };
224 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
225
226 registry = new autoconfig.Registry(rulesConfig);
227 registry = registry.lintSourceCode(sourceCode, defaultOptions);
228 registry = registry.stripFailingConfigs();
229 });
230
231 it("should remove all registryItems with a non-zero errorCount", () => {
232 assert.lengthOf(registry.rules.semi, 2);
233 assert.lengthOf(registry.rules["semi-spacing"], 3);
234 assert.lengthOf(registry.rules.quotes, 1);
235 registry.rules.semi.forEach(registryItem => {
236 assert.strictEqual(registryItem.errorCount, 0);
237 });
238 registry.rules["semi-spacing"].forEach(registryItem => {
239 assert.strictEqual(registryItem.errorCount, 0);
240 });
241 registry.rules.quotes.forEach(registryItem => {
242 assert.strictEqual(registryItem.errorCount, 0);
243 });
244 });
245 });
246
247 describe("getFailingRulesRegistry()", () => {
248 let failingRegistry;
249
250 beforeEach(() => {
251 const config = { ignore: false };
252 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
253 let registry = new autoconfig.Registry(errorRulesConfig);
254
255 registry = registry.lintSourceCode(sourceCode, defaultOptions);
256 failingRegistry = registry.getFailingRulesRegistry();
257 });
258
259 it("should return a registry with no registryItems with an errorCount of zero", () => {
260 const failingRules = Object.keys(failingRegistry.rules);
261
262 assert.deepStrictEqual(failingRules, ["no-unused-vars"]);
263 assert.lengthOf(failingRegistry.rules["no-unused-vars"], 1);
264 assert(failingRegistry.rules["no-unused-vars"][0].errorCount > 0);
265 });
266 });
267
268 describe("createConfig()", () => {
269 let createdConfig;
270
271 beforeEach(() => {
272 const config = { ignore: false };
273 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
274 let registry = new autoconfig.Registry(rulesConfig);
275
276 registry = registry.lintSourceCode(sourceCode, defaultOptions);
277 registry = registry.stripFailingConfigs();
278 createdConfig = registry.createConfig();
279 });
280
281 it("should create a config with a rules property", () => {
282 assert.property(createdConfig, "rules");
283 });
284
285 it("should add rules which have only one registryItem to the config", () => {
286 const configuredRules = Object.keys(createdConfig.rules);
287
288 assert.deepStrictEqual(configuredRules, ["quotes"]);
289 });
290
291 it("should set the configuration of the rule to the registryItem's `config` value", () => {
292 assert.deepStrictEqual(createdConfig.rules.quotes, [2, "double", "avoid-escape"]);
293 });
294
295 it("should not care how many errors the config has", () => {
296 const config = { ignore: false };
297 const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
298 let registry = new autoconfig.Registry(errorRulesConfig);
299
300 registry = registry.lintSourceCode(sourceCode, defaultOptions);
301 const failingRegistry = registry.getFailingRulesRegistry();
302
303 createdConfig = failingRegistry.createConfig();
304 const configuredRules = Object.keys(createdConfig.rules);
305
306 assert.deepStrictEqual(configuredRules, ["no-unused-vars"]);
307 });
308 });
309
310 describe("filterBySpecificity()", () => {
311 let registry;
312
313 beforeEach(() => {
314 registry = new autoconfig.Registry(rulesConfig);
315 });
316
317 it("should return a registry where all configs have a desired specificity", () => {
318 const filteredRegistry1 = registry.filterBySpecificity(1);
319 const filteredRegistry2 = registry.filterBySpecificity(2);
320 const filteredRegistry3 = registry.filterBySpecificity(3);
321
322 assert.lengthOf(filteredRegistry1.rules.semi, 1);
323 assert.lengthOf(filteredRegistry1.rules["semi-spacing"], 1);
324 assert.lengthOf(filteredRegistry1.rules.quotes, 1);
325 assert.lengthOf(filteredRegistry2.rules.semi, 2);
326 assert.lengthOf(filteredRegistry2.rules["semi-spacing"], 4);
327 assert.lengthOf(filteredRegistry2.rules.quotes, 3);
328 assert.lengthOf(filteredRegistry3.rules.quotes, 3);
329 });
330 });
331 });
332
333 describe("extendFromRecommended()", () => {
334 it("should return a configuration which has `extends` key with Array type value", () => {
335 const oldConfig = { extends: [], rules: {} };
336 const newConfig = autoconfig.extendFromRecommended(oldConfig);
337
338 assert.exists(newConfig.extends);
339 assert.isArray(newConfig.extends);
340 });
341
342 it("should return a configuration which has array property `extends`", () => {
343 const oldConfig = { extends: [], rules: {} };
344 const newConfig = autoconfig.extendFromRecommended(oldConfig);
345
346 assert.include(newConfig.extends, "eslint:recommended");
347 });
348
349 it("should return a configuration which preserves the previous extending configurations", () => {
350 const oldConfig = { extends: ["previous:configuration1", "previous:configuration2"], rules: {} };
351 const newConfig = autoconfig.extendFromRecommended(oldConfig);
352
353 assert.includeMembers(newConfig.extends, oldConfig.extends);
354 });
355
356 it("should return a configuration which has `eslint:recommended` at the first of `extends`", () => {
357 const oldConfig = { extends: ["previous:configuration1", "previous:configuration2"], rules: {} };
358 const newConfig = autoconfig.extendFromRecommended(oldConfig);
359 const [firstExtendInNewConfig] = newConfig.extends;
360
361 assert.strictEqual(firstExtendInNewConfig, "eslint:recommended");
362 });
363
364 it("should return a configuration which not includes rules configured in `eslint:recommended`", () => {
365 const oldConfig = { extends: [], rules: { ...recommendedConfig.rules } };
366 const newConfig = autoconfig.extendFromRecommended(oldConfig);
367
368 assert.notInclude(newConfig.rules, oldConfig.rules);
369 });
370 });
371 });