text: /**
   * @fileoverview Tests for ConfigArrayFactory class.
   * @author Toru Nagashima <https://github.com/mysticatea>
   */
  "use strict";
  
  //-----------------------------------------------------------------------------
  // Requirements
  //-----------------------------------------------------------------------------
  
  const path = require("path");
  const fs = require("fs");
  const { assert } = require("chai");
  const { spy } = require("sinon");
  const {
      Legacy: {
          ConfigArray,
          ConfigArrayFactory,
          OverrideTester,
          createConfigArrayFactoryContext: createContext
      }
  } = require("../../lib/");
  const { createCustomTeardown } = require("../_utils");
  const systemTempDir = require("temp-dir");
  
  //-----------------------------------------------------------------------------
  // Helpers
  //-----------------------------------------------------------------------------
  
  const eslintAllPath = path.resolve(__dirname, "../fixtures/eslint-all.js");
  const eslintRecommendedPath = path.resolve(__dirname, "../fixtures/eslint-recommended.js");
  const tempDir = path.join(systemTempDir, "eslintrc/config-array-factory");
  
  /**
   * Assert a config array element.
   * @param {Object} actual The actual value.
   * @param {Object} providedExpected The expected value.
   * @returns {void}
   */
  function assertConfigArrayElement(actual, providedExpected) {
      const expected = {
          name: "",
          filePath: "",
          criteria: null,
          env: void 0,
          globals: void 0,
          ignorePattern: void 0,
          noInlineConfig: void 0,
          parser: void 0,
          parserOptions: void 0,
          plugins: void 0,
          processor: void 0,
          reportUnusedDisableDirectives: void 0,
          root: void 0,
          rules: void 0,
          settings: void 0,
          type: "config",
          ...providedExpected
      };
  
      assert.deepStrictEqual(actual, expected);
  }
  
  /**
   * Assert a config array element.
   * @param {Object} actual The actual value.
   * @param {Object} providedExpected The expected value.
   * @returns {void}
   */
  function assertConfig(actual, providedExpected) {
      const expected = {
          env: {},
          globals: {},
          ignorePatterns: [],
          noInlineConfig: void 0,
          parser: null,
          parserOptions: {},
          plugins: [],
          reportUnusedDisableDirectives: void 0,
          rules: {},
          settings: {},
          ...providedExpected
      };
  
      assert.deepStrictEqual(actual, expected);
  }
  
  /**
   * Assert a plugin definition.
   * @param {Object} actual The actual value.
   * @param {Object} providedExpected The expected value.
   * @returns {void}
   */
  function assertPluginDefinition(actual, providedExpected) {
      const expected = {
          configs: {},
          environments: {},
          processors: {},
          rules: {},
          ...providedExpected
      };
  
      assert.deepStrictEqual(actual, expected);
  }
  
  describe("ConfigArrayFactory", () => {
  
      describe("'create(configData, options)' method should normalize the config data.", () => {
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir
          });
  
          /** @type {ConfigArrayFactory} */
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          it("should return an empty config array if 'configData' is null.", () => {
              assert.strictEqual(factory.create(null).length, 0);
          });
  
          it("should throw an error if the config data had invalid properties,", () => {
              assert.throws(() => {
                  factory.create({ files: true });
              }, /Unexpected top-level property "files"/u);
          });
  
          it("should call '_normalizeConfigData(configData, ctx)' with given arguments.", () => {
              const configData = {};
              const basePath = tempDir;
              const filePath = __filename;
              const name = "example";
              const normalizeConfigData = spy(factory, "_normalizeConfigData");
  
              factory.create(configData, { basePath, filePath, name });
  
              assert.strictEqual(normalizeConfigData.callCount, 1);
              assert.deepStrictEqual(normalizeConfigData.args[0], [
                  configData,
                  createContext({ cwd: tempDir }, void 0, name, filePath, basePath)
              ]);
          });
  
          it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
              const elements = [{}, {}];
  
              factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
  
              const configArray = factory.create({});
  
              assert.strictEqual(configArray.length, 2);
              assert.strictEqual(configArray[0], elements[0]);
              assert.strictEqual(configArray[1], elements[1]);
          });
      });
  
      describe("'loadFile(filePath, options)' method should load a config file.", () => {
          const basicFiles = {
              "js/.eslintrc.js": "exports.settings = { name: 'js/.eslintrc.js' }",
              "cjs/.eslintrc.cjs": "exports.settings = { name: 'cjs/.eslintrc.cjs' }",
              "json/.eslintrc.json": "{ \"settings\": { \"name\": \"json/.eslintrc.json\" } }",
              "legacy-json/.eslintrc": "{ \"settings\": { \"name\": \"legacy-json/.eslintrc\" } }",
              "legacy-yml/.eslintrc": "settings:\n  name: legacy-yml/.eslintrc",
              "package-json/package.json": "{ \"eslintConfig\": { \"settings\": { \"name\": \"package-json/package.json\" } } }",
              "yml/.eslintrc.yml": "settings:\n  name: yml/.eslintrc.yml",
              "yaml/.eslintrc.yaml": "settings:\n  name: yaml/.eslintrc.yaml"
          };
  
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir,
              files: {
                  ...basicFiles,
                  "invalid-property.json": "{ \"files\": \"*.js\" }",
                  "package-json-no-config/package.json": "{ \"name\": \"foo\" }"
              }
          });
  
          /** @type {ConfigArrayFactory} */
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          it("should throw an error if 'filePath' is null.", () => {
              assert.throws(() => factory.loadFile(null));
          });
  
          it("should throw an error if 'filePath' doesn't exist.", () => {
              assert.throws(() => {
                  factory.loadFile("non-exist");
              }, /Cannot read config file:.*non-exist/su);
          });
  
          it("should throw an error if 'filePath' was 'package.json' and it doesn't have 'eslintConfig' field.", () => {
              assert.throws(() => {
                  factory.loadFile("package-json-no-config/package.json");
              }, /Cannot read config file:.*package.json/su);
          });
  
          it("should throw an error if the config data had invalid properties,", () => {
              assert.throws(() => {
                  factory.loadFile("invalid-property.json");
              }, /Unexpected top-level property "files"/u);
          });
  
          for (const filePath of Object.keys(basicFiles)) {
              it(`should load '${filePath}' then return a config array what contains that file content.`, () => { // eslint-disable-line no-loop-func
                  const configArray = factory.loadFile(filePath);
  
                  assert.strictEqual(configArray.length, 1);
                  assertConfigArrayElement(configArray[0], {
                      filePath: path.resolve(tempDir, filePath),
                      name: path.relative(tempDir, path.resolve(tempDir, filePath)),
                      settings: { name: filePath }
                  });
              });
          }
  
          it("should call '_normalizeConfigData(configData, ctx)' with the loaded config data and given options.", () => {
              const basePath = tempDir;
              const filePath = "js/.eslintrc.js";
              const name = "example";
              const normalizeConfigData = spy(factory, "_normalizeConfigData");
  
              factory.loadFile(filePath, { basePath, name });
  
              assert.strictEqual(normalizeConfigData.callCount, 1);
              assert.deepStrictEqual(normalizeConfigData.args[0], [
                  { settings: { name: filePath } },
                  createContext({ cwd: tempDir }, void 0, name, filePath, basePath)
              ]);
          });
  
          it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
              const elements = [{}, {}];
  
              factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
  
              const configArray = factory.loadFile("js/.eslintrc.js");
  
              assert.strictEqual(configArray.length, 2);
              assert.strictEqual(configArray[0], elements[0]);
              assert.strictEqual(configArray[1], elements[1]);
          });
      });
  
      describe("'loadInDirectory(directoryPath, options)' method should load the config file of a directory.", () => {
          const basicFiles = {
              "js/.eslintrc.js": "exports.settings = { name: 'js/.eslintrc.js' }",
              "cjs/.eslintrc.cjs": "exports.settings = { name: 'cjs/.eslintrc.cjs' }",
              "json/.eslintrc.json": "{ \"settings\": { \"name\": \"json/.eslintrc.json\" } }",
              "legacy-json/.eslintrc": "{ \"settings\": { \"name\": \"legacy-json/.eslintrc\" } }",
              "legacy-yml/.eslintrc": "settings:\n  name: legacy-yml/.eslintrc",
              "package-json/package.json": "{ \"eslintConfig\": { \"settings\": { \"name\": \"package-json/package.json\" } } }",
              "yml/.eslintrc.yml": "settings:\n  name: yml/.eslintrc.yml",
              "yaml/.eslintrc.yaml": "settings:\n  name: yaml/.eslintrc.yaml"
          };
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir,
              files: {
                  ...basicFiles,
                  "invalid-property/.eslintrc.json": "{ \"files\": \"*.js\" }",
                  "package-json-no-config/package.json": "{ \"name\": \"foo\" }"
              }
          });
  
          /** @type {ConfigArrayFactory} */
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          it("should throw an error if 'directoryPath' is null.", () => {
              assert.throws(() => factory.loadInDirectory(null));
          });
  
          it("should return an empty config array if the config file of 'directoryPath' doesn't exist.", () => {
              assert.strictEqual(factory.loadInDirectory("non-exist").length, 0);
          });
  
          it("should return an empty config array if the config file of 'directoryPath' was package.json and it didn't have 'eslintConfig' field.", () => {
              assert.strictEqual(factory.loadInDirectory("package-json-no-config").length, 0);
          });
  
          it("should throw an error if the config data had invalid properties,", () => {
              assert.throws(() => {
                  factory.loadInDirectory("invalid-property");
              }, /Unexpected top-level property "files"/u);
          });
  
          for (const filePath of Object.keys(basicFiles)) {
              const directoryPath = filePath.split("/")[0];
  
              it(`should load '${directoryPath}' then return a config array what contains the config file of that directory.`, () => { // eslint-disable-line no-loop-func
                  const configArray = factory.loadInDirectory(directoryPath);
  
                  assert.strictEqual(configArray.length, 1);
                  assertConfigArrayElement(configArray[0], {
                      filePath: path.resolve(tempDir, filePath),
                      name: path.relative(tempDir, path.resolve(tempDir, filePath)),
                      settings: { name: filePath }
                  });
              });
          }
  
          it("should call '_normalizeConfigData(configData, ctx)' with the loaded config data and given options.", () => {
              const basePath = tempDir;
              const directoryPath = "js";
              const name = "example";
              const normalizeConfigData = spy(factory, "_normalizeConfigData");
  
              factory.loadInDirectory(directoryPath, { basePath, name });
  
              assert.strictEqual(normalizeConfigData.callCount, 1);
              assert.deepStrictEqual(normalizeConfigData.args[0], [
                  { settings: { name: `${directoryPath}/.eslintrc.js` } },
                  createContext({ cwd: tempDir }, void 0, name, path.join(directoryPath, ".eslintrc.js"), basePath)
              ]);
          });
  
          it("should return a config array that contains the yielded elements from '_normalizeConfigData(configData, ctx)'.", () => {
              const elements = [{}, {}];
  
              factory._normalizeConfigData = () => elements; // eslint-disable-line no-underscore-dangle
  
              const configArray = factory.loadInDirectory("js");
  
              assert.strictEqual(configArray.length, 2);
              assert.strictEqual(configArray[0], elements[0]);
              assert.strictEqual(configArray[1], elements[1]);
          });
      });
  
      /*
       * All of `create`, `loadFile`, and `loadInDirectory` call this method.
       * So this section tests the common part of the three.
       */
      describe("'_normalizeConfigData(configData, ctx)' method should normalize the config data.", () => {
  
          /** @type {ConfigArrayFactory} */
          let factory = null;
  
          /**
           * Call `_normalizeConfigData` method with given arguments.
           * @param {ConfigData} configData The config data to normalize.
           * @param {Object} [options] The options.
           * @param {string} [options.filePath] The path to the config file of the config data.
           * @param {string} [options.name] The name of the config file of the config data.
           * @returns {ConfigArray} The created config array.
           */
          function create(configData, { filePath, name } = {}) {
              const ctx = createContext({ cwd: tempDir }, void 0, name, filePath, void 0);
  
              return new ConfigArray(...factory._normalizeConfigData(configData, ctx)); // eslint-disable-line no-underscore-dangle
          }
  
          describe("misc", () => {
              const { prepare, cleanup, getPath } = createCustomTeardown({
                  cwd: tempDir
              });
  
              factory = new ConfigArrayFactory({ cwd: getPath() });
  
              beforeEach(prepare);
              afterEach(cleanup);
  
              describe("if the config data was empty, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({});
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the default values in the element.", () => {
                      assertConfigArrayElement(configArray[0], {});
                  });
              });
  
              describe("if the config data had 'env' property, the returned value", () => {
                  const env = { node: true };
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ env });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'env' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { env });
                  });
              });
  
              describe("if the config data had 'globals' property, the returned value", () => {
                  const globals = { window: "readonly" };
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ globals });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'globals' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { globals });
                  });
              });
  
              describe("if the config data had 'parser' property, the returned value", () => {
                  const parser = "espree";
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ parser });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'parser' value in the element.", () => {
                      assert.strictEqual(configArray[0].parser.id, parser);
                  });
              });
  
              describe("if the config data had 'parserOptions' property, the returned value", () => {
                  const parserOptions = { ecmaVersion: 2015 };
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ parserOptions });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'parserOptions' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { parserOptions });
                  });
              });
  
              describe("if the config data had 'plugins' property, the returned value", () => {
                  const plugins = [];
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ plugins });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'plugins' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { plugins: {} });
                  });
              });
  
              describe("if the config data had 'root' property, the returned value", () => {
                  const root = true;
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ root });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'root' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { root });
                  });
              });
  
              describe("if the config data had 'rules' property, the returned value", () => {
                  const rules = { eqeqeq: "error" };
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ rules });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'rules' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { rules });
                  });
              });
  
              describe("if the config data had 'settings' property, the returned value", () => {
                  const settings = { foo: 777 };
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ settings });
                  });
  
                  it("should have an element.", () => {
                      assert.strictEqual(configArray.length, 1);
                  });
  
                  it("should have the 'settings' value in the element.", () => {
                      assertConfigArrayElement(configArray[0], { settings });
                  });
              });
          });
  
          describe("'parser' details", () => {
  
              const { prepare, cleanup, getPath } = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "node_modules/xxx-parser/index.js": "exports.name = 'xxx-parser';",
                      "subdir/node_modules/xxx-parser/index.js": "exports.name = 'subdir/xxx-parser';",
                      "parser.js": "exports.name = './parser.js';"
                  }
              });
  
              before(async () => {
                  await prepare();
                  factory = new ConfigArrayFactory({ cwd: getPath() });
              });
  
              after(cleanup);
  
              describe("if the 'parser' property was a valid package, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ parser: "xxx-parser" })[0];
                  });
  
                  it("should have the package ID at 'parser.id' property.", () => {
                      assert.strictEqual(element.parser.id, "xxx-parser");
                  });
  
                  it("should have the package object at 'parser.definition' property.", () => {
                      assert.deepStrictEqual(element.parser.definition, { name: "xxx-parser" });
                  });
  
                  it("should have the path to the package at 'parser.filePath' property.", () => {
                      assert.strictEqual(element.parser.filePath, path.join(getPath(), "node_modules/xxx-parser/index.js"));
                  });
              });
  
              describe("if the 'parser' property was an invalid package, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ parser: "invalid-parser" })[0];
                  });
  
                  it("should have the package ID at 'parser.id' property.", () => {
                      assert.strictEqual(element.parser.id, "invalid-parser");
                  });
  
                  it("should have the loading error at 'parser.error' property.", () => {
                      assert.match(element.parser.error.message, /Cannot find module 'invalid-parser'/u);
                  });
              });
  
              describe("if the 'parser' property was a valid relative path, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ parser: "./parser" })[0];
                  });
  
                  it("should have the given path at 'parser.id' property.", () => {
                      assert.strictEqual(element.parser.id, "./parser");
                  });
  
                  it("should have the file's object at 'parser.definition' property.", () => {
                      assert.deepStrictEqual(element.parser.definition, { name: "./parser.js" });
                  });
  
                  it("should have the absolute path to the file at 'parser.filePath' property.", () => {
                      assert.strictEqual(element.parser.filePath, path.join(getPath(), "./parser.js"));
                  });
              });
  
              describe("if the 'parser' property was an invalid relative path, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ parser: "./invalid-parser" })[0];
                  });
  
                  it("should have the given path at 'parser.id' property.", () => {
                      assert.strictEqual(element.parser.id, "./invalid-parser");
                  });
  
                  it("should have the loading error at 'parser.error' property.", () => {
                      assert.match(element.parser.error.message, /Cannot find module '.\/invalid-parser'/u);
                  });
              });
  
              describe("if 'parser' property was given and 'filePath' option was given, the parser", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create(
                          { parser: "xxx-parser" },
                          { filePath: path.join(getPath(), "subdir/.eslintrc") }
                      )[0];
                  });
  
                  it("should be resolved relative to the 'filePath' option.", () => {
                      assert.strictEqual(
                          element.parser.filePath,
  
                          // rather than "xxx-parser" at the project root.
                          path.join(getPath(), "subdir/node_modules/xxx-parser/index.js")
                      );
                  });
              });
          });
  
          describe("'plugins' details", () => {
              const { prepare, cleanup, getPath } = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "node_modules/eslint-plugin-ext/index.js": "exports.processors = { '.abc': {}, '.xyz': {}, other: {} };",
                      "node_modules/eslint-plugin-subdir/index.js": "",
                      "node_modules/eslint-plugin-xxx/index.js": "exports.configs = { name: 'eslint-plugin-xxx' };",
                      "subdir/node_modules/eslint-plugin-subdir/index.js": "",
                      "parser.js": ""
                  }
              });
  
              before(() => {
                  factory = new ConfigArrayFactory({ cwd: getPath() });
              });
  
              beforeEach(prepare);
              afterEach(cleanup);
  
              it("should throw an error if a 'plugins' value is a file path.", () => {
                  assert.throws(() => {
                      create({ plugins: ["./path/to/plugin"] });
                  }, /Plugins array cannot includes file paths/u);
              });
  
              describe("if the 'plugins' property was a valid package, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ plugins: ["xxx"] })[0];
                  });
  
                  it("should have 'plugins[id]' property.", () => {
                      assert.notStrictEqual(element.plugins.xxx, void 0);
                  });
  
                  it("should have the package ID at 'plugins[id].id' property.", () => {
                      assert.strictEqual(element.plugins.xxx.id, "xxx");
                  });
  
                  it("should have the package object at 'plugins[id].definition' property.", () => {
                      assertPluginDefinition(
                          element.plugins.xxx.definition,
                          { configs: { name: "eslint-plugin-xxx" } }
                      );
                  });
  
                  it("should have the path to the package at 'plugins[id].filePath' property.", () => {
                      assert.strictEqual(element.plugins.xxx.filePath, path.join(getPath(), "node_modules/eslint-plugin-xxx/index.js"));
                  });
              });
  
              describe("if the 'plugins' property was an invalid package, the first config array element", () => {
                  let element;
  
                  beforeEach(() => {
                      element = create({ plugins: ["invalid"] })[0];
                  });
  
                  it("should have 'plugins[id]' property.", () => {
                      assert.notStrictEqual(element.plugins.invalid, void 0);
                  });
  
                  it("should have the package ID at 'plugins[id].id' property.", () => {
                      assert.strictEqual(element.plugins.invalid.id, "invalid");
                  });
  
                  it("should have the loading error at 'plugins[id].error' property.", () => {
                      assert.match(element.plugins.invalid.error.message, /Cannot find module 'eslint-plugin-invalid'/u);
                  });
              });
  
              describe("even if 'plugins' property was given and 'filePath' option was given,", () => {
                  it("should load the plugin from 'subdir'.", () => {
                      const configArray = create(
                          { plugins: ["subdir"] },
                          { filePath: path.resolve(tempDir, "subdir/a.js") }
                      );
  
                      assert.strictEqual(
                          configArray[0].plugins.subdir.filePath,
                          path.resolve(tempDir, "subdir/node_modules/eslint-plugin-subdir/index.js")
                      );
                  });
              });
  
              describe("if 'plugins' property was given and the plugin has two file extension processors, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({ plugins: ["ext"] });
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  describe("the first element", () => {
                      let element;
  
                      beforeEach(() => {
                          element = configArray[0];
                      });
  
                      it("should be named '#processors[\"ext/.abc\"]'.", () => {
                          assert.strictEqual(element.name, "#processors[\"ext/.abc\"]");
                      });
  
                      it("should not have 'plugins' property.", () => {
                          assert.strictEqual(element.plugins, void 0);
                      });
  
                      it("should have 'processor' property.", () => {
                          assert.strictEqual(element.processor, "ext/.abc");
                      });
  
                      it("should have 'criteria' property which matches '.abc'.", () => {
                          assert.strictEqual(element.criteria.test(path.join(getPath(), "1234.abc")), true);
                          assert.strictEqual(element.criteria.test(path.join(getPath(), "1234.xyz")), false);
                      });
                  });
  
                  describe("the second element", () => {
                      let element;
  
                      beforeEach(() => {
                          element = configArray[1];
                      });
  
                      it("should be named '#processors[\"ext/.xyz\"]'.", () => {
                          assert.strictEqual(element.name, "#processors[\"ext/.xyz\"]");
                      });
  
                      it("should not have 'plugins' property.", () => {
                          assert.strictEqual(element.plugins, void 0);
                      });
  
                      it("should have 'processor' property.", () => {
                          assert.strictEqual(element.processor, "ext/.xyz");
                      });
  
                      it("should have 'criteria' property which matches '.xyz'.", () => {
                          assert.strictEqual(element.criteria.test(path.join(getPath(), "1234.abc")), false);
                          assert.strictEqual(element.criteria.test(path.join(getPath(), "1234.xyz")), true);
                      });
                  });
  
                  describe("the third element", () => {
                      let element;
  
                      beforeEach(() => {
                          element = configArray[2];
                      });
  
                      it("should have 'plugins' property.", () => {
                          assert.strictEqual(element.plugins.ext.id, "ext");
                      });
  
                      it("should not have 'processor' property.", () => {
                          assert.strictEqual(element.processor, void 0);
                      });
                  });
              });
          });
  
          describe("'extends' details", () => {
  
              let prepare, cleanup, getPath;
  
              before(() => {
  
                  ({ prepare, cleanup, getPath } = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "node_modules/eslint-config-foo/index.js": "exports.env = { browser: true }",
                          "node_modules/eslint-config-one/index.js": "module.exports = { extends: 'two', env: { browser: true } }",
                          "node_modules/eslint-config-two/index.js": "module.exports = { env: { node: true } }",
                          "node_modules/eslint-config-override/index.js": `
                              module.exports = {
                                  rules: { regular: 1 },
                                  overrides: [
                                      { files: '*.xxx', rules: { override: 1 } },
                                      { files: '*.yyy', rules: { override: 2 } }
                                  ]
                              }
                          `,
                          "node_modules/eslint-plugin-foo/index.js": "exports.configs = { bar: { env: { es6: true } } }",
                          "node_modules/eslint-plugin-invalid-config/index.js": "exports.configs = { foo: {} }",
                          "node_modules/eslint-plugin-error/index.js": "throw new Error('xxx error')",
                          "base.js": "module.exports = { rules: { semi: [2, 'always'] } };"
                      }
                  }));
  
                  factory = new ConfigArrayFactory({
                      cwd: getPath(),
                      eslintAllPath,
                      eslintRecommendedPath
                  });
              });
  
              beforeEach(() => prepare());
              afterEach(() => cleanup());
  
              it("should throw an error when extends config module is not found", () => {
                  assert.throws(() => {
                      create({
                          extends: "not-exist",
                          rules: { eqeqeq: 2 }
                      });
                  }, /Failed to load config "not-exist" to extend from./u);
              });
  
              it("should throw an error when an eslint config is not found", () => {
                  assert.throws(() => {
                      create({
                          extends: "eslint:foo",
                          rules: { eqeqeq: 2 }
                      });
                  }, /Failed to load config "eslint:foo" to extend from./u);
              });
  
              it("should throw an error when a plugin threw while loading.", () => {
                  assert.throws(() => {
                      create({
                          extends: "plugin:error/foo",
                          rules: { eqeqeq: 2 }
                      });
                  }, /xxx error/u);
              });
  
              it("should throw an error when a plugin extend is a file path.", () => {
                  assert.throws(() => {
                      create({
                          extends: "plugin:./path/to/foo",
                          rules: { eqeqeq: 2 }
                      });
                  }, /'extends' cannot use a file path for plugins/u);
              });
  
              it("should throw an error when an eslint config is not found", () => {
                  assert.throws(() => {
                      create({
                          extends: "eslint:foo",
                          rules: { eqeqeq: 2 }
                      });
                  }, /Failed to load config "eslint:foo" to extend from./u);
              });
  
              describe("if 'extends' property was 'eslint:all', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "eslint:all", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have two elements.", () => {
                      assert.strictEqual(configArray.length, 2);
                  });
  
                  it("should have the config data of 'eslint:all' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » eslint:all",
                          filePath: eslintAllPath,
                          ...require(eslintAllPath)
                      });
                  });
  
                  it("should have the given config data at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was 'eslint:recommended', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "eslint:recommended", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have two elements.", () => {
                      assert.strictEqual(configArray.length, 2);
                  });
  
                  it("should have the config data of 'eslint:recommended' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » eslint:recommended",
                          filePath: eslintRecommendedPath,
                          ...require(eslintRecommendedPath)
                      });
                  });
  
                  it("should have the given config data at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was 'foo', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "foo", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have two elements.", () => {
                      assert.strictEqual(configArray.length, 2);
                  });
  
                  it("should have the config data of 'eslint-config-foo' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » eslint-config-foo",
                          filePath: path.join(getPath(), "node_modules/eslint-config-foo/index.js"),
                          env: { browser: true }
                      });
                  });
  
                  it("should have the given config data at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was 'plugin:foo/bar', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "plugin:foo/bar", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have two elements.", () => {
                      assert.strictEqual(configArray.length, 2);
                  });
  
                  it("should have the config data of 'plugin:foo/bar' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » plugin:foo/bar",
                          filePath: path.join(getPath(), "node_modules/eslint-plugin-foo/index.js"),
                          env: { es6: true }
                      });
                  });
  
                  it("should have the given config data at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was './base', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "./base", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have two elements.", () => {
                      assert.strictEqual(configArray.length, 2);
                  });
  
                  it("should have the config data of './base' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » ./base",
                          filePath: path.join(getPath(), "base.js"),
                          rules: { semi: [2, "always"] }
                      });
                  });
  
                  it("should have the given config data at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was 'one' and the 'one' extends 'two', the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "one", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  it("should have the config data of 'eslint-config-two' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » eslint-config-one » eslint-config-two",
                          filePath: path.join(getPath(), "node_modules/eslint-config-two/index.js"),
                          env: { node: true }
                      });
                  });
  
                  it("should have the config data of 'eslint-config-one' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc » eslint-config-one",
                          filePath: path.join(getPath(), "node_modules/eslint-config-one/index.js"),
                          env: { browser: true }
                      });
                  });
  
                  it("should have the given config data at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
  
              describe("if 'extends' property was 'override' and the 'override' has 'overrides' property, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create(
                          { extends: "override", rules: { eqeqeq: 1 } },
                          { name: ".eslintrc" }
                      );
                  });
  
                  it("should have four elements.", () => {
                      assert.strictEqual(configArray.length, 4);
                  });
  
                  it("should have the config data of 'eslint-config-override' at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          name: ".eslintrc » eslint-config-override",
                          filePath: path.join(getPath(), "node_modules/eslint-config-override/index.js"),
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the 'overrides[0]' config data of 'eslint-config-override' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: ".eslintrc » eslint-config-override#overrides[0]",
                          filePath: path.join(getPath(), "node_modules/eslint-config-override/index.js"),
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { override: 1 }
                      });
                  });
  
                  it("should have the 'overrides[1]' config data of 'eslint-config-override' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: ".eslintrc » eslint-config-override#overrides[1]",
                          filePath: path.join(getPath(), "node_modules/eslint-config-override/index.js"),
                          criteria: OverrideTester.create(["*.yyy"], [], tempDir),
                          rules: { override: 2 }
                      });
                  });
  
                  it("should have the given config data at the fourth element.", () => {
                      assertConfigArrayElement(configArray[3], {
                          name: ".eslintrc",
                          rules: { eqeqeq: 1 }
                      });
                  });
              });
          });
  
          describe("'overrides' details", () => {
  
              const { prepare, cleanup, getPath } = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "node_modules/eslint-config-foo/index.js": `
                          module.exports = {
                              rules: { eqeqeq: "error" }
                          }
                      `,
                      "node_modules/eslint-config-has-overrides/index.js": `
                          module.exports = {
                              rules: { eqeqeq: "error" },
                              overrides: [
                                  {
                                      files: ["**/foo/**/*.js"],
                                      rules: { eqeqeq: "off" }
                                  }
                              ]
                          }
                      `,
                      "node_modules/eslint-config-root/index.js": `
                          module.exports = {
                              root: true,
                              rules: { eqeqeq: "error" }
                          }
                      `
                  }
              });
  
              factory = new ConfigArrayFactory({ cwd: getPath() });
              beforeEach(prepare);
              afterEach(cleanup);
  
              describe("if 'overrides' property was given, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({
                          rules: { regular: 1 },
                          overrides: [
                              { files: "*.xxx", rules: { override: 1 } },
                              { files: "*.yyy", rules: { override: 2 } }
                          ]
                      });
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  it("should have the given config data at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0]' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: "#overrides[0]",
                          criteria: OverrideTester.create(["*.xxx"], [], tempDir),
                          rules: { override: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[1]' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: "#overrides[1]",
                          criteria: OverrideTester.create(["*.yyy"], [], tempDir),
                          rules: { override: 2 }
                      });
                  });
              });
  
              describe("if a config in 'overrides' property had 'extends' property, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({
                          rules: { regular: 1 },
                          overrides: [
                              {
                                  files: "*.xxx",
                                  extends: "foo",
                                  rules: { override: 1 }
                              }
                          ]
                      });
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  it("should have the given config data at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0] » eslint-config-foo' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: "#overrides[0] » eslint-config-foo",
                          filePath: path.join(getPath(), "node_modules/eslint-config-foo/index.js"),
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { eqeqeq: "error" }
                      });
                  });
  
                  it("should have the config data of 'overrides[0]' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: "#overrides[0]",
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { override: 1 }
                      });
                  });
              });
  
              describe("if a config in 'overrides' property had 'extends' property and the shareable config has 'overrides' property, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({
                          rules: { regular: 1 },
                          overrides: [
                              {
                                  files: "*.xxx",
                                  extends: "has-overrides",
                                  rules: { override: 1 }
                              }
                          ]
                      });
                  });
  
                  it("should have four elements.", () => {
                      assert.strictEqual(configArray.length, 4);
                  });
  
                  it("should have the given config data at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0] » eslint-config-has-overrides' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: "#overrides[0] » eslint-config-has-overrides",
                          filePath: path.join(getPath(), "node_modules/eslint-config-has-overrides/index.js"),
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { eqeqeq: "error" }
                      });
                  });
  
                  it("should have the config data of 'overrides[0] » eslint-config-has-overrides#overrides[0]' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: "#overrides[0] » eslint-config-has-overrides#overrides[0]",
                          filePath: path.join(getPath(), "node_modules/eslint-config-has-overrides/index.js"),
                          criteria: OverrideTester.and(
                              OverrideTester.create(["*.xxx"], [], getPath()),
                              OverrideTester.create(["**/foo/**/*.js"], [], getPath())
                          ),
                          rules: { eqeqeq: "off" }
                      });
                  });
  
                  it("should have the config data of 'overrides[0]' at the fourth element.", () => {
                      assertConfigArrayElement(configArray[3], {
                          name: "#overrides[0]",
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { override: 1 }
                      });
                  });
              });
  
              describe("if a config in 'overrides' property had 'overrides' property, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({
                          rules: { regular: 1 },
                          overrides: [
                              {
                                  files: "*.xxx",
                                  rules: { override: 1 },
                                  overrides: [
                                      {
                                          files: "*.yyy",
                                          rules: { override: 2 }
                                      }
                                  ]
                              }
                          ]
                      });
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  it("should have the given config data at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0]' at the second element.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: "#overrides[0]",
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { override: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0].overrides[0]' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: "#overrides[0]#overrides[0]",
                          criteria: OverrideTester.and(
                              OverrideTester.create(["*.xxx"], [], getPath()),
                              OverrideTester.create(["*.yyy"], [], getPath())
                          ),
                          rules: { override: 2 }
                      });
                  });
              });
  
              describe("if a config in 'overrides' property had 'root' property, the returned value", () => {
                  let configArray;
  
                  beforeEach(() => {
                      configArray = create({
                          rules: { regular: 1 },
                          overrides: [
                              {
                                  files: "*.xxx",
                                  extends: "root",
                                  rules: { override: 1 }
                              }
                          ]
                      });
                  });
  
                  it("should have three elements.", () => {
                      assert.strictEqual(configArray.length, 3);
                  });
  
                  it("should have the given config data at the first element.", () => {
                      assertConfigArrayElement(configArray[0], {
                          rules: { regular: 1 }
                      });
                  });
  
                  it("should have the config data of 'overrides[0] » eslint-config-root' at the second element; it doesn't have 'root' property.", () => {
                      assertConfigArrayElement(configArray[1], {
                          name: "#overrides[0] » eslint-config-root",
                          filePath: path.join(getPath(), "node_modules/eslint-config-root/index.js"),
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { eqeqeq: "error" }
                      });
                  });
  
                  it("should have the config data of 'overrides[0]' at the third element.", () => {
                      assertConfigArrayElement(configArray[2], {
                          name: "#overrides[0]",
                          criteria: OverrideTester.create(["*.xxx"], [], getPath()),
                          rules: { override: 1 }
                      });
                  });
              });
          });
  
          describe("additional plugin pool", () => {
              const { prepare, cleanup, getPath } = createCustomTeardown({
                  cwd: tempDir
              });
  
              beforeEach(async () => {
                  await prepare();
                  factory = new ConfigArrayFactory({
                      cwd: getPath(),
                      additionalPluginPool: new Map([
                          ["abc", { configs: { name: "abc" } }],
                          ["eslint-plugin-def", { configs: { name: "def" } }]
                      ])
                  });
              });
  
              afterEach(cleanup);
  
              it("should use the matched plugin in the additional plugin pool; short to short", () => {
                  const configArray = create({ plugins: ["abc"] });
  
                  assert.strictEqual(configArray[0].plugins.abc.id, "abc");
                  assertPluginDefinition(
                      configArray[0].plugins.abc.definition,
                      { configs: { name: "abc" } }
                  );
              });
  
              it("should use the matched plugin in the additional plugin pool; long to short", () => {
                  const configArray = create({ plugins: ["eslint-plugin-abc"] });
  
                  assert.strictEqual(configArray[0].plugins.abc.id, "abc");
                  assertPluginDefinition(
                      configArray[0].plugins.abc.definition,
                      { configs: { name: "abc" } }
                  );
              });
  
              it("should use the matched plugin in the additional plugin pool; short to long", () => {
                  const configArray = create({ plugins: ["def"] });
  
                  assert.strictEqual(configArray[0].plugins.def.id, "def");
                  assertPluginDefinition(
                      configArray[0].plugins.def.definition,
                      { configs: { name: "def" } }
                  );
              });
  
              it("should use the matched plugin in the additional plugin pool; long to long", () => {
                  const configArray = create({ plugins: ["eslint-plugin-def"] });
  
                  assert.strictEqual(configArray[0].plugins.def.id, "def");
                  assertPluginDefinition(
                      configArray[0].plugins.def.definition,
                      { configs: { name: "def" } }
                  );
              });
          });
      });
  
      // This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
      describe("'extends' property should handle the content of extended configs properly.", () => {
          const files = {
              "node_modules/eslint-config-foo/index.js": "exports.env = { browser: true }",
              "node_modules/eslint-config-one/index.js": "module.exports = { extends: 'two', env: { browser: true } }",
              "node_modules/eslint-config-two/index.js": "module.exports = { env: { node: true } }",
              "node_modules/eslint-plugin-invalid-parser/index.js": "exports.configs = { foo: { parser: 'nonexistent-parser' } }",
              "node_modules/eslint-plugin-invalid-config/index.js": "exports.configs = { foo: {} }",
              "js/.eslintrc.js": "module.exports = { rules: { semi: [2, 'always'] } };",
              "cjs/.eslintrc.cjs": "module.exports = { rules: { semi: [2, 'always'] } };",
              "json/.eslintrc.json": "{ \"rules\": { \"quotes\": [2, \"double\"] } }",
              "package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }",
              "yaml/.eslintrc.yaml": "env:\n    browser: true"
          };
          const { prepare, cleanup, getPath } = createCustomTeardown({ cwd: tempDir, files });
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({
                  cwd: getPath(),
                  eslintAllPath,
                  eslintRecommendedPath
              });
          });
  
          afterEach(cleanup);
  
          /**
           * Apply `extends` property.
           * @param {Object} configData The config that has `extends` property.
           * @param {string} [filePath] The path to the config data.
           * @returns {Object} The applied config data.
           */
          function applyExtends(configData, filePath = "whatever") {
              return factory
                  .create(configData, { filePath })
                  .extractConfig(filePath)
                  .toCompatibleObjectAsConfigFileContent();
          }
  
          it("should apply extension 'foo' when specified from root directory config", () => {
              const config = applyExtends({
                  extends: "foo",
                  rules: { eqeqeq: 2 }
              });
  
              assertConfig(config, {
                  env: { browser: true },
                  rules: { eqeqeq: [2] }
              });
          });
  
          it("should apply all rules when extends config includes 'eslint:all'", () => {
              const config = applyExtends({
                  extends: "eslint:all"
              });
  
              assert.strictEqual(config.rules.eqeqeq[0], "error");
              assert.strictEqual(config.rules.curly[0], "error");
          });
  
          it("should throw an error when extends config module is not found", () => {
              assert.throws(() => {
                  applyExtends({
                      extends: "not-exist",
                      rules: { eqeqeq: 2 }
                  });
              }, /Failed to load config "not-exist" to extend from./u);
          });
  
          it("should throw an error when an eslint config is not found", () => {
              assert.throws(() => {
                  applyExtends({
                      extends: "eslint:foo",
                      rules: { eqeqeq: 2 }
                  });
              }, /Failed to load config "eslint:foo" to extend from./u);
          });
  
          it("should throw an error when a parser in a plugin config is not found", () => {
              assert.throws(() => {
                  applyExtends({
                      extends: "plugin:invalid-parser/foo",
                      rules: { eqeqeq: 2 }
                  });
              }, /Failed to load parser 'nonexistent-parser' declared in 'whatever » plugin:invalid-parser\/foo'/u);
          });
  
          it("should fall back to default parser when a parser called 'espree' is not found", () => {
              const config = applyExtends({ parser: "espree" });
  
              assertConfig(config, {
                  parser: require.resolve("espree")
              });
          });
  
          it("should throw an error when a plugin config is not found", () => {
              assert.throws(() => {
                  applyExtends({
                      extends: "plugin:invalid-config/bar",
                      rules: { eqeqeq: 2 }
                  });
              }, /Failed to load config "plugin:invalid-config\/bar" to extend from./u);
          });
  
          it("should throw an error with a message template when a plugin config specifier is missing config name", () => {
              try {
                  applyExtends({
                      extends: "plugin:some-plugin",
                      rules: { eqeqeq: 2 }
                  });
              } catch (err) {
                  assert.strictEqual(err.messageTemplate, "plugin-invalid");
                  assert.deepStrictEqual(err.messageData, {
                      configName: "plugin:some-plugin",
                      importerName: path.join(getPath(), "whatever")
                  });
                  return;
              }
              assert.fail("Expected to throw an error");
          });
  
          it("should throw an error with a message template when a plugin referenced for a plugin config is not found", () => {
              try {
                  applyExtends({
                      extends: "plugin:nonexistent-plugin/baz",
                      rules: { eqeqeq: 2 }
                  });
              } catch (err) {
                  assert.strictEqual(err.messageTemplate, "plugin-missing");
                  assert.deepStrictEqual(err.messageData, {
                      pluginName: "eslint-plugin-nonexistent-plugin",
                      resolvePluginsRelativeTo: getPath(),
                      importerName: "whatever"
                  });
                  return;
              }
  
              assert.fail("Expected to throw an error");
          });
  
          it("should throw an error with a message template when a plugin in the plugins list is not found", () => {
              try {
                  applyExtends({
                      plugins: ["nonexistent-plugin"]
                  });
              } catch (err) {
                  assert.strictEqual(err.messageTemplate, "plugin-missing");
                  assert.deepStrictEqual(err.messageData, {
                      pluginName: "eslint-plugin-nonexistent-plugin",
                      resolvePluginsRelativeTo: getPath(),
                      importerName: "whatever"
                  });
                  return;
              }
              assert.fail("Expected to throw an error");
          });
  
          it("should apply extensions recursively when specified from package", () => {
              const config = applyExtends({
                  extends: "one",
                  rules: { eqeqeq: 2 }
              });
  
              assertConfig(config, {
                  env: { browser: true, node: true },
                  rules: { eqeqeq: [2] }
              });
          });
  
          it("should apply extensions when specified from a JavaScript file", () => {
              const config = applyExtends({
                  extends: ".eslintrc.js",
                  rules: { eqeqeq: 2 }
              }, "js/foo.js");
  
              assertConfig(config, {
                  rules: {
                      semi: [2, "always"],
                      eqeqeq: [2]
                  }
              });
          });
  
          it("should apply extensions when specified from a YAML file", () => {
              const config = applyExtends({
                  extends: ".eslintrc.yaml",
                  rules: { eqeqeq: 2 }
              }, "yaml/foo.js");
  
              assertConfig(config, {
                  env: { browser: true },
                  rules: {
                      eqeqeq: [2]
                  }
              });
          });
  
          it("should apply extensions when specified from a JSON file", () => {
              const config = applyExtends({
                  extends: ".eslintrc.json",
                  rules: { eqeqeq: 2 }
              }, "json/foo.js");
  
              assertConfig(config, {
                  rules: {
                      eqeqeq: [2],
                      quotes: [2, "double"]
                  }
              });
          });
  
          it("should apply extensions when specified from a package.json file in a sibling directory", () => {
              const config = applyExtends({
                  extends: "../package-json/package.json",
                  rules: { eqeqeq: 2 }
              }, "json/foo.js");
  
              assertConfig(config, {
                  env: { es6: true },
                  rules: {
                      eqeqeq: [2]
                  }
              });
          });
      });
  
      // This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
      describe("loading config files should work properly.", () => {
  
          let cleanup;
  
          beforeEach(() => {
              cleanup = () => {};
          });
  
          afterEach(() => cleanup());
  
          /**
           * Load a given config file.
           * @param {ConfigArrayFactory} factory The factory to load.
           * @param {string} filePath The path to a config file.
           * @returns {Object} The applied config data.
           */
          function load(factory, filePath) {
              return factory
                  .loadFile(filePath)
                  .extractConfig(filePath)
                  .toCompatibleObjectAsConfigFileContent();
          }
  
          it("should throw error if file doesn't exist", async () => {
              const teardown = createCustomTeardown({ cwd: tempDir });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
  
              assert.throws(() => {
                  load(factory, "legacy/nofile.js");
              });
  
              assert.throws(() => {
                  load(factory, "legacy/package.json");
              });
          });
  
          it("should load information from a legacy file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "legacy/.eslintrc": "{ rules: { eqeqeq: 2 } }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "legacy/.eslintrc");
  
              assertConfig(config, {
                  rules: {
                      eqeqeq: [2]
                  }
              });
          });
  
          it("should load information from a JavaScript file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "js/.eslintrc.js": "module.exports = { rules: { semi: [2, 'always'] } };"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
  
              const config = load(factory, "js/.eslintrc.js");
  
              assertConfig(config, {
                  rules: {
                      semi: [2, "always"]
                  }
              });
          });
  
          it("should load information from a JavaScript file with a .cjs extension", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "cjs/.eslintrc.cjs": "module.exports = { rules: { semi: [2, 'always'] } };"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
  
              const config = load(factory, "cjs/.eslintrc.cjs");
  
              assertConfig(config, {
                  rules: {
                      semi: [2, "always"]
                  }
              });
          });
  
          it("should throw error when loading invalid JavaScript file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "js/.eslintrc.broken.js": "module.exports = { rules: { semi: [2, 'always'] }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              assert.throws(() => {
                  load(factory, "js/.eslintrc.broken.js");
              }, /Cannot read config file/u);
          });
  
          it("should interpret parser module name when present in a JavaScript file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "node_modules/foo/index.js": "",
                      "js/node_modules/foo/index.js": "",
                      "js/.eslintrc.parser.js": `module.exports = {
                          parser: 'foo',
                          rules: { semi: [2, 'always'] }
                      };`
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "js/.eslintrc.parser.js");
  
              assertConfig(config, {
                  parser: path.resolve(teardown.getPath(), "js/node_modules/foo/index.js"),
                  rules: {
                      semi: [2, "always"]
                  }
              });
          });
  
          it("should interpret parser path when present in a JavaScript file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "js/.eslintrc.parser2.js": `module.exports = {
                          parser: './not-a-config.js',
                          rules: { semi: [2, 'always'] }
                      };`,
                      "js/not-a-config.js": ""
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "js/.eslintrc.parser2.js");
  
              assertConfig(config, {
                  parser: path.resolve(teardown.getPath(), "js/not-a-config.js"),
                  rules: {
                      semi: [2, "always"]
                  }
              });
          });
  
          it("should interpret parser module name or path when parser is set to default parser in a JavaScript file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "js/.eslintrc.parser3.js": `module.exports = {
                          parser: 'espree',
                          rules: { semi: [2, 'always'] }
                      };`
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "js/.eslintrc.parser3.js");
  
              assertConfig(config, {
                  parser: require.resolve("espree"),
                  rules: {
                      semi: [2, "always"]
                  }
              });
          });
  
          it("should load information from a JSON file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "json/.eslintrc.json": "{ \"rules\": { \"quotes\": [2, \"double\"] } }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "json/.eslintrc.json");
  
              assertConfig(config, {
                  rules: {
                      quotes: [2, "double"]
                  }
              });
          });
  
          it("should load fresh information from a JSON file", () => {
              const factory = new ConfigArrayFactory({ cwd: tempDir });
              const filename = "fresh-test.json";
              const filePath = path.resolve(tempDir, filename);
              const initialConfig = {
                  rules: {
                      quotes: [2, "double"]
                  }
              };
              const updatedConfig = {
                  rules: {
                      quotes: [0]
                  }
              };
              let config;
  
              fs.mkdirSync(tempDir);
              fs.writeFileSync(filePath, JSON.stringify(initialConfig));
              config = load(factory, filename);
              assertConfig(config, initialConfig);
  
              fs.writeFileSync(filePath, JSON.stringify(updatedConfig));
              config = load(factory, filename);
              assertConfig(config, updatedConfig);
  
              fs.unlinkSync(filePath);
              fs.rmdirSync(tempDir);
          });
  
          it("should load information from a package.json file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "package-json/package.json");
  
              assertConfig(config, {
                  env: { es6: true }
              });
          });
  
          it("should throw error when loading invalid package.json file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "broken-package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              assert.throws(() => {
                  try {
                      load(factory, "broken-package-json/package.json");
                  } catch (error) {
                      assert.strictEqual(error.messageTemplate, "failed-to-read-json");
                      throw error;
                  }
              }, /Cannot read config file/u);
          });
  
          it("should load fresh information from a package.json file", () => {
              const factory = new ConfigArrayFactory({ cwd: tempDir });
              const filename = "package.json";
              const filePath = path.resolve(tempDir, filename);
  
              const initialConfig = {
                  eslintConfig: {
                      rules: {
                          quotes: [2, "double"]
                      }
                  }
              };
              const updatedConfig = {
                  eslintConfig: {
                      rules: {
                          quotes: [0]
                      }
                  }
              };
              let config;
  
              fs.mkdirSync(tempDir);
              fs.writeFileSync(filePath, JSON.stringify(initialConfig));
              config = load(factory, filename);
              assertConfig(config, initialConfig.eslintConfig);
  
              fs.writeFileSync(filePath, JSON.stringify(updatedConfig));
              config = load(factory, filename);
              assertConfig(config, updatedConfig.eslintConfig);
  
              fs.unlinkSync(filePath);
              fs.rmdirSync(tempDir);
          });
  
          it("should load fresh information from a .eslintrc.js file", () => {
              const factory = new ConfigArrayFactory({ cwd: tempDir });
              const filename = ".eslintrc.js";
              const filePath = path.resolve(tempDir, filename);
              const initialConfig = {
                  rules: {
                      quotes: [2, "double"]
                  }
              };
              const updatedConfig = {
                  rules: {
                      quotes: [0]
                  }
              };
              let config;
  
              fs.mkdirSync(tempDir);
              fs.writeFileSync(filePath, `module.exports = ${JSON.stringify(initialConfig)}`);
              config = load(factory, filePath);
              assertConfig(config, initialConfig);
  
              fs.writeFileSync(filePath, `module.exports = ${JSON.stringify(updatedConfig)}`);
              config = load(factory, filePath);
              assertConfig(config, updatedConfig);
  
              fs.unlinkSync(filePath);
              fs.rmdirSync(tempDir);
          });
  
          it("should load information from a YAML file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "yaml/.eslintrc.yaml": "env:\n    browser: true"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "yaml/.eslintrc.yaml");
  
              assertConfig(config, {
                  env: { browser: true }
              });
          });
  
          it("should load information from an empty YAML file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "yaml/.eslintrc.empty.yaml": "{}"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "yaml/.eslintrc.empty.yaml");
  
              assertConfig(config, {});
          });
  
          it("should load information from a YML file", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "yml/.eslintrc.yml": "env:\n    node: true"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "yml/.eslintrc.yml");
  
              assertConfig(config, {
                  env: { node: true }
              });
          });
  
          it("should load information from a YML file and apply extensions", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "extends/.eslintrc.yml": "extends: ../package-json/package.json\nrules:\n    booya: 2",
                      "package-json/package.json": "{ \"eslintConfig\": { \"env\": { \"es6\": true } } }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "extends/.eslintrc.yml");
  
              assertConfig(config, {
                  env: { es6: true },
                  rules: { booya: [2] }
              });
          });
  
          it("should load information from `extends` chain.", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "extends-chain/node_modules/eslint-config-a/node_modules/eslint-config-b/node_modules/eslint-config-c/index.js": "module.exports = { rules: { c: 2 } };",
                      "extends-chain/node_modules/eslint-config-a/node_modules/eslint-config-b/index.js": "module.exports = { extends: 'c', rules: { b: 2 } };",
                      "extends-chain/node_modules/eslint-config-a/index.js": "module.exports = { extends: 'b', rules: { a: 2 } };",
                      "extends-chain/.eslintrc.json": "{ \"extends\": \"a\" }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "extends-chain/.eslintrc.json");
  
              assertConfig(config, {
                  rules: {
                      a: [2], // from node_modules/eslint-config-a
                      b: [2], // from node_modules/eslint-config-a/node_modules/eslint-config-b
                      c: [2] // from node_modules/eslint-config-a/node_modules/eslint-config-b/node_modules/eslint-config-c
                  }
              });
          });
  
          it("should load information from `extends` chain with relative path.", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "extends-chain-2/node_modules/eslint-config-a/index.js": "module.exports = { extends: './relative.js', rules: { a: 2 } };",
                      "extends-chain-2/node_modules/eslint-config-a/relative.js": "module.exports = { rules: { relative: 2 } };",
                      "extends-chain-2/.eslintrc.json": "{ \"extends\": \"a\" }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "extends-chain-2/.eslintrc.json");
  
              assertConfig(config, {
                  rules: {
                      a: [2], // from node_modules/eslint-config-a/index.js
                      relative: [2] // from node_modules/eslint-config-a/relative.js
                  }
              });
          });
  
          it("should load information from `extends` chain in .eslintrc with relative path.", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "extends-chain-2/node_modules/eslint-config-a/index.js": "module.exports = { extends: './relative.js', rules: { a: 2 } };",
                      "extends-chain-2/node_modules/eslint-config-a/relative.js": "module.exports = { rules: { relative: 2 } };",
                      "extends-chain-2/relative.eslintrc.json": "{ \"extends\": \"./node_modules/eslint-config-a/index.js\" }"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "extends-chain-2/relative.eslintrc.json");
  
              assertConfig(config, {
                  rules: {
                      a: [2], // from node_modules/eslint-config-a/index.js
                      relative: [2] // from node_modules/eslint-config-a/relative.js
                  }
              });
          });
  
          it("should load information from `parser` in .eslintrc with relative path.", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "extends-chain-2/parser.eslintrc.json": "{ \"parser\": \"./parser.js\" }",
                      "extends-chain-2/parser.js": ""
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              const config = load(factory, "extends-chain-2/parser.eslintrc.json");
  
              assertConfig(config, {
                  parser: path.resolve(teardown.getPath(), "extends-chain-2/parser.js")
              });
          });
  
          describe("Plugins", () => {
              it("should load information from a YML file and load plugins", async () => {
                  const teardown = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "node_modules/eslint-plugin-test/index.js": `
                              module.exports = {
                                  environments: {
                                      bar: { globals: { bar: true } }
                                  }
                              }
                          `,
                          "plugins/.eslintrc.yml": `
                              plugins:
                                  - test
                              rules:
                                  test/foo: 2
                              env:
                                  test/bar: true
                          `
                      }
                  });
  
                  cleanup = teardown.cleanup;
  
                  await teardown.prepare();
                  const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
                  const config = load(factory, "plugins/.eslintrc.yml");
  
                  assertConfig(config, {
                      env: { "test/bar": true },
                      plugins: ["test"],
                      rules: {
                          "test/foo": [2]
                      }
                  });
              });
  
              it("should load two separate configs from a plugin", async () => {
                  const teardown = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "node_modules/eslint-plugin-test2/index.js": `
                              module.exports = {
                                  configs: {
                                      foo: { rules: { semi: 2, quotes: 1 } },
                                      bar: { rules: { quotes: 2, yoda: 2 } }
                                  }
                              }
                          `,
                          "plugins/.eslintrc.yml": `
                              extends:
                                  - plugin:test2/foo
                                  - plugin:test2/bar
                          `
                      }
                  });
  
                  cleanup = teardown.cleanup;
  
                  await teardown.prepare();
                  const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
                  const config = load(factory, "plugins/.eslintrc.yml");
  
                  assertConfig(config, {
                      rules: {
                          semi: [2],
                          quotes: [2],
                          yoda: [2]
                      }
                  });
              });
          });
  
          describe("even if config files have Unicode BOM,", () => {
              it("should read the JSON config file correctly.", async () => {
                  const teardown = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "bom/.eslintrc.json": "\uFEFF{ \"rules\": { \"semi\": \"error\" } }"
                      }
                  });
  
                  cleanup = teardown.cleanup;
  
                  await teardown.prepare();
                  const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
                  const config = load(factory, "bom/.eslintrc.json");
  
                  assertConfig(config, {
                      rules: {
                          semi: ["error"]
                      }
                  });
              });
  
              it("should read the YAML config file correctly.", async () => {
                  const teardown = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "bom/.eslintrc.yaml": "\uFEFFrules:\n  semi: error"
                      }
                  });
  
                  cleanup = teardown.cleanup;
  
                  await teardown.prepare();
                  const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
                  const config = load(factory, "bom/.eslintrc.yaml");
  
                  assertConfig(config, {
                      rules: {
                          semi: ["error"]
                      }
                  });
              });
  
              it("should read the config in package.json correctly.", async () => {
                  const teardown = createCustomTeardown({
                      cwd: tempDir,
                      files: {
                          "bom/package.json": "\uFEFF{ \"eslintConfig\": { \"rules\": { \"semi\": \"error\" } } }"
                      }
                  });
  
                  cleanup = teardown.cleanup;
  
                  await teardown.prepare();
                  const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
                  const config = load(factory, "bom/package.json");
  
                  assertConfig(config, {
                      rules: {
                          semi: ["error"]
                      }
                  });
              });
          });
  
          it("throws an error including the config file name if the config file is invalid", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "invalid/invalid-top-level-property.yml": "invalidProperty: 3"
                  }
              });
  
              cleanup = teardown.cleanup;
  
              await teardown.prepare();
              const factory = new ConfigArrayFactory({ cwd: teardown.getPath() });
  
              try {
                  load(factory, "invalid/invalid-top-level-property.yml");
              } catch (err) {
                  assert.include(err.message, `ESLint configuration in ${`invalid${path.sep}invalid-top-level-property.yml`} is invalid`);
                  return;
              }
              assert.fail();
          });
      });
  
      // This group moved from 'tests/lib/config/config-file.js' when refactoring to keep the cumulated test cases.
      describe("'extends' property should resolve the location of configs properly.", async () => {
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir,
              files: {
                  "node_modules/eslint-config-foo/index.js": "",
                  "node_modules/eslint-config-foo/bar.js": "",
                  "node_modules/eslint-config-eslint-configfoo/index.js": "",
                  "node_modules/@foo/eslint-config/index.js": "",
                  "node_modules/@foo/eslint-config-bar/index.js": "",
                  "node_modules/eslint-plugin-foo/index.js": "exports.configs = { bar: {} }",
                  "node_modules/@foo/eslint-plugin/index.js": "exports.configs = { bar: {} }",
                  "node_modules/@foo/eslint-plugin-bar/index.js": "exports.configs = { baz: {} }",
                  "foo/bar/.eslintrc": "",
                  ".eslintrc": ""
              }
          });
  
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          /**
           * Resolve `extends` module.
           * @param {string} request The module name to resolve.
           * @param {string} [relativeTo] The importer path to resolve.
           * @returns {string} The resolved path.
           */
          function resolve(request, relativeTo) {
              return factory.create(
                  { extends: request },
                  { filePath: relativeTo }
              )[0];
          }
  
          describe("Relative to CWD", () => {
              for (const { input, expected } of [
                  { input: ".eslintrc", expected: path.resolve(tempDir, ".eslintrc") },
                  { input: "eslint-config-foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
                  { input: "eslint-config-foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
                  { input: "foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
                  { input: "foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
                  { input: "eslint-configfoo", expected: path.resolve(tempDir, "node_modules/eslint-config-eslint-configfoo/index.js") },
                  { input: "@foo/eslint-config", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
                  { input: "@foo", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
                  { input: "@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config-bar/index.js") },
                  { input: "plugin:foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-plugin-foo/index.js") },
                  { input: "plugin:@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin/index.js") },
                  { input: "plugin:@foo/bar/baz", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin-bar/index.js") }
              ]) {
                  it(`should return ${expected} when passed ${input}`, () => {
                      const result = resolve(input);
  
                      assert.strictEqual(result.filePath, expected);
                  });
              }
          });
  
          describe("Relative to config file", () => {
              const relativePath = path.resolve(tempDir, "./foo/bar/.eslintrc");
  
              for (const { input, expected } of [
                  { input: ".eslintrc", expected: path.join(path.dirname(relativePath), ".eslintrc") },
                  { input: "eslint-config-foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
                  { input: "eslint-config-foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
                  { input: "foo", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/index.js") },
                  { input: "foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-config-foo/bar.js") },
                  { input: "eslint-configfoo", expected: path.resolve(tempDir, "node_modules/eslint-config-eslint-configfoo/index.js") },
                  { input: "@foo/eslint-config", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
                  { input: "@foo", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config/index.js") },
                  { input: "@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-config-bar/index.js") },
                  { input: "plugin:foo/bar", expected: path.resolve(tempDir, "node_modules/eslint-plugin-foo/index.js") },
                  { input: "plugin:@foo/bar", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin/index.js") },
                  { input: "plugin:@foo/bar/baz", expected: path.resolve(tempDir, "node_modules/@foo/eslint-plugin-bar/index.js") }
              ]) {
                  it(`should return ${expected} when passed ${input}`, () => {
                      const result = resolve(input, relativePath);
  
                      assert.strictEqual(result.filePath, expected);
                  });
              }
          });
      });
  
      // This group moved from 'tests/lib/config/plugins.js' when refactoring to keep the cumulated test cases.
      describe("'plugins' property should load a correct plugin.", () => {
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir,
              files: {
                  "node_modules/@scope/eslint-plugin-example/index.js": "exports.configs = { name: '@scope/eslint-plugin-example' };",
                  "node_modules/eslint-plugin-example/index.js": "exports.configs = { name: 'eslint-plugin-example' };",
                  "node_modules/eslint-plugin-throws-on-load/index.js": "throw new Error('error thrown while loading this module')"
              }
          });
  
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          /**
           * Load a plugin.
           * @param {string} request A request to load a plugin.
           * @param {ConfigArrayFactory} [configArrayFactory] The factory to use
           * @returns {Map<string,Object>} The loaded plugins.
           */
          function load(request, configArrayFactory = factory) {
              const config = configArrayFactory.create({ plugins: [request] });
  
              return new Map(
                  Object
                      .entries(config[0].plugins)
                      .map(([id, entry]) => {
                          if (entry.error) {
                              throw entry.error;
                          }
                          return [id, entry.definition];
                      })
              );
          }
  
          it("should load a plugin when referenced by short name", () => {
              const loadedPlugins = load("example");
  
              assertPluginDefinition(
                  loadedPlugins.get("example"),
                  { configs: { name: "eslint-plugin-example" } }
              );
          });
  
          it("should load a plugin when referenced by short name, even when using a custom loadPluginsRelativeTo value", async () => {
              const teardown = createCustomTeardown({
                  cwd: tempDir,
                  files: {
                      "subdir/node_modules/eslint-plugin-example/index.js": "exports.configs = { name: 'eslint-plugin-example' };"
                  }
              });
  
              await teardown.prepare();
              const factoryWithCustomPluginPath = new ConfigArrayFactory({
                  cwd: teardown.getPath(),
                  resolvePluginsRelativeTo: "subdir"
              });
  
              const loadedPlugins = load("example", factoryWithCustomPluginPath);
  
              assertPluginDefinition(
                  loadedPlugins.get("example"),
                  { configs: { name: "eslint-plugin-example" } }
              );
  
              await teardown.cleanup();
          });
  
          it("should load a plugin when referenced by long name", () => {
              const loadedPlugins = load("eslint-plugin-example");
  
              assertPluginDefinition(
                  loadedPlugins.get("example"),
                  { configs: { name: "eslint-plugin-example" } }
              );
          });
  
          it("should throw an error when a plugin has whitespace", () => {
              assert.throws(() => {
                  load("whitespace ");
              }, /Whitespace found in plugin name 'whitespace '/u);
              assert.throws(() => {
                  load("whitespace\t");
              }, /Whitespace found in plugin name/u);
              assert.throws(() => {
                  load("whitespace\n");
              }, /Whitespace found in plugin name/u);
              assert.throws(() => {
                  load("whitespace\r");
              }, /Whitespace found in plugin name/u);
          });
  
          it("should throw an error when a plugin doesn't exist", () => {
              assert.throws(() => {
                  load("nonexistentplugin");
              }, /Failed to load plugin/u);
          });
  
          it("should rethrow an error that a plugin throws on load", () => {
              assert.throws(() => {
                  load("throws-on-load");
              }, /error thrown while loading this module/u);
          });
  
          it("should load a scoped plugin when referenced by short name", () => {
              const loadedPlugins = load("@scope/example");
  
              assertPluginDefinition(
                  loadedPlugins.get("@scope/example"),
                  { configs: { name: "@scope/eslint-plugin-example" } }
              );
          });
  
          it("should load a scoped plugin when referenced by long name", () => {
              const loadedPlugins = load("@scope/eslint-plugin-example");
  
              assertPluginDefinition(
                  loadedPlugins.get("@scope/example"),
                  { configs: { name: "@scope/eslint-plugin-example" } }
              );
          });
  
          describe("when referencing a scope plugin and omitting @scope/", () => {
              it("should load a scoped plugin when referenced by short name, but should not get the plugin if '@scope/' is omitted", () => {
                  const loadedPlugins = load("@scope/example");
  
                  assert.strictEqual(loadedPlugins.get("example"), void 0);
              });
  
              it("should load a scoped plugin when referenced by long name, but should not get the plugin if '@scope/' is omitted", () => {
                  const loadedPlugins = load("@scope/eslint-plugin-example");
  
                  assert.strictEqual(loadedPlugins.get("example"), void 0);
              });
          });
      });
  
      // This group moved from 'tests/lib/config/plugins.js' when refactoring to keep the cumulated test cases.
      describe("'plugins' property should load some correct plugins.", () => {
          const { prepare, cleanup, getPath } = createCustomTeardown({
              cwd: tempDir,
              files: {
                  "node_modules/eslint-plugin-example1/index.js": "exports.configs = { name: 'eslint-plugin-example1' };",
                  "node_modules/eslint-plugin-example2/index.js": "exports.configs = { name: 'eslint-plugin-example2' };"
              }
          });
  
          let factory;
  
          beforeEach(async () => {
              await prepare();
              factory = new ConfigArrayFactory({ cwd: getPath() });
          });
  
          afterEach(cleanup);
  
          /**
           * Load a plugin.
           * @param {string[]} request A request to load a plugin.
           * @returns {Map<string,Object>} The loaded plugins.
           */
          function loadAll(request) {
              const config = factory.create({ plugins: request });
  
              return new Map(
                  Object
                      .entries(config[0].plugins)
                      .map(([id, entry]) => {
                          if (entry.error) {
                              throw entry.error;
                          }
                          return [id, entry.definition];
                      })
              );
          }
  
          it("should load plugins when passed multiple plugins", () => {
              const loadedPlugins = loadAll(["example1", "example2"]);
  
              assertPluginDefinition(
                  loadedPlugins.get("example1"),
                  { configs: { name: "eslint-plugin-example1" } }
              );
              assertPluginDefinition(
                  loadedPlugins.get("example2"),
                  { configs: { name: "eslint-plugin-example2" } }
              );
          });
      });
  });
  