2 * @fileoverview Used for creating a suggested configuration based on project code.
3 * @author Ian VanSchooten
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
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");
17 const defaultOptions
= Object
.assign({}, baseDefaultOptions
, { cwd
: process
.cwd() });
19 //------------------------------------------------------------------------------
21 //------------------------------------------------------------------------------
23 const SOURCE_CODE_FIXTURE_FILENAME
= "./tests/fixtures/autoconfig/source.js";
24 const CONFIG_COMMENTS_FILENAME
= "./tests/fixtures/autoconfig/source-with-comments.js";
27 //------------------------------------------------------------------------------
29 //------------------------------------------------------------------------------
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 }]
42 [SEVERITY
, "backtick"],
43 [SEVERITY
, "single", "avoid-escape"],
44 [SEVERITY
, "double", "avoid-escape"],
45 [SEVERITY
, "backtick", "avoid-escape"]]
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 }]
58 describe("autoconfig", () => {
60 describe("Registry", () => {
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
);
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);
76 it("should not have any rules if constructed without a config argument", () => {
77 const registry
= new autoconfig
.Registry();
79 assert
.isObject(registry
.rules
);
80 assert
.lengthOf(Object
.keys(registry
.rules
), 0);
83 it("should create registryItems for each rule with the proper keys", () => {
84 const registry
= new autoconfig
.Registry(rulesConfig
);
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");
94 it("should populate the config property correctly", () => {
95 const registry
= new autoconfig
.Registry(rulesConfig
);
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"]);
106 it("should assign the correct specificity", () => {
107 const registry
= new autoconfig
.Registry(rulesConfig
);
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);
114 it("should initially leave the errorCount as undefined", () => {
115 const registry
= new autoconfig
.Registry(rulesConfig
);
117 assert
.isUndefined(registry
.rules
.quotes
[0].errorCount
);
118 assert
.isUndefined(registry
.rules
.quotes
[1].errorCount
);
119 assert
.isUndefined(registry
.rules
.quotes
[6].errorCount
);
122 describe("populateFromCoreRules()", () => {
124 it("should add core rules to registry", () => {
125 const registry
= new autoconfig
.Registry();
127 registry
.populateFromCoreRules();
128 const finalRuleCount
= Object
.keys(registry
.rules
).length
;
130 assert(finalRuleCount
> 0);
131 assert
.include(Object
.keys(registry
.rules
), "eqeqeq");
134 it("should not add duplicate rules", () => {
135 const registry
= new autoconfig
.Registry(rulesConfig
);
137 registry
.populateFromCoreRules();
138 const semiCount
= Object
.keys(registry
.rules
).filter(ruleId
=> ruleId
=== "semi").length
;
140 assert
.strictEqual(semiCount
, 1);
144 describe("buildRuleSets()", () => {
148 const registry
= new autoconfig
.Registry(rulesConfig
);
150 ruleSets
= registry
.buildRuleSets();
153 it("should create an array of rule configuration sets", () => {
154 assert
.isArray(ruleSets
);
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"]);
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
});
165 it("should create as many ruleSets as the highest number of configs in a rule", () => {
167 // `quotes` has 7 possible configurations
168 assert
.lengthOf(ruleSets
, 7);
172 describe("lintSourceCode()", () => {
176 const config
= { ignore
: false };
177 const sourceCode
= sourceCodeUtils
.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME
, config
);
179 registry
= new autoconfig
.Registry(rulesConfig
);
180 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
183 it("should populate the errorCount of all registryItems", () => {
184 const expectedRules
= ["semi", "semi-spacing", "quotes"];
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
);
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);
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 }
211 registry
= new autoconfig
.Registry(rulesConfig
);
212 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
214 assert
.deepStrictEqual(registry
.rules
.semi
, expectedRegistry
);
218 describe("stripFailingConfigs()", () => {
222 const config
= { ignore
: false };
223 const sourceCode
= sourceCodeUtils
.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME
, config
);
225 registry
= new autoconfig
.Registry(rulesConfig
);
226 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
227 registry
= registry
.stripFailingConfigs();
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);
237 registry
.rules
["semi-spacing"].forEach(registryItem
=> {
238 assert
.strictEqual(registryItem
.errorCount
, 0);
240 registry
.rules
.quotes
.forEach(registryItem
=> {
241 assert
.strictEqual(registryItem
.errorCount
, 0);
246 describe("getFailingRulesRegistry()", () => {
250 const config
= { ignore
: false };
251 const sourceCode
= sourceCodeUtils
.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME
, config
);
252 let registry
= new autoconfig
.Registry(errorRulesConfig
);
254 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
255 failingRegistry
= registry
.getFailingRulesRegistry();
258 it("should return a registry with no registryItems with an errorCount of zero", () => {
259 const failingRules
= Object
.keys(failingRegistry
.rules
);
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);
267 describe("createConfig()", () => {
271 const config
= { ignore
: false };
272 const sourceCode
= sourceCodeUtils
.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME
, config
);
273 let registry
= new autoconfig
.Registry(rulesConfig
);
275 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
276 registry
= registry
.stripFailingConfigs();
277 createdConfig
= registry
.createConfig();
280 it("should create a config with a rules property", () => {
281 assert
.property(createdConfig
, "rules");
284 it("should add rules which have only one registryItem to the config", () => {
285 const configuredRules
= Object
.keys(createdConfig
.rules
);
287 assert
.deepStrictEqual(configuredRules
, ["quotes"]);
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"]);
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
);
299 registry
= registry
.lintSourceCode(sourceCode
, defaultOptions
);
300 const failingRegistry
= registry
.getFailingRulesRegistry();
302 createdConfig
= failingRegistry
.createConfig();
303 const configuredRules
= Object
.keys(createdConfig
.rules
);
305 assert
.deepStrictEqual(configuredRules
, ["no-unused-vars"]);
309 describe("filterBySpecificity()", () => {
313 registry
= new autoconfig
.Registry(rulesConfig
);
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);
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);