Repository: eslint/eslint (js)

Issue:
keyword-spacing else ghost default
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for bug reports. If you are here for another reason, please see below:

    1. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**Tell us about your environment**

<!--
    If you are using ESLint v6.5.0 or later, you can run ESLint with the `--env-info` flag and paste the output here.
-->

* **ESLint Version:** 6.5.1
* **Node Version:** 10.16.3
* **npm Version:** 6.9.0

**What parser (default, Babel-ESLint, etc.) are you using?**
default
**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```yml
rules: {
  keyword-spacing: ["error", {
    before: false,
    after: true,
    overrides: {
      else: {after: false},
      if: {after: false}
    }
  }],
}
```

</details>

**What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.**

<!-- Paste the source code below: -->
```js
if(false) {
  console.info("will not log");
}else{
  console.info("will log");
}
```

<!-- Paste the command you used to run ESLint: -->
```bash
eslint index.js
```

**What did you expect to happen?**
`before: false` should set it so every keyword requires no spacing before it, as no overrides set it to `true`.

**What actually happened? Please include the actual, raw output from ESLint.**
```bash
/path/to/my/file/index.js
  3:2  error  Expected space(s) before "else"  keyword-spacing
```
Although the `before` property appears to work on every other keyword added to the overrides I've tried (`if`, for example, works fine using the above config), `else` for some reason sets it to true. Explicitly setting `before: false` in the `else` override appears to be a temporary solution to this bug.

**Are you willing to submit a pull request to fix this bug?**
I am unsure of how it would be fixed, but I would be willing to submit a PR if I did.

