Repository: jshint/jshint
Pull request #2066 (2014-12-31 17:49:04)

Support generators in class body
I was getting errors about generators in ES6 classes.

This commit fixes that issue. It also adds several lines of positive tests to guard against regression, including several suggested by rwaldron.

For reference, generators in classes are in the latest ES6 draft spec and work well with 6to5.

NB: I'm resubmitting this PR as Coveralls on Travis kept looking for a nonexistent commit. Original PR was [#2059](https://github.com/jshint/jshint/pull/2059)

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1681167/badge)](https://coveralls.io/builds/1681167)

Coverage increased (+0.01%) when pulling **ff889e4cca3e21be7ea87b2a40b5460c7f75352c on foysavas:master** into **825ce01f622e266c8465a267e9c711f8a781a313 on jshint:master**.

rwaldron: Please update the commit message to follow https://github.com/jshint/jshint/blob/master/CONTRIBUTING.md#commit-message-guidelines Thanks!!
rwaldron: @foysavas go ahead and squash this into one commit when you update the commit message—thanks!

Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 12658a63..9ad155c3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,5 @@
-# How to contribute
+How to contribute
+=================
 
 The best way to make sure your issue is addressed is to submit a patch. We accept
 patches through all mediums: pull requests, email, issue comment, tweet with a link
@@ -6,65 +7,55 @@ to a snippet, graffiti outside of Anton's apartment, etc.
 
 However, before sending a patch, please make sure that the following applies:
 
-* Your commit message follows the [Commit Message Guidelines](#commit-message-guidelines).
+* Your commit message links to that issue.
+* Your commit message is very descriptive ([example](https://github.com/jshint/jshint/commit/5751c5ed249b7a035758a3ae876cfa1a360fd144)).
 * Your patch doesn't have useless merge commits.
 * Your coding style is similar to ours (see below).
 * Your patch is 100% tested. We don't accept any test regressions.
 * All tests and lint checks pass (`npm test`).
 * You understand that we're super grateful for your patch.
 
-## Development Environment
+Coding Style
+------------
 
-JSHint is developed using [Node.js](http://nodejs.org/) and has a number of
-dependencies specified in its `package.json` file. To install them just run the
-following command from within your repo directory:
+This section describes our coding style guide. You might not agree with it and that's
+fine but if you're going to send us patches treat this guide as a law.
 
-    $ npm install
+### Our main rule is simple:
 
-After that, you will be able to run the edge version of JSHint using
-`bin/jshint` or build the release bundles using `bin/build`.
+> All code in any code-base should look like a single person typed it, no matter how
+many people contributed. —[idiomatic.js](https://github.com/rwldrn/idiomatic.js/)
 
-## Coding Style
-
-This section describes our coding style guide. You might not agree with it and
-that's fine but if you're going to send us patches treat this guide as a law.
-
-**Our main rule is simple:**
-
-> All code in any code-base should look like a single person typed it, no
-> matter how many people contributed.
-> —[idiomatic.js](https://github.com/rwaldron/idiomatic.js/)
-
-### Whitespace
+### Whitespace:
 
 * We use two spaces everywhere.
 * Use one space after `if`, `for`, `while`, etc.
 * Use one space after `function` for anonymous functions but not for named functions:
 
-    ```javascript
-    var a = function () {};
-    function a() {}
-    ```
+```javascript
+var a = function () {};
+function a() {}
+```
 
 * Feel free to indent variable assignments or property definitions if it makes the code look better. But don't abuse that:
 
-    ```javascript
-    // Good
-    var next = token.peak();
-    var prev = token.peak(-1);
-    var cur  = token.current;
-
-    var scope = {
-      name:   "(global)",
-      parent: parentScope,
-      vars:   [],
-      uses:   []
-    };
-
-    // Bad
-    var cur         = token.current;
-    var isSemicolon = cur.isPunctuator(";");
-    ```
+```javascript
+// Good
+var next = token.peak();
+var prev = token.peak(-1);
+var cur  = token.current;
+
+var scope = {
+  name:   "(global)",
+  parent: parentScope,
+  vars:   [],
+  uses:   []
+};
+
+// Bad
+var cur         = token.current;
+var isSemicolon = cur.isPunctuator(";");
+```
 
 * Wrap multi-line comments with new lines on both sides.
 
@@ -72,16 +63,17 @@ that's fine but if you're going to send us patches treat this guide as a law.
 
 * Use one `var` per variable unless you don't assign any values to it (and it's short enough):
 
-    ```javascript
-    var token = tokens.find(index);
-    var scope = scopes.current;
-    var next, prev, cur;
-    ```
+```javascript
+var token = tokens.find(index);
+var scope = scopes.current;
+var next, prev, cur;
+```
 
 * Don't be overly descriptive with your variable names but don't abuse one-letter variables either. Find a sweet spot somewhere in between.
 
 ### Comments
 
+* Use `//` for all comments.
 * Comment everything that is not obvious.
 * If you're adding a new check, write a comment describing why this check is important and what it checks for.
 
@@ -94,97 +86,14 @@ that's fine but if you're going to send us patches treat this guide as a law.
 * Try not to chain stuff unless it **really** helps (e.g. in tests).
 * Don't short-circuit expressions if you're not assigning the result:
 
-    ```javascript
-    // Good
-    token = token || tokens.find(0);
-
-    // Bad
-    token.isPunctuator(";") && report.addWarning("W001");
-
-    // Good
-    if (token.isPunctuator(";"))
-      report.addWarning("W001");
-    ```
-
-Commit Message Guidelines
--------------------------
-
-### Overview
-
-Commit messages are written in a simple format which clearly describes the purpose of a change.
-
-The format in general should look like this:
-
-```
-[[TYPE]] <Short description>
-<Blank line>
-
-<Body / Detailed description>
-
-<Footer>
-```
-
-Line lengths in commit messages are not strict, but good commit messages should have headers of no
-more than 60 characters, and bodies/footers wrapped at 100 columns. This renders nicely on Github's
-UI.
+```javascript
+// Good
+token = token || tokens.find(0);
 
-### Header
+// Bad
+token.isPunctuator(";") && report.addWarning("W001");
 
-The first line is the commit message header, which will indicate the type of change, and a general
-description of the change. This should fit within 60 characters, ideally. For instance:
-
-```
-[[FIX]] Ignore "nocomma" when parsing object literals
+// Good
+if (token.isPunctuator(";"))
+  report.addWarning("W001");
 ```
-
-The title `[[FIX]]` indicates that the change is a bugfix, while the remainder clarifies what the
-change actually contains.
-
-Several commit types are used by jshint:
-
-1. `[[FIX]]` --- Commit fixes a bug or regression
-2. `[[FEAT]]` --- Commit introduces new functionality
-3. `[[DOCS]]` --- Commit modifies documentation. Docs commits should only touch comments in source code, or scripts and assets which are used to generate the documentation.
-4. `[[TEST]]` --- Commit modifies tests or test infrastructure only
-
-### Body
-
-`<Body>` is a detailed commit message explaining exactly what has changed, and a summary of the
-reason why. Lines in the body should be wrapped to 100 characters for best rendering.
-
-For a historical example, see this [example](https://github.com/jshint/jshint/commit/5751c5ed249b7a035758a3ae876cfa1a360fd144)
-
-### Footer
-
-`<Footer>` contains a description of any breaking changes, no matter how subtle, as well as a list
-of issues affected or fixed by this commit. Lines in the footer should be wrapped to 100 characters
-for best rendering.
-
-For instance:
-
-```
-[[FEAT]] Enable `norecurs` option by default
-
-Commit 124124a7f introduced an option which forbids recursion. We liked it so much, we've enabled
-it by default.
-
-BREAKING CHANGE:
-
-This change will break the CI builds of many applications and frameworks.
-
-In order to work around this issue, you will need to re-engineer your applications and frameworks
-to avoid making recursive calls. Use Arrays as stacks rather than relying on the VM call stack.
-
-Fixes #1000009
-Closes #888888
-Closes #77777
-```
-
-## License
-
-Most files are published using [the standard MIT Expat
-license](https://www.gnu.org/licenses/license-list.html#Expat). One file,
-however, is provided under a slightly modified version of that license. The
-so-called [JSON license](https://www.gnu.org/licenses/license-list.html#JSON)
-is a non-free license, and unfortunately, we can't change it due to historical
-reasons. This license is included as an in-line within the file it concerns.
diff --git a/dist/jshint-rhino.js b/dist/jshint-rhino.js
index d8d56ce7..5b5ac404 100755
--- a/dist/jshint-rhino.js
+++ b/dist/jshint-rhino.js
@@ -4988,7 +4988,7 @@ exports.bool = {
     /**
      * This option requires all `for in` loops to filter object's items. The
      * for in statement allows for looping through the names of all of the
-     * properties of an object including those inherited through the prototype
+     * properties of an object including those inherited throught the prototype
      * chain. This behavior can lead to unexpected items in your object so it
      * is generally safer to always filter inherited properties out as shown in
      * the example:
@@ -6675,12 +6675,10 @@ exports.mocha = {
   beforeEach  : false,
   afterEach   : false,
   // TDD
-  suite         : false,
-  test          : false,
-  setup         : false,
-  teardown      : false,
-  suiteSetup    : false,
-  suiteTeardown : false
+  suite       : false,
+  test        : false,
+  setup       : false,
+  teardown    : false
 };
 
 exports.jasmine = {
diff --git a/dist/jshint.js b/dist/jshint.js
index ffd1144d..840ad4aa 100644
--- a/dist/jshint.js
+++ b/dist/jshint.js
@@ -4986,7 +4986,7 @@ exports.bool = {
     /**
      * This option requires all `for in` loops to filter object's items. The
      * for in statement allows for looping through the names of all of the
-     * properties of an object including those inherited through the prototype
+     * properties of an object including those inherited throught the prototype
      * chain. This behavior can lead to unexpected items in your object so it
      * is generally safer to always filter inherited properties out as shown in
      * the example:
@@ -6673,12 +6673,10 @@ exports.mocha = {
   beforeEach  : false,
   afterEach   : false,
   // TDD
-  suite         : false,
-  test          : false,
-  setup         : false,
-  teardown      : false,
-  suiteSetup    : false,
-  suiteTeardown : false
+  suite       : false,
+  test        : false,
+  setup       : false,
+  teardown    : false
 };
 
 exports.jasmine = {
diff --git a/src/jshint.js b/src/jshint.js
index 0527565e..4ce4b5c3 100644
--- a/src/jshint.js
+++ b/src/jshint.js
@@ -447,7 +447,8 @@ var JSHINT = (function () {
           }
         }
       } else {
-        if ((!state.option.shadow || _.contains([ "inner", "outer" ], state.option.shadow)) &&
+        if (((!state.option.shadow && !opts.param) ||
+            _.contains([ "inner", "outer" ], state.option.shadow)) &&
             type !== "exception" || funct["(blockscope)"].getlabel(name)) {
           warning("W004", state.tokens.next, name);
         }
@@ -1168,10 +1169,14 @@ var JSHINT = (function () {
     var x = symbol(s, 42);
 
     x.led = function (left) {
+      if (!state.option.esnext) {
+        warning("W119", state.tokens.curr, "arrow function syntax (=>)");
+      }
+
       nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
 
       this.left = left;
-      this.right = doFunction(undefined, undefined, false, { loneArg: left });
+      this.right = doFunction(undefined, undefined, false, left);
       return this;
     };
     return x;
@@ -1450,14 +1455,6 @@ var JSHINT = (function () {
       }
     } else {
       error("E030", state.tokens.next, state.tokens.next.value);
-
-      // The token should be consumed after a warning is issued so the parser
-      // can continue as though an identifier were found. The semicolon token
-      // should not be consumed in this way so that the parser interprets it as
-      // a statement delimeter;
-      if (state.tokens.next.id !== ";") {
-        advance();
-      }
     }
   }
 
@@ -1880,18 +1877,6 @@ var JSHINT = (function () {
       var f;
       var block;
 
-      // If this identifier is the lone parameter to a shorthand "fat arrow"
-      // function definition, i.e.
-      //
-      //     x => x;
-      //
-      // ...it should not be considered as a variable in the current scope. It
-      // will be added to the scope of the new function when the next token is
-      // parsed, so it can be safely ignored for now.
-      if (state.tokens.next.id === "=>") {
-        return this;
-      }
-
       if (typeof s === "function") {
         // Protection against accidental inheritance.
         s = undefined;
@@ -2442,8 +2427,8 @@ var JSHINT = (function () {
       }
       if (!left.identifier && left.id !== "." && left.id !== "[" &&
           left.id !== "(" && left.id !== "&&" && left.id !== "||" &&
-          left.id !== "?" && !(state.option.esnext && left["(name)"])) {
-        warning("W067", that);
+          left.id !== "?" && !(state.option.esnext && left.id === "=>")) {
+        warning("W067", left);
       }
     }
 
@@ -2453,11 +2438,13 @@ var JSHINT = (function () {
 
   prefix("(", function () {
     var bracket, brackets = [];
-    var pn = state.tokens.next, pn1, i = -1;
+    var pn, pn1, i = 0;
     var ret, triggerFnExpr;
     var parens = 1;
 
     do {
+      pn = peek(i);
+
       if (pn.value === "(") {
         parens += 1;
       } else if (pn.value === ")") {
@@ -2465,27 +2452,19 @@ var JSHINT = (function () {
       }
 
       i += 1;
-      pn1 = pn;
-      pn = peek(i);
-    } while (!(parens === 0 && pn1.value === ")") &&
-             pn.value !== ";" && pn.type !== "(end)");
+      pn1 = peek(i);
+    } while (!(parens === 0 && pn.value === ")") &&
+             pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)");
 
     if (state.tokens.next.id === "function") {
       triggerFnExpr = state.tokens.next.immed = true;
     }
 
-    // If the balanced grouping operator is followed by a "fat arrow", the
-    // current token marks the beginning of a "fat arrow" function and parsing
-    // should proceed accordingly.
-    if (pn.value === "=>") {
-      return doFunction(null, null, null, { parsedParen: true });
-    }
-
     var exprs = [];
 
     if (state.tokens.next.id !== ")") {
       for (;;) {
-        if (pn.value === "=>" && _.contains(["{", "["], state.tokens.next.value)) {
+        if (pn1.value === "=>" && _.contains(["{", "["], state.tokens.next.value)) {
           bracket = state.tokens.next;
           bracket.left = destructuringExpression();
           brackets.push(bracket);
@@ -2630,19 +2609,8 @@ var JSHINT = (function () {
     }
     while (state.tokens.next.id !== "(end)") {
       while (state.tokens.next.id === ",") {
-        if (!state.option.elision) {
-          if (!state.option.inES5()) {
-            // Maintain compat with old options --- ES5 mode without
-            // elision=true will warn once per comma
-            warning("W070");
-          } else {
-            warning("W128");
-            do {
-              advance(",");
-            } while(state.tokens.next.id === ",");
-            continue;
-          }
-        }
+        if (!state.option.inES5())
+          warning("W070");
         advance(",");
       }
 
@@ -2714,25 +2682,40 @@ var JSHINT = (function () {
     return id;
   }
 
-  function functionparams(fatarrow) {
-    var next;
+  function functionparams(parsed) {
+    var curr, next;
     var params = [];
     var ident;
     var tokens = [];
     var t;
     var pastDefault = false;
-    var loneArg = fatarrow && fatarrow.loneArg;
 
-    if (loneArg && loneArg.identifier === true) {
-      addlabel(loneArg.value, { type: "unused", token: loneArg });
-      return [loneArg];
+    if (parsed) {
+      if (Array.isArray(parsed)) {
+        for (var i in parsed) {
+          curr = parsed[i];
+          if (curr.value === "...") {
+            if (!state.option.esnext) {
+              warning("W119", curr, "spread/rest operator");
+            }
+            continue;
+          } else if (curr.value !== ",") {
+            params.push(curr.value);
+            addlabel(curr.value, { type: "unused", token: curr, param: true });
+          }
+        }
+        return params;
+      } else {
+        if (parsed.identifier === true) {
+          addlabel(parsed.value, { type: "unused", token: parsed, param: true });
+          return [parsed];
+        }
+      }
     }
 
     next = state.tokens.next;
 
-    if (!fatarrow || !fatarrow.parsedParen) {
-      advance("(");
-    }
+    advance("(");
 
     if (state.tokens.next.id === ")") {
       advance(")");
@@ -2746,7 +2729,7 @@ var JSHINT = (function () {
           t = tokens[t];
           if (t.id) {
             params.push(t.id);
-            addlabel(t.id, { type: "unused", token: t.token });
+            addlabel(t.id, { type: "unused", token: t.token, param: true });
           }
         }
       } else if (state.tokens.next.value === "...") {
@@ -2756,11 +2739,11 @@ var JSHINT = (function () {
         advance("...");
         ident = identifier(true);
         params.push(ident);
-        addlabel(ident, { type: "unused", token: state.tokens.curr });
+        addlabel(ident, { type: "unused", token: state.tokens.curr, param: true });
       } else {
         ident = identifier(true);
         params.push(ident);
-        addlabel(ident, { type: "unused", token: state.tokens.curr });
+        addlabel(ident, { type: "unused", token: state.tokens.curr, param: true });
       }
 
       // it is a syntax error to have a regular argument after a default argument
@@ -2858,18 +2841,7 @@ var JSHINT = (function () {
     };
   }
 
-  /**
-   * @param {Object} [fatarrow] In the case that the function being parsed
-   *                            takes the "fat arrow" form, this object will
-   *                            contain details about the in-progress parsing
-   *                            operation.
-   * @param {Token} [fatarrow.loneArg] The argument to the function in cases
-   *                                   where it was defined using the single-
-   *                                   argument shorthand.
-   * @param {bool} [fatarrow.parsedParen] Whether the opening parenthesis has
-   *                                      already been parsed.
-   */
-  function doFunction(name, statement, generator, fatarrow) {
+  function doFunction(name, statement, generator, fatarrowparams) {
     var f;
     var oldOption = state.option;
     var oldIgnored = state.ignored;
@@ -2894,20 +2866,19 @@ var JSHINT = (function () {
       addlabel(name, { type: "function" });
     }
 
-    funct["(params)"] = functionparams(fatarrow);
+    funct["(params)"] = functionparams(fatarrowparams);
     funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]);
 
-    if (fatarrow) {
-      if (!state.option.esnext) {
-        warning("W119", state.tokens.curr, "arrow function syntax (=>)");
-      }
+    // So we parse fat-arrow functions after we encounter =>. So basically
+    // doFunction is called with the left side of => as its last argument.
+    // This means that the parser, at that point, had already added its
+    // arguments to the undefs array and here we undo that.
 
-      if (!fatarrow.loneArg) {
-        advance("=>");
-      }
-    }
+    JSHINT.undefs = _.filter(JSHINT.undefs, function (item) {
+      return !_.contains(_.union(fatarrowparams), item[2]);
+    });
 
-    block(false, true, true, !!fatarrow);
+    block(false, true, true, fatarrowparams ? true : false);
 
     if (!state.option.noyield && generator &&
         funct["(generator)"] !== "yielded") {
@@ -3475,6 +3446,7 @@ var JSHINT = (function () {
   function classbody(c) {
     var name;
     var isStatic;
+    var isGenerator;
     var getset;
     var props = {};
     var staticProps = {};
@@ -3482,7 +3454,13 @@ var JSHINT = (function () {
     for (var i = 0; state.tokens.next.id !== "}"; ++i) {
       name = state.tokens.next;
       isStatic = false;
+      isGenerator = false;
       getset = null;
+      if (name.id === "*") {
+        isGenerator = true;
+        advance("*");
+        name = state.tokens.next;
+      }
       if (name.id === "[") {
         name = computedPropertyName();
       } else if (isPropertyName(name)) {
@@ -3490,6 +3468,10 @@ var JSHINT = (function () {
         advance();
         computed = false;
         if (name.identifier && name.value === "static") {
+          if (checkPunctuators(state.tokens.next, ["*"])) {
+            isGenerator = true;
+            advance("*");
+          }
           if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") {
             computed = state.tokens.next.id === "[";
             isStatic = true;
@@ -3552,7 +3534,7 @@ var JSHINT = (function () {
 
       propertyName(name);
 
-      doFunction(null, c, false, null);
+      doFunction(null, c, isGenerator, null);
     }
 
     checkProperties(props);
diff --git a/src/messages.js b/src/messages.js
index 09cc6923..803c7a08 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -201,8 +201,7 @@ var warnings = {
   W124: "A generator function shall contain a yield statement.",
   W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp",
   W126: "Grouping operator is unnecessary for lone expressions.",
-  W127: "Unexpected use of a comma operator.",
-  W128: "Empty array elements require elision=true."
+  W127: "Unexpected use of a comma operator."
 };
 
 var info = {
diff --git a/src/options.js b/src/options.js
index 3efdf869..0fb90e2b 100644
--- a/src/options.js
+++ b/src/options.js
@@ -503,13 +503,7 @@ exports.bool = {
      * * [Draft Specification for ES.next (ECMA-262 Ed.
      *   6)](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts)
      */
-    esnext      : true,
-
-    /**
-     * This option tells JSHint that your code uses ES3 array elision elements,
-     * or empty elements (for example, `[1, , , 4, , , 7]`).
-     */
-    elision     : true,
+    esnext      : true
   },
 
   // Third party globals
diff --git a/src/vars.js b/src/vars.js
index b975df81..e3b4d709 100644
--- a/src/vars.js
+++ b/src/vars.js
@@ -675,12 +675,10 @@ exports.mocha = {
   beforeEach  : false,
   afterEach   : false,
   // TDD
-  suite         : false,
-  test          : false,
-  setup         : false,
-  teardown      : false,
-  suiteSetup    : false,
-  suiteTeardown : false
+  suite       : false,
+  test        : false,
+  setup       : false,
+  teardown    : false
 };
 
 exports.jasmine = {
@@ -697,11 +695,5 @@ exports.jasmine = {
   // Jasmine 1.3
   runs        : false,
   waitsFor    : false,
-  waits       : false,
-  // Jasmine 2.1
-  beforeAll   : false,
-  afterAll    : false,
-  fail        : false,
-  fdescribe   : false,
-  fit         : false
+  waits       : false
 };


Test patch:
diff --git a/tests/cli.js b/tests/cli.js
index 14111083..62baf46e 100644
--- a/tests/cli.js
+++ b/tests/cli.js
@@ -3,159 +3,140 @@
 var path  = require("path");
 var shjs  = require("shelljs");
 var sinon = require("sinon");
-
-var cliPath = path.resolve(__dirname, "../src/cli.js");
-var cli;
-
-exports.setUp = function(done) {
-  this.sinon = sinon.sandbox.create();
-
-  // The CLI module maintains some internal state in order to optimize
-  // filesystem operations. This state can lead to undesirable test case
-  // interdependencies. While re-loading the CLI module for every test may
-  // negatively effect the execution time of this test suite, it is the most
-  // maintainable way to avoid any current or future problems relating to
-  // shared internal state.
-  cli = require("../src/cli.js");
-
-  done();
-};
-
-exports.tearDown = function(done) {
-  this.sinon.restore();
-
-  cli = null;
-  delete require.cache[cliPath];
-
-  done();
-};
+var cli   = require("../src/cli.js");
 
 exports.group = {
   setUp: function (cb) {
-    this.sinon.stub(cli, "exit");
+    sinon.stub(cli, "exit");
     cb();
   },
 
-  config: {
-    setUp: function (done) {
-      this.sinon.stub(shjs, "cat")
-        .withArgs(sinon.match(/file\.js$/)).returns("var a = function () {}; a();")
-        .withArgs(sinon.match(/file1\.json$/)).returns("wat")
-        .withArgs(sinon.match(/file2\.json$/)).returns("{\"node\":true,\"globals\":{\"foo\":true,\"bar\":true}}")
-        .withArgs(sinon.match(/file4\.json$/)).returns("{\"extends\":\"file3.json\"}")
-        .withArgs(sinon.match(/file5\.json$/)).returns("{\"extends\":\"file2.json\"}")
-        .withArgs(sinon.match(/file6\.json$/)).returns("{\"extends\":\"file2.json\",\"node\":false}")
-        .withArgs(sinon.match(/file7\.json$/)).returns("{\"extends\":\"file2.json\",\"globals\":{\"bar\":false,\"baz\":true}}");
-
-      this.sinon.stub(shjs, "test")
-        .withArgs("-e", sinon.match(/file\.js$/)).returns(true)
-        .withArgs("-e", sinon.match(/file1\.json$/)).returns(true)
-        .withArgs("-e", sinon.match(/file2\.json$/)).returns(true)
-        .withArgs("-e", sinon.match(/file3\.json$/)).returns(false)
-        .withArgs("-e", sinon.match(/file4\.json$/)).returns(true)
-        .withArgs("-e", sinon.match(/file5\.json$/)).returns(true)
-        .withArgs("-e", sinon.match(/file6\.json$/)).returns(true);
-
-      var _cli = require("cli");
-      this.out = this.sinon.stub(_cli, "error");
-
-      done();
-    },
-
-    normal: function (test) {
-      this.sinon.stub(cli, "run").returns(true);
-
-      // Merges existing valid files
-      cli.interpret([
-        "node", "jshint", "file.js", "--config", "file5.json"
-      ]);
-      test.equal(cli.run.lastCall.args[0].config.node, true);
-      test.equal(cli.run.lastCall.args[0].config['extends'], void 0);
+  tearDown: function (cb) {
+    cli.exit.restore();
+    cb();
+  },
+
+  testConfig: function (test) {
+    var _cli = require("cli");
+    var out = sinon.stub(_cli, "error");
+    sinon.stub(cli, "run").returns(true);
+
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/file\.js$/)).returns("var a = function () {}; a();")
+      .withArgs(sinon.match(/file1\.json$/)).returns("wat")
+      .withArgs(sinon.match(/file2\.json$/)).returns("{\"node\":true,\"globals\":{\"foo\":true,\"bar\":true}}")
+      .withArgs(sinon.match(/file4\.json$/)).returns("{\"extends\":\"file3.json\"}")
+      .withArgs(sinon.match(/file5\.json$/)).returns("{\"extends\":\"file2.json\"}")
+      .withArgs(sinon.match(/file6\.json$/)).returns("{\"extends\":\"file2.json\",\"node\":false}")
+      .withArgs(sinon.match(/file7\.json$/)).returns("{\"extends\":\"file2.json\",\"globals\":{\"bar\":false,\"baz\":true}}");
+
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/file\.js$/)).returns(true)
+      .withArgs("-e", sinon.match(/file1\.json$/)).returns(true)
+      .withArgs("-e", sinon.match(/file2\.json$/)).returns(true)
+      .withArgs("-e", sinon.match(/file3\.json$/)).returns(false)
+      .withArgs("-e", sinon.match(/file4\.json$/)).returns(true)
+      .withArgs("-e", sinon.match(/file5\.json$/)).returns(true)
+      .withArgs("-e", sinon.match(/file6\.json$/)).returns(true);
 
-      // Overwrites options after extending
+    cli.exit.restore();
+    sinon.stub(cli, "exit").throws("ProcessExit");
+
+    // File doesn't exist.
+    try {
       cli.interpret([
-        "node", "jshint", "file.js", "--config", "file6.json"
+        "node", "jshint", "file.js", "--config", "file3.json"
       ]);
-      test.equal(cli.run.lastCall.args[0].config.node, false);
+    } catch (err) {
+      var msg = out.args[0][0];
+      test.equal(msg.slice(0, 23), "Can't find config file:");
+      test.equal(msg.slice(msg.length - 10), "file3.json");
+      test.equal(err, "ProcessExit");
+    }
 
-      // Valid config
+    // Invalid config
+    try {
       cli.interpret([
-        "node", "jshint", "file.js", "--config", "file2.json"
+        "node", "jshint", "file.js", "--config", "file1.json"
       ]);
+    } catch (err) {
+      var msg = out.args[1][0];
+      test.equal(msg.slice(0, 24), "Can't parse config file:");
+      test.equal(msg.slice(msg.length - 10), "file1.json");
+      test.equal(err, "ProcessExit");
+    }
 
-      // Performs a deep merge of "globals" configuration
+    // Invalid merged filed
+    try {
       cli.interpret([
-        "node", "jshint", "file2.js", "--config", "file7.json"
+        "node", "jshint", "file.js", "--config", "file4.json"
       ]);
-      test.deepEqual(cli.run.lastCall.args[0].config.globals, { foo: true, bar: false, baz: true });
-
-      test.done();
-    },
-
-    failure: function (test) {
-      var out = this.out;
-      cli.exit.throws("ProcessExit");
-
-      // File doesn't exist.
-      try {
-        cli.interpret([
-          "node", "jshint", "file.js", "--config", "file3.json"
-        ]);
-      } catch (err) {
-        var msg = out.args[0][0];
-        test.equal(msg.slice(0, 23), "Can't find config file:");
-        test.equal(msg.slice(msg.length - 10), "file3.json");
-        test.equal(err, "ProcessExit");
-      }
+    } catch (err) {
+      var msg = out.args[2][0];
+      test.equal(msg.slice(0, 23), "Can't find config file:");
+      test.equal(msg.slice(msg.length - 10), "file3.json");
+      test.equal(err, "ProcessExit");
+    }
 
-      // Invalid config
-      try {
-        cli.interpret([
-          "node", "jshint", "file.js", "--config", "file1.json"
-        ]);
-      } catch (err) {
-        var msg = out.args[1][0];
-        test.equal(msg.slice(0, 24), "Can't parse config file:");
-        test.equal(msg.slice(msg.length - 10), "file1.json");
-        test.equal(err, "ProcessExit");
-      }
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
 
-      // Invalid merged filed
-      try {
-        cli.interpret([
-          "node", "jshint", "file.js", "--config", "file4.json"
-        ]);
-      } catch (err) {
-        var msg = out.args[2][0];
-        test.equal(msg.slice(0, 23), "Can't find config file:");
-        test.equal(msg.slice(msg.length - 10), "file3.json");
-        test.equal(err, "ProcessExit");
-      }
+    // Merges existing valid files
+    cli.interpret([
+      "node", "jshint", "file.js", "--config", "file5.json"
+    ]);
+    test.equal(cli.run.lastCall.args[0].config.node, true);
+    test.equal(cli.run.lastCall.args[0].config['extends'], void 0);
 
+    // Overwrites options after extending
+    cli.interpret([
+      "node", "jshint", "file.js", "--config", "file6.json"
+    ]);
+    test.equal(cli.run.lastCall.args[0].config.node, false);
 
-      test.done();
-    }
+    // Valid config
+    cli.interpret([
+      "node", "jshint", "file.js", "--config", "file2.json"
+    ]);
+
+    // Performs a deep merge of "globals" configuration
+    cli.interpret([
+      "node", "jshint", "file2.js", "--config", "file7.json"
+    ]);
+    test.deepEqual(cli.run.lastCall.args[0].config.globals, { foo: true, bar: false, baz: true });
+
+    _cli.error.restore();
+    cli.run.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
+    test.done();
   },
 
   testPrereq: function (test) {
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/file\.js$/)).returns("a();")
       .withArgs(sinon.match(/prereq.js$/)).returns("var a = 1;")
       .withArgs(sinon.match(/config.json$/))
         .returns("{\"undef\":true,\"prereq\":[\"prereq.js\", \"prereq2.js\"]}");
 
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
       .withArgs("-e", sinon.match(/file\.js$/)).returns(true)
       .withArgs("-e", sinon.match(/prereq.js$/)).returns(true)
       .withArgs("-e", sinon.match(/config.json$/)).returns(true);
 
-    cli.exit.withArgs(0).returns(true)
+    cli.exit.restore();
+    sinon.stub(cli, "exit")
+      .withArgs(0).returns(true)
       .withArgs(1).throws("ProcessExit");
 
     cli.interpret([
       "node", "jshint", "file.js", "--config", "config.json"
     ]);
 
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.done();
   },
 
@@ -171,20 +152,22 @@ exports.group = {
       }
     };
 
-    this.sinon.stub(process, "cwd").returns(dir);
-    this.sinon.stub(rep, "reporter");
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(rep, "reporter");
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/foo\.js$/)).returns("a()")
       .withArgs(sinon.match(/bar\.js$/)).returns("a()")
       .withArgs(sinon.match(/config\.json$/))
         .returns(JSON.stringify(config));
 
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
       .withArgs("-e", sinon.match(/foo\.js$/)).returns(true)
       .withArgs("-e", sinon.match(/bar\.js$/)).returns(true)
       .withArgs("-e", sinon.match(/config\.json$/)).returns(true);
 
-    cli.exit.withArgs(0).returns(true)
+    cli.exit.restore();
+    sinon.stub(cli, "exit")
+      .withArgs(0).returns(true)
       .withArgs(1).throws("ProcessExit");
 
     // Test successful file
@@ -200,6 +183,11 @@ exports.group = {
     test.ok(rep.reporter.args[1][0].length > 0, "Error was expected but not thrown");
     test.equal(rep.reporter.args[1][0][0].error.code, "W033");
 
+    process.cwd.restore();
+    rep.reporter.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.done();
   },
 
@@ -215,18 +203,20 @@ exports.group = {
       }
     };
 
-    this.sinon.stub(process, "cwd").returns(dir);
-    this.sinon.stub(rep, "reporter");
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(rep, "reporter");
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/bar\.js$/)).returns("a()")
       .withArgs(sinon.match(/config\.json$/))
         .returns(JSON.stringify(config));
 
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
       .withArgs("-e", sinon.match(/bar\.js$/)).returns(true)
       .withArgs("-e", sinon.match(/config\.json$/)).returns(true);
 
-    cli.exit.withArgs(0).returns(true)
+    cli.exit.restore();
+    sinon.stub(cli, "exit")
+      .withArgs(0).returns(true)
       .withArgs(1).throws("ProcessExit");
 
     cli.interpret([
@@ -234,6 +224,11 @@ exports.group = {
     ]);
     test.ok(rep.reporter.args[0][0].length === 1);
 
+    process.cwd.restore();
+    rep.reporter.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.done();
   },
 
@@ -242,12 +237,13 @@ exports.group = {
 
     var _cli = require("cli");
     var rep = require("../examples/reporter.js");
-    var run = this.sinon.stub(cli, "run");
-    var out = this.sinon.stub(_cli, "error");
+    var run = sinon.stub(cli, "run");
+    var out = sinon.stub(_cli, "error");
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
-    cli.exit.throws("ProcessExit");
+    cli.exit.restore();
+    sinon.stub(cli, "exit").throws("ProcessExit");
 
     // Test failed attempt.
     try {
@@ -263,12 +259,16 @@ exports.group = {
 
     // Test successful attempt.
     run.restore();
-    this.sinon.stub(rep, "reporter");
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/file\.js$/)).returns(true);
+    sinon.stub(rep, "reporter");
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/file\.js$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(true);
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/file\.js$/)).returns("func()");
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/file\.js$/)).returns("func()")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
 
     try {
       cli.interpret([
@@ -283,12 +283,16 @@ exports.group = {
       test.ok(rep.reporter.calledOnce);
     }
 
+    rep.reporter.restore();
+    shjs.test.restore();
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testJSLintReporter: function (test) {
     var rep = require("../src/reporters/jslint_xml.js");
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
 
     cli.interpret([
       "node", "jshint", "file.js", "--reporter", "jslint"
@@ -300,12 +304,13 @@ exports.group = {
     ]);
     test.equal(run.args[1][0].reporter, rep.reporter);
 
+    run.restore();
     test.done();
   },
 
   testCheckStyleReporter: function (test) {
     var rep = require("../src/reporters/checkstyle.js");
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
 
     cli.interpret([
       "node", "jshint", "file.js", "--reporter", "checkstyle"
@@ -317,23 +322,25 @@ exports.group = {
     ]);
     test.equal(run.args[1][0].reporter, rep.reporter);
 
+    run.restore();
     test.done();
   },
 
   testShowNonErrors: function (test) {
     var rep = require("../src/reporters/non_error.js");
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
 
     cli.interpret([
       "node", "jshint", "file.js", "--show-non-errors"
     ]);
     test.equal(run.args[0][0].reporter, rep.reporter);
 
+    run.restore();
     test.done();
   },
 
   testExtensions: function (test) {
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
 
     cli.interpret([
       "node", "jshint", "file.js"
@@ -345,15 +352,16 @@ exports.group = {
     ]);
     test.equal(run.args[1][0].extensions, ".json");
 
+    run.restore();
     test.done();
   },
 
   testMalformedNpmFile: function (test) {
-    this.sinon.stub(process, "cwd").returns(__dirname);
+    sinon.stub(process, "cwd").returns(__dirname);
     var localNpm = path.normalize(__dirname + "/package.json");
     var localRc = path.normalize(__dirname + "/.jshintrc");
-    var testStub = this.sinon.stub(shjs, "test");
-    var catStub = this.sinon.stub(shjs, "cat");
+    var testStub = sinon.stub(shjs, "test");
+    var catStub = sinon.stub(shjs, "cat");
 
     // stub rc file
     testStub.withArgs("-e", localRc).returns(true);
@@ -372,14 +380,17 @@ exports.group = {
     ]);
     test.equal(cli.exit.args[0][0], 0); // lint with wrong package.json
 
+    shjs.test.restore();
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testRcFile: function (test) {
-    this.sinon.stub(process, "cwd").returns(__dirname);
+    sinon.stub(process, "cwd").returns(__dirname);
     var localRc = path.normalize(__dirname + "/.jshintrc");
-    var testStub = this.sinon.stub(shjs, "test");
-    var catStub = this.sinon.stub(shjs, "cat");
+    var testStub = sinon.stub(shjs, "test");
+    var catStub = sinon.stub(shjs, "cat");
 
     // stub rc file
     testStub.withArgs("-e", localRc).returns(true);
@@ -394,13 +405,16 @@ exports.group = {
     ]);
     test.equal(cli.exit.args[0][0], 0); // eval allowed = rc file found
 
+    shjs.test.restore();
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testHomeRcFile: function (test) {
     var homeRc = path.join(process.env.HOME || process.env.HOMEPATH, ".jshintrc");
-    var testStub = this.sinon.stub(shjs, "test");
-    var catStub = this.sinon.stub(shjs, "cat");
+    var testStub = sinon.stub(shjs, "test");
+    var catStub = sinon.stub(shjs, "cat");
 
     // stub rc file
     testStub.withArgs("-e", homeRc).returns(true);
@@ -415,6 +429,8 @@ exports.group = {
     ]);
     test.equal(cli.exit.args[0][0], 0); // eval allowed = rc file found
 
+    shjs.test.restore();
+    shjs.cat.restore();
     test.done();
   },
 
@@ -423,10 +439,10 @@ exports.group = {
     var parentRc = path.join(srcDir, ".jshintrc");
 
     var cliDir = path.join(srcDir, "cli/");
-    this.sinon.stub(process, "cwd").returns(cliDir);
+    sinon.stub(process, "cwd").returns(cliDir);
 
-    var testStub = this.sinon.stub(shjs, "test");
-    var catStub = this.sinon.stub(shjs, "cat");
+    var testStub = sinon.stub(shjs, "test");
+    var catStub = sinon.stub(shjs, "cat");
 
     // stub rc file
     testStub.withArgs("-e", parentRc).returns(true);
@@ -441,16 +457,19 @@ exports.group = {
     ]);
     test.equal(cli.exit.args[0][0], 0); // eval allowed = rc file found
 
+    shjs.test.restore();
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testTargetRelativeRcLookup: function (test) {
     // working from outside the project
-    this.sinon.stub(process, "cwd").returns(process.env.HOME || process.env.HOMEPATH);
+    sinon.stub(process, "cwd").returns(process.env.HOME || process.env.HOMEPATH);
     var projectRc = path.normalize(__dirname + "/.jshintrc");
     var srcFile = __dirname + "/sub/file.js";
-    var testStub = this.sinon.stub(shjs, "test");
-    var catStub = this.sinon.stub(shjs, "cat");
+    var testStub = sinon.stub(shjs, "test");
+    var catStub = sinon.stub(shjs, "cat");
 
     // stub rc file
     testStub.withArgs("-e", projectRc).returns(true);
@@ -465,13 +484,16 @@ exports.group = {
     ]);
     test.equal(cli.exit.args[0][0], 0); // eval allowed = rc file found
 
+    shjs.test.restore();
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testIgnores: function (test) {
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     cli.interpret([
       "node", "jshint", "file.js", "--exclude=exclude.js"
@@ -482,21 +504,29 @@ exports.group = {
     test.equal(run.args[0][0].ignores[2], path.resolve(dir, "another.js"));
 
     run.restore();
-    process.cwd.returns(__dirname + "/../");
+    process.cwd.restore();
 
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(process, "cwd").returns(__dirname + "/../");
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/file.js$/)).returns("console.log('Hello');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
       .withArgs(sinon.match(/\.jshintignore$/)).returns("examples");
 
-    test.equal(shjs.cat.args.length, 0);
+    var args = shjs.cat.args.filter(function (arg) {
+      return !/\.jshintrc$/.test(arg[0]) && !/\.jshintignore$/.test(arg[0]);
+    });
+
+    test.equal(args.length, 0);
 
+    process.cwd.restore();
+    shjs.cat.restore();
     test.done();
   },
 
   testExcludePath: function (test) {
-    var run = this.sinon.stub(cli, "run");
+    var run = sinon.stub(cli, "run");
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     cli.interpret([
       "node", "jshint", "file.js", "--exclude-path=../examples/.customignore"
@@ -505,20 +535,28 @@ exports.group = {
     test.equal(run.args[0][0].ignores[0], path.resolve(dir, "exclude.js"));
 
     run.restore();
-    process.cwd.returns(__dirname + "/../");
+    process.cwd.restore();
 
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(process, "cwd").returns(__dirname + "/../");
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/file.js$/)).returns("console.log('Hello');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
       .withArgs(sinon.match(/\.jshintignore$/)).returns("examples");
 
-    test.equal(shjs.cat.args.length, 0);
+    var args = shjs.cat.args.filter(function (arg) {
+      return !/\.jshintrc$/.test(arg[0]) && !/\.jshintignore$/.test(arg[0]);
+    });
+
+    test.equal(args.length, 0);
 
+    process.cwd.restore();
+    shjs.cat.restore();
     test.done();
   },
 
   testAPIIgnores: function (test) {
     var dir = __dirname + "/../data/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
     var result = null;
 
     cli.run({
@@ -529,23 +567,25 @@ exports.group = {
 
     test.deepEqual(result, []);
 
+    process.cwd.restore();
     test.done();
   },
 
   testCollectFiles: function (test) {
-    var gather = this.sinon.stub(cli, "gather");
+    var gather = sinon.stub(cli, "gather");
     var args = [];
 
     gather.returns([]);
 
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
       .withArgs("-e", sinon.match(/.*/)).returns(true);
 
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/file2?\.js$/)).returns("console.log('Hello');")
       .withArgs(sinon.match(/ignore[\/\\]file\d\.js$/)).returns("console.log('Hello, ignore me');")
       .withArgs(sinon.match(/ignore[\/\\]dir[\/\\]file\d\.js$/)).returns("print('Ignore me');")
       .withArgs(sinon.match(/node_script$/)).returns("console.log('Hello, ignore me');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
       .withArgs(sinon.match(/\.jshintignore$/)).returns(path.join("ignore", "**"));
 
     cli.interpret([
@@ -563,20 +603,24 @@ exports.group = {
     test.equal(args.args[5], path.join("ignore", "dir", "file1.js"));
     test.equal(args.ignores, path.resolve(path.join("ignore", "**")));
 
+    shjs.test.restore();
     shjs.cat.restore();
 
-    shjs.test.withArgs("-d", sinon.match(/src$/)).returns(true)
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/.*/)).returns(true)
+      .withArgs("-d", sinon.match(/src$/)).returns(true)
       .withArgs("-d", sinon.match(/src[\/\\]lib$/)).returns(true);
 
-    this.sinon.stub(shjs, "ls")
+    sinon.stub(shjs, "ls")
       .withArgs(sinon.match(/src$/)).returns(["lib", "file4.js"])
       .withArgs(sinon.match(/src[\/\\]lib$/)).returns(["file5.js"]);
 
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/file2?\.js$/)).returns("console.log('Hello');")
       .withArgs(sinon.match(/file3\.json$/)).returns("{}")
       .withArgs(sinon.match(/src[\/\\]file4\.js$/)).returns("print('Hello');")
       .withArgs(sinon.match(/src[\/\\]lib[\/\\]file5\.js$/)).returns("print('Hello');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
       .withArgs(sinon.match(/\.jshintignore$/)).returns("");
 
     cli.interpret([
@@ -592,8 +636,14 @@ exports.group = {
     test.equal(args.args[3], "src");
     test.equal(args.ignores, false);
 
-    shjs.cat
-      .withArgs(sinon.match(/reporter\.js$/)).returns("console.log('Hello');");
+    shjs.test.restore();
+    shjs.ls.restore();
+    shjs.cat.restore();
+
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/reporter\.js$/)).returns("console.log('Hello');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
 
     cli.interpret([
       "node", "jshint", "examples"
@@ -605,13 +655,20 @@ exports.group = {
     test.equal(args.args[0], "examples");
     test.equal(args.ignores.length, 0);
 
+    shjs.cat.restore();
+
+    gather.restore();
     test.done();
   },
 
   testGatherOptionalParameters: function (test) {
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(true)
       .withArgs("-e", sinon.match(/file.js$/)).returns(true);
 
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns(path.join("ignore", "**"));
+
     var files = cli.gather({
       args: ["file.js"]
     });
@@ -619,27 +676,31 @@ exports.group = {
     test.equal(files.length, 1);
     test.equal(files[0], "file.js");
 
+    shjs.test.restore();
+    shjs.cat.restore();
     test.done();
   },
 
   testGather: function (test) {
     var dir = __dirname + "/../examples/";
     var files = [];
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var demoFiles = [
       [ /file2?\.js$/, "console.log('Hello');" ],
       [ /ignore[\/\\]file\d\.js$/, "console.log('Hello, ignore me');" ],
       [ /ignore[\/\\]dir[\/\\]file\d\.js$/, "print('Ignore me');" ],
-      [ /node_script$/, "console.log('Hello, ignore me');" ]
+      [ /node_script$/, "console.log('Hello, ignore me');" ],
+      [ /\.jshintrc$/, "{}" ],
+      [ /\.jshintignore$/, path.join("ignore", "**") ],
     ];
 
-    var testStub = this.sinon.stub(shjs, "test");
+    var testStub = sinon.stub(shjs, "test");
     demoFiles.forEach(function (file) {
       testStub = testStub.withArgs("-e", sinon.match(file[0])).returns(true);
     });
 
-    var catStub = this.sinon.stub(shjs, "cat");
+    var catStub = sinon.stub(shjs, "cat");
     demoFiles.forEach(function (file) {
       catStub = catStub.withArgs(sinon.match(file[0])).returns(file[1]);
     });
@@ -654,19 +715,29 @@ exports.group = {
       extensions: ""
     });
 
-    test.equal(shjs.cat.args.length, 0);
+    var args = shjs.cat.args.filter(function (arg) {
+      return !/\.jshintrc$/.test(arg[0]) && !/\.jshintignore$/.test(arg[0]);
+    });
+
+    test.equal(args.length, 0);
     test.equal(files.length, 3);
     test.equal(files[0], "file.js");
     test.equal(files[1], "file2.js");
     test.equal(files[2], "node_script");
 
+    shjs.test.restore();
+    shjs.cat.restore();
+
     demoFiles = [
       [ /file2?\.js$/, "console.log('Hello');" ],
       [ /file3\.json$/, "{}" ],
       [ /src[\/\\]file4\.js$/, "print('Hello');" ],
-      [ /src[\/\\]lib[\/\\]file5\.js$/, "print('Hello'); "]
+      [ /src[\/\\]lib[\/\\]file5\.js$/, "print('Hello'); "],
+      [ /\.jshintrc$/, "{}" ],
+      [ /\.jshintignore$/, "" ]
     ];
 
+    testStub = sinon.stub(shjs, "test");
     demoFiles.forEach(function (file) {
       testStub = testStub.withArgs("-e", sinon.match(file[0])).returns(true);
     });
@@ -677,10 +748,11 @@ exports.group = {
       .withArgs("-d", sinon.match(/src$/)).returns(true)
       .withArgs("-d", sinon.match(/src[\/\\]lib$/)).returns(true);
 
-    this.sinon.stub(shjs, "ls")
+    sinon.stub(shjs, "ls")
       .withArgs(sinon.match(/src$/)).returns(["lib", "file4.js"])
       .withArgs(sinon.match(/src[\/\\]lib$/)).returns(["file5.js"]);
 
+    catStub = sinon.stub(shjs, "cat");
     demoFiles.forEach(function (file) {
       catStub = catStub.withArgs(sinon.match(file[0])).returns(file[1]);
     });
@@ -695,7 +767,11 @@ exports.group = {
       ignores: []
     });
 
-    test.equal(shjs.cat.args.length, 5);
+    args = shjs.cat.args.filter(function (arg) {
+      return !/\.jshintrc$/.test(arg[0]) && !/\.jshintignore$/.test(arg[0]);
+    });
+
+    test.equal(args.length, 5);
     test.equal(files.length, 5);
     test.equal(files[0], "file.js");
     test.equal(files[1], "file2.js");
@@ -708,9 +784,11 @@ exports.group = {
     shjs.cat.restore();
     process.cwd.restore();
 
-    this.sinon.stub(process, "cwd").returns(__dirname + "/../");
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/reporter\.js$/)).returns("console.log('Hello');");
+    sinon.stub(process, "cwd").returns(__dirname + "/../");
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/reporter\.js$/)).returns("console.log('Hello');")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
 
     files = cli.gather({
       args: ["examples"],
@@ -718,25 +796,36 @@ exports.group = {
       ignores: []
     });
 
-    test.equal(shjs.cat.args.length, 0);
+    args = shjs.cat.args.filter(function (arg) {
+      return !/\.jshintrc$/.test(arg[0]) && !/\.jshintignore$/.test(arg[0]);
+    });
+
+    test.equal(args.length, 0);
     test.equal(files.length, 1);
     test.equal(files[0], path.join("examples", "reporter.js"));
 
+    shjs.cat.restore();
+    process.cwd.restore();
     test.done();
   },
 
   testStatusCode: function (test) {
     var rep = require("../examples/reporter.js");
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(rep, "reporter");
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(rep, "reporter");
+    sinon.stub(process, "cwd").returns(dir);
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/(pass\.js|fail\.js)$/)).returns(true);
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/(pass\.js|fail\.js|\.jshintrc|\.jshintignore)$/)).returns(true);
 
-    this.sinon.stub(shjs, "cat")
+    sinon.stub(shjs, "cat")
       .withArgs(sinon.match(/pass\.js$/)).returns("function test() { return 0; }")
-      .withArgs(sinon.match(/fail\.js$/)).returns("console.log('Hello')");
+      .withArgs(sinon.match(/fail\.js$/)).returns("console.log('Hello')")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
+
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
 
     cli.interpret([
       "node", "jshint", "pass.js", "--reporter=reporter.js"
@@ -749,13 +838,23 @@ exports.group = {
     test.strictEqual(cli.exit.args[0][0], 0);
     test.equal(cli.exit.args[1][0], 2);
 
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.test.restore();
+    shjs.cat.restore();
+
     test.done();
   }
 };
 
 exports.extract = {
   setUp: function (cb) {
-    this.sinon.stub(cli, "exit");
+    sinon.stub(cli, "exit");
+    cb();
+  },
+
+  tearDown: function (cb) {
+    cli.exit.restore();
     cb();
   },
 
@@ -815,12 +914,12 @@ exports.extract = {
   withIndentReportLocation: function (test) {
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var html = [
       "<html>",
@@ -832,17 +931,26 @@ exports.extract = {
       "</html>"
     ].join("\n");
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/indent\.html$/)).returns(html);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/indent\.html$/)).returns(html)
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}");
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/indent\.html$/)).returns(true);
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/indent\.html$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(false)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true);
 
     cli.interpret([
       "node", "jshint", "indent.html", "--extract", "always", "--reporter=reporter.js"
     ]);
     test.equal(cli.exit.args[0][0], 2);
 
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.equal(errors.length, 1, "found single error");
     var lintError = errors[0].error;
     test.ok(lintError, "have error object");
@@ -856,12 +964,12 @@ exports.extract = {
   withIndentReportLocationMultipleFragments: function (test) {
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var html = [
       "<html>",
@@ -878,17 +986,26 @@ exports.extract = {
       "</html>"
     ].join("\n");
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/indent\.html$/)).returns(html);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/indent\.html$/)).returns(html)
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}");
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/indent\.html$/)).returns(true);
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/indent\.html$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(false)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true);
 
     cli.interpret([
       "node", "jshint", "indent.html", "--extract", "always", "--reporter=reporter.js"
     ]);
     test.equal(cli.exit.args[0][0], 2);
 
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.equal(errors.length, 2, "found two errors");
 
     test.equal(errors[0].error.line, 5, "first error line");
@@ -903,12 +1020,12 @@ exports.extract = {
   firstLine: function (test) {
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var html = [
       "<script>",
@@ -918,17 +1035,29 @@ exports.extract = {
       "</script>"
     ].join("\n");
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/firstLine\.html$/)).returns(html);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/firstLine\.html$/)).returns(html)
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns("{}");
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/firstLine\.html$/)).returns(true);
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/firstLine\.html$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(false)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true);
+
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
 
     cli.interpret([
       "node", "jshint", "firstLine.html", "--extract", "always", "--reporter=reporter.js"
     ]);
     test.equal(cli.exit.args[0][0], 0);
 
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.equal(errors.length, 0, "found no errors");
 
     var js = [
@@ -947,12 +1076,12 @@ exports.extract = {
   sameLine: function (test) {
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var html = [
     "<script>",
@@ -966,17 +1095,29 @@ exports.extract = {
     "</script>"
     ].join("\n");
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/sameLine\.html$/)).returns(html);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/sameLine\.html$/)).returns(html)
+      .withArgs(sinon.match(/.\jshintignore$/)).returns("")
+      .withArgs(sinon.match(/.\jshintrc$/)).returns("{}");
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/sameLine\.html$/)).returns(true);
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/sameLine\.html$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintignore$/)).returns(false)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true);
+
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
 
     cli.interpret([
       "node", "jshint", "sameLine.html", "--extract", "always", "--reporter=reporter.js"
     ]);
     test.equal(cli.exit.args[0][0], 0);
 
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
+
     test.equal(errors.length, 0, "found no errors");
 
     var js = [
@@ -1000,27 +1141,39 @@ exports.extract = {
 exports.useStdin = {
   setUp: function (cb) {
     this.stdin = require('mock-stdin').stdin();
-    this.sinon.stub(cli, "exit");
+    sinon.stub(cli, "exit");
+    cb();
+  },
+
+  tearDown: function (cb) {
+    this.stdin.restore();
+    cli.exit.restore();
     cb();
   },
 
   testFilenameOption: function (test) {
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var jshintrc = JSON.stringify({ undef: true });
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/[\/\\]fake[\/\\]\.jshintrc$/)).returns(jshintrc);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/[\/\\]fake[\/\\]\.jshintrc$/)).returns(jshintrc)
+      .withArgs(sinon.match(/\/\.jshintrc$/)).returns("")
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
+
+    sinon.stub(shjs, "test")
+      .withArgs("-e", sinon.match(/fake[\/\\]\.jshintrc$/)).returns(true)
+      .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(false);
 
-    this.sinon.stub(shjs, "test")
-      .withArgs("-e", sinon.match(/fake[\/\\]\.jshintrc$/)).returns(true);
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
 
     cli.interpret([
       "node", "jshint", "--filename", "fake/fakescript.js", "--reporter=reporter.js", "-"
@@ -1038,7 +1191,10 @@ exports.useStdin = {
 
     test.equal(errors.length, 1, "should be a single error.");
     test.equal(cli.exit.args[0][0], 2, "status code should be 2 when there is a linting error.");
-
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
     test.done();
   },
 
@@ -1046,12 +1202,12 @@ exports.useStdin = {
     test.expect(4);
     var rep = require("../examples/reporter.js");
     var errors = [];
-    this.sinon.stub(rep, "reporter", function (res) {
+    sinon.stub(rep, "reporter", function (res) {
       errors = errors.concat(res);
     });
 
     var dir = __dirname + "/../examples/";
-    this.sinon.stub(process, "cwd").returns(dir);
+    sinon.stub(process, "cwd").returns(dir);
 
     var jshintrc = JSON.stringify({
       undef: false,
@@ -1062,13 +1218,17 @@ exports.useStdin = {
       }
     });
 
-    this.sinon.stub(shjs, "cat")
-      .withArgs(sinon.match(/\.jshintrc$/)).returns(jshintrc);
+    sinon.stub(shjs, "cat")
+      .withArgs(sinon.match(/\.jshintrc$/)).returns(jshintrc)
+      .withArgs(sinon.match(/\.jshintignore$/)).returns("");
 
-    this.sinon.stub(shjs, "test")
+    sinon.stub(shjs, "test")
       .withArgs("-e", sinon.match(/fake[\/\\]\.jshintrc$/)).returns(true)
       .withArgs("-e", sinon.match(/\.jshintrc$/)).returns(true);
 
+    cli.exit.restore();
+    sinon.stub(cli, "exit");
+
     cli.interpret([
       "node", "jshint", "--filename", "fake/fakescript.js", "--reporter=reporter.js", "-"
     ]);
@@ -1088,7 +1248,7 @@ exports.useStdin = {
 
     errors.length = 0;
     cli.exit.restore();
-    this.sinon.stub(cli, "exit");
+    sinon.stub(cli, "exit");
 
     this.stdin.restore();
     this.stdin = require('mock-stdin').stdin();
@@ -1101,6 +1261,10 @@ exports.useStdin = {
 
     test.equal(errors.length, 0, "should be no errors.");
     test.equal(cli.exit.args[0][0], 0, "status code should be 0 when there is no linting error.");
+    rep.reporter.restore();
+    process.cwd.restore();
+    shjs.cat.restore();
+    shjs.test.restore();
     test.done();
   }
 };
diff --git a/tests/unit/core.js b/tests/unit/core.js
index f94f4cdc..1fbcef12 100644
--- a/tests/unit/core.js
+++ b/tests/unit/core.js
@@ -524,7 +524,7 @@ exports.testSparseArrays = function (test) {
     .test(src, {es3: true});
 
   TestRun(test)
-    .test(src, { elision: true }); // es5
+    .test(src, {}); // es5
 
   test.done();
 };
diff --git a/tests/unit/fixtures/nestedFunctions-locations.js b/tests/unit/fixtures/nestedFunctions-locations.js
index 72c0829b..c1808333 100644
--- a/tests/unit/fixtures/nestedFunctions-locations.js
+++ b/tests/unit/fixtures/nestedFunctions-locations.js
@@ -220,18 +220,32 @@
     "last": 69,
     "lastcharacter": 18
   },
+  {
+    "name": "genMethod",
+    "line": 70,
+    "character": 14,
+    "last": 70,
+    "lastcharacter": 18
+  },
+  {
+    "name": "staticGenMethod",
+    "line": 71,
+    "character": 27,
+    "last": 71,
+    "lastcharacter": 31
+  },
   {
     "name": "(empty)",
-    "line": 72,
+    "line": 74,
     "character": 26,
-    "last": 72,
+    "last": 74,
     "lastcharacter": 30
   },
   {
     "name": "default",
-    "line": 74,
+    "line": 76,
     "character": 25,
-    "last": 74,
+    "last": 76,
     "lastcharacter": 29
   }
 ]
diff --git a/tests/unit/fixtures/nestedFunctions.js b/tests/unit/fixtures/nestedFunctions.js
index 629229f6..9362ca8e 100644
--- a/tests/unit/fixtures/nestedFunctions.js
+++ b/tests/unit/fixtures/nestedFunctions.js
@@ -67,6 +67,8 @@ var VarDeclClass = class {
   method() {}                      // "method"
   get getter() {}                  // "get getter"
   set setter() {}                  // "set setter"
+  *genMethod() {}                  // "genMethod"
+  static *staticGenMethod() {}     // "staticGenMethod"
 };
 
 var grouping = (function() {});
diff --git a/tests/unit/options.js b/tests/unit/options.js
index 490c5ce1..d4d234cf 100644
--- a/tests/unit/options.js
+++ b/tests/unit/options.js
@@ -1766,40 +1766,3 @@ exports.singleGroups = function (test) {
 
   test.done();
 };
-
-exports.elision = function (test) {
-  var code = [
-    "var a = [1,,2];",
-    "var b = [1,,,,2];",
-    "var c = [1,2,];",
-    "var d = [,1,2];",
-    "var e = [,,1,2];",
-  ];
-
-  TestRun(test, "elision=false ES5")
-    .addError(1, "Empty array elements require elision=true.")
-    .addError(2, "Empty array elements require elision=true.")
-    .addError(4, "Empty array elements require elision=true.")
-    .addError(5, "Empty array elements require elision=true.")
-    .test(code, { elision: false, es3: false });
-
-  TestRun(test, "elision=false ES3")
-    .addError(1, "Extra comma. (it breaks older versions of IE)")
-    .addError(2, "Extra comma. (it breaks older versions of IE)")
-    .addError(2, "Extra comma. (it breaks older versions of IE)")
-    .addError(2, "Extra comma. (it breaks older versions of IE)")
-    .addError(3, "Extra comma. (it breaks older versions of IE)")
-    .addError(4, "Extra comma. (it breaks older versions of IE)")
-    .addError(5, "Extra comma. (it breaks older versions of IE)")
-    .addError(5, "Extra comma. (it breaks older versions of IE)")
-    .test(code, { elision: false, es3: true });
-
-  TestRun(test, "elision=true ES5")
-    .test(code, { elision: true, es3: false });
-
-  TestRun(test, "elision=true ES3")
-    .addError(3, "Extra comma. (it breaks older versions of IE)")
-    .test(code, { elision: true, es3: true });
-
-  test.done();
-};
diff --git a/tests/unit/parser.js b/tests/unit/parser.js
index 9e1ea181..c7bf938b 100644
--- a/tests/unit/parser.js
+++ b/tests/unit/parser.js
@@ -312,10 +312,6 @@ exports.numbers = function (test) {
     "var j = 1e-10;", // GH-821
     "var k = 0o1234567;",
     "var l = 0b101;",
-    "var m = 0x;",
-    "var n = 09;",
-    "var o = 1e-A;",
-    "var p = 1/;",
   ];
 
   TestRun(test)
@@ -329,11 +325,6 @@ exports.numbers = function (test) {
     .addError(9, "A dot following a number can be confused with a decimal point.")
     .addError(11, "'Octal integer literal' is only available in ES6 (use esnext option).")
     .addError(12, "'Binary integer literal' is only available in ES6 (use esnext option).")
-    .addError(13, "Bad number '0x'.")
-    .addError(15, "Unexpected '1'.")
-    .addError(16, "Expected an identifier and instead saw ';'.")
-    .addError(16, "Expected an identifier and instead saw 'var'.")
-    .addError(16, "Missing semicolon.")
     .test(code, {es3: true});
 
   // Octals are prohibited in strict mode.
@@ -538,15 +529,14 @@ exports.strings = function (test) {
     "var b = \'\\g\';",
     "var c = '\\u0022\\u0070\\u005C';",
     "var e = '\\x6b..\\x6e';",
-    "var f = '\\b\\f\\n\\/';",
-    "var g = 'ax",
+    "var f = 'ax"
   ];
 
   var run = TestRun(test)
     .addError(1, "Control character in string: <non-printable>.", {character: 10})
     .addError(1, "This character may get silently deleted by one or more browsers.")
-    .addError(6, "Unclosed string.")
-    .addError(6, "Missing semicolon.");
+    .addError(5, "Unclosed string.")
+    .addError(5, "Missing semicolon.");
   run.test(code, {es3: true});
   run.test(code, {}); // es5
   run.test(code, {esnext: true});
@@ -830,6 +820,8 @@ exports["destructuring var in function scope"] = function (test) {
     .addError(9,  "'a' is already defined.")
     .addError(9,  "'bar' is already defined.")
     .addError(10,  "Expected an identifier and instead saw '1'.")
+    .addError(10,  "Expected ',' and instead saw '1'.")
+    .addError(10,  "Expected an identifier and instead saw ']'.")
     .addError(11, "Expected ',' and instead saw ';'.")
     .addError(11, "'a' is already defined.")
     .addError(11, "'b' is already defined.")
@@ -1004,6 +996,8 @@ exports["destructuring var errors"] = function (test) {
 
   TestRun(test)
     .addError(9,  "Expected an identifier and instead saw '1'.")
+    .addError(9,  "Expected ',' and instead saw '1'.")
+    .addError(9,  "Expected an identifier and instead saw ']'.")
     .addError(10, "Expected ',' and instead saw ';'.")
     .addError(11, "Expected ']' to match '[' from line 11 and instead saw ';'.")
     .addError(11, "Missing semicolon.")
@@ -1223,6 +1217,8 @@ exports["destructuring const errors"] = function (test) {
     .addError(2, "const 'b' has already been declared.")
     .addError(2, "const 'c' has already been declared.")
     .addError(3, "Expected an identifier and instead saw '1'.")
+    .addError(3, "Expected ',' and instead saw '1'.")
+    .addError(3, "Expected an identifier and instead saw ']'.")
     .addError(4, "Expected ',' and instead saw ';'.")
     .addError(5, "Expected ']' to match '[' from line 5 and instead saw ';'.")
     .addError(5, "Missing semicolon.")
@@ -1376,7 +1372,7 @@ exports["destructuring assign of empty values as moz"] = function (test) {
     .addError(2, "'d' is defined but never used.")
     .addError(3, "'e' is defined but never used.")
     .addError(3, "'f' is defined but never used.")
-    .test(code, {moz: true, unused: true, undef: true, laxcomma: true, elision: true});
+    .test(code, {moz: true, unused: true, undef: true, laxcomma: true});
 
   test.done();
 };
@@ -1394,7 +1390,7 @@ exports["destructuring assign of empty values as esnext"] = function (test) {
     .addError(2, "'d' is defined but never used.")
     .addError(3, "'e' is defined but never used.")
     .addError(3, "'f' is defined but never used.")
-    .test(code, {esnext: true, unused: true, undef: true, elision: true});
+    .test(code, {esnext: true, unused: true, undef: true});
 
   test.done();
 };
@@ -1415,7 +1411,7 @@ exports["destructuring assign of empty values as es5"] = function (test) {
     .addError(3, "'destructuring expression' is available in ES6 (use esnext option) or Mozilla JS extensions (use moz).")
     .addError(3, "'e' is defined but never used.")
     .addError(3, "'f' is defined but never used.")
-    .test(code, {unused: true, undef: true, elision: true}); // es5
+    .test(code, {unused: true, undef: true}); // es5
 
   test.done();
 };
@@ -3703,53 +3699,6 @@ exports["fat arrows support"] = function (test) {
   test.done();
 };
 
-exports["fat arrow nested function scoping"] = function (test) {
-  var code = [
-    "(() => {",
-    "  for (var i = 0; i < 10; i++) {",
-    "    var x;",
-    "  }",
-    "  var arrow = (x) => {",
-    "    return x;",
-    "  };",
-    "  var arrow2 = (x) => x;",
-    "  arrow();",
-    "  arrow2();",
-    "})();",
-    "(function() {",
-    "  for (var i = 0; i < 10; i++) {",
-    "    var x;",
-    "  }",
-    "  var arrow = (x) => {",
-    "    return x;",
-    "  };",
-    "  var arrow2 = (x) => x;",
-    "  arrow();",
-    "  arrow2();",
-    "})();"
-  ];
-
-  TestRun(test)
-    .test(code, {esnext: true});
-
-  test.done();
-};
-
-exports["default arguments in fat arrow functions"] = function (test) {
-  TestRun(test)
-    .test("(x = 0) => { return x; };", { expr: true, unused: true, esnext: true });
-
-  test.done();
-};
-
-exports["expressions in place of arrow function parameters"] = function (test) {
-  TestRun(test)
-    .addError(1, "Expected an identifier and instead saw '1'.")
-    .test("(1) => {};", { expr: true, esnext: true });
-
-  test.done();
-};
-
 var conciseMethods = exports.conciseMethods = {};
 
 conciseMethods.basicSupport = function (test) {
@@ -4250,6 +4199,14 @@ exports["class and method naming"] = function (test) {
     "  set lonely() {}",
     "  set lonel2",
     "            () {}",
+    "  *validGenerator() { yield; }",
+    "  static *validStaticGenerator() { yield; }",
+    "  *[1]() { yield; }",
+    "  static *[1]() { yield; }",
+    "  * ['*']() { yield; }",
+    "  static *['*']() { yield; }",
+    "  * [('*')]() { yield; }",
+    "  static *[('*')]() { yield; }",
     "}"
   ];
   var run = TestRun(test)
@@ -5146,3 +5103,17 @@ exports.testStrictDirectiveASI = function (test) {
 
   test.done();
 };
+
+exports.testGH1928 = function (test) {
+  var code = [
+    "var foo = {",
+    "  bar(bar) {",
+    "    return bar;",
+    "  }",
+    "};"
+  ];
+
+  TestRun(test).test(code, { esnext: true });
+
+  test.done();
+};