Repository: codekie/openapi-examples-validator
Pull request #173 (2022-06-16 20:10:07)

All properties required option #169
I made the code related to `--no-additional-properties` a bit more generic in order to reuse much of it in order to implement this feature.

It was not so difficult because the code is structured very well.

I will now work on the unit tests, but feel free to start taking a look at it if you have time.


Patch:
diff --git a/README.md b/README.md
index 2fbcf48..da25da1 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,7 @@ Options:
                                              example's paths. Use this option, if your mapping-files use relative paths
                                              for the examples
   -n, --no-additional-properties             don't allow properties that are not described in the schema
+  -r, --all-properties-required              make all the properties in the schema required
   -h, --help                                 output usage information
 ````
 
@@ -67,9 +68,11 @@ To validate multiple external examples, pass a mapping file with a similar struc
     "test/data/external-examples-valid-example2.json",
     "test/data/external-examples-invalid-type.json"
   ],
-  "$.paths./.get.responses.300.schema": "test/data/external-examples-invalid-missing-link.json"
+  "$.paths./.get.responses.300.schema": "test/data/external-examples-invalid-missing-link.json",
+  "$.paths./.post.parameters[?(@.in==="body")].schema": "test/data/v2/post-request/*.json"
 }
 ```
+It is possible to use wildcards in the command line to select multiple mapping files, and it is possible to use wildcards inside the mapping file to select multiple examples.
 
 Errors will be written to `stderr`.
 
@@ -108,10 +111,7 @@ Caveat
 
 - The formats `int32`, `float` and `double` are supported for the type `number`. The format `int64` is only available
   for the type `string`, though (due to the precision-limitations of Javascript).
-- The option `--no-additional-properties` does not work, if `allOf` is used to combine subschemas.
-  - Enabling this flag will not apply `additionalProperties` to any subschemas that use
-    [these](https://json-schema.org/understanding-json-schema/reference/combining.html) combiner keywords.
-  - A warning will be logged if setting the `additionalProperties` flag has been skipped.
+- The options `--no-additional-properties` and `--all-properties-required` are not compatible with [sub-schemas combiner keyword](https://json-schema.org/understanding-json-schema/reference/combining.html). A warning will be logged if one model is skipped because it contains a combiner keyword.
 
 Test
 ----
diff --git a/package-lock.json b/package-lock.json
index 1b266e8..49899ea 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5636,9 +5636,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001274",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001274.tgz",
-      "integrity": "sha512-+Nkvv0fHyhISkiMIjnyjmf5YJcQ1IQHZN6U9TLUMroWR38FNwpsC51Gb68yueafX1V6ifOisInSgP9WJFS13ew==",
+      "version": "1.0.30001361",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz",
+      "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==",
       "dev": true
     },
     "caseless": {
@@ -6170,12 +6170,6 @@
             "picocolors": "^1.0.0"
           }
         },
-        "caniuse-lite": {
-          "version": "1.0.30001284",
-          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz",
-          "integrity": "sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw==",
-          "dev": true
-        },
         "electron-to-chromium": {
           "version": "1.4.10",
           "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.10.tgz",
diff --git a/src/cli.js b/src/cli.js
index 6cbc388..858ab32 100755
--- a/src/cli.js
+++ b/src/cli.js
@@ -29,6 +29,7 @@ program
     .option('-c, --cwd-to-mapping-file', "changes to the directory of the mapping-file, before resolving the example's"
         + ' paths. Use this option, if your mapping-files use relative paths for the examples')
     .option('-n, --no-additional-properties', 'don\'t allow properties that are not described in the schema')
+    .option('-r, --all-properties-required', 'make all the properties in the schema required')
     .option('-o, --ignore-formats <ignored-formats...>', 'Datatype formats to ignore '
         + '(to prevent "unknown format" errors.)')
     .action(processAction);
@@ -43,7 +44,7 @@ module.exports = program.parseAsync(process.argv);
 // IMPLEMENTATION DETAILS
 
 async function processAction(filepath, options) {
-    const { schemaJsonpath, exampleFilepath, mappingFilepath, cwdToMappingFile } = options,
+    const { schemaJsonpath, exampleFilepath, mappingFilepath, cwdToMappingFile, allPropertiesRequired } = options,
         noAdditionalProperties = !options.additionalProperties,
         ignoreFormats = _prepareIgnoreFormats(options.ignoreFormats);
     let result;
@@ -52,19 +53,22 @@ async function processAction(filepath, options) {
         result = await validateExamplesByMap(filepath, mappingFilepath, {
             cwdToMappingFile,
             noAdditionalProperties,
-            ignoreFormats
+            ignoreFormats,
+            allPropertiesRequired
         });
     } else if (schemaJsonpath && exampleFilepath) {
         console.log('Validating single external example');
         result = await validateExample(filepath, schemaJsonpath, exampleFilepath, {
             noAdditionalProperties,
-            ignoreFormats
+            ignoreFormats,
+            allPropertiesRequired
         });
     } else {
         console.log('Validating examples');
         result = await validateFile(filepath, {
             noAdditionalProperties,
-            ignoreFormats
+            ignoreFormats,
+            allPropertiesRequired
         });
     }
     _handleResult(result);
diff --git a/src/impl/service/all-properties-required.js b/src/impl/service/all-properties-required.js
new file mode 100644
index 0000000..5583184
--- /dev/null
+++ b/src/impl/service/all-properties-required.js
@@ -0,0 +1,21 @@
+const { applyCallbackToAllObjectModels } = require('./common');
+
+module.exports = {
+    setAllPropertiesRequired
+};
+
+/**
+ * Sets all properties of each object to required
+ * @param {Object}                  openApiSpec         The to-be-modified schema
+ * @param {Array.<String>}          [examplePaths=[]]   The paths to the examples, which's content must not be modified
+ */
+function setAllPropertiesRequired(openApiSpec, examplePaths = []) {
+    applyCallbackToAllObjectModels(openApiSpec, examplePaths,
+        () => {
+            return (value) => {
+                if (value.hasOwnProperty('properties')) {
+                    value.required = Object.keys(value.properties);
+                }
+            };
+        });
+}
diff --git a/src/impl/service/disallow-additional-properties.js b/src/impl/service/common.js
similarity index 55%
rename from src/impl/service/disallow-additional-properties.js
rename to src/impl/service/common.js
index 2a2206e..c90d8af 100644
--- a/src/impl/service/disallow-additional-properties.js
+++ b/src/impl/service/common.js
@@ -6,15 +6,8 @@ const JSON_PATHS__OBJECTS = [
     '$..schema..[?(@.properties && (@property === "schema" || @property === "items" || @.type === "object"))]'
 ];
 
-const JSON_SCHEMA_COMBINERS = [
-    'oneOf',
-    'allOf',
-    'anyOf',
-    'not'
-];
-
 module.exports = {
-    setNoAdditionalProperties
+    applyCallbackToAllObjectModels
 };
 
 /**
@@ -36,56 +29,36 @@ module.exports = {
  */
 
 /**
- * Sets the flag to indicate that it doesn't allow properties that are not described in the schema
- * @param {Object}                  openApiSpec         The to-be-modified schema
- * @param {Array.<String>}          [examplePaths=[]]   The paths to the examples, which's content must not be modified
- * @param {JsonPathMatchCallback}   [createCallback=_createCallbackObjectTypeForNoAdditionalProperties] Function that
- *                                                      creates a callback to be called on a match
- * @private
+ * Function to build a callback that is applied to a JSONPath-match.
+ * @callback JsonPathMatchCallbackBuilder
+ * @param {string}                 jsPath  Path to the property that matched
+ * @return {JsonPathMatchCallback}         Callback that is applied to a JSONPath-match
+ */
+
+/**
+ * Apply the input rule to all models of type object in the input openApiSpec
+ * @param {Object}                 openApiSpec           The to-be-modified schema
+ * @param {Array.<String>}         [examplePaths]        The paths to the examples, which's content must not be modified
+ * @param {JsonPathMatchCallbackBuilder}  [matchCallbackBuilder]  Function to build a callback
+ *                                                                that will be called on each match
  */
-function setNoAdditionalProperties(openApiSpec, examplePaths = [],
-    createCallback = _createCallbackObjectTypeForNoAdditionalProperties
-) {
+function applyCallbackToAllObjectModels(openApiSpec, examplePaths, matchCallbackBuilder) {
     // Find all matches
     const paths = new Set();
     JSON_PATHS__OBJECTS.forEach(jsPath => {
         _find(openApiSpec, jsPath)
             .forEach(match => {
-                // remove all references to paths including any of the JSON schema combiners
-                if (!JSON_SCHEMA_COMBINERS.some((combiner) => match.includes(`['${combiner}']`))) {
-                    paths.add(match);
-                } else {
-                    console.warn('"additionalProperties" flag not set '
-                        + `for ${match} because it contains JSON-schema combiner keywords.`);
-                }
+                paths.add(match);
             });
     });
     // Exclude examples
     _excludeExamples(openApiSpec, paths, examplePaths);
     // Set flag
     for (const jsPath of paths) {
-        _find(openApiSpec, jsPath, ResultType.value, createCallback(jsPath));
+        _find(openApiSpec, jsPath, ResultType.value, matchCallbackBuilder(jsPath));
     }
 }
 
-/**
- * Callback, to set the `additionalProperties` to `false` the object-schemas
- * @type JsonPathMatchCallback
- * @private
- */
-function _createCallbackObjectTypeForNoAdditionalProperties(path) {
-    return (value) => {
-        const asString = JSON.stringify(value);
-        // any schema's that use JSON schema combiners should also be excluded
-        if (!JSON_SCHEMA_COMBINERS.some((combiner) => asString.includes(`"${combiner}"`))) {
-            value.additionalProperties = false;
-        } else {
-            console.warn('"additionalProperties" flag not set '
-                + `for ${path} because it contains JSON-schema combiner keywords.`);
-        }
-    };
-}
-
 /**
  * Find matching elements in JSON.
  * @param {Object}                  json                JSON to be searched
diff --git a/src/impl/service/no-additional-properties.js b/src/impl/service/no-additional-properties.js
new file mode 100644
index 0000000..5a4683b
--- /dev/null
+++ b/src/impl/service/no-additional-properties.js
@@ -0,0 +1,57 @@
+const { applyCallbackToAllObjectModels } = require('./common');
+
+module.exports = {
+    setNoAdditionalProperties
+};
+
+const JSON_SCHEMA_COMBINERS = [
+    'oneOf',
+    'allOf',
+    'anyOf',
+    'not'
+];
+
+/**
+ * Sets the flag to indicate that it doesn't allow properties that are not described in the schema
+ * @param {Object}                  openApiSpec         The to-be-modified schema
+ * @param {Array.<String>}          [examplePaths=[]]   The paths to the examples, which's content must not be modified
+ */
+function setNoAdditionalProperties(openApiSpec, examplePaths = []) {
+    // Match all combiner keywords that are not preceded by a 'properties' keyword.
+    // This allow to have objects that have as property name one of the combiner keywords.
+    const hasJsonCombinerParentRegex
+        = new RegExp('(?<!\\[\'properties\'\\])\\[\'(?:' + JSON_SCHEMA_COMBINERS.join('|') + ')\'\\]');
+
+    applyCallbackToAllObjectModels(openApiSpec, examplePaths,
+        (path) => {
+            return (schema) => {
+                // Exclude schema that have a JSON combiner as parent
+                if (hasJsonCombinerParentRegex.test(path)) {
+                    console.warn('"additionalProperties" flag not set '
+                        + `for ${path} because it has a parent with a JSON-schema combiner keyword.`);
+                    return;
+                }
+                // Exclude schema that contains a JSON combiner
+                if (JSON_SCHEMA_COMBINERS.some((combiner) => schema.hasOwnProperty(combiner))) {
+                    console.warn('"additionalProperties" flag not set '
+                        + `for ${path} because it contains JSON-schema combiner keyword.`);
+                    return;
+                }
+                // Exclude schema that already contains additionalProperties
+                if (schema.hasOwnProperty('additionalProperties')) {
+                    return;
+                }
+                // Exclude schema that are not objects
+                if (!isAnObjectSchema(schema)) {
+                    return;
+                }
+                schema.additionalProperties = false;
+            };
+        });
+}
+
+function isAnObjectSchema(schema) {
+    return schema.hasOwnProperty('properties')
+        || schema.hasOwnProperty('additionalProperties')
+        || (schema.hasOwnProperty('type') && schema.type === 'object');
+}
diff --git a/src/impl/v2/index.js b/src/impl/v2/index.js
index d5ab73b..5cca192 100644
--- a/src/impl/v2/index.js
+++ b/src/impl/v2/index.js
@@ -3,8 +3,9 @@
  */
 
 const { JSONPath: jsonPath } = require('jsonpath-plus'),
-    { setNoAdditionalProperties } = require('../service/disallow-additional-properties'),
-    cloneDeep = require('lodash.clonedeep');
+    cloneDeep = require('lodash.clonedeep'),
+    { setAllPropertiesRequired } = require('../service/all-properties-required'),
+    { setNoAdditionalProperties } = require('../service/no-additional-properties');
 
 // CONSTANTS
 
@@ -50,11 +51,13 @@ function buildValidationMap(pathsExamples) {
  * The passed spec won't be modified. If a modification happens, a modified copy will be returned.
  * @param {Object}  openapiSpec                     The OpenAPI-spec as JSON-schema
  * @param {boolean} [noAdditionalProperties=false]  Don't allow properties that are not defined in the schema
+ * @param {boolean} [allPropertiesRequired=false]   Make all properties required
  * @return {Object} The prepared OpenAPI-spec
  */
-function prepare(openapiSpec, { noAdditionalProperties } = {}) {
+function prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired } = {}) {
     const openapiSpecCopy = cloneDeep(openapiSpec);
     noAdditionalProperties && setNoAdditionalProperties(openapiSpecCopy, getJsonPathsToExamples());
+    allPropertiesRequired && setAllPropertiesRequired(openapiSpecCopy, getJsonPathsToExamples());
     return openapiSpecCopy;
 }
 
diff --git a/src/impl/v3/index.js b/src/impl/v3/index.js
index a12392f..70e8c2a 100644
--- a/src/impl/v3/index.js
+++ b/src/impl/v3/index.js
@@ -5,7 +5,8 @@
 const { JSONPath: jsonPath } = require('jsonpath-plus'),
     cloneDeep = require('lodash.clonedeep'),
     { ApplicationError, ErrorType } = require('../../application-error'),
-    { setNoAdditionalProperties } = require('../service/disallow-additional-properties');
+    { setAllPropertiesRequired } = require('../service/all-properties-required'),
+    { setNoAdditionalProperties } = require('../service/no-additional-properties');
 
 // CONSTANTS
 
@@ -79,11 +80,13 @@ function buildValidationMap(pathsExamples) {
  * The passed spec won't be modified. If a modification happens, a modified copy will be returned.
  * @param {Object}  openapiSpec     The OpenAPI-spec as JSON-schema
  * @param {boolean} [noAdditionalProperties=false]  Don't allow properties that are not defined in the schema
+ * @param {boolean} [allPropertiesRequired=false]   Make all properties required
  * @return {Object} The prepared OpenAPI-spec
  */
-function prepare(openapiSpec, { noAdditionalProperties } = {}) {
+function prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired } = {}) {
     const openapiSpecCopy = cloneDeep(openapiSpec);
     noAdditionalProperties && setNoAdditionalProperties(openapiSpecCopy, getJsonPathsToExamples());
+    allPropertiesRequired && setAllPropertiesRequired(openapiSpecCopy, getJsonPathsToExamples());
     return openapiSpecCopy;
 }
 
diff --git a/src/index.js b/src/index.js
index 431cdd3..e27f3cd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -93,16 +93,17 @@ module.exports = {
  * Validates OpenAPI-spec with embedded examples.
  * @param {Object}  openapiSpec OpenAPI-spec
  * @param {boolean} [noAdditionalProperties=false]  Don't allow properties that are not defined in the schema
+ * @param {boolean} [allPropertiesRequired=false]   Make all properties required
  * @param {Array.<string>} [ignoreFormats]          List of datatype formats that shall be ignored (to prevent
  *                                                  "unsupported format" errors). If an Array with only one string is
  *                                                  provided where the formats are separated with `\n`, the entries
  *                                                  will be expanded to a new array containing all entries.
  * @returns {ValidationResponse}
  */
-async function validateExamples(openapiSpec, { noAdditionalProperties, ignoreFormats } = {}) {
+async function validateExamples(openapiSpec, { noAdditionalProperties, ignoreFormats, allPropertiesRequired } = {}) {
     const impl = Determiner.getImplementation(openapiSpec);
     openapiSpec = await refParser.dereference(openapiSpec);
-    openapiSpec = impl.prepare(openapiSpec, { noAdditionalProperties });
+    openapiSpec = impl.prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired });
     let pathsExamples = impl.getJsonPathsToExamples()
         .reduce((res, pathToExamples) => {
             return res.concat(_extractExamplePaths(openapiSpec, pathToExamples));
@@ -115,20 +116,21 @@ async function validateExamples(openapiSpec, { noAdditionalProperties, ignoreFor
  * Validates OpenAPI-spec with embedded examples.
  * @param {string}  filePath                        File-path to the OpenAPI-spec
  * @param {boolean} [noAdditionalProperties=false]  Don't allow properties that are not defined in the schema
+ * @param {boolean} [allPropertiesRequired=false]   Make all properties required
  * @param {Array.<string>} [ignoreFormats]          List of datatype formats that shall be ignored (to prevent
  *                                                  "unsupported format" errors). If an Array with only one string is
  *                                                  provided where the formats are separated with `\n`, the entries
  *                                                  will be expanded to a new array containing all entries.
  * @returns {ValidationResponse}
  */
-async function validateFile(filePath, { noAdditionalProperties, ignoreFormats } = {}) {
+async function validateFile(filePath, { noAdditionalProperties, ignoreFormats, allPropertiesRequired } = {}) {
     let openapiSpec = null;
     try {
         openapiSpec = await _parseSpec(filePath);
     } catch (err) {
         return createValidationResponse({ errors: [ApplicationError.create(err)] });
     }
-    return validateExamples(openapiSpec, { noAdditionalProperties, ignoreFormats });
+    return validateExamples(openapiSpec, { noAdditionalProperties, ignoreFormats, allPropertiesRequired });
 }
 
 /**
@@ -140,6 +142,7 @@ async function validateFile(filePath, { noAdditionalProperties, ignoreFormats }
  * @param {boolean} [cwdToMappingFile=false]    Change working directory for resolving the example-paths (relative to
  *                                              the mapping-file)
  * @param {boolean} [noAdditionalProperties=false] Don't allow properties that are not defined in the schema
+ * @param {boolean} [allPropertiesRequired=false]  Make all properties required
  * @param {Array.<string>} [ignoreFormats]      List of datatype formats that shall be ignored (to prevent
  *                                              "unsupported format" errors). If an Array with only one string is
  *                                              provided where the formats are separated with `\n`, the entries
@@ -147,7 +150,7 @@ async function validateFile(filePath, { noAdditionalProperties, ignoreFormats }
  * @returns {ValidationResponse}
  */
 async function validateExamplesByMap(filePathSchema, globMapExternalExamples,
-    { cwdToMappingFile, noAdditionalProperties, ignoreFormats } = {}
+    { cwdToMappingFile, noAdditionalProperties, ignoreFormats, allPropertiesRequired } = {}
 ) {
     let matchingFilePathsMapping = 0;
     const filePathsMaps = glob.sync(
@@ -165,7 +168,7 @@ async function validateExamplesByMap(filePathSchema, globMapExternalExamples,
             mapExternalExamples = JSON.parse(fs.readFileSync(filePathMapExternalExamples, 'utf-8'));
             openapiSpec = await _parseSpec(filePathSchema);
             openapiSpec = Determiner.getImplementation(openapiSpec)
-                .prepare(openapiSpec, { noAdditionalProperties });
+                .prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired });
         } catch (err) {
             responses.push(createValidationResponse({ errors: [ApplicationError.create(err)] }));
             continue;
@@ -208,6 +211,7 @@ async function validateExamplesByMap(filePathSchema, globMapExternalExamples,
  * @param {String}  pathSchema                      JSON-path to the schema
  * @param {String}  filePathExample                 File-path to the external example-file
  * @param {boolean} [noAdditionalProperties=false]  Don't allow properties that are not described in the schema
+ * @param {boolean} [allPropertiesRequired=false]   Make all properties required
  * @param {Array.<string>} [ignoreFormats]          List of datatype formats that shall be ignored (to prevent
  *                                                  "unsupported format" errors). If an Array with only one string is
  *                                                  provided where the formats are separated with `\n`, the entries
@@ -216,7 +220,8 @@ async function validateExamplesByMap(filePathSchema, globMapExternalExamples,
  */
 async function validateExample(filePathSchema, pathSchema, filePathExample, {
     noAdditionalProperties,
-    ignoreFormats
+    ignoreFormats,
+    allPropertiesRequired
 } = {}) {
     let example = null,
         schema = null,
@@ -225,7 +230,7 @@ async function validateExample(filePathSchema, pathSchema, filePathExample, {
         example = JSON.parse(fs.readFileSync(filePathExample, 'utf-8'));
         openapiSpec = await _parseSpec(filePathSchema);
         openapiSpec = Determiner.getImplementation(openapiSpec)
-            .prepare(openapiSpec, { noAdditionalProperties });
+            .prepare(openapiSpec, { noAdditionalProperties, allPropertiesRequired });
         schema = _extractSchema(pathSchema, openapiSpec);
     } catch (err) {
         return createValidationResponse({ errors: [ApplicationError.create(err)] });
@@ -324,22 +329,35 @@ function _handleExamplesByMapValidation(openapiSpec, mapExternalExamples, statis
         return flatMap(
             flatten([filePathsExample]),
             filePathExample => {
-                let example = null;
+                let examples = [];
                 try {
                     const resolvedFilePathExample = cwdToMappingFile
                         ? path.join(dirPathMapExternalExamples, filePathExample)
                         : filePathExample;
-                    example = JSON.parse(fs.readFileSync(resolvedFilePathExample, 'utf-8'));
+                    const globResolvedFilePathExample = glob.sync(resolvedFilePathExample);
+                    if (globResolvedFilePathExample.length === 0) {
+                        return [ApplicationError.create({
+                            type: ErrorType.jsENOENT,
+                            message: `No such file or directory: '${resolvedFilePathExample}'`,
+                            path: resolvedFilePathExample
+                        })];
+                    }
+                    for (const filePathExample of globResolvedFilePathExample) {
+                        examples.push({
+                            path: path.normalize(filePathExample),
+                            content: JSON.parse(fs.readFileSync(filePathExample, 'utf-8'))
+                        });
+                    }
                 } catch (err) {
                     return [ApplicationError.create(err)];
                 }
-                return _validateExample({
+                return flatMap(examples, example => _validateExample({
                     createValidator: _initValidatorFactory(openapiSpec, { ignoreFormats }),
                     schema,
-                    example,
+                    example: example.content,
                     statistics,
-                    filePathExample
-                });
+                    filePathExample: example.path
+                }));
             }
         );
     });
@@ -572,7 +590,7 @@ function _initValidatorFactory(specSchema, { ignoreFormats }) {
  * Extracts the schema in the OpenAPI-spec at the given JSON-path.
  * @param   {string}    pathSchema                          JSON-path to the schema
  * @param   {Object}    openapiSpec                         OpenAPI-spec
- * @param   {boolean}   [suppressErrorIfNotFound=false]     Don't throw `ErrorJsonPathNotFound` if the repsonse does not
+ * @param   {boolean}   [suppressErrorIfNotFound=false]     Don't throw `ErrorJsonPathNotFound` if the response does not
  *                                                          exist at the given JSON-path
  * @returns {Object|Array.<Object>|undefined} Matching schema(s)
  * @throws  {ErrorJsonPathNotFound} Thrown, when there is no schema at the given path and


Test patch:
diff --git a/test/data/output-help.js b/test/data/output-help.js
index 2c12f40..b16d2fd 100644
--- a/test/data/output-help.js
+++ b/test/data/output-help.js
@@ -13,6 +13,7 @@ Options:
   -m, --mapping-filepath <mapping-filepath>  file path to map, containing schema-paths as key and the file-path(s) to examples as value. If wildcards are used, the parameter has to be put in quotes.
   -c, --cwd-to-mapping-file                  changes to the directory of the mapping-file, before resolving the example's paths. Use this option, if your mapping-files use relative paths for the examples
   -n, --no-additional-properties             don't allow properties that are not described in the schema
+  -r, --all-properties-required              make all the properties in the schema required
   -o, --ignore-formats <ignored-formats...>  Datatype formats to ignore (to prevent "unknown format" errors.)
   -h, --help                                 display help for command
 
diff --git a/test/data/output/api-with-examples-and-all-properties-required.js b/test/data/output/api-with-examples-and-all-properties-required.js
new file mode 100644
index 0000000..a09f7f0
--- /dev/null
+++ b/test/data/output/api-with-examples-and-all-properties-required.js
@@ -0,0 +1,8 @@
+module.exports.value = `Validating examples
+Schemas with examples found: 2
+Examples without schema found: 0
+Total examples found: 3
+
+Errors found.
+
+`;
diff --git a/test/data/v2/map-external-examples-with-wildcards.json b/test/data/v2/map-external-examples-with-wildcards.json
new file mode 100644
index 0000000..cad19a5
--- /dev/null
+++ b/test/data/v2/map-external-examples-with-wildcards.json
@@ -0,0 +1,8 @@
+{
+  "$.paths./.get.responses.200.schema": [
+    "test/data/v2/external-examples-valid-example1.json",
+    "test/data/v2/external-*-valid-*.json",
+    "test/data/v2/external-*-invalid-*.json"
+  ],
+  "$.paths./.get.responses.300.schema": "test/data/v2/external-examples-valid-*.json"
+}
diff --git a/test/data/v2/map-external-examples-without-wildcards.json b/test/data/v2/map-external-examples-without-wildcards.json
new file mode 100644
index 0000000..a1d5463
--- /dev/null
+++ b/test/data/v2/map-external-examples-without-wildcards.json
@@ -0,0 +1,13 @@
+{
+  "$.paths./.get.responses.200.schema": [
+    "test/data/v2/external-examples-valid-example1.json",
+    "test/data/v2/external-examples-valid-example1.json",
+    "test/data/v2/external-examples-valid-example2.json",
+    "test/data/v2/external-examples-invalid-missing-link.json",
+    "test/data/v2/external-examples-invalid-type.json"
+  ],
+  "$.paths./.get.responses.300.schema": [
+    "test/data/v2/external-examples-valid-example1.json",
+    "test/data/v2/external-examples-valid-example2.json"
+  ]
+}
\ No newline at end of file
diff --git a/test/data/v2/valid-with-all-properties-required.json b/test/data/v2/valid-with-all-properties-required.json
new file mode 100644
index 0000000..fa5569e
--- /dev/null
+++ b/test/data/v2/valid-with-all-properties-required.json
@@ -0,0 +1,155 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "Simple API overview",
+    "version": "v2"
+  },
+  "paths": {
+    "/": {
+      "get": {
+        "operationId": "listVersionsv2",
+        "summary": "List API versions",
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "200": {
+            "description": "200 response",
+            "examples": {
+              "application/json": {
+                "versions": [
+                  {
+                    "status": "CURRENT",
+                    "updated": "2011-01-21T11:33:21Z",
+                    "id": "v2.0",
+                    "links": [
+                      {
+                        "href": "http://127.0.0.1:8774/v2/",
+                        "rel": "self"
+                      }
+                    ]
+                  },
+                  {
+                    "status": "EXPERIMENTAL",
+                    "updated": "2013-07-23T11:33:21Z",
+                    "id": "v3.0",
+                    "links": [
+                      {
+                        "href": "http://127.0.0.1:8774/v3/",
+                        "rel": "self"
+                      }
+                    ]
+                  }
+                ]
+              }
+            },
+            "schema": {
+              "type": "object",
+              "required": [
+                "versions"
+              ],
+              "properties": {
+                "versions": {
+                  "type": "array",
+                  "items": {
+                    "type": "object",
+                    "required": [
+                      "status",
+                      "updated",
+                      "id",
+                      "links"
+                    ],
+                    "properties": {
+                      "status": {
+                        "type": "string"
+                      },
+                      "updated": {
+                        "type": "string"
+                      },
+                      "id": {
+                        "type": "string"
+                      },
+                      "links": {
+                        "type": "array",
+                        "items": {
+                          "type": "object",
+                          "required": [
+                            "href",
+                            "rel"
+                          ],
+                          "properties": {
+                            "href": {
+                              "type": "string"
+                            },
+                            "rel": {
+                              "type": "string"
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "300": {
+            "description": "300 response",
+            "schema": {
+              "type": "object",
+              "required": [
+                "versions"
+              ],
+              "properties": {
+                "versions": {
+                  "type": "array",
+                  "items": {
+                    "type": "object",
+                    "required": [
+                      "status",
+                      "updated",
+                      "id",
+                      "links"
+                    ],
+                    "properties": {
+                      "status": {
+                        "type": "string"
+                      },
+                      "updated": {
+                        "type": "string"
+                      },
+                      "id": {
+                        "type": "string"
+                      },
+                      "links": {
+                        "type": "array",
+                        "items": {
+                          "type": "object",
+                          "required": [
+                            "href",
+                            "rel"
+                          ],
+                          "properties": {
+                            "href": {
+                              "type": "string"
+                            },
+                            "rel": {
+                              "type": "string"
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "consumes": [
+    "application/json"
+  ]
+}
diff --git a/test/data/v2/valid-with-no-additional-properties.json b/test/data/v2/valid-with-no-additional-properties.json
new file mode 100644
index 0000000..48f2fc9
--- /dev/null
+++ b/test/data/v2/valid-with-no-additional-properties.json
@@ -0,0 +1,157 @@
+{
+  "swagger": "2.0",
+  "info": {
+    "title": "Simple API overview",
+    "version": "v2"
+  },
+  "paths": {
+    "/": {
+      "get": {
+        "operationId": "listVersionsv2",
+        "summary": "List API versions",
+        "produces": [
+          "application/json"
+        ],
+        "responses": {
+          "200": {
+            "description": "200 response",
+            "examples": {
+              "application/json": {
+                "versions": [
+                  {
+                    "status": "CURRENT",
+                    "updated": "2011-01-21T11:33:21Z",
+                    "id": "v2.0",
+                    "links": [
+                      {
+                        "href": "http://127.0.0.1:8774/v2/",
+                        "rel": "self"
+                      }
+                    ]
+                  },
+                  {
+                    "status": "EXPERIMENTAL",
+                    "updated": "2013-07-23T11:33:21Z",
+                    "id": "v3.0",
+                    "links": [
+                      {
+                        "href": "http://127.0.0.1:8774/v3/",
+                        "rel": "self"
+                      }
+                    ]
+                  }
+                ]
+              }
+            },
+            "schema": {
+              "type": "object",
+              "required": [
+                "versions"
+              ],
+              "properties": {
+                "versions": {
+                  "type": "array",
+                  "items": {
+                    "additionalProperties": false,
+                    "type": "object",
+                    "required": [
+                      "status",
+                      "id",
+                      "links"
+                    ],
+                    "properties": {
+                      "status": {
+                        "type": "string"
+                      },
+                      "updated": {
+                        "type": "string"
+                      },
+                      "id": {
+                        "type": "string"
+                      },
+                      "links": {
+                        "type": "array",
+                        "items": {
+                          "additionalProperties": false,
+                          "type": "object",
+                          "required": [
+                            "href",
+                            "rel"
+                          ],
+                          "properties": {
+                            "href": {
+                              "type": "string"
+                            },
+                            "rel": {
+                              "type": "string"
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "300": {
+            "description": "300 response",
+            "schema": {
+              "type": "object",
+              "required": [
+                "versions"
+              ],
+              "properties": {
+                "versions": {
+                  "type": "array",
+                  "items": {
+                    "additionalProperties": false,
+                    "type": "object",
+                    "required": [
+                      "status",
+                      "id",
+                      "links"
+                    ],
+                    "properties": {
+                      "status": {
+                        "type": "string"
+                      },
+                      "updated": {
+                        "type": "string"
+                      },
+                      "id": {
+                        "type": "string"
+                      },
+                      "links": {
+                        "type": "array",
+                        "items": {
+                          "additionalProperties": false,
+                          "type": "object",
+                          "required": [
+                            "href",
+                            "rel"
+                          ],
+                          "properties": {
+                            "href": {
+                              "type": "string"
+                            },
+                            "rel": {
+                              "type": "string"
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  },
+  "consumes": [
+    "application/json"
+  ]
+}
diff --git a/test/data/v3/additional-properties/errors-schema-with-schema-combiner-as-property.json b/test/data/v3/additional-properties/errors-schema-with-schema-combiner-as-property.json
new file mode 100644
index 0000000..c7c302e
--- /dev/null
+++ b/test/data/v3/additional-properties/errors-schema-with-schema-combiner-as-property.json
@@ -0,0 +1,13 @@
+[
+    {
+        "type": "Validation",
+        "message": "should NOT have additional properties",
+        "keyword": "additionalProperties",
+        "dataPath": ".allOf.anyOf.oneOf.not",
+        "schemaPath": "#/properties/allOf/properties/anyOf/properties/oneOf/properties/not/additionalProperties",
+        "params": {
+            "additionalProperty": "anotherProperty"
+        },
+        "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/example"
+    }
+]
\ No newline at end of file
diff --git a/test/data/v3/additional-properties/schema-with-schema-combiner-as-property-invalid.yaml b/test/data/v3/additional-properties/schema-with-schema-combiner-as-property-invalid.yaml
new file mode 100644
index 0000000..908c26d
--- /dev/null
+++ b/test/data/v3/additional-properties/schema-with-schema-combiner-as-property-invalid.yaml
@@ -0,0 +1,82 @@
+openapi: 3.0.0
+info:
+  version: 1.0.0
+  title: Swagger Petstore
+  license:
+    name: MIT
+servers:
+  - url: 'http://petstore.swagger.io/v1'
+paths:
+  '/pets/{petId}':
+    get:
+      summary: Info for a specific pet
+      operationId: showPetById
+      parameters:
+        - name: petId
+          in: path
+          required: true
+          description: The id of the pet to retrieve
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Expected response to a valid request
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Pet'
+              example:
+                id: 0
+                name: Marco
+                allOf:
+                  anyOf:
+                    oneOf:
+                      not:
+                        color: black
+                        anotherProperty: 'This property will be marked as error in case of --no-additional-properties'
+        default:
+          description: unexpected error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+components:
+  schemas:
+    Pet:
+      required:
+        - id
+        - name
+      type: object
+      properties:
+        id:
+          type: number
+        name:
+          type: string
+        # This intentionally is a property called `allOf`
+        allOf:
+          type: object
+          properties:
+            # This intentionally is a property called `anyOf`
+            anyOf:
+              type: object
+              properties:
+                # This intentionally is a property called `oneOf`
+                oneOf:
+                  type: object
+                  properties:
+                    # This intentionally is a property called `not`
+                    not:
+                      # This should be extended with an `additionalProperties: false`
+                      type: object
+                      properties:
+                        color:
+                          type: string
+    Error:
+      required:
+        - code
+        - message
+      properties:
+        code:
+          type: number
+        message:
+          type: string
diff --git a/test/data/v3/additional-properties/schema-with-schema-combiner-invalid.yaml b/test/data/v3/additional-properties/schema-with-schema-combiner-invalid.yaml
index f68da6d..1c8fe48 100644
--- a/test/data/v3/additional-properties/schema-with-schema-combiner-invalid.yaml
+++ b/test/data/v3/additional-properties/schema-with-schema-combiner-invalid.yaml
@@ -20,7 +20,7 @@ paths:
             type: string
       responses:
         '200':
-          description: successfull response
+          description: successful response
           content:
             application/json:
               schema:
diff --git a/test/data/v3/additional-properties/schema-with-schema-combiner-valid.yaml b/test/data/v3/additional-properties/schema-with-schema-combiner-valid.yaml
index 56010b8..750712c 100644
--- a/test/data/v3/additional-properties/schema-with-schema-combiner-valid.yaml
+++ b/test/data/v3/additional-properties/schema-with-schema-combiner-valid.yaml
@@ -20,7 +20,7 @@ paths:
             type: string
       responses:
         '200':
-          description: successfull response
+          description: successful response
           content:
             application/json:
               schema:
diff --git a/test/data/v3/additional-properties/simple-api-with-no-additional-properties.json b/test/data/v3/additional-properties/simple-api-with-no-additional-properties.json
new file mode 100644
index 0000000..85a815c
--- /dev/null
+++ b/test/data/v3/additional-properties/simple-api-with-no-additional-properties.json
@@ -0,0 +1,210 @@
+{
+  "openapi": "3.0.0",
+  "info": {
+    "version": "1.0.0",
+    "title": "Swagger Petstore",
+    "license": {
+      "name": "MIT"
+    }
+  },
+  "servers": [
+    {
+      "url": "http://petstore.swagger.io/v1"
+    }
+  ],
+  "paths": {
+    "/pets": {
+      "get": {
+        "summary": "List all pets",
+        "operationId": "listPets",
+        "tags": [
+          "pets"
+        ],
+        "parameters": [
+          {
+            "name": "limit",
+            "in": "query",
+            "description": "How many items to return at one time (max 100)",
+            "required": false,
+            "schema": {
+              "type": "number"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "An paged array of pets",
+            "headers": {
+              "x-next": {
+                "description": "A link to the next page of responses",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "additionalProperties": false,
+                    "required": [
+                      "id",
+                      "name"
+                    ],
+                    "properties": {
+                      "id": {
+                        "type": "number"
+                      },
+                      "name": {
+                        "type": "string"
+                      },
+                      "tag": {
+                        "type": "string"
+                      }
+                    }
+                  }
+                },
+                "example": [
+                  {
+                    "id": 0,
+                    "name": "Herbert",
+                    "tag": "Doggo"
+                  }
+                ]
+              }
+            }
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "additionalProperties": false,
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      },
+      "post": {
+        "summary": "Create a pet",
+        "operationId": "createPets",
+        "tags": [
+          "pets"
+        ],
+        "responses": {
+          "201": {
+            "description": "Null response"
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "additionalProperties": false,
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/pets/{petId}": {
+      "get": {
+        "summary": "Info for a specific pet",
+        "operationId": "showPetById",
+        "tags": [
+          "pets"
+        ],
+        "parameters": [
+          {
+            "name": "petId",
+            "in": "path",
+            "required": true,
+            "description": "The id of the pet to retrieve",
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Expected response to a valid request",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "additionalProperties": false,
+                    "required": [
+                      "id",
+                      "name"
+                    ],
+                    "properties": {
+                      "id": {
+                        "type": "number"
+                      },
+                      "name": {
+                        "type": "string"
+                      },
+                      "tag": {
+                        "type": "string"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "additionalProperties": false,
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/test/data/v3/all-properties-required/errors-schema-with-examples.json b/test/data/v3/all-properties-required/errors-schema-with-examples.json
new file mode 100644
index 0000000..af25976
--- /dev/null
+++ b/test/data/v3/all-properties-required/errors-schema-with-examples.json
@@ -0,0 +1,46 @@
+[
+    {
+        "type": "Validation",
+        "message": "should have required property 'age'",
+        "keyword": "required",
+        "dataPath": "",
+        "schemaPath": "#/oneOf/0/allOf/1/required",
+        "params": {
+            "missingProperty": "age"
+        },
+        "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value"
+    },
+    {
+        "type": "Validation",
+        "message": "should have required property 'bark'",
+        "keyword": "required",
+        "dataPath": "",
+        "schemaPath": "#/oneOf/1/allOf/1/required",
+        "params": {
+            "missingProperty": "bark"
+        },
+        "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value"
+    },
+    {
+        "type": "Validation",
+        "message": "should have required property 'breed'",
+        "keyword": "required",
+        "dataPath": "",
+        "schemaPath": "#/oneOf/1/allOf/1/required",
+        "params": {
+            "missingProperty": "breed"
+        },
+        "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value"
+    },
+    {
+        "type": "Validation",
+        "message": "should match exactly one schema in oneOf",
+        "keyword": "oneOf",
+        "dataPath": "",
+        "schemaPath": "#/oneOf",
+        "params": {
+            "passingSchemas": null
+        },
+        "examplePath": "/paths/~1pets~1{petId}/get/responses/200/content/application~1json/examples/Cat example/value"
+    }
+]
\ No newline at end of file
diff --git a/test/data/v3/all-properties-required/schema-with-examples.yaml b/test/data/v3/all-properties-required/schema-with-examples.yaml
new file mode 100644
index 0000000..9cecd2a
--- /dev/null
+++ b/test/data/v3/all-properties-required/schema-with-examples.yaml
@@ -0,0 +1,89 @@
+openapi: 3.0.0
+info:
+  version: 1.0.0
+  title: Swagger Petstore
+  license:
+    name: MIT
+servers:
+  - url: 'http://petstore.swagger.io/v1'
+paths:
+  '/pets/{petId}':
+    get:
+      summary: Info for a specific pet
+      operationId: showPetById
+      parameters:
+        - name: petId
+          in: path
+          required: true
+          description: The id of the pet to retrieve
+          schema:
+            type: string
+      responses:
+        '200':
+          description: successful response
+          content:
+            application/json:
+              schema:
+                oneOf:
+                  - $ref: '#/components/schemas/Cat'
+                  - $ref: '#/components/schemas/Dog'
+              examples:
+                'Dog example':
+                  value:
+                    name: 'Dog 1'
+                    bark: true
+                    breed: 'Dingo'
+                'Cat example':
+                  value:
+                    name: 'Cat 1'
+                    hunts: true
+                    # This example don't have the optional property 'age'
+        '404':
+          description: unexpected error
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Error'
+              example:
+                code: 1000
+                message: 'could not find pet'
+components:
+  schemas:
+    Error:
+      type: object
+      properties:
+        code:
+          type: number
+        message:
+          type: string
+    Pet:
+      type: object
+      required:
+        - name
+      properties:
+        name:
+          type: string
+    Dog:
+      allOf:
+        - $ref: '#/components/schemas/Pet'
+        - type: object
+          required:
+            - bark
+            - breed
+          properties:
+            bark:
+              type: boolean
+            breed:
+              type: string
+              enum: [ Dingo, Husky, Retriever, Shepherd ]
+    Cat:
+      allOf:
+        - $ref: '#/components/schemas/Pet'
+        - type: object
+          required:
+            - hunts
+          properties:
+            hunts:
+              type: boolean
+            age:
+              type: integer
diff --git a/test/data/v3/all-properties-required/simple-api-with-all-properties-required.json b/test/data/v3/all-properties-required/simple-api-with-all-properties-required.json
new file mode 100644
index 0000000..19f8e6a
--- /dev/null
+++ b/test/data/v3/all-properties-required/simple-api-with-all-properties-required.json
@@ -0,0 +1,207 @@
+{
+  "openapi": "3.0.0",
+  "info": {
+    "version": "1.0.0",
+    "title": "Swagger Petstore",
+    "license": {
+      "name": "MIT"
+    }
+  },
+  "servers": [
+    {
+      "url": "http://petstore.swagger.io/v1"
+    }
+  ],
+  "paths": {
+    "/pets": {
+      "get": {
+        "summary": "List all pets",
+        "operationId": "listPets",
+        "tags": [
+          "pets"
+        ],
+        "parameters": [
+          {
+            "name": "limit",
+            "in": "query",
+            "description": "How many items to return at one time (max 100)",
+            "required": false,
+            "schema": {
+              "type": "number"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "An paged array of pets",
+            "headers": {
+              "x-next": {
+                "description": "A link to the next page of responses",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "required": [
+                      "id",
+                      "name",
+                      "tag"
+                    ],
+                    "properties": {
+                      "id": {
+                        "type": "number"
+                      },
+                      "name": {
+                        "type": "string"
+                      },
+                      "tag": {
+                        "type": "string"
+                      }
+                    }
+                  }
+                },
+                "example": [
+                  {
+                    "id": 0,
+                    "name": "Herbert",
+                    "tag": "Doggo"
+                  }
+                ]
+              }
+            }
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      },
+      "post": {
+        "summary": "Create a pet",
+        "operationId": "createPets",
+        "tags": [
+          "pets"
+        ],
+        "responses": {
+          "201": {
+            "description": "Null response"
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/pets/{petId}": {
+      "get": {
+        "summary": "Info for a specific pet",
+        "operationId": "showPetById",
+        "tags": [
+          "pets"
+        ],
+        "parameters": [
+          {
+            "name": "petId",
+            "in": "path",
+            "required": true,
+            "description": "The id of the pet to retrieve",
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Expected response to a valid request",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "required": [
+                      "id",
+                      "name",
+                      "tag"
+                    ],
+                    "properties": {
+                      "id": {
+                        "type": "number"
+                      },
+                      "name": {
+                        "type": "string"
+                      },
+                      "tag": {
+                        "type": "string"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "default": {
+            "description": "unexpected error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "required": [
+                    "code",
+                    "message"
+                  ],
+                  "properties": {
+                    "code": {
+                      "type": "number"
+                    },
+                    "message": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/test/specs/cli.js b/test/specs/cli.js
index 1843146..531c53a 100644
--- a/test/specs/cli.js
+++ b/test/specs/cli.js
@@ -125,11 +125,11 @@ describe('CLI-module', function() {
                     stderr.should.equal(JSON.stringify(
                         require('../data/v3/additional-properties/errors-schema-with-examples.json'),
                         null,
-                        '    '
+                        4
                     ));
                 }
             });
-            it('should show no errors due to the `allOf`-combiner in schema', async function() {
+            it('should show error even if `allOf`-combiner in another example', async function() {
                 const pathSchema
                     = getPathOfTestData('v3/additional-properties/schema-with-schema-combiner-invalid.yaml', true);
                 try {
@@ -141,6 +141,21 @@ describe('CLI-module', function() {
                     stderr.should.include('extra_property');
                 }
             });
+            it('should show error even if inside an object with a property called "allOf"', async function() {
+                const pathSchema = getPathOfTestData(
+                    'v3/additional-properties/schema-with-schema-combiner-as-property-invalid.yaml', true);
+                try {
+                    await exec(`${CMD__RUN} -n ${pathSchema}`);
+                    should.fail('Expected to throw an error');
+                } catch ({ stdout, stderr }) {
+                    stdout.should.include('Errors found.');
+                    stderr.should.equal(JSON.stringify(
+                        require('../data/v3/additional-properties/errors-schema-with-schema-combiner-as-property.json'),
+                        null,
+                        4
+                    ));
+                }
+            });
             it('should show no errors with `allOf`-combiner in schema', async function() {
                 const pathSchema
                     = getPathOfTestData('v3/additional-properties/schema-with-schema-combiner-valid.yaml', true);
@@ -156,6 +171,29 @@ describe('CLI-module', function() {
             });
         });
     });
+    describe('with all properties required', function() {
+        it('should show no error when properties not required are allowed', async function() {
+            const pathSchema
+                = getPathOfTestData('v3/all-properties-required/schema-with-examples.yaml', true);
+            const { stdout, stderr } = await exec(`${CMD__RUN} ${pathSchema}`);
+            stdout.should.include('No errors found.');
+            stderr.should.equal('');
+        });
+        it('should show error with providing the flag', async function() {
+            const pathSchema = getPathOfTestData('v3/all-properties-required/schema-with-examples.yaml', true);
+            try {
+                await exec(`${CMD__RUN} -r ${pathSchema}`);
+                should.fail('Expected to throw an error');
+            } catch ({ stdout, stderr }) {
+                stdout.should.equal(require('../data/output/api-with-examples-and-all-properties-required').value);
+                stderr.should.equal(JSON.stringify(
+                    require('../data/v3/all-properties-required/errors-schema-with-examples.json'),
+                    null,
+                    4
+                ));
+            }
+        });
+    });
     describe('ignore datatype formats', function() {
         it('should show an error when no formats have been passed', async function() {
             const pathSchema = getPathOfTestData('v3/unknown-formats.json', true);
@@ -196,7 +234,7 @@ describe('CLI-module', function() {
                     this.output += chunk;
                 }
             };
-            // Capture sterr-stream
+            // Capture stderr-stream
             this.error = '';
             this.origStderrWrite = process.stderr.write.bind(process.stderr);
             process.stderr.write = (chunk) => {
diff --git a/test/specs/impl/service/schema-extender.js b/test/specs/impl/service/schema-extender.js
index 8cae3dd..cd158a2 100644
--- a/test/specs/impl/service/schema-extender.js
+++ b/test/specs/impl/service/schema-extender.js
@@ -1,4 +1,4 @@
-const { setNoAdditionalProperties } = require('../../../../src/impl/service/disallow-additional-properties'),
+const { applyCallbackToAllObjectModels } = require('../../../../src/impl/service/common'),
     { getJsonPathsToExamples } = require('../../../../src/impl/v3/index');
 
 const SCHEMA = _getSchema(),
@@ -7,7 +7,7 @@ const SCHEMA = _getSchema(),
 describe('The schema extender', function() {
     it('should find the right matches', function() {
         const paths = [];
-        setNoAdditionalProperties(SCHEMA, getJsonPathsToExamples(), () => (value, resultType, data) => {
+        applyCallbackToAllObjectModels(SCHEMA, getJsonPathsToExamples(), () => (value, resultType, data) => {
             paths.push(data.path);
         });
         paths.sort().should.deep.equal(JSON_PATHS__OBJECTS.sort());
diff --git a/test/specs/impl/v2/index.js b/test/specs/impl/v2/index.js
index 36bcca2..f9d865b 100644
--- a/test/specs/impl/v2/index.js
+++ b/test/specs/impl/v2/index.js
@@ -2,6 +2,7 @@ const path = require('path'),
     { loadTestData, normalizeValidationResultPaths } = require('../../../util/setup-tests'),
     { validateExample, 'default': validateExamples, validateExamplesByMap } = require('../../../../src/index'),
     { ApplicationError, ErrorType } = require('../../../../src/application-error');
+const { prepare } = require('../../../../src/impl/v2');
 
 const PATH__SCHEMA_EXTERNAL_EXAMPLE = '$.paths./.get.responses.200.schema',
     PATH__SCHEMA_EXTERNAL_EXAMPLE_INVALID = '$.hmm.what.am.i.gonna.get.for.lunch',
@@ -13,7 +14,11 @@ const PATH__SCHEMA_EXTERNAL_EXAMPLE = '$.paths./.get.responses.200.schema',
     FILE_PATH__EXTERNAL_EXAMPLES_GLOB_INVALID1 = path.join(FILE_PATH__DATA, 'map-external-examples-glob-invalid1.json'),
     FILE_PATH__EXTERNAL_EXAMPLES_GLOB_INVALID2 = path.join(FILE_PATH__DATA, 'map-external-examples-glob-invalid2.json'),
     FILE_PATH__EXTERNAL_EXAMPLES_MAP = path.join(FILE_PATH__DATA, 'map-external-examples.json'),
-    FILE_PATH__EXTERNAL_EXAMPLES_MAP__RELATIVE = path.join(FILE_PATH__DATA, 'map-external-examples-relative.json'),
+    FILE_PATH__EXTERNAL_EXAMPLES_MAP_RELATIVE = path.join(FILE_PATH__DATA, 'map-external-examples-relative.json'),
+    FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_WILDCARDS = path.join(FILE_PATH__DATA,
+        'map-external-examples-with-wildcards.json'),
+    FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITHOUT_WILDCARDS = path.join(FILE_PATH__DATA,
+        'map-external-examples-without-wildcards.json'),
     FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_WRONG_SCHEMA_PATH = path.join(FILE_PATH__DATA,
         'map-external-examples-map-with-wrong-schema-path.json'),
     FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_MISSING_EXAMPLE = path.join(FILE_PATH__DATA,
@@ -186,6 +191,52 @@ describe('Main-module, for v2 should', () => {
                 })
             ]);
         });
+        it('should be able to expand examples wildcards', async() => {
+            const result = await validateExamplesByMap(FILE_PATH__EXTERNAL_EXAMPLES_SCHEMA,
+                FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_WILDCARDS);
+            result.valid.should.equal(false);
+            result.statistics.should.deep.equal({
+                examplesTotal: 7,
+                examplesWithoutSchema: 0,
+                matchingFilePathsMapping: 1,
+                schemasWithExamples: 2
+            });
+            result.errors.should.deep.equal([{
+                type: 'Validation',
+                message: "should have required property 'links'",
+                keyword: 'required',
+                dataPath: '.versions[0]',
+                schemaPath: '#/properties/versions/items/required',
+                exampleFilePath: path.normalize('test/data/v2/external-examples-invalid-missing-link.json'),
+                mapFilePath: path.normalize(
+                    path.join(__dirname, '../../../../test/data/v2/map-external-examples-with-wildcards.json')),
+                params: {
+                    missingProperty: 'links'
+                }
+            }, {
+                type: 'Validation',
+                message: 'should be string',
+                keyword: 'type',
+                dataPath: '.versions[0].id',
+                schemaPath: '#/properties/versions/items/properties/id/type',
+                exampleFilePath: path.normalize('test/data/v2/external-examples-invalid-type.json'),
+                mapFilePath: path.normalize(
+                    path.join(__dirname, '../../../../test/data/v2/map-external-examples-with-wildcards.json')),
+                params: {
+                    type: 'string'
+                }
+            }]);
+        });
+        it('map of examples with wildcards should be equal to without wildcards', async() => {
+            const resultWithWildcards = await validateExamplesByMap(FILE_PATH__EXTERNAL_EXAMPLES_SCHEMA,
+                FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_WILDCARDS);
+            const resultWithoutWildcards = await validateExamplesByMap(FILE_PATH__EXTERNAL_EXAMPLES_SCHEMA,
+                FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITHOUT_WILDCARDS);
+            resultWithWildcards.valid.should.equal(resultWithoutWildcards.valid);
+            resultWithWildcards.statistics.should.deep.equal(resultWithoutWildcards.statistics);
+            removeMapFilePath(resultWithWildcards.errors).should.deep.equal(
+                removeMapFilePath(resultWithoutWildcards.errors));
+        });
     });
     describe('should throw errors', () => {
         describe("when files can't be found:", () => {
@@ -210,7 +261,7 @@ describe('Main-module, for v2 should', () => {
                 result.errors.should.deep.equal([
                     new ApplicationError(ErrorType.jsENOENT, {
                         mapFilePath: FILE_PATH__EXTERNAL_EXAMPLES_MAP_WITH_MISSING_EXAMPLE,
-                        message: "ENOENT: no such file or directory, open 'test/data/v2/blegh forgot the sugar in the"
+                        message: "No such file or directory: 'test/data/v2/blegh forgot the sugar in the"
                             + " coffee'",
                         params: {
                             path: 'test/data/v2/blegh forgot the sugar in the coffee'
@@ -338,7 +389,7 @@ describe('Main-module, for v2 should', () => {
     describe('with set `cwd-to-mapping-file`-flag', () => {
         it('resolve the relative paths in the mapping-files', async() => {
             const result = await validateExamplesByMap(FILE_PATH__EXTERNAL_EXAMPLES_SCHEMA,
-                FILE_PATH__EXTERNAL_EXAMPLES_MAP__RELATIVE, { cwdToMappingFile: true });
+                FILE_PATH__EXTERNAL_EXAMPLES_MAP_RELATIVE, { cwdToMappingFile: true });
             result.valid.should.equal(true);
             result.statistics.should.deep.equal({
                 schemasWithExamples: 2,
@@ -348,4 +399,27 @@ describe('Main-module, for v2 should', () => {
             });
         });
     });
+    describe('prepare', () => {
+        it('should set noAdditionalProperties in the openapiSpec, if flag provided', async() => {
+            const preparedOpenapi = prepare(
+                loadTestData('v2/valid-without-examples'),
+                { noAdditionalProperties: true }
+            );
+            preparedOpenapi.should.deep.equal(loadTestData('v2/valid-with-no-additional-properties'));
+        });
+        it('should set allPropertiesRequired in the openapiSpec, if flag provided', async() => {
+            const preparedOpenapi = prepare(
+                loadTestData('v2/valid-without-examples'),
+                { allPropertiesRequired: true }
+            );
+            preparedOpenapi.should.deep.equal(loadTestData('v2/valid-with-all-properties-required'));
+        });
+    });
 });
+
+function removeMapFilePath(errors) {
+    return errors.map(error => {
+        delete error.mapFilePath;
+        return error;
+    });
+}
diff --git a/test/specs/impl/v3/index.js b/test/specs/impl/v3/index.js
index 004e879..4d0bb8e 100644
--- a/test/specs/impl/v3/index.js
+++ b/test/specs/impl/v3/index.js
@@ -17,6 +17,7 @@ const path = require('path'),
         = require('../../../data/v3/draft-04-properties/errors-exclusive-minimum.json'),
     errorsEscapedErrorNames
         = require('../../../data/v3/errors/simple-api-with-example-names-to-be-escaped.json');
+const { prepare } = require('../../../../src/impl/v3');
 
 const JSON_PATH__CONTEXT_MUTUALLY_EXCLUSIVE = '/paths/~1pets/get/responses/200/content/application~1json',
     REL_PATH__EXAMPLE__SIMPLE = 'v3/simple-api-with-example',
@@ -328,8 +329,8 @@ describe('Main-module, for v3 should', function() {
                 .statistics.schemasWithExamples.should.equal(2);
         });
     });
-    describe('with additional properties', function() {
-        describe('with flag not set', function() {
+    describe('with noAdditionalProperties option', function() {
+        describe('with option not set', function() {
             it('`validateFile` should not show any error', async function() {
                 (await validateFile(FILE_PATH__SCHEMA__WITH_ADDITIONAL_PROPERTIES_WITH_EXAMPLES))
                     .valid.should.equal(true);
@@ -360,7 +361,7 @@ describe('Main-module, for v3 should', function() {
                 )).valid.should.equal(true);
             });
         });
-        describe('with flag set', function() {
+        describe('with option set', function() {
             it('`validateFile` should throw an error', async function() {
                 (await validateFile(
                     FILE_PATH__SCHEMA__WITH_ADDITIONAL_PROPERTIES_WITH_EXAMPLES,
@@ -396,7 +397,10 @@ describe('Main-module, for v3 should', function() {
                     FILE_PATH__SCHEMA__WITH_ADDITIONAL_PROPERTIES,
                     FILE_PATH__MAP__WITH_ADDITIONAL_PROPERTIES,
                     { noAdditionalProperties: true }
-                )).errors.should.deep.equal(_expandFilePathOfErrors(errorsAdditionalPropertiesMap, 'mapFilePath'));
+                )).errors.should.deep.equal(
+                    _normalizeFilePathOfErrors(
+                        _expandFilePathOfErrors(errorsAdditionalPropertiesMap, 'mapFilePath'), 'exampleFilePath')
+                );
             });
         });
     });
@@ -415,11 +419,36 @@ describe('Main-module, for v3 should', function() {
                 .errors.should.deep.equal(errorsEscapedErrorNames);
         });
     });
+    describe('prepare', () => {
+        it('should set noAdditionalProperties in the openapiSpec, if flag provided', async() => {
+            const preparedOpenapi = prepare(
+                loadTestData('v3/simple-api-with-example'),
+                { noAdditionalProperties: true }
+            );
+            preparedOpenapi.should.deep.equal(
+                loadTestData('v3/additional-properties/simple-api-with-no-additional-properties'));
+        });
+        it('should set allPropertiesRequired in the openapiSpec, if flag provided', async() => {
+            const preparedOpenapi = prepare(
+                loadTestData('v3/simple-api-with-example'),
+                { allPropertiesRequired: true }
+            );
+            preparedOpenapi.should.deep.equal(
+                loadTestData('v3/all-properties-required/simple-api-with-all-properties-required'));
+        });
+    });
 });
 
 function _expandFilePathOfErrors(errors, propertyName) {
     errors.forEach(error => {
-        error[propertyName] = path.join(__dirname, '../../../..', error[propertyName]);
+        error[propertyName] = path.normalize(path.join(__dirname, '../../../..', error[propertyName]));
+    });
+    return errors;
+}
+
+function _normalizeFilePathOfErrors(errors, propertyName) {
+    errors.forEach(error => {
+        error[propertyName] = path.normalize(error[propertyName]);
     });
     return errors;
 }