import webpackSchema from "webpack/schemas/WebpackOptions.json";

import { validate } from "../src";

import schema from "./fixtures/schema.json";

describe("Validation", () => {
  function createSuccessTestCase(
    name,
    config,
    options = {},
    testSchema = schema
  ) {
    it(`should pass validation for ${name}`, () => {
      let error;

      try {
        validate(testSchema, config, options.name);
      } catch (maybeValidationError) {
        if (maybeValidationError.name !== "ValidationError") {
          throw maybeValidationError;
        }

        error = maybeValidationError;
      }

      expect(error).toBeUndefined();
    });
  }

  function createFailedTestCase(name, config, fn, configuration = {}) {
    it(`should fail validation for ${name}`, () => {
      try {
        validate(schema, config, configuration);
      } catch (error) {
        if (error.name !== "ValidationError") {
          throw error;
        }

        expect(error.message).toMatch(
          new RegExp(
            `^Invalid ${configuration.baseDataPath || "configuration"} object`
          )
        );
        fn(error.message);

        return;
      }

      throw new Error("Validation didn't fail");
    });
  }

  createSuccessTestCase("empty array", {
    arrayType: [],
  });

  createSuccessTestCase("non empty array", {
    arrayType2: ["1", 2, true],
  });

  createSuccessTestCase("only additional items", {
    onlyAdditionalItems: ["1", 2, true],
  });

  createSuccessTestCase("boolean type", {
    booleanType: true,
  });

  createSuccessTestCase("number keywords without number type", {
    numberWithoutType: true,
  });

  createSuccessTestCase("number keywords without number type #2", {
    numberWithoutType: 25,
  });

  createSuccessTestCase("number keywords without number type #3", {
    numberWithoutType2: true,
  });

  createSuccessTestCase("number keywords without number type #4", {
    numberWithoutType2: 20,
  });

  createSuccessTestCase("string keywords without string type", {
    stringWithoutType: true,
  });

  createSuccessTestCase("string keywords without string type", {
    stringWithoutType: 127,
  });

  createSuccessTestCase("string keywords without string type #2", {
    stringWithoutType: "127.0.0.1",
  });

  createSuccessTestCase("array keywords without array type", {
    arrayWithoutType: true,
  });

  createSuccessTestCase("array keywords without array type #2", {
    arrayWithoutType: [1, "test", true, false],
  });

  createSuccessTestCase("array keywords without array type #3", {
    arrayWithoutType: "string",
  });

  createSuccessTestCase("object with required and properties", {
    justAnObject: { foo: "test", bar: 4, qwerty: "qwerty" },
  });

  createSuccessTestCase("object with patternRequired", {
    objectTest4: { fao: true, fbo: true, c: true },
  });

  createSuccessTestCase("array with items with true", {
    itemsTrue: [1, 2, 3, "test"],
  });

  createSuccessTestCase("empty const", {
    emptyConst: "",
  });

  createSuccessTestCase("ref inside object inside allOf", {
    refAndAnyOf: { foo: [/test/] },
  });

  createSuccessTestCase("additionalProperties inside oneOf", {
    additionalPropertiesInsideOneOf: { foo: 100 },
  });

  createSuccessTestCase("additionalProperties inside oneOf #2", {
    additionalPropertiesInsideOneOf2: { foo: 100, bar: "baz" },
  });

  createSuccessTestCase("single item in contains", {
    singleContainsItems: [1, "test", true],
  });

  createSuccessTestCase("array with contains", {
    arrayKeyword17: [/test/, 1, "test", true],
  });

  createSuccessTestCase("const", {
    constKeyword: "foo",
  });

  createSuccessTestCase("const #2", {
    constKeyword2: ["foo", "bar"],
  });

  createSuccessTestCase("const with array notation", {
    constWithArrayNotation: [1, 2, 3],
  });

  createSuccessTestCase("const with object notation", {
    constWithObjectNotation: { foo: "bar", baz: 123 },
  });

  createSuccessTestCase("items and additionalItems", {
    additionalItemsWithoutType: [1, 2, 3, 4, 5],
  });

  createSuccessTestCase("items and additionalItems #2", {
    additionalItemsWithoutType2: [
      1,
      true,
      /test/,
      "string",
      [1, 2, 3],
      { foo: "bar" },
      null,
    ],
  });

  createSuccessTestCase("items and additionalItems #3", {
    additionalItemsWithoutType3: ["string", "other-string", 1, true, 2, false],
  });

  createSuccessTestCase("contains and additionalItems", {
    containsAndAdditionalItems: [/test/, true, "string"],
  });

  createSuccessTestCase("contains and additionalItems", {
    containsAndAdditionalItems: [/test/, 1, "string"],
  });

  createSuccessTestCase("contains inside items", {
    containsInsideItem: [1, "test", true, /test/],
  });

  createSuccessTestCase("contains inside items #2", {
    containsInsideItem: ["test", "test", "test"],
  });

  createSuccessTestCase("contains inside items #3", {
    containsInsideItem: [["test", 1], "1", /test/],
  });

  createSuccessTestCase("contains inside items #3", {
    containsInsideItem: [[1, "test"], "1", /test/],
  });

  createSuccessTestCase("object without properties", {
    emptyObject: {},
  });

  createSuccessTestCase("non empty object", {
    nonEmptyObject: { bar: 123 },
  });

  createSuccessTestCase("non empty object #2", {
    nonEmptyObject: {},
  });

  createSuccessTestCase("non empty object #3", {
    nonEmptyObject2: { foo: "test" },
  });

  createSuccessTestCase("oneOf", {
    optimization: {
      runtimeChunk: {
        name: "fef",
      },
    },
  });

  createSuccessTestCase("not array", {
    notArray: 1,
  });

  createSuccessTestCase("no type like number with minimum", {
    noTypeLikeNumberMinimum: 6,
  });

  createSuccessTestCase("no type like number with minimum", {
    noTypeLikeNumberMinimum: true,
  });

  createSuccessTestCase("no type like number with maximum", {
    noTypeLikeNumberMaximum: 4,
  });

  createSuccessTestCase("no type like number with maximum", {
    noTypeLikeNumberMaximum: true,
  });

  createSuccessTestCase("no type like number with minimum", {
    noTypeLikeNumberExclusiveMinimum: 6,
  });

  createSuccessTestCase("no type like number with minimum", {
    noTypeLikeNumberExclusiveMinimum: true,
  });

  createSuccessTestCase("no type like number with maximum", {
    noTypeLikeNumberExclusiveMaximum: 4,
  });

  createSuccessTestCase("no type like number with maximum", {
    noTypeLikeNumberExclusiveMaximum: true,
  });

  createSuccessTestCase("no type like number with multipleOf", {
    noTypeLikeNumberMultipleOf: true,
  });

  createSuccessTestCase("no type like string with pattern", {
    noTypeLikeStringPattern: 1,
  });

  createSuccessTestCase("no type like string with pattern #2", {
    noTypeLikeStringPattern: "a",
  });

  createSuccessTestCase("no type like string with MinLength equals 1", {
    noTypeLikeStringMinLength1: 1,
  });

  createSuccessTestCase("no type like array with additionalItems", {
    noTypeLikeArrayAdditionalItems: true,
  });

  createSuccessTestCase("absolutePath", {
    testAbsolutePath: "/directory/deep/tree",
  });

  createSuccessTestCase("absolutePath #1", {
    testAbsolutePath: "c:\\directory\\deep\\tree",
  });

  createSuccessTestCase("absolutePath #2", {
    testAbsolutePath: "C:\\directory\\deep\\tree",
  });

  createSuccessTestCase("absolutePath #3", {
    testAbsolutePath: "C:/directory/deep/tree",
  });

  createSuccessTestCase("absolutePath #4", {
    testAbsolutePath: "\\\\server\\directory\\deep\\tree",
  });

  createSuccessTestCase("absolutePath #5", {
    testAbsolutePath: "//server/directory/deep/tree",
  });

  createSuccessTestCase("$data", {
    dollarData: {
      smaller: 5,
      larger: 7,
    },
  });

  createSuccessTestCase("enum with undefinedAsNull", {
    // eslint-disable-next-line no-undefined
    enumKeywordAndUndefined: undefined,
  });

  createSuccessTestCase("enum with undefinedAsNull #2", {
    enumKeywordAndUndefined: 0,
  });

  createSuccessTestCase("array with enum and undefinedAsNull", {
    arrayStringAndEnum: ["a", "b", "c"],
  });

  createSuccessTestCase("array with enum and undefinedAsNull #2", {
    // eslint-disable-next-line no-undefined
    arrayStringAndEnum: [undefined, false, undefined, 0, "test", undefined],
  });

  createSuccessTestCase("array with enum and undefinedAsNull #3", {
    // eslint-disable-next-line no-undefined
    arrayStringAndEnum: [undefined, null, false, 0, ""],
  });

  createSuccessTestCase("string and undefinedAsNull #3", {
    stringTypeAndUndefinedAsNull: "test",
  });

  // The "name" option
  createFailedTestCase(
    "webpack name",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Webpack",
    }
  );

  createFailedTestCase(
    "css-loader name",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "CSS Loader",
    }
  );

  createFailedTestCase(
    "terser-webpack-plugin name",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Terser Plugin",
    }
  );

  // The "dataPath" option
  createFailedTestCase(
    "configuration dataPath",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Webpack",
      baseDataPath: "configuration",
    }
  );

  createFailedTestCase(
    "configuration dataPath #1",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "MyPlugin",
      baseDataPath: "options",
    }
  );

  // The "postFormatter" option
  createFailedTestCase(
    "postFormatter",
    {
      debug: true,
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Webpack",
      baseDataPath: "configuration",
      postFormatter: (formattedError, error) => {
        if (
          error.keyword === "additionalProperties" &&
          !error.dataPath &&
          error.params.additionalProperty === "debug"
        ) {
          return (
            `${formattedError}\n` +
            "The 'debug' property was removed in webpack 2.0.0.\n" +
            "Loaders should be updated to allow passing this option via loader options in module.rules.\n" +
            "Until loaders are updated one can use the LoaderOptionsPlugin to switch loaders into debug mode:\n" +
            "plugins: [\n" +
            "  new webpack.LoaderOptionsPlugin({\n" +
            "    debug: true\n" +
            "  })\n" +
            "]"
          );
        }

        return formattedError;
      },
    }
  );

  createFailedTestCase(
    "postFormatter #1",
    {
      minify: true,
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Webpack",
      baseDataPath: "configuration",
      postFormatter: (formattedError, error) => {
        if (
          error.keyword === "additionalProperties" &&
          !error.dataPath &&
          error.params.additionalProperty
        ) {
          return (
            `${formattedError}\n` +
            "For typos: please correct them.\n" +
            "For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.\n" +
            "  Loaders should be updated to allow passing options via loader options in module.rules.\n" +
            "  Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:\n" +
            "  plugins: [\n" +
            "    new webpack.LoaderOptionsPlugin({\n" +
            "      // test: /\\.xxx$/, // may apply this only for some modules\n" +
            "      options: {\n" +
            `        ${error.params.additionalProperty}: …\n` +
            "      }\n" +
            "    })\n" +
            "  ]"
          );
        }

        return formattedError;
      },
    }
  );

  createFailedTestCase(
    "postFormatter #2",
    {
      entry: "foo.js",
      output: {
        filename: "/bar",
      },
    },
    (msg) => expect(msg).toMatchSnapshot(),
    {
      name: "Webpack",
      baseDataPath: "configuration",
      postFormatter: (formattedError, error) => {
        if (
          error.children &&
          error.children.some(
            (child) =>
              child.keyword === "absolutePath" &&
              child.instancePath === "/output/filename"
          )
        ) {
          return (
            `${formattedError}\n` +
            "Please use output.path to specify absolute path and output.filename for the file name."
          );
        }

        return formattedError;
      },
    }
  );

  // eslint-disable-next-line no-undefined
  createFailedTestCase("undefined configuration", undefined, (msg) =>
    expect(msg).toMatchSnapshot()
  );

  createFailedTestCase("null configuration", null, (msg) =>
    expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty entry string",
    {
      entry: "",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty entry bundle array",
    {
      entry: {
        bundle: [],
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "invalid instanceof",
    {
      entry: "a",
      module: {
        wrappedContextRegExp: 1337,
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "invalid minimum",
    {
      entry: "a",
      parallelism: 0,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "repeated value",
    {
      entry: ["abc", "def", "abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple errors",
    {
      entry: [/a/],
      output: {
        filename: /a/,
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple configurations",
    [
      {
        entry: [/a/],
      },
      {
        entry: "a",
        output: {
          filename: /a/,
        },
      },
    ],
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "deep error",
    {
      entry: "a",
      module: {
        rules: [
          {
            oneOf: [
              {
                test: "/a",
                passer: {
                  amd: false,
                },
              },
            ],
          },
        ],
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additional key on root",
    {
      entry: "a",
      postcss: () => {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "enum",
    {
      entry: "a",
      devtool: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  // Require for integration with webpack
  createFailedTestCase(
    "! in path",
    {
      entry: "foo.js",
      output: {
        path: "/somepath/!test",
        filename: "bar",
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "relative path",
    {
      entry: "foo.js",
      output: {
        filename: "/bar",
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path",
    {
      entry: "foo.js",
      output: {
        filename: "bar",
      },
      context: "baz",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "missing stats option",
    {
      entry: "foo.js",
      stats: {
        foobar: true,
      },
    },
    (msg) => {
      expect(
        msg
          .replace(/object \{ .* \}/g, "object {...}")
          .replace(/"none" \| .+/g, '"none" | ...')
      ).toMatchSnapshot();
    }
  );

  createFailedTestCase(
    "invalid plugin provided: bool",
    {
      entry: "foo.js",
      plugins: [false],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "invalid plugin provided: array",
    {
      entry: "foo.js",
      plugins: [[]],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "invalid plugin provided: string",
    {
      entry: "foo.js",
      plugins: ["abc123"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "Invalid plugin provided: int",
    {
      entry: "foo.js",
      plugins: [12],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "Invalid plugin provided: object without apply function",
    {
      entry: "foo.js",
      plugins: [{}],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "invalid mode",
    {
      mode: "protuction",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "min length",
    {
      minLengthTwo: "1",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "min properties",
    {
      entry: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer type",
    {
      integerType: "type",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "null type",
    {
      nullType: "type",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "boolean type",
    {
      bail: "true",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array type",
    {
      dependencies: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "number type",
    {
      parallelism: "1",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object in object with anyOf",
    {
      allOfRef: { alias: 123 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "non empty string in object with anyOf",
    {
      allOfRef: { aliasFields: 123 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "boolean and object in object with anyOf",
    {
      allOfRef: { unsafeCache: [] },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "boolean and number in object with anyOf",
    {
      watchOptions: { poll: "1" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer and null in object with anyOf",
    {
      customObject: { anyOfKeyword: "1" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxLength",
    {
      customObject: { maxLength: "11111" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxItems",
    {
      customObject: { maxItems: ["1", "2", "3", "4"] },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties",
    {
      customObject: {
        maxProperties: { one: "one", two: "two", three: "three", four: "four" },
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "minimum",
    {
      customObject: { minimumKeyword: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maximum",
    {
      customObject: { maximumKeyword: 11111 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multipleOf",
    {
      customObject: { multipleOfKeyword: 11111 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "pattern",
    {
      customObject: { patternKeyword: "def" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format",
    {
      customObject: { formatKeyword: "def" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains",
    {
      customObject: { containsKeyword: ["def"] },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains #1",
    {
      multipleContains2: [/test/],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf #1",
    {
      entry: { foo: () => [] },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf #2",
    {
      optimization: {
        runtimeChunk: {
          name: /fef/,
        },
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf #3",
    {
      optimization: {
        runtimeChunk: (name) => name,
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "allOf",
    {
      objectType: { objectProperty: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "anyOf",
    {
      anyOfKeyword: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array without items",
    {
      nestedArrayWithoutItems: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object without items",
    {
      nestedObjectWithoutItems: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple types in array",
    {
      arrayType2: ["1", 2, true, /test/],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple types",
    {
      multipleTypes: /test/,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "zero max items",
    {
      zeroMaxItems: [1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple types in contains",
    {
      multipleContains: [/test/],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "exclusiveMinimum",
    {
      exclusiveMinimumKeyword: 4.5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "exclusiveMaximum",
    {
      exclusiveMaximumKeyword: 5.5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "uniqueItems",
    {
      uniqueItemsKeyword: [1, 2, 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "minProperties",
    {
      minPropertiesKeyword: { foo: "bar" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties",
    {
      maxPropertiesKeyword: { foo: "bar", bar: "foo", foobaz: "foobaz" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "required",
    {
      requiredKeyword: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "required #2",
    {
      requiredKeyword: { b: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "required with additionalProperties",
    {
      requiredKeywordWithAdditionalProperties: { b: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "enum",
    {
      enumKeyword: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatMinimum",
    {
      formatMinimumKeyword: "2016-02-05",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatMaximum",
    {
      formatMaximumKeyword: "2016-02-07",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatExclusiveMinimum",
    {
      formatExclusiveMinimumKeyword: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatExclusiveMaximum",
    {
      formatExclusiveMaximumKeyword: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format and formatMinimum and formatMaximum and formatExclusiveMaximum",
    {
      formatMinMaxExclusiveMinKeyword: "2016-02-05",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format and formatMinimum and formatMaximum and formatExclusiveMaximum",
    {
      formatMinMaxExclusiveMaxKeyword: "2016-02-05",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "minItems Keyword",
    {
      minItemsKeyword: ["1"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxItems Keyword",
    {
      maxItemsKeyword: ["1", "2", "3", "4"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "items",
    {
      itemsKeyword: ["1"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "items",
    {
      itemsKeyword2: [true],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalItems",
    {
      additionalItemsKeyword: [1, "abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalItems #2",
    {
      additionalItemsKeyword2: ["abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalItems #3",
    {
      additionalItemsKeyword3: ["abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalItems #4",
    {
      additionalItemsKeyword4: [1, 1, "foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "properties",
    {
      propertiesKeyword: { foo: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternProperties",
    {
      patternPropertiesKeyword: { foo: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternProperties #1",
    {
      patternPropertiesKeyword2: { b: "t" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with only number",
    {
      arrayWithOnlyNumber: ["foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "only required",
    {
      onlyRequired: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "dependencies",
    {
      dependenciesKeyword: { foo: 1, bar: 2 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "dependencies #2",
    {
      dependenciesKeyword2: { foo: 1, bar: "2" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternRequired",
    {
      patternRequiredKeyword: { bar: 2 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternRequired #2",
    {
      patternRequiredKeyword2: { foo: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "only properties",
    {
      onlyProperties: { foo: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "only properties #2",
    {
      onlyProperties2: { foo: "a", bar: 2, break: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "only items",
    {
      onlyItems: [1, "abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "only items #2",
    {
      onlyItems2: ["abc", 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties",
    {
      additionalPropertiesKeyword: { a: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties #2",
    {
      additionalPropertiesKeyword: { foo: 1, baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties #3",
    {
      additionalPropertiesKeyword: { foo: "1", baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties #4",
    {
      additionalPropertiesKeyword2: { a: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties #5",
    {
      additionalPropertiesKeyword2: { foo: 1, baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties #6",
    {
      additionalPropertiesKeyword2: { foo: 1, bar: "3" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "propertyNames",
    {
      propertyNamesKeyword: { foo: "any value" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "constKeyword",
    {
      constKeyword: "bar",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "constKeyword #2",
    {
      constKeyword2: "baz",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else",
    {
      ifThenElseKeyword: { power: 10000 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else #2",
    {
      ifThenElseKeyword: { power: 10000, confidence: true },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else #3",
    {
      ifThenElseKeyword: { power: 1000 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else #4",
    {
      ifThenElseKeyword2: 11,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else #5",
    {
      ifThenElseKeyword2: 2000,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "if/then/else #6",
    {
      ifThenElseKeyword2: 0,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string",
    {
      stringKeyword: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string #1",
    {
      stringKeyword: "abc",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string with link",
    {
      stringKeywordWithLink: "abc",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array",
    {
      arrayKeyword: "abc",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #1",
    {
      arrayKeyword: ["abc"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #2",
    {
      arrayKeyword: [1, "string", 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #3",
    {
      arrayKeyword: [1, "string", "1", "other", "foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #4",
    {
      arrayKeyword2: [1, "1", 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #5",
    {
      arrayKeyword2: [1, 2, true, false],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #4",
    {
      arrayKeyword3: ["1", "2", "3"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #5",
    {
      arrayKeyword3: [1, "1", 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #6",
    {
      arrayKeyword3: [1, 2, true, false],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #7",
    {
      arrayKeyword4: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #8",
    {
      arrayKeyword5: [1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #9",
    {
      arrayKeyword6: [1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #10",
    {
      arrayKeyword6: ["true", "1"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #11",
    {
      arrayKeyword6: [true, "1"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #12",
    {
      arrayKeyword7: ["test", 1, /test/],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #13",
    {
      arrayKeyword8: ["test", 1, "test", true],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #14",
    {
      arrayKeyword8: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #15",
    {
      arrayKeyword9: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #16",
    {
      arrayKeyword10: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #17",
    {
      arrayKeyword11: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #18",
    {
      arrayKeyword12: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #19",
    {
      arrayKeyword13: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #20",
    {
      arrayKeyword14: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #21",
    {
      arrayKeyword15: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #22",
    {
      arrayKeyword16: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #23",
    {
      arrayKeyword17: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #24",
    {
      arrayKeyword17: [1, /test/, () => {}],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #25",
    {
      arrayKeyword18: [1, 2, 3],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array #26",
    {
      arrayKeyword19: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "recursion",
    {
      recursion: { person: { name: "Foo", children: {} } },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "extending",
    {
      extending: {
        shipping_address: {
          street_address: "1600 Pennsylvania Avenue NW",
          city: "Washington",
          state: "DC",
        },
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "module",
    {
      module: { rules: [{ compiler: true }] },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with string items and minLength",
    {
      longString: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer equals to 5",
    {
      integerEqualsTo5: 6,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with minimum",
    {
      integerWithMinimum: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with minimum and maximum",
    {
      integerWithMinimum: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with exclusive minimum",
    {
      integerWithExclusiveMinimum: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with exclusive minimum",
    {
      integerWithExclusiveMinimum: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with exclusive maximum",
    {
      integerWithExclusiveMaximum: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with exclusive maximum",
    {
      integerWithExclusiveMaximum: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "number with minimum and maximum",
    {
      numberWithMinimum: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multipleOf with minimum and maximum",
    {
      multipleOfProp: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string with minLength, maxLength and pattern",
    {
      stringWithMinAndMaxLength: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string with minLength and maxLength",
    {
      stringWithMinAndMaxLength: "def",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format, formatMaximum and formatExclusiveMaximum",
    {
      strictFormat: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format, formatMaximum and formatExclusiveMaximum #2",
    {
      strictFormat: "2016-02-07",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format, formatMinimum and formatExclusiveMinimum",
    {
      strictFormat2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format, formatMinimum and formatExclusiveMinimum #2",
    {
      strictFormat2: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "uniqueItems",
    {
      uniqueItemsProp: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "uniqueItems #2",
    {
      uniqueItemsProp: [1, 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties and minProperties",
    {
      maxPropertiesAndMinProperties: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties and minProperties #2",
    {
      maxPropertiesAndMinProperties: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties and minProperties #3",
    {
      maxPropertiesAndMinProperties: { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object",
    {
      objectTest: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #2",
    {
      objectTest2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #3",
    {
      objectTest3: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #4",
    {
      objectTest4: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #5",
    {
      objectTest4: { foo: "test", b: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #6",
    {
      objectTest5: {
        "foo@gmail.com.com": 1,
        "foo1@bar.com": 1,
        "foo@bar.com": 1,
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #7",
    {
      objectTest5: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #8",
    {
      objectTest6: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #9",
    {
      objectTest7: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #9",
    {
      objectTest8: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #10",
    {
      objectTest7: { baz: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #11",
    {
      objectTest9: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object #12",
    {
      objectTest9: { foo: "test", baz: "test", bar: 1 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string with empty pattern",
    {
      stringWithEmptyPattern: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array keywords without array type",
    {
      likeArray: ["test"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with empty items, empty additionalItems, empty contains",
    {
      arrayWithEmptyItemsAndEmptyAdditionalItemsAndEmptyContains: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalItems with false",
    {
      additionalItemsFalse: [1, 1, "foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "required without object type",
    {
      requiredWithoutType: { b: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "dependencies without object type",
    {
      dependenciesWithoutType: { foo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "propertyNames without object type",
    {
      propertyNamesWithoutType: { foo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternRequired without object type",
    {
      patternRequiredWithoutType: { boo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties without object type",
    {
      additionalPropertiesWithoutType: { boo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxProperties without object type",
    {
      maxPropertiesWithoutType: { boo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with required and properties",
    {
      justAnObject: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with absolutePath item",
    {
      arrayWithAbsolutePath: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "allOf",
    {
      allOfKeyword: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "allOf #1",
    {
      allOfKeyword: 4.5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "allOf #2",
    {
      allOfKeyword: 5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf with description",
    {
      oneOfnumberAndDescriptionAndArray: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "number and description",
    {
      numberAndDescription: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "const with description",
    {
      constWithDescription: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with items with true",
    {
      itemsTrue: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty const",
    {
      emptyConst: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "one const",
    {
      oneConst: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "const with empty string",
    {
      constWithEmptyString: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "ref inside object inside allOf",
    {
      refAndAnyOf: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties inside oneOf",
    {
      additionalPropertiesInsideOneOf: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties inside oneOf #2",
    {
      additionalPropertiesInsideOneOf: { foo: 100, bar: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "additionalProperties inside oneOf #3",
    {
      additionalPropertiesInsideOneOf2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "single item in contains",
    {
      singleContainsItems: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with dependencies",
    {
      objectWithPropertyDependency: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with dependencies #2",
    {
      objectWithPropertyDependency2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with dependencies #3",
    {
      objectWithPropertyDependency3: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with dependencies #4",
    {
      objectWithPropertyDependency4: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf with if",
    {
      oneOfWithIf: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "const with array notation",
    {
      constWithArrayNotation: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "const with object notation",
    {
      constWithObjectNotation: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "items and additionalItems",
    {
      additionalItemsWithoutType: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "items and additionalItems #2",
    {
      additionalItemsWithoutType2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "items and additionalItems #3",
    {
      additionalItemsWithoutType3: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains and additionalItems",
    {
      containsAndAdditionalItems: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains and additionalItems #2",
    {
      containsAndAdditionalItems: [/test/, "string"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains inside items",
    {
      containsInsideItem: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "contains inside items #2",
    {
      containsInsideItem: [["test"], "1", /test/],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty object",
    {
      emptyObject: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty object #2",
    {
      emptyObject: { a: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "non empty object",
    {
      nonEmptyObject: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "non empty object #2",
    {
      nonEmptyObject2: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "holey array",
    // eslint-disable-next-line no-sparse-arrays
    [
      {
        mode: "production",
      },
      ,
      {
        mode: "development",
      },
    ],
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "missing cache group name",
    {
      optimization: {
        splitChunks: {
          cacheGroups: {
            test: /abc/,
          },
        },
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not enum",
    {
      notEnum: 2,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not const",
    {
      notConst: "foo",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not number",
    {
      notNumber: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not integer",
    {
      notNumber: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not string",
    {
      notString: "test",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not boolean",
    {
      notBoolean: true,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not array",
    {
      notArray: [1, 2, 3],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not object",
    {
      notObject: { foo: "test" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not null",
    {
      notNull: null,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not not null",
    {
      notNotNull: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not not not null",
    {
      NotNotNotNull: null,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not not not null",
    {
      notMultipleTypes: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not array less than 3 items",
    {
      notMaxItemsArray: [1, 2],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like number with minimum",
    {
      noTypeLikeNumberMinimum: 4,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like number with maximum",
    {
      noTypeLikeNumberMaximum: 6,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like number with exclusive minimum",
    {
      noTypeLikeNumberExclusiveMinimum: 4,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like number with exclusive maximum",
    {
      noTypeLikeNumberExclusiveMaximum: 6,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "minimum with type number",
    {
      minimumWithTypeNumber: 4,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maximum with type number",
    {
      maximumWithTypeNumber: 6,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "exclusive minimum with type number",
    {
      exclusiveMinimumWithTypeNumber: 4,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "exclusive maximum with type number",
    {
      exclusiveMaximumWithTypeNumber: 6,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like number with multipleOf",
    {
      noTypeLikeNumberMultipleOf: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multipleOf with type number",
    {
      multipleOfWithNumberType: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with minLength",
    {
      noTypeLikeStringMinLength: "a",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with maxLength",
    {
      noTypeLikeStringMaxLength: "aaa",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "minLength with type string",
    {
      stringWithMinLength: "a",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "maxLength with type string",
    {
      stringWithMaxLength: "aaa",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with pattern",
    {
      noTypeLikeStringPattern: "def",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "pattern with type string",
    {
      patternWithStringType: "def",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with format",
    {
      noTypeLikeStringFormat: "abc",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "format with type string",
    {
      stringWithFormat: "abc",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with formatMaximum",
    {
      noTypeLikeStringFormatMaximum: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatMaximum with type string",
    {
      stringWithFormatMaximum: "2016-02-06",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "multiple instanceof ",
    {
      multipleInstanceof: "test",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object with patternRequired",
    {
      noTypeLikeObjectPatternRequired: { bar: 2 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "patternRequired with type object",
    {
      objectWithPatternRequired: { bar: 2 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like string with minLength equals 1",
    {
      noTypeLikeStringMinLength1: "",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with minItems equals 1",
    {
      noTypeLikeArrayMinItems1: [],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with minItems",
    {
      noTypeLikeArrayMinItems: [],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with minItems",
    {
      arrayWithMinItems: [],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with minItems",
    {
      noTypeMinProperties: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with minItems",
    {
      noTypeMinProperties1: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with minItems",
    {
      objectMinProperties: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with maxItems",
    {
      noTypeLikeArrayMaxItems: [1, 2, 3, 4],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with maxItems",
    {
      arrayMaxItems: [1, 2, 3, 4],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object with maxProperties",
    {
      noTypeLikeObjectMaxProperties: { a: 1, b: 2, c: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with maxProperties",
    {
      objectMaxProperties: { a: 1, b: 2, c: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object with maxProperties",
    {
      noTypeLikeArrayUniqueItems: [1, 2, 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object with maxProperties",
    {
      arrayWithUniqueItems: [1, 2, 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with additionalItems",
    {
      noTypeLikeArrayAdditionalItems: [1, 1, "foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with additionalItems",
    {
      arrayWithAdditionalItems: [1, 1, "foo"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like array with contains",
    {
      noTypeLikeArrayContains: ["foo", "bar"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with contains",
    {
      arrayWithContains: ["foo", "bar"],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "anyOf with item without type",
    {
      anyOfNoTypeInItem: 4.5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "oneOf with item without type",
    {
      oneOfNoTypeInItem: 4.5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object propertyNames",
    {
      noTypeLikeObjectPropertyNames: { foo: "any value" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object dependencies",
    {
      objectPropertyNames: { foo: "any value" },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object dependencies",
    {
      noTypeLikeObjectDependencies: { foo: 1, baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "object dependencies",
    {
      objectWithDependencies: { foo: 1, baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object additionalProperties",
    {
      noTypeLikeObjectAdditionalProperties: { foo: 1, baz: 3 },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "no type like object required",
    {
      noTypeLikeObjectRequired: {},
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "$data",
    {
      dollarData: {
        smaller: 5,
        larger: 4,
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "$data #2",
    {
      dollarData2: {
        "date-time": "1",
        email: "joe.bloggs@example.com",
      },
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "enum nested",
    {
      enumNested: "string",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path",
    {
      testAbsolutePath: "bar",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path #1",
    {
      testAbsolutePath: "bar\\\\baz",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path #2",
    {
      testAbsolutePath: "bar/baz",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path #3",
    {
      testAbsolutePath: ".",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "absolute path #4",
    {
      testAbsolutePath: "..",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not empty string #1",
    {
      notEmptyString: "",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "not empty string #2",
    {
      notEmptyString2: "",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty string #1",
    {
      emptyString: "1",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "empty string #2",
    {
      emptyString2: "1",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with not minimum and maximum",
    {
      integerWithNotMinMax: 10,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer with not minimum",
    {
      integerNotWithMinimum: 5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer zero",
    {
      integerZero: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "integer not zero",
    {
      integerNotZero: 0,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "several not in number type",
    {
      notMultipleOf: 5,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createSuccessTestCase(
    "webpack schema",
    { mode: "development" },
    {},
    webpackSchema
  );

  createFailedTestCase(
    "formatExclusiveMaximum #1",
    {
      formatExclusiveMaximum: "2016-02-05",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "formatExclusiveMaximum #2",
    {
      formatExclusiveMaximum: "2016-12-27",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "enum and undefinedAsNull",
    {
      enumKeywordAndUndefined: "foo",
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with enum and undefinedAsNull",
    {
      arrayStringAndEnum: ["foo", "bar", 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with enum and undefinedAsNull #2",
    {
      // eslint-disable-next-line no-undefined
      arrayStringAndEnum: ["foo", "bar", undefined, 1],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "array with enum and undefinedAsNull #3",
    {
      // eslint-disable-next-line no-undefined
      arrayStringAndEnumAndNoUndefined: ["foo", "bar", undefined],
    },
    (msg) => expect(msg).toMatchSnapshot()
  );

  createFailedTestCase(
    "string and undefinedAsNull",
    {
      stringTypeAndUndefinedAsNull: 1,
    },
    (msg) => expect(msg).toMatchSnapshot()
  );
});