Pull request:
Update: remove default overrides in keyword-spacing (fixes #12369)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[X] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Remove `default` property in overrides scheme
I found that `the overrides scheme's default value` override `the undeclared overrides option's value`

**Is there anything you'd like reviewers to focus on?**
fix #12369,



Patch:
diff --git a/README.md b/README.md
index c12264b9f..dd414f1d1 100644
--- a/README.md
+++ b/README.md
@@ -156,8 +156,9 @@ ESLint follows [semantic versioning](https://semver.org). However, due to the na
     * A new CLI capability is created.
     * New capabilities to the public API are added (new classes, new methods, new arguments to existing methods, etc.).
     * A new formatter is created.
+    * `eslint:recommended` is updated and will result in strictly fewer errors (e.g., rule removals).
 * Major release (likely to break your lint build)
-    * `eslint:recommended` is updated.
+    * `eslint:recommended` is updated and may result in new errors (e.g., rule additions, most rule option updates).
     * A new option to an existing rule that results in ESLint reporting more errors by default.
     * An existing formatter is removed.
     * Part of the public API is removed or changed in an incompatible way.
@@ -264,7 +265,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <h3>Gold Sponsors</h3>
 <p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://opensource.facebook.com"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
-<p><a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://www.minitool.com"><img src="https://images.opencollective.com/minitool-software-ltd/6d68e16/logo.png" alt="MiniTool Software Ltd" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://www.codacy.com/?utm_source=eslint&utm_medium=cpm&utm_campaign=eslint-sponsorship"><img src="https://images.opencollective.com/codacy/ed22716/logo.png" alt="Codacy" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a></p>
+<p><a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://www.crosswordsolver.com"><img src="https://images.opencollective.com/crosswordsolver/d4481d6/logo.png" alt="Crosswordsolver" height="32"></a> <a href="https://www.codacy.com/?utm_source=eslint&utm_medium=cpm&utm_campaign=eslint-sponsorship"><img src="https://images.opencollective.com/codacy/ed22716/logo.png" alt="Codacy" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://www.minitool.com"><img src="https://images.opencollective.com/minitool-software-ltd/6d68e16/logo.png" alt="MiniTool Software Ltd" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a></p>
 <!--sponsorsend-->
 
 ## <a name="technology-sponsors"></a>Technology Sponsors
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 464d6dbd1..f5ec84616 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -80,13 +80,22 @@ const codeLines = SourceCode.splitLines(code);
 
 ## Linter
 
-The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files. You can retrieve instances of `Linter` like this:
+The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files.
+The `Linter` is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:
+
+* `cwd` - Path to a directory that should be considered as the current working directory. It is accessible to rules by calling `context.getCwd()` (see [The Context Object](./working-with-rules.md#The-Context-Object)). If `cwd` is `undefined`, it will be normalized to `process.cwd()` if the global `process` object is defined (for example, in the Node.js runtime) , or `undefined` otherwise.
+
+For example:
 
 ```js
 const Linter = require("eslint").Linter;
-const linter = new Linter();
+const linter1 = new Linter({ cwd: 'path/to/project' });
+const linter2 = new Linter();
 ```
 
+In this example, rules run on `linter1` will get `path/to/project` when calling `context.getCwd()`.
+Those run on `linter2` will get `process.cwd()` if the global `process` object is defined or `undefined` otherwise (e.g. on the browser https://eslint.org/demo).
+
 ### Linter#verify
 
 The most important method on `Linter` is `verify()`, which initiates linting of the given text. This method accepts three arguments:
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 35f224b32..ef6cbd634 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -126,6 +126,7 @@ The `context` object contains additional functionality that is helpful for rules
 Additionally, the `context` object has the following methods:
 
 * `getAncestors()` - returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
+* `getCwd()` - returns the `cwd` passed to [Linter](./nodejs-api.md#Linter). It is a path to a directory that should be considered as the current working directory.
 * `getDeclaredVariables(node)` - returns a list of [variables](./scope-manager-interface.md#variable-interface) declared by the given node. This information can be used to track references to variables.
     * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned.
     * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned.
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 172e79736..e68294205 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -376,11 +376,11 @@ For example:
         "plugin:@foo/foo/recommended",
         "plugin:@bar/recommended"
     ],
-    "rules": [
+    "rules": {
         "jquery/a-rule": "error",
         "@foo/foo/some-rule": "error",
         "@bar/another-rule": "error"
-    ],
+    },
     "env": {
         "jquery/jquery": true,
         "@foo/foo/env-foo": true,
diff --git a/docs/user-guide/migrating-to-6.0.0.md b/docs/user-guide/migrating-to-6.0.0.md
index 2cc1575a3..3baec19d9 100644
--- a/docs/user-guide/migrating-to-6.0.0.md
+++ b/docs/user-guide/migrating-to-6.0.0.md
@@ -247,7 +247,7 @@ With this change, any unknown values in a `globals` object result in a config va
 
 **To address:** If you see config validation errors related to globals after updating, ensure that all values configured for globals are either `readonly`, `writable`, or `off`. (ESLint also accepts some alternate spellings and variants for compatibility.)
 
-## <a name="experimental-object-rest-spread"></a> The depreacted `experimentalObjectRestSpread` option has been removed
+## <a name="experimental-object-rest-spread"></a> The deprecated `experimentalObjectRestSpread` option has been removed
 
 Previously, when using the default parser, a config could use the `experimentalObjectRestSpread` option to enable parsing support for object rest/spread properties:
 
diff --git a/lib/cli-engine/cli-engine.js b/lib/cli-engine/cli-engine.js
index e768da837..17ed8d9f0 100644
--- a/lib/cli-engine/cli-engine.js
+++ b/lib/cli-engine/cli-engine.js
@@ -567,7 +567,7 @@ class CLIEngine {
         });
         const lintResultCache =
             options.cache ? new LintResultCache(cacheFilePath) : null;
-        const linter = new Linter();
+        const linter = new Linter({ cwd: options.cwd });
 
         /** @type {ConfigArray[]} */
         const lastConfigArrays = [configArrayFactory.getConfigArrayForFile()];
diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 5b9ce07a5..8bd29b947 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -810,9 +810,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
  * @param {Object} settings The settings that were enabled in the config
  * @param {string} filename The reported filename of the code
  * @param {boolean} disableFixes If true, it doesn't make `fix` properties.
+ * @param {string | undefined} cwd cwd of the cli
  * @returns {Problem[]} An array of reported problems
  */
-function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes) {
+function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd) {
     const emitter = createEmitter();
     const nodeQueue = [];
     let currentNode = sourceCode.ast;
@@ -839,6 +840,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
             {
                 getAncestors: () => getAncestors(currentNode),
                 getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
+                getCwd: () => cwd,
                 getFilename: () => filename,
                 getScope: () => getScope(sourceCode.scopeManager, currentNode),
                 getSourceCode: () => sourceCode,
@@ -985,6 +987,24 @@ function getRule(slots, ruleId) {
     );
 }
 
+/**
+ * Normalize the value of the cwd
+ * @param {string | undefined} cwd raw value of the cwd, path to a directory that should be considered as the current working directory, can be undefined.
+ * @returns {string | undefined} normalized cwd
+ */
+function normalizeCwd(cwd) {
+    if (cwd) {
+        return cwd;
+    }
+    if (typeof process === "object") {
+        return process.cwd();
+    }
+
+    // It's more explicit to assign the undefined
+    // eslint-disable-next-line no-undefined
+    return undefined;
+}
+
 /**
  * The map to store private data.
  * @type {WeakMap<Linter, LinterInternalSlots>}
@@ -1001,8 +1021,14 @@ const internalSlotsMap = new WeakMap();
  */
 class Linter {
 
-    constructor() {
+    /**
+     * Initialize the Linter.
+     * @param {Object} [config] the config object
+     * @param {string} [config.cwd]  path to a directory that should be considered as the current working directory, can be undefined.
+     */
+    constructor({ cwd } = {}) {
         internalSlotsMap.set(this, {
+            cwd: normalizeCwd(cwd),
             lastConfigArray: null,
             lastSourceCode: null,
             parserMap: new Map([["espree", espree]]),
@@ -1134,7 +1160,8 @@ class Linter {
                 parserName,
                 settings,
                 options.filename,
-                options.disableFixes
+                options.disableFixes,
+                slots.cwd
             );
         } catch (err) {
             err.message += `\nOccurred while linting ${options.filename}`;
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index ef619aa77..2b3fef33b 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -86,8 +86,8 @@ module.exports = {
                             retv[key] = {
                                 type: "object",
                                 properties: {
-                                    before: { type: "boolean", default: true },
-                                    after: { type: "boolean", default: true }
+                                    before: { type: "boolean" },
+                                    after: { type: "boolean" }
                                 },
                                 additionalProperties: false
                             };
diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js
index 64a04c5cc..403d04da9 100644
--- a/lib/rules/no-multi-spaces.js
+++ b/lib/rules/no-multi-spaces.js
@@ -121,7 +121,7 @@ module.exports = {
 
                     context.report({
                         node: rightToken,
-                        loc: rightToken.loc.start,
+                        loc: { start: leftToken.loc.end, end: rightToken.loc.start },
                         message: "Multiple spaces found before '{{displayValue}}'.",
                         data: { displayValue },
                         fix: fixer => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ")
diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js
index 9a06ebba6..705d0f409 100644
--- a/lib/rules/no-self-assign.js
+++ b/lib/rules/no-self-assign.js
@@ -61,6 +61,9 @@ function isSameMember(left, right) {
     if (lobj.type === "MemberExpression") {
         return isSameMember(lobj, robj);
     }
+    if (lobj.type === "ThisExpression") {
+        return true;
+    }
     return lobj.type === "Identifier" && lobj.name === robj.name;
 }
 
diff --git a/lib/rules/space-in-parens.js b/lib/rules/space-in-parens.js
index 35ded5e78..85ee74210 100644
--- a/lib/rules/space-in-parens.js
+++ b/lib/rules/space-in-parens.js
@@ -232,7 +232,7 @@ module.exports = {
                     if (token.value === "(" && openerMissingSpace(token, nextToken)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: token.loc,
                             messageId: "missingOpeningSpace",
                             fix(fixer) {
                                 return fixer.insertTextAfter(token, " ");
@@ -244,7 +244,7 @@ module.exports = {
                     if (token.value === "(" && openerRejectsSpace(token, nextToken)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: { start: token.loc.end, end: nextToken.loc.start },
                             messageId: "rejectedOpeningSpace",
                             fix(fixer) {
                                 return fixer.removeRange([token.range[1], nextToken.range[0]]);
@@ -256,7 +256,7 @@ module.exports = {
                     if (token.value === ")" && closerMissingSpace(prevToken, token)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: token.loc,
                             messageId: "missingClosingSpace",
                             fix(fixer) {
                                 return fixer.insertTextBefore(token, " ");
@@ -268,7 +268,7 @@ module.exports = {
                     if (token.value === ")" && closerRejectsSpace(prevToken, token)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: { start: prevToken.loc.end, end: token.loc.start },
                             messageId: "rejectedClosingSpace",
                             fix(fixer) {
                                 return fixer.removeRange([prevToken.range[1], token.range[0]]);
diff --git a/package.json b/package.json
index 39d8967d7..778365194 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
   "main": "./lib/api.js",
   "scripts": {
     "test": "node Makefile.js test",
+    "test:cli": "mocha",
     "lint": "node Makefile.js lint",
     "fix": "node Makefile.js lint -- fix",
     "fuzz": "node Makefile.js fuzz",
@@ -63,7 +64,7 @@
     "ignore": "^4.0.6",
     "import-fresh": "^3.0.0",
     "imurmurhash": "^0.1.4",
-    "inquirer": "^6.4.1",
+    "inquirer": "^7.0.0",
     "is-glob": "^4.0.0",
     "js-yaml": "^3.13.1",
     "json-stable-stringify-without-jsonify": "^1.0.1",


Test patch:
diff --git a/docs/developer-guide/unit-tests.md b/docs/developer-guide/unit-tests.md
index 3c45d67a4..9b9bd4407 100644
--- a/docs/developer-guide/unit-tests.md
+++ b/docs/developer-guide/unit-tests.md
@@ -12,6 +12,10 @@ This automatically starts Mocha and runs all tests in the `tests` directory. You
 
 If you want to quickly run just one test, you can do so by running Mocha directly and passing in the filename. For example:
 
-    ./node_modules/.bin/mocha tests/lib/rules/no-wrap-func.js
+    npm test:cli tests/lib/rules/no-wrap-func.js
 
 Running individual tests is useful when you're working on a specific bug and iterating on the solution. You should be sure to run `npm test` before submitting a pull request.
+
+## More Control on Unit Testing
+
+`npm test:cli` is an alias of the Mocha cli in `./node_modules/.bin/mocha`. [Options](https://mochajs.org/#command-line-usage) are available to be provided to help to better control the test to run.
diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js
index e4e4e163e..4d04eb34d 100644
--- a/tests/lib/linter/linter.js
+++ b/tests/lib/linter/linter.js
@@ -3195,6 +3195,58 @@ describe("Linter", () => {
         });
     });
 
+    describe("when receiving cwd in options during instantiation", () => {
+        const code = "a;\nb;";
+        const config = { rules: { checker: "error" } };
+
+        it("should get cwd correctly in the context", () => {
+            const cwd = "cwd";
+            const linterWithOption = new Linter({ cwd });
+            let spy;
+
+            linterWithOption.defineRule("checker", context => {
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), cwd);
+                });
+                return { Program: spy };
+            });
+
+            linterWithOption.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+
+        it("should assign process.cwd() to it if cwd is undefined", () => {
+            let spy;
+            const linterWithOption = new Linter({ });
+
+            linterWithOption.defineRule("checker", context => {
+
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), process.cwd());
+                });
+                return { Program: spy };
+            });
+
+            linterWithOption.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+
+        it("should assign process.cwd() to it if the option is undefined", () => {
+            let spy;
+
+            linter.defineRule("checker", context => {
+
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), process.cwd());
+                });
+                return { Program: spy };
+            });
+
+            linter.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+    });
+
     describe("reportUnusedDisable option", () => {
         it("reports problems for unused eslint-disable comments", () => {
             assert.deepStrictEqual(
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index 9c0bf8d0a..9971facf1 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -545,6 +545,8 @@ ruleTester.run("keyword-spacing", rule, {
         { code: "if (a) {}else{}", options: [override("else", NEITHER)] },
         "if (a) {}\nelse\n{}",
         { code: "if(a) {}\nelse\n{}", options: [NEITHER] },
+        { code: "if(a){ }else{ }", options: [{ before: false, after: true, overrides: { else: { after: false }, if: { after: false } } }] },
+        { code: "if(a){ }else{ }", options: [{ before: true, after: false, overrides: { else: { before: false }, if: { before: false } } }] },
 
         // not conflict with `semi-spacing`
         "if (a);else;",
diff --git a/tests/lib/rules/no-multi-spaces.js b/tests/lib/rules/no-multi-spaces.js
index db77ff391..4a8e6034e 100644
--- a/tests/lib/rules/no-multi-spaces.js
+++ b/tests/lib/rules/no-multi-spaces.js
@@ -112,7 +112,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "function foo(a, b) {}",
             errors: [{
                 message: "Multiple spaces found before 'b'.",
-                type: "Identifier"
+                type: "Identifier",
+                column: 16,
+                endColumn: 18
             }]
         },
         {
@@ -121,7 +123,9 @@ ruleTester.run("no-multi-spaces", rule, {
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Multiple spaces found before 'b'.",
-                type: "Identifier"
+                type: "Identifier",
+                column: 14,
+                endColumn: 16
             }]
         },
         {
@@ -129,7 +133,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var a = 1",
             errors: [{
                 message: "Multiple spaces found before '1'.",
-                type: "Numeric"
+                type: "Numeric",
+                column: 8,
+                endColumn: 10
             }]
         },
         {
@@ -153,7 +159,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var arr = {'a': 1, 'b': 2};",
             errors: [{
                 message: "Multiple spaces found before ''b''.",
-                type: "String"
+                type: "String",
+                column: 19,
+                endColumn: 21
             }]
         },
         {
@@ -213,16 +221,24 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "[ , 1, , 3, , ]",
             errors: [{
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 2,
+                endColumn: 4
             }, {
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 8,
+                endColumn: 10
             }, {
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 14,
+                endColumn: 16
             }, {
                 message: "Multiple spaces found before ']'.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 17,
+                endColumn: 19
             }]
         },
         {
@@ -273,7 +289,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "function foo () {}",
             errors: [{
                 message: "Multiple spaces found before '('.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 13,
+                endColumn: 19
             }]
         },
         {
@@ -389,7 +407,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var x = 5;",
             errors: [{
                 message: "Multiple spaces found before '5'.",
-                type: "Numeric"
+                type: "Numeric",
+                column: 8,
+                endColumn: 11
             }]
         },
 
@@ -415,7 +435,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var x = 5; // comment",
             errors: [{
                 message: "Multiple spaces found before '// comment'.",
-                type: "Line"
+                type: "Line",
+                column: 11,
+                endColumn: 13
             }]
         },
         {
@@ -582,7 +604,9 @@ ruleTester.run("no-multi-spaces", rule, {
             options: [{ ignoreEOLComments: false }],
             errors: [{
                 message: "Multiple spaces found before '/*comment...*/'.",
-                type: "Block"
+                type: "Block",
+                column: 11,
+                endColumn: 13
             }]
         },
         {
diff --git a/tests/lib/rules/no-self-assign.js b/tests/lib/rules/no-self-assign.js
index 4e168a897..eaa0d02d1 100644
--- a/tests/lib/rules/no-self-assign.js
+++ b/tests/lib/rules/no-self-assign.js
@@ -70,6 +70,14 @@ ruleTester.run("no-self-assign", rule, {
         {
             code: "a[\n    'b'\n] = a[\n    'b'\n]",
             options: [{ props: false }]
+        },
+        {
+            code: "this.x = this.y",
+            options: [{ props: true }]
+        },
+        {
+            code: "this.x = this.x",
+            options: [{ props: false }]
         }
     ],
     invalid: [
@@ -120,6 +128,11 @@ ruleTester.run("no-self-assign", rule, {
         { code: "a.b.c = a.b.c", options: [{ props: true }], errors: ["'a.b.c' is assigned to itself."] },
         { code: "a[b] = a[b]", options: [{ props: true }], errors: ["'a[b]' is assigned to itself."] },
         { code: "a['b'] = a['b']", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] },
-        { code: "a[\n    'b'\n] = a[\n    'b'\n]", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] }
+        { code: "a[\n    'b'\n] = a[\n    'b'\n]", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] },
+        {
+            code: "this.x = this.x",
+            options: [{ props: true }],
+            errors: ["'this.x' is assigned to itself."]
+        }
     ]
 });
diff --git a/tests/lib/rules/space-in-parens.js b/tests/lib/rules/space-in-parens.js
index 6f90da52b..a68c6bae7 100644
--- a/tests/lib/rules/space-in-parens.js
+++ b/tests/lib/rules/space-in-parens.js
@@ -128,8 +128,17 @@ ruleTester.run("space-in-parens", rule, {
             output: "bar(baz)",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 10 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 6 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 9, endColumn: 10 }
+            ]
+        },
+        {
+            code: "bar(  baz  )",
+            output: "bar(baz)",
+            options: ["never"],
+            errors: [
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 7 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 10, endColumn: 12 }
             ]
         },
         {
@@ -137,8 +146,17 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 6 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5, endColumn: 6 }
+            ]
+        },
+        {
+            code: "foo(  )",
+            output: "foo()",
+            options: ["never"],
+            errors: [
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 7 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5, endColumn: 7 }
             ]
         },
         {
@@ -151,7 +169,7 @@ ruleTester.run("space-in-parens", rule, {
             code: "foo\n(\nbar )",
             output: "foo\n(\nbar)",
             options: ["never"],
-            errors: [{ messageId: "rejectedClosingSpace", line: 3, column: 5 }]
+            errors: [{ messageId: "rejectedClosingSpace", line: 3, column: 4 }]
         },
         {
             code: "foo\n(bar\n)\n",
@@ -170,8 +188,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo( bar )",
             options: ["always"],
             errors: [
-                { messageId: "missingOpeningSpace", line: 1, column: 4 },
-                { messageId: "missingClosingSpace", line: 1, column: 8 }
+                { messageId: "missingOpeningSpace", line: 1, column: 4, endColumn: 5 },
+                { messageId: "missingClosingSpace", line: 1, column: 8, endColumn: 9 }
             ]
         },
 
@@ -248,7 +266,7 @@ ruleTester.run("space-in-parens", rule, {
             code: "foo( /* bar */ baz)",
             output: "foo(/* bar */ baz)",
             options: ["never"],
-            errors: [{ messageId: "rejectedOpeningSpace", line: 1, column: 4 }]
+            errors: [{ messageId: "rejectedOpeningSpace", line: 1, column: 5 }]
         },
 
         // exceptions
@@ -266,8 +284,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["always", { exceptions: ["()", "empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5 }
             ]
         },
         {
@@ -275,8 +293,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["always", { exceptions: ["empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5 }
             ]
         },
         {
@@ -284,7 +302,7 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo( bar())",
             options: ["always", { exceptions: ["()", "empty"] }],
             errors: [
-                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 11 }
             ]
         },
         {
@@ -300,10 +318,10 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo(bar( ))",
             options: ["never", { exceptions: ["empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
                 { messageId: "missingOpeningSpace", line: 1, column: 9 },
                 { messageId: "missingClosingSpace", line: 1, column: 10 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 11 }
             ]
         },
         {
@@ -312,7 +330,7 @@ ruleTester.run("space-in-parens", rule, {
             options: ["never", { exceptions: ["[]"] }],
             errors: [
                 { messageId: "missingOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 18 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 17 }
             ]
         },
         {
@@ -449,8 +467,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "(( 1 + 2 ))",
             options: ["always", { exceptions: ["()"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 1 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 13 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 2 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
             ]
         },
         {
@@ -458,10 +476,10 @@ ruleTester.run("space-in-parens", rule, {
             output: "((1 + 2))",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 1 },
-                { messageId: "rejectedOpeningSpace", line: 1, column: 3 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 11 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 13 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 2 },
+                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 10 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
             ]
         },
         {
@@ -506,7 +524,7 @@ ruleTester.run("space-in-parens", rule, {
             output: "var result = ( 1 / ( 1 + 2 )) + 3",
             options: ["always", { exceptions: ["()"] }],
             errors: [
-                { messageId: "rejectedClosingSpace", line: 1, column: 30 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 29 }
             ]
         },
         {
@@ -524,7 +542,7 @@ ruleTester.run("space-in-parens", rule, {
             errors: [
                 { messageId: "missingOpeningSpace", line: 1, column: 14 },
                 { messageId: "missingClosingSpace", line: 1, column: 26 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 28 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 27 }
             ]
         },
 
@@ -535,8 +553,8 @@ ruleTester.run("space-in-parens", rule, {
             options: ["never"],
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 19 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 27 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 20 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 26 }
             ]
         },
         {