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