]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/rules/utils/ast-utils.js
2 * @fileoverview Tests for ast utils.
3 * @author Gyandeep Singh
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
12 const assert
= require("chai").assert
,
13 espree
= require("espree"),
14 astUtils
= require("../../../../lib/rules/utils/ast-utils"),
15 { Linter
} = require("../../../../lib/linter"),
16 { SourceCode
} = require("../../../../lib/source-code");
18 //------------------------------------------------------------------------------
20 //------------------------------------------------------------------------------
22 const ESPREE_CONFIG
= {
29 const linter
= new Linter();
31 describe("ast-utils", () => {
35 callCounts
= new Map();
39 * Asserts that a given function is called at least once during a test
40 * @param {Function} func The function that must be called at least once
41 * @returns {Function} A wrapper around the same function
43 function mustCall(func
) {
44 callCounts
.set(func
, 0);
45 return function Wrapper(...args
) {
46 callCounts
.set(func
, callCounts
.get(func
) + 1);
48 return func
.call(this, ...args
);
53 callCounts
.forEach((callCount
, func
) => {
56 `Expected ${func.toString()} to be called at least once but it was not called`
61 describe("isTokenOnSameLine", () => {
62 it("should return false if the tokens are not on the same line", () => {
63 linter
.defineRule("checker", mustCall(context
=> ({
64 BlockStatement
: mustCall(node
=> {
65 assert
.isFalse(astUtils
.isTokenOnSameLine(context
.getTokenBefore(node
), node
));
69 linter
.verify("if(a)\n{}", { rules
: { checker
: "error" } });
72 it("should return true if the tokens are on the same line", () => {
74 linter
.defineRule("checker", mustCall(context
=> ({
75 BlockStatement
: mustCall(node
=> {
76 assert
.isTrue(astUtils
.isTokenOnSameLine(context
.getTokenBefore(node
), node
));
80 linter
.verify("if(a){}", { rules
: { checker
: "error" } });
84 describe("isNullOrUndefined", () => {
85 it("should return true if the argument is null", () => {
86 assert
.isTrue(astUtils
.isNullOrUndefined(espree
.parse("null").body
[0].expression
));
89 it("should return true if the argument is undefined", () => {
90 assert
.isTrue(astUtils
.isNullOrUndefined(espree
.parse("undefined").body
[0].expression
));
93 it("should return false if the argument is a number", () => {
94 assert
.isFalse(astUtils
.isNullOrUndefined(espree
.parse("1").body
[0].expression
));
97 it("should return false if the argument is a string", () => {
98 assert
.isFalse(astUtils
.isNullOrUndefined(espree
.parse("'test'").body
[0].expression
));
101 it("should return false if the argument is a boolean", () => {
102 assert
.isFalse(astUtils
.isNullOrUndefined(espree
.parse("true").body
[0].expression
));
105 it("should return false if the argument is an object", () => {
106 assert
.isFalse(astUtils
.isNullOrUndefined(espree
.parse("({})").body
[0].expression
));
109 it("should return false if the argument is a unicode regex", () => {
110 assert
.isFalse(astUtils
.isNullOrUndefined(espree
.parse("/abc/u", { ecmaVersion
: 6 }).body
[0].expression
));
114 describe("checkReference", () => {
117 it("should return true if reference is assigned for catch", () => {
118 linter
.defineRule("checker", mustCall(context
=> ({
119 CatchClause
: mustCall(node
=> {
120 const variables
= context
.getDeclaredVariables(node
);
122 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[0].references
), 1);
126 linter
.verify("try { } catch (e) { e = 10; }", { rules
: { checker
: "error" } });
130 it("should return true if reference is assigned for const", () => {
131 linter
.defineRule("checker", mustCall(context
=> ({
132 VariableDeclaration
: mustCall(node
=> {
133 const variables
= context
.getDeclaredVariables(node
);
135 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[0].references
), 1);
139 linter
.verify("const a = 1; a = 2;", { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 6 } });
142 it("should return false if reference is not assigned for const", () => {
143 linter
.defineRule("checker", mustCall(context
=> ({
144 VariableDeclaration
: mustCall(node
=> {
145 const variables
= context
.getDeclaredVariables(node
);
147 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[0].references
), 0);
151 linter
.verify("const a = 1; c = 2;", { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 6 } });
155 it("should return true if reference is assigned for class", () => {
156 linter
.defineRule("checker", mustCall(context
=> ({
157 ClassDeclaration
: mustCall(node
=> {
158 const variables
= context
.getDeclaredVariables(node
);
160 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[0].references
), 1);
161 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[1].references
), 0);
165 linter
.verify("class A { }\n A = 1;", { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 6 } });
168 it("should return false if reference is not assigned for class", () => {
169 linter
.defineRule("checker", mustCall(context
=> ({
170 ClassDeclaration
: mustCall(node
=> {
171 const variables
= context
.getDeclaredVariables(node
);
173 assert
.lengthOf(astUtils
.getModifyingReferences(variables
[0].references
), 0);
177 linter
.verify("class A { } foo(A);", { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 6 } });
181 describe("isDirectiveComment", () => {
184 * Asserts the node is NOT a directive comment
185 * @param {ASTNode} node node to assert
189 function assertFalse(node
) {
190 assert
.isFalse(astUtils
.isDirectiveComment(node
));
194 * Asserts the node is a directive comment
195 * @param {ASTNode} node node to assert
199 function assertTrue(node
) {
200 assert
.isTrue(astUtils
.isDirectiveComment(node
));
203 it("should return false if it is not a directive line comment", () => {
205 "// lalala I'm a normal comment",
206 "// trying to confuse eslint ",
207 "//trying to confuse eslint-directive-detection",
208 "//eslint is awesome"
210 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
211 const sourceCode
= new SourceCode(code
, ast
);
212 const comments
= sourceCode
.getAllComments();
214 comments
.forEach(assertFalse
);
217 it("should return false if it is not a directive block comment", () => {
219 "/* lalala I'm a normal comment */",
220 "/* trying to confuse eslint */",
221 "/* trying to confuse eslint-directive-detection */",
222 "/*eSlInT is awesome*/"
224 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
225 const sourceCode
= new SourceCode(code
, ast
);
226 const comments
= sourceCode
.getAllComments();
228 comments
.forEach(assertFalse
);
231 it("should return true if it is a directive line comment", () => {
233 "// eslint-disable-line no-undef",
234 "// eslint-secret-directive 4 8 15 16 23 42 ",
235 "// eslint-directive-without-argument",
236 "//eslint-directive-without-padding"
238 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
239 const sourceCode
= new SourceCode(code
, ast
);
240 const comments
= sourceCode
.getAllComments();
242 comments
.forEach(assertTrue
);
245 it("should return true if it is a directive block comment", () => {
247 "/* eslint-disable no-undef */",
248 "/*eslint-enable no-undef*/",
249 "/* eslint-env {\"es6\": true} */",
253 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
254 const sourceCode
= new SourceCode(code
, ast
);
255 const comments
= sourceCode
.getAllComments();
257 comments
.forEach(assertTrue
);
261 describe("isParenthesised", () => {
262 it("should return false for not parenthesised nodes", () => {
263 const code
= "condition ? 1 : 2";
264 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
265 const sourceCode
= new SourceCode(code
, ast
);
267 assert
.isFalse(astUtils
.isParenthesised(sourceCode
, ast
.body
[0].expression
));
270 it("should return true for not parenthesised nodes", () => {
271 const code
= "(condition ? 1 : 2)";
272 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
273 const sourceCode
= new SourceCode(code
, ast
);
275 assert
.isTrue(astUtils
.isParenthesised(sourceCode
, ast
.body
[0].expression
));
279 describe("isFunction", () => {
280 it("should return true for FunctionDeclaration", () => {
281 const ast
= espree
.parse("function a() {}");
282 const node
= ast
.body
[0];
284 assert(astUtils
.isFunction(node
));
287 it("should return true for FunctionExpression", () => {
288 const ast
= espree
.parse("(function a() {})");
289 const node
= ast
.body
[0].expression
;
291 assert(astUtils
.isFunction(node
));
294 it("should return true for AllowFunctionExpression", () => {
295 const ast
= espree
.parse("(() => {})", { ecmaVersion
: 6 });
296 const node
= ast
.body
[0].expression
;
298 assert(astUtils
.isFunction(node
));
301 it("should return false for Program, VariableDeclaration, BlockStatement", () => {
302 const ast
= espree
.parse("var a; { }");
304 assert(!astUtils
.isFunction(ast
));
305 assert(!astUtils
.isFunction(ast
.body
[0]));
306 assert(!astUtils
.isFunction(ast
.body
[1]));
310 describe("isLoop", () => {
311 it("should return true for DoWhileStatement", () => {
312 const ast
= espree
.parse("do {} while (a)");
313 const node
= ast
.body
[0];
315 assert(astUtils
.isLoop(node
));
318 it("should return true for ForInStatement", () => {
319 const ast
= espree
.parse("for (var k in obj) {}");
320 const node
= ast
.body
[0];
322 assert(astUtils
.isLoop(node
));
325 it("should return true for ForOfStatement", () => {
326 const ast
= espree
.parse("for (var x of list) {}", { ecmaVersion
: 6 });
327 const node
= ast
.body
[0];
329 assert(astUtils
.isLoop(node
));
332 it("should return true for ForStatement", () => {
333 const ast
= espree
.parse("for (var i = 0; i < 10; ++i) {}");
334 const node
= ast
.body
[0];
336 assert(astUtils
.isLoop(node
));
339 it("should return true for WhileStatement", () => {
340 const ast
= espree
.parse("while (a) {}");
341 const node
= ast
.body
[0];
343 assert(astUtils
.isLoop(node
));
346 it("should return false for Program, VariableDeclaration, BlockStatement", () => {
347 const ast
= espree
.parse("var a; { }");
349 assert(!astUtils
.isLoop(ast
));
350 assert(!astUtils
.isLoop(ast
.body
[0]));
351 assert(!astUtils
.isLoop(ast
.body
[1]));
355 describe("isInLoop", () => {
358 * Asserts that the unique node of the given type in the code is either
359 * in a loop or not in a loop.
360 * @param {string} code the code to check.
361 * @param {string} nodeType the type of the node to consider. The code
362 * must have exactly one node of ths type.
363 * @param {boolean} expectedInLoop the expected result for whether the
367 function assertNodeTypeInLoop(code
, nodeType
, expectedInLoop
) {
370 linter
.defineRule("checker", mustCall(() => ({
371 [nodeType
]: mustCall(node
=> {
372 results
.push(astUtils
.isInLoop(node
));
375 linter
.verify(code
, { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 6 } });
377 assert
.lengthOf(results
, 1);
378 assert
.strictEqual(results
[0], expectedInLoop
);
381 it("should return true for a loop itself", () => {
382 assertNodeTypeInLoop("while (a) {}", "WhileStatement", true);
385 it("should return true for a loop condition", () => {
386 assertNodeTypeInLoop("while (a) {}", "Identifier", true);
389 it("should return true for a loop assignee", () => {
390 assertNodeTypeInLoop("for (var a in b) {}", "VariableDeclaration", true);
393 it("should return true for a node within a loop body", () => {
394 assertNodeTypeInLoop("for (var a of b) { console.log('Hello'); }", "Literal", true);
397 it("should return false for a node outside a loop body", () => {
398 assertNodeTypeInLoop("while (true) {} a(b);", "CallExpression", false);
401 it("should return false when the loop is not in the current function", () => {
402 assertNodeTypeInLoop("while (true) { funcs.push(() => { var a; }); }", "VariableDeclaration", false);
406 describe("getStaticStringValue", () => {
408 /* eslint-disable quote-props */
409 const expectedResults
= {
435 "12.34e5": "1234000",
436 "12.34e-5": "0.0001234",
449 "/[0-9]/": "/[0-9]/",
450 "/(?<zero>0)/": "/(?<zero>0)/",
451 "/(?<zero>0)/s": "/(?<zero>0)/s",
452 "/(?<=a)b/s": "/(?<=a)b/s",
454 // simple template literals
470 "(function () {})": null
472 /* eslint-enable quote-props */
474 Object
.keys(expectedResults
).forEach(key
=> {
475 it(`should return ${expectedResults[key]} for ${key}`, () => {
476 const ast
= espree
.parse(key
, { ecmaVersion
: 2018 });
478 assert
.strictEqual(astUtils
.getStaticStringValue(ast
.body
[0].expression
), expectedResults
[key
]);
483 describe("getStaticPropertyName", () => {
484 it("should return 'b' for `a.b`", () => {
485 const ast
= espree
.parse("a.b");
486 const node
= ast
.body
[0].expression
;
488 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
491 it("should return 'b' for `a['b']`", () => {
492 const ast
= espree
.parse("a['b']");
493 const node
= ast
.body
[0].expression
;
495 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
498 it("should return 'b' for `a[`b`]`", () => {
499 const ast
= espree
.parse("a[`b`]", { ecmaVersion
: 6 });
500 const node
= ast
.body
[0].expression
;
502 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
505 it("should return '100' for `a[100]`", () => {
506 const ast
= espree
.parse("a[100]");
507 const node
= ast
.body
[0].expression
;
509 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "100");
512 it("should return null for `a[b]`", () => {
513 const ast
= espree
.parse("a[b]");
514 const node
= ast
.body
[0].expression
;
516 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
519 it("should return null for `a['a' + 'b']`", () => {
520 const ast
= espree
.parse("a['a' + 'b']");
521 const node
= ast
.body
[0].expression
;
523 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
526 it("should return null for `a[tag`b`]`", () => {
527 const ast
= espree
.parse("a[tag`b`]", { ecmaVersion
: 6 });
528 const node
= ast
.body
[0].expression
;
530 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
533 it("should return null for `a[`${b}`]`", () => {
534 const ast
= espree
.parse("a[`${b}`]", { ecmaVersion
: 6 });
535 const node
= ast
.body
[0].expression
;
537 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
540 it("should return 'b' for `b: 1`", () => {
541 const ast
= espree
.parse("({b: 1})");
542 const node
= ast
.body
[0].expression
.properties
[0];
544 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
547 it("should return 'b' for `b() {}`", () => {
548 const ast
= espree
.parse("({b() {}})", { ecmaVersion
: 6 });
549 const node
= ast
.body
[0].expression
.properties
[0];
551 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
554 it("should return 'b' for `get b() {}`", () => {
555 const ast
= espree
.parse("({get b() {}})", { ecmaVersion
: 6 });
556 const node
= ast
.body
[0].expression
.properties
[0];
558 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
561 it("should return 'b' for `['b']: 1`", () => {
562 const ast
= espree
.parse("({['b']: 1})", { ecmaVersion
: 6 });
563 const node
= ast
.body
[0].expression
.properties
[0];
565 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
568 it("should return 'b' for `['b']() {}`", () => {
569 const ast
= espree
.parse("({['b']() {}})", { ecmaVersion
: 6 });
570 const node
= ast
.body
[0].expression
.properties
[0];
572 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
575 it("should return 'b' for `[`b`]: 1`", () => {
576 const ast
= espree
.parse("({[`b`]: 1})", { ecmaVersion
: 6 });
577 const node
= ast
.body
[0].expression
.properties
[0];
579 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "b");
582 it("should return '100' for` [100]: 1`", () => {
583 const ast
= espree
.parse("({[100]: 1})", { ecmaVersion
: 6 });
584 const node
= ast
.body
[0].expression
.properties
[0];
586 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "100");
589 it("should return '/(?<zero>0)/' for `[/(?<zero>0)/]: 1`", () => {
590 const ast
= espree
.parse("({[/(?<zero>0)/]: 1})", { ecmaVersion
: 2018 });
591 const node
= ast
.body
[0].expression
.properties
[0];
593 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), "/(?<zero>0)/");
596 it("should return null for `[b]: 1`", () => {
597 const ast
= espree
.parse("({[b]: 1})", { ecmaVersion
: 6 });
598 const node
= ast
.body
[0].expression
.properties
[0];
600 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
603 it("should return null for `['a' + 'b']: 1`", () => {
604 const ast
= espree
.parse("({['a' + 'b']: 1})", { ecmaVersion
: 6 });
605 const node
= ast
.body
[0].expression
.properties
[0];
607 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
610 it("should return null for `[tag`b`]: 1`", () => {
611 const ast
= espree
.parse("({[tag`b`]: 1})", { ecmaVersion
: 6 });
612 const node
= ast
.body
[0].expression
.properties
[0];
614 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
617 it("should return null for `[`${b}`]: 1`", () => {
618 const ast
= espree
.parse("({[`${b}`]: 1})", { ecmaVersion
: 6 });
619 const node
= ast
.body
[0].expression
.properties
[0];
621 assert
.strictEqual(astUtils
.getStaticPropertyName(node
), null);
624 it("should return null for non member expressions", () => {
625 const ast
= espree
.parse("foo()");
627 assert
.strictEqual(astUtils
.getStaticPropertyName(ast
.body
[0].expression
), null);
628 assert
.strictEqual(astUtils
.getStaticPropertyName(ast
.body
[0]), null);
629 assert
.strictEqual(astUtils
.getStaticPropertyName(ast
.body
), null);
630 assert
.strictEqual(astUtils
.getStaticPropertyName(ast
), null);
631 assert
.strictEqual(astUtils
.getStaticPropertyName(null), null);
635 describe("getDirectivePrologue", () => {
636 it("should return empty array if node is not a Program, FunctionDeclaration, FunctionExpression, or ArrowFunctionExpression", () => {
637 const ast
= espree
.parse("if (a) { b(); }");
638 const node
= ast
.body
[0];
640 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
643 it("should return empty array if node is a braceless ArrowFunctionExpression node", () => {
644 const ast
= espree
.parse("var foo = () => 'use strict';", { ecmaVersion
: 6 });
645 const node
= ast
.body
[0].declarations
[0].init
;
647 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
650 it("should return empty array if there are no directives in Program body", () => {
651 const ast
= espree
.parse("var foo;");
654 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
657 it("should return empty array if there are no directives in FunctionDeclaration body", () => {
658 const ast
= espree
.parse("function foo() { return bar; }");
659 const node
= ast
.body
[0];
661 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
664 it("should return empty array if there are no directives in FunctionExpression body", () => {
665 const ast
= espree
.parse("var foo = function() { return bar; }");
666 const node
= ast
.body
[0].declarations
[0].init
;
668 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
671 it("should return empty array if there are no directives in ArrowFunctionExpression body", () => {
672 const ast
= espree
.parse("var foo = () => { return bar; };", { ecmaVersion
: 6 });
673 const node
= ast
.body
[0].declarations
[0].init
;
675 assert
.deepStrictEqual(astUtils
.getDirectivePrologue(node
), []);
678 it("should return directives in Program body", () => {
679 const ast
= espree
.parse("'use strict'; 'use asm'; var foo;");
680 const result
= astUtils
.getDirectivePrologue(ast
);
682 assert
.strictEqual(result
.length
, 2);
683 assert
.strictEqual(result
[0].expression
.value
, "use strict");
684 assert
.strictEqual(result
[1].expression
.value
, "use asm");
687 it("should return directives in FunctionDeclaration body", () => {
688 const ast
= espree
.parse("function foo() { 'use strict'; 'use asm'; return bar; }");
689 const result
= astUtils
.getDirectivePrologue(ast
.body
[0]);
691 assert
.strictEqual(result
.length
, 2);
692 assert
.strictEqual(result
[0].expression
.value
, "use strict");
693 assert
.strictEqual(result
[1].expression
.value
, "use asm");
696 it("should return directives in FunctionExpression body", () => {
697 const ast
= espree
.parse("var foo = function() { 'use strict'; 'use asm'; return bar; }");
698 const result
= astUtils
.getDirectivePrologue(ast
.body
[0].declarations
[0].init
);
700 assert
.strictEqual(result
.length
, 2);
701 assert
.strictEqual(result
[0].expression
.value
, "use strict");
702 assert
.strictEqual(result
[1].expression
.value
, "use asm");
705 it("should return directives in ArrowFunctionExpression body", () => {
706 const ast
= espree
.parse("var foo = () => { 'use strict'; 'use asm'; return bar; };", { ecmaVersion
: 6 });
707 const result
= astUtils
.getDirectivePrologue(ast
.body
[0].declarations
[0].init
);
709 assert
.strictEqual(result
.length
, 2);
710 assert
.strictEqual(result
[0].expression
.value
, "use strict");
711 assert
.strictEqual(result
[1].expression
.value
, "use asm");
716 const expectedResults
= {
728 describe("isDecimalInteger", () => {
729 Object
.keys(expectedResults
).forEach(key
=> {
730 it(`should return ${expectedResults[key]} for ${key}`, () => {
731 assert
.strictEqual(astUtils
.isDecimalInteger(espree
.parse(key
).body
[0].expression
), expectedResults
[key
]);
736 describe("isDecimalIntegerNumericToken", () => {
737 Object
.keys(expectedResults
).forEach(key
=> {
738 it(`should return ${expectedResults[key]} for ${key}`, () => {
739 assert
.strictEqual(astUtils
.isDecimalIntegerNumericToken(espree
.tokenize(key
)[0]), expectedResults
[key
]);
745 describe("getFunctionNameWithKind", () => {
746 const expectedResults
= {
747 "function foo() {}": "function 'foo'",
748 "(function foo() {})": "function 'foo'",
749 "(function() {})": "function",
750 "function* foo() {}": "generator function 'foo'",
751 "(function* foo() {})": "generator function 'foo'",
752 "(function*() {})": "generator function",
753 "() => {}": "arrow function",
754 "async () => {}": "async arrow function",
755 "({ foo: function foo() {} })": "method 'foo'",
756 "({ foo: function() {} })": "method 'foo'",
757 "({ '': function() {} })": "method ''",
758 "({ ['foo']: function() {} })": "method 'foo'",
759 "({ ['']: function() {} })": "method ''",
760 "({ [foo]: function() {} })": "method",
761 "({ foo() {} })": "method 'foo'",
762 "({ foo: function* foo() {} })": "generator method 'foo'",
763 "({ foo: function*() {} })": "generator method 'foo'",
764 "({ ['foo']: function*() {} })": "generator method 'foo'",
765 "({ [foo]: function*() {} })": "generator method",
766 "({ *foo() {} })": "generator method 'foo'",
767 "({ foo: async function foo() {} })": "async method 'foo'",
768 "({ foo: async function() {} })": "async method 'foo'",
769 "({ ['foo']: async function() {} })": "async method 'foo'",
770 "({ [foo]: async function() {} })": "async method",
771 "({ async foo() {} })": "async method 'foo'",
772 "({ get foo() {} })": "getter 'foo'",
773 "({ set foo(a) {} })": "setter 'foo'",
774 "class A { constructor() {} }": "constructor",
775 "class A { foo() {} }": "method 'foo'",
776 "class A { *foo() {} }": "generator method 'foo'",
777 "class A { async foo() {} }": "async method 'foo'",
778 "class A { ['foo']() {} }": "method 'foo'",
779 "class A { *['foo']() {} }": "generator method 'foo'",
780 "class A { async ['foo']() {} }": "async method 'foo'",
781 "class A { [foo]() {} }": "method",
782 "class A { *[foo]() {} }": "generator method",
783 "class A { async [foo]() {} }": "async method",
784 "class A { get foo() {} }": "getter 'foo'",
785 "class A { set foo(a) {} }": "setter 'foo'",
786 "class A { static foo() {} }": "static method 'foo'",
787 "class A { static *foo() {} }": "static generator method 'foo'",
788 "class A { static async foo() {} }": "static async method 'foo'",
789 "class A { static get foo() {} }": "static getter 'foo'",
790 "class A { static set foo(a) {} }": "static setter 'foo'"
793 Object
.keys(expectedResults
).forEach(key
=> {
794 it(`should return "${expectedResults[key]}" for "${key}".`, () => {
795 linter
.defineRule("checker", mustCall(() => ({
796 ":function": mustCall(node
=> {
798 astUtils
.getFunctionNameWithKind(node
),
804 linter
.verify(key
, { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 8 } });
809 describe("getFunctionHeadLoc", () => {
810 const expectedResults
= {
811 "function foo() {}": [0, 12],
812 "(function foo() {})": [1, 13],
813 "(function() {})": [1, 9],
814 "function* foo() {}": [0, 13],
815 "(function* foo() {})": [1, 14],
816 "(function*() {})": [1, 10],
818 "async () => {}": [9, 11],
819 "({ foo: function foo() {} })": [3, 20],
820 "({ foo: function() {} })": [3, 16],
821 "({ ['foo']: function() {} })": [3, 20],
822 "({ [foo]: function() {} })": [3, 18],
823 "({ foo() {} })": [3, 6],
824 "({ foo: function* foo() {} })": [3, 21],
825 "({ foo: function*() {} })": [3, 17],
826 "({ ['foo']: function*() {} })": [3, 21],
827 "({ [foo]: function*() {} })": [3, 19],
828 "({ *foo() {} })": [3, 7],
829 "({ foo: async function foo() {} })": [3, 26],
830 "({ foo: async function() {} })": [3, 22],
831 "({ ['foo']: async function() {} })": [3, 26],
832 "({ [foo]: async function() {} })": [3, 24],
833 "({ async foo() {} })": [3, 12],
834 "({ get foo() {} })": [3, 10],
835 "({ set foo(a) {} })": [3, 10],
836 "class A { constructor() {} }": [10, 21],
837 "class A { foo() {} }": [10, 13],
838 "class A { *foo() {} }": [10, 14],
839 "class A { async foo() {} }": [10, 19],
840 "class A { ['foo']() {} }": [10, 17],
841 "class A { *['foo']() {} }": [10, 18],
842 "class A { async ['foo']() {} }": [10, 23],
843 "class A { [foo]() {} }": [10, 15],
844 "class A { *[foo]() {} }": [10, 16],
845 "class A { async [foo]() {} }": [10, 21],
846 "class A { get foo() {} }": [10, 17],
847 "class A { set foo(a) {} }": [10, 17],
848 "class A { static foo() {} }": [10, 20],
849 "class A { static *foo() {} }": [10, 21],
850 "class A { static async foo() {} }": [10, 26],
851 "class A { static get foo() {} }": [10, 24],
852 "class A { static set foo(a) {} }": [10, 24]
855 Object
.keys(expectedResults
).forEach(key
=> {
856 const expectedLoc
= {
859 column
: expectedResults
[key
][0]
863 column
: expectedResults
[key
][1]
867 it(`should return "${JSON.stringify(expectedLoc)}" for "${key}".`, () => {
868 linter
.defineRule("checker", mustCall(() => ({
869 ":function": mustCall(node
=> {
870 assert
.deepStrictEqual(
871 astUtils
.getFunctionHeadLoc(node
, linter
.getSourceCode()),
877 linter
.verify(key
, { rules
: { checker
: "error" }, parserOptions
: { ecmaVersion
: 8 } }, "test.js", true);
882 describe("isEmptyBlock", () => {
883 const expectedResults
= {
889 Object
.keys(expectedResults
).forEach(key
=> {
890 it(`should return ${expectedResults[key]} for ${key}`, () => {
891 const ast
= espree
.parse(key
);
893 assert
.strictEqual(astUtils
.isEmptyBlock(ast
.body
[0]), expectedResults
[key
]);
898 describe("isEmptyFunction", () => {
899 const expectedResults
= {
900 "(function foo() {})": true,
901 "(function foo() { a })": false,
903 "(a) => { a }": false,
907 Object
.keys(expectedResults
).forEach(key
=> {
908 it(`should return ${expectedResults[key]} for ${key}`, () => {
909 const ast
= espree
.parse(key
, { ecmaVersion
: 6 });
911 assert
.strictEqual(astUtils
.isEmptyFunction(ast
.body
[0].expression
), expectedResults
[key
]);
916 describe("getNextLocation", () => {
918 /* eslint-disable quote-props */
919 const expectedResults
= {
921 "\n": [[1, 0], [2, 0], null],
922 "\r\n": [[1, 0], [2, 0], null],
923 "foo": [[1, 0], [1, 1], [1, 2], [1, 3], null],
924 "foo\n": [[1, 0], [1, 1], [1, 2], [1, 3], [2, 0], null],
925 "foo\r\n": [[1, 0], [1, 1], [1, 2], [1, 3], [2, 0], null],
926 "foo;\n": [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [2, 0], null],
927 "a\nb": [[1, 0], [1, 1], [2, 0], [2, 1], null],
928 "a\nb\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
929 "a\r\nb\r\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
930 "a\nb\r\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
931 "a\n\n": [[1, 0], [1, 1], [2, 0], [3, 0], null],
932 "a\r\n\r\n": [[1, 0], [1, 1], [2, 0], [3, 0], null],
933 "\n\r\n\n\r\n": [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0], null],
934 "ab\u2029c": [[1, 0], [1, 1], [1, 2], [2, 0], [2, 1], null],
935 "ab\ncde\n": [[1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2], [2, 3], [3, 0], null],
936 "a ": [[1, 0], [1, 1], [1, 2], null],
937 "a\t": [[1, 0], [1, 1], [1, 2], null],
938 "a \n": [[1, 0], [1, 1], [1, 2], [2, 0], null]
940 /* eslint-enable quote-props */
942 Object
.keys(expectedResults
).forEach(code
=> {
943 it(`should return expected locations for "${code}".`, () => {
944 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
945 const sourceCode
= new SourceCode(code
, ast
);
946 const locations
= expectedResults
[code
];
948 for (let i
= 0; i
< locations
.length
- 1; i
++) {
949 const location
= { line
: locations
[i
][0], column
: locations
[i
][1] };
950 const expectedNextLocation
= locations
[i
+ 1]
951 ? { line
: locations
[i
+ 1][0], column
: locations
[i
+ 1][1] }
954 assert
.deepStrictEqual(
955 astUtils
.getNextLocation(sourceCode
, location
),
963 describe("getParenthesisedText", () => {
964 const expectedResults
= {
965 "(((foo))); bar;": "(((foo)))",
966 "(/* comment */(((foo.bar())))); baz();": "(/* comment */(((foo.bar()))))",
967 "(foo, bar)": "(foo, bar)"
970 Object
.keys(expectedResults
).forEach(key
=> {
971 it(`should return ${expectedResults[key]} for ${key}`, () => {
972 const ast
= espree
.parse(key
, { tokens
: true, comment
: true, range
: true, loc
: true });
973 const sourceCode
= new SourceCode(key
, ast
);
975 assert
.strictEqual(astUtils
.getParenthesisedText(sourceCode
, ast
.body
[0].expression
), expectedResults
[key
]);
980 describe("couldBeError", () => {
981 const EXPECTED_RESULTS
= {
995 "(foo, 2, 3)": false,
1000 "foo ? 1 : 2": false,
1001 "foo ? bar : 2": true,
1002 "foo ? 1 : bar": true,
1004 "({ foo: 1 })": false
1007 Object
.keys(EXPECTED_RESULTS
).forEach(key
=> {
1008 it(`returns ${EXPECTED_RESULTS[key]} for ${key}`, () => {
1009 const ast
= espree
.parse(key
, { ecmaVersion
: 6 });
1011 assert
.strictEqual(astUtils
.couldBeError(ast
.body
[0].expression
), EXPECTED_RESULTS
[key
]);
1016 describe("isArrowToken", () => {
1017 const code
= "() => 5";
1018 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1019 const expected
= [false, false, true, false];
1021 tokens
.forEach((token
, index
) => {
1022 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1023 assert
.strictEqual(astUtils
.isArrowToken(token
), expected
[index
]);
1029 const code
= "if (obj && foo) { obj[foo](); }";
1030 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1031 const expected
= [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true];
1033 describe("isClosingBraceToken", () => {
1034 tokens
.forEach((token
, index
) => {
1035 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1036 assert
.strictEqual(astUtils
.isClosingBraceToken(token
), expected
[index
]);
1041 describe("isNotClosingBraceToken", () => {
1042 tokens
.forEach((token
, index
) => {
1043 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1044 assert
.strictEqual(astUtils
.isNotClosingBraceToken(token
), !expected
[index
]);
1051 const code
= "if (obj && foo) { obj[foo](); }";
1052 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1053 const expected
= [false, false, false, false, false, false, false, false, false, false, true, false, false, false, false];
1055 describe("isClosingBracketToken", () => {
1056 tokens
.forEach((token
, index
) => {
1057 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1058 assert
.strictEqual(astUtils
.isClosingBracketToken(token
), expected
[index
]);
1063 describe("isNotClosingBracketToken", () => {
1064 tokens
.forEach((token
, index
) => {
1065 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1066 assert
.strictEqual(astUtils
.isNotClosingBracketToken(token
), !expected
[index
]);
1073 const code
= "if (obj && foo) { obj[foo](); }";
1074 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1075 const expected
= [false, false, false, false, false, true, false, false, false, false, false, false, true, false, false];
1077 describe("isClosingParenToken", () => {
1078 tokens
.forEach((token
, index
) => {
1079 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1080 assert
.strictEqual(astUtils
.isClosingParenToken(token
), expected
[index
]);
1085 describe("isNotClosingParenToken", () => {
1086 tokens
.forEach((token
, index
) => {
1087 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1088 assert
.strictEqual(astUtils
.isNotClosingParenToken(token
), !expected
[index
]);
1095 const code
= "const obj = {foo: 1, bar: 2};";
1096 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1097 const expected
= [false, false, false, false, false, true, false, false, false, true, false, false, false];
1099 describe("isColonToken", () => {
1100 tokens
.forEach((token
, index
) => {
1101 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1102 assert
.strictEqual(astUtils
.isColonToken(token
), expected
[index
]);
1107 describe("isNotColonToken", () => {
1108 tokens
.forEach((token
, index
) => {
1109 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1110 assert
.strictEqual(astUtils
.isNotColonToken(token
), !expected
[index
]);
1117 const code
= "const obj = {foo: 1, bar: 2};";
1118 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1119 const expected
= [false, false, false, false, false, false, false, true, false, false, false, false, false];
1121 describe("isCommaToken", () => {
1122 tokens
.forEach((token
, index
) => {
1123 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1124 assert
.strictEqual(astUtils
.isCommaToken(token
), expected
[index
]);
1129 describe("isNotCommaToken", () => {
1130 tokens
.forEach((token
, index
) => {
1131 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1132 assert
.strictEqual(astUtils
.isNotCommaToken(token
), !expected
[index
]);
1139 const code
= "const obj = {foo: 1.5, bar: a.b};";
1140 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1141 const expected
= [false, false, false, false, false, false, false, false, false, false, false, true, false, false, false];
1143 describe("isDotToken", () => {
1144 tokens
.forEach((token
, index
) => {
1145 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1146 assert
.strictEqual(astUtils
.isDotToken(token
), expected
[index
]);
1151 describe("isNotDotToken", () => {
1152 tokens
.forEach((token
, index
) => {
1153 it(`should return ${!expected[index]} for '${token.value}'.`, () => {
1154 assert
.strictEqual(astUtils
.isNotDotToken(token
), !expected
[index
]);
1160 describe("isCommentToken", () => {
1161 const code
= "const obj = /*block*/ {foo: 1, bar: 2}; //line";
1162 const ast
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true, comment
: true });
1164 ast
.tokens
.forEach(token
=> {
1165 it(`should return false for '${token.value}'.`, () => {
1166 assert
.strictEqual(astUtils
.isCommentToken(token
), false);
1169 ast
.comments
.forEach(comment
=> {
1170 it(`should return true for '${comment.value}'.`, () => {
1171 assert
.strictEqual(astUtils
.isCommentToken(comment
), true);
1176 describe("isKeywordToken", () => {
1177 const code
= "const obj = {foo: 1, bar: 2};";
1178 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1179 const expected
= [true, false, false, false, false, false, false, false, false, false, false, false, false];
1181 tokens
.forEach((token
, index
) => {
1182 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1183 assert
.strictEqual(astUtils
.isKeywordToken(token
), expected
[index
]);
1189 const code
= "if (obj && foo) { obj[foo](); }";
1190 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1191 const expected
= [false, false, false, false, false, false, true, false, false, false, false, false, false, false, false];
1193 describe("isOpeningBraceToken", () => {
1194 tokens
.forEach((token
, index
) => {
1195 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1196 assert
.strictEqual(astUtils
.isOpeningBraceToken(token
), expected
[index
]);
1201 describe("isNotOpeningBraceToken", () => {
1202 tokens
.forEach((token
, index
) => {
1203 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1204 assert
.strictEqual(astUtils
.isNotOpeningBraceToken(token
), !expected
[index
]);
1211 const code
= "if (obj && foo) { obj[foo](); }";
1212 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1213 const expected
= [false, false, false, false, false, false, false, false, true, false, false, false, false, false, false];
1215 describe("isOpeningBracketToken", () => {
1216 tokens
.forEach((token
, index
) => {
1217 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1218 assert
.strictEqual(astUtils
.isOpeningBracketToken(token
), expected
[index
]);
1223 describe("isNotOpeningBracketToken", () => {
1224 tokens
.forEach((token
, index
) => {
1225 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1226 assert
.strictEqual(astUtils
.isNotOpeningBracketToken(token
), !expected
[index
]);
1233 const code
= "if (obj && foo) { obj[foo](); }";
1234 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1235 const expected
= [false, true, false, false, false, false, false, false, false, false, false, true, false, false, false];
1237 describe("isOpeningParenToken", () => {
1238 tokens
.forEach((token
, index
) => {
1239 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1240 assert
.strictEqual(astUtils
.isOpeningParenToken(token
), expected
[index
]);
1245 describe("isNotOpeningParenToken", () => {
1246 tokens
.forEach((token
, index
) => {
1247 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1248 assert
.strictEqual(astUtils
.isNotOpeningParenToken(token
), !expected
[index
]);
1255 const code
= "if (obj && foo) { obj[foo](); }";
1256 const tokens
= espree
.parse(code
, { ecmaVersion
: 6, tokens
: true }).tokens
;
1257 const expected
= [false, false, false, false, false, false, false, false, false, false, false, false, false, true, false];
1259 describe("isSemicolonToken", () => {
1260 tokens
.forEach((token
, index
) => {
1261 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1262 assert
.strictEqual(astUtils
.isSemicolonToken(token
), expected
[index
]);
1267 describe("isNotSemicolonToken", () => {
1268 tokens
.forEach((token
, index
) => {
1269 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1270 assert
.strictEqual(astUtils
.isNotSemicolonToken(token
), !expected
[index
]);
1276 describe("isNullLiteral", () => {
1277 const EXPECTED_RESULTS
= {
1286 Object
.keys(EXPECTED_RESULTS
).forEach(key
=> {
1287 it(`returns ${EXPECTED_RESULTS[key]} for ${key}`, () => {
1288 const ast
= espree
.parse(key
, { ecmaVersion
: 6 });
1290 assert
.strictEqual(astUtils
.isNullLiteral(ast
.body
[0].expression
), EXPECTED_RESULTS
[key
]);
1295 describe("createGlobalLinebreakMatcher", () => {
1296 it("returns a regular expression with the g flag", () => {
1297 assert
.instanceOf(astUtils
.createGlobalLinebreakMatcher(), RegExp
);
1298 assert(astUtils
.createGlobalLinebreakMatcher().toString().endsWith("/gu"));
1300 it("returns unique objects on each call", () => {
1301 const firstObject
= astUtils
.createGlobalLinebreakMatcher();
1302 const secondObject
= astUtils
.createGlobalLinebreakMatcher();
1304 assert
.notStrictEqual(firstObject
, secondObject
);
1306 describe("correctly matches linebreaks", () => {
1307 const LINE_COUNTS
= {
1313 "foo\r\u2028bar": 3,
1317 Object
.keys(LINE_COUNTS
).forEach(text
=> {
1319 assert
.strictEqual(text
.split(astUtils
.createGlobalLinebreakMatcher()).length
, LINE_COUNTS
[text
]);
1325 describe("canTokensBeAdjacent", () => {
1326 const CASES
= new Map([
1327 [["foo", "bar"], false],
1328 [[";foo", "bar"], false],
1329 [[";", "bar"], true],
1330 [[")", "bar"], true],
1331 [["foo0", "bar"], false],
1332 [["foo;", "bar"], true],
1333 [["foo", "0"], false],
1334 [["of", ".2"], true],
1335 [["2", ".2"], false],
1336 [["of", "'foo'"], true],
1337 [["foo", "`bar`"], true],
1338 [["`foo`", "in"], true],
1339 [["of", "0.2"], false],
1340 [["of", "0."], false],
1341 [[".2", "foo"], false],
1342 [["2.", "foo"], false],
1344 [["++", "-"], true],
1345 [["+", "--"], true],
1346 [["++", "--"], true],
1348 [["--", "+"], true],
1349 [["-", "++"], true],
1350 [["--", "++"], true],
1351 [["+", "+"], false],
1352 [["-", "-"], false],
1353 [["++", "+"], false],
1354 [["--", "-"], false],
1355 [["+", "++"], false],
1356 [["-", "--"], false],
1357 [["a/", "b"], true],
1358 [["a/", "+b"], true],
1359 [["a+", "/^regex$/"], true],
1360 [["a/", "/^regex$/"], false],
1361 [["a+", "/**/b"], true],
1362 [["a/", "/**/b"], false],
1363 [["a+", "//\nb"], true],
1364 [["a/", "//\nb"], false],
1365 [["a/**/", "b"], true],
1366 [["/**/a", "b"], false],
1367 [["a", "/**/b"], true],
1368 [["a", "b/**/"], false],
1369 [["a", "//\nb"], true],
1370 [["a", "b//"], false],
1371 [["#!/usr/bin/env node", "("], false],
1372 [["123invalidtoken", "("], false],
1373 [["(", "123invalidtoken"], false],
1374 [["(", "1n"], true],
1375 [["1n", "+"], true],
1376 [["1n", "in"], false]
1379 CASES
.forEach((expectedResult
, tokenStrings
) => {
1380 it(tokenStrings
.join(", "), () => {
1381 assert
.strictEqual(astUtils
.canTokensBeAdjacent(tokenStrings
[0], tokenStrings
[1]), expectedResult
);
1385 it("#!/usr/bin/env node, (", () => {
1387 astUtils
.canTokensBeAdjacent(
1388 { type
: "Shebang", value
: "#!/usr/bin/env node" },
1389 { type
: "Punctuator", value
: "(" }
1396 describe("equalTokens", () => {
1397 it("should return true if tokens are equal", () => {
1398 const code
= "a=0;a=0;";
1399 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
1400 const sourceCode
= new SourceCode(code
, ast
);
1402 assert
.strictEqual(astUtils
.equalTokens(ast
.body
[0], ast
.body
[1], sourceCode
), true);
1405 it("should return false if tokens are not equal", () => {
1406 const code
= "a=0;a=1;";
1407 const ast
= espree
.parse(code
, ESPREE_CONFIG
);
1408 const sourceCode
= new SourceCode(code
, ast
);
1410 assert
.strictEqual(astUtils
.equalTokens(ast
.body
[0], ast
.body
[1], sourceCode
), false);
1414 describe("hasOctalEscapeSequence", () => {
1416 /* eslint-disable quote-props */
1417 const expectedResults
= {
1481 /* eslint-enable quote-props */
1483 Object
.keys(expectedResults
).forEach(key
=> {
1484 it(`should return ${expectedResults[key]} for ${key}`, () => {
1485 const ast
= espree
.parse(`"${key}"`);
1487 assert
.strictEqual(astUtils
.hasOctalEscapeSequence(ast
.body
[0].expression
.raw
), expectedResults
[key
]);