diff --git a/.gitignore b/.gitignore
index 6b7e9586d4a9017cdce94a43976f072762c1e5db..4ac0229c425999f972a8480e63396c1daa92d87b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 *~
 *.log
 *.tgz
+*.todo
 .nyc_output
 .DS_Store
 /lib
diff --git a/README.md b/README.md
index 823f38f9a2a55c84795f1846331f63d23798d14e..ea51bf7f16907c107b041121ce8fe9747b5d0f03 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@
 
 [![Inline docs](http://inch-ci.org/github/json-schema-faker/json-schema-faker.svg?branch=master)](http://inch-ci.org/github/json-schema-faker/json-schema-faker)
 [![Typedoc](https://img.shields.io/badge/typedoc-provided-blue.svg)](http://json-schema-faker.github.io/json-schema-faker/)
+[![Known Vulnerabilities](https://snyk.io/test/github/json-schema-faker/json-schema-faker/badge.svg)](https://snyk.io/test/github/json-schema-faker/json-schema-faker)
 
 > Use [JSON Schema](http://json-schema.org/draft-04/json-schema-core.html) along with fake generators to provide consistent and meaningful fake data for your system.
 
diff --git a/dist/json-schema-faker.bundle.min.js b/dist/bundle.umd.min.js
similarity index 53%
rename from dist/json-schema-faker.bundle.min.js
rename to dist/bundle.umd.min.js
index 26ed29064b812440883c968d55f618e62f78b0a3..9009fe48a4acb3224e84e09a2a3ea0176d75373e 100644
Binary files a/dist/json-schema-faker.bundle.min.js and b/dist/bundle.umd.min.js differ
diff --git a/dist/json-schema-faker.cjs.js b/dist/index.js
similarity index 89%
rename from dist/json-schema-faker.cjs.js
rename to dist/index.js
index 0e936f75e8f03237aa51eb5f38b57c6207c917db..917e600af5e1b36ef78486fb718200a8e6dd8787 100644
Binary files a/dist/json-schema-faker.cjs.js and b/dist/index.js differ
diff --git a/dist/json-schema-faker.es.js b/dist/index.mjs
similarity index 89%
rename from dist/json-schema-faker.es.js
rename to dist/index.mjs
index c65055f725938a7b8e0acf60720a09acea00a0ff..459fbd7449b8953900b9e6b2f99d79140d8a5fd9 100644
Binary files a/dist/json-schema-faker.es.js and b/dist/index.mjs differ
diff --git a/dist/index.umd.js b/dist/index.umd.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c678eaedbdc8865a94837d75b390d62eabb752b
Binary files /dev/null and b/dist/index.umd.js differ
diff --git a/dist/index.umd.min.js b/dist/index.umd.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..6bd7b6adb6f91280f0c9350addca69ccd86873b1
Binary files /dev/null and b/dist/index.umd.min.js differ
diff --git a/dist/index.umd.min.js.map b/dist/index.umd.min.js.map
new file mode 100644
index 0000000000000000000000000000000000000000..0df08a47a0281e36ae78826bccb2d1293fc4261d
Binary files /dev/null and b/dist/index.umd.min.js.map differ
diff --git a/dist/json-schema-faker.js b/dist/json-schema-faker.js
deleted file mode 100644
index 81e67a5ff46f45a1326d8ef3371787b614423fba..0000000000000000000000000000000000000000
Binary files a/dist/json-schema-faker.js and /dev/null differ
diff --git a/dist/json-schema-faker.min.js b/dist/json-schema-faker.min.js
deleted file mode 100644
index c5b7659846e1dc1688f864f2f17f81d4968d108b..0000000000000000000000000000000000000000
Binary files a/dist/json-schema-faker.min.js and /dev/null differ
diff --git a/dist/json-schema-faker.min.js.map b/dist/json-schema-faker.min.js.map
deleted file mode 100644
index 0741cacbbb6cb2df9f522957d0c4386c22303a61..0000000000000000000000000000000000000000
Binary files a/dist/json-schema-faker.min.js.map and /dev/null differ
diff --git a/docs/README.md b/docs/README.md
index f966c8aed1711a803bd288b76cab9ab384cfe3e8..903ae34d5f0e9127ebad30af2a6425eb9abd8b5b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -109,7 +109,7 @@ jsf.locate('faker');
 - `ignoreMissingRefs` — If enabled, it will resolve to `{}` for unknown references (default: `false`)
 - `failOnInvalidTypes` — If enabled, it will throw an `Error` for unknown types (default: `true`)
 - `failOnInvalidFormat` — If enabled, it will throw an `Error` for unknown formats (default: `true`)
-- `alwaysFakeOptionals` — When enabled, it will set `optionalsProbability` as `1.0` (default: `false`)
+- `alwaysFakeOptionals` — When enabled, it will set `optionalsProbability: 1.0` and ` fixedProbabilities: true` (default: `false`)
 - `optionalsProbability` — A value from `0.0` to `1.0` to generate values in a consistent way, e.g. `0.5` will generate from `0%` to `50%` of values. Using arrays it means items, on objects they're properties, etc. (default: `false`)
 - `fixedProbabilities` — If enabled, then `optionalsProbability: 0.5` will always generate the half of values (default: `false`)
 - `useExamplesValue` — If enabled, it will return a random value from `examples` if they're present (default: `false`)
diff --git a/package-lock.json b/package-lock.json
index e736b4f30e651aeab77b77e74215c2f531a4c5ac..4ff3ccd92ed2923b27aea6d850a4d309b7852fc0 100644
Binary files a/package-lock.json and b/package-lock.json differ
diff --git a/package.json b/package.json
index 010f8b4157efe31c783e95d7debecee841c786ae..15fb8b928be7308311ae3bf5b73f6a77c875dafe 100644
--- a/package.json
+++ b/package.json
@@ -3,21 +3,21 @@
   "version": "0.5.0-rc16",
   "description": "JSON-Schema + fake data generators",
   "homepage": "http://json-schema-faker.js.org",
-  "main": "dist/json-schema-faker.cjs.js",
-  "module": "dist/json-schema-faker.es.js",
-  "browser": "dist/json-schema-faker.min.js",
+  "main": "dist/index.js",
+  "module": "dist/index.mjs",
+  "browser": "dist/index.umd.min.js",
   "scripts": {
-    "build:concat:dist": "concat -o dist/json-schema-faker.bundle.min.js node_modules/json-schema-ref-parser/dist/ref-parser.min.js node_modules/jsonpath/jsonpath.js dist/json-schema-faker.min.js",
-    "build:browser": "bili --banner --target browser --format umd,umd-min --moduleName JSONSchemaFaker --name json-schema-faker --js buble && npm run build:concat:dist",
-    "build:node": "bili src/index.js --target node --js buble --format es,cjs",
+    "build:concat:dist": "concat -o dist/bundle.umd.min.js node_modules/json-schema-ref-parser/dist/ref-parser.min.js node_modules/jsonpath/jsonpath.js dist/index.umd.min.js",
+    "build:browser": "bili --banner --format umd --format umd-min --module-name JSONSchemaFaker --minimal && npm run build:concat:dist",
+    "build:node": "bili src/index.js --minimal --format es --format cjs",
     "build": "npm run build:browser && npm run build:node",
     "dev": "npm test -- -w",
     "test": "npm run test:unit --",
     "test:ci": "npm run coverage:all && npm run report -- -r lcov",
     "test:all": "npm run test:run tests && npm run report -- -r html",
     "test:run": "NODE_ENV=test _mocha --exit --recursive --watch-extensions js,json -r esm -bR spec",
-    "test:unit": "npm run test:run tests/unit",
-    "test:schema": "npm run test:run tests/schema",
+    "test:unit": "npm run test:run tests/unit --",
+    "test:schema": "npm run test:run tests/schema --",
     "coverage": "nyc -x '**/tests/**' -x '**/*.spec.js'",
     "coverage:all": "npm run coverage -- npm run test:all",
     "coverage:unit": "npm run coverage -- npm run test:unit",
@@ -53,7 +53,7 @@
   },
   "devDependencies": {
     "ajv": "^6.5.3",
-    "bili": "^3.1.2",
+    "bili": "^4.2.5",
     "chai": "^4.1.2",
     "chance": "^1.0.9",
     "clone": "^2.1.2",
@@ -64,19 +64,19 @@
     "fs-extra": "^7.0.0",
     "glob": "^7.1.2",
     "is-my-json-valid": "^2.19.0",
-    "mocha": "^5.2.0",
-    "nyc": "^13.0.1",
-    "rollup": "^0.66.2",
+    "mocha": "^6.0.0",
+    "nyc": "^13.3.0",
+    "rollup": "^1.2.2",
     "rollup-plugin-commonjs": "^9.1.0",
-    "rollup-plugin-node-resolve": "^3.0.0",
-    "seedrandom": "^2.4.3",
+    "rollup-plugin-node-resolve": "^4.0.0",
+    "seedrandom": "^3.0.1",
     "semver": "^5.3.0",
     "tv4": "^1.3.0",
     "z-schema": "^3.18.4"
   },
   "dependencies": {
-    "json-schema-ref-parser": "^5.0.0",
-    "jsonpath": "^1.0.0",
+    "json-schema-ref-parser": "^6.0.2",
+    "jsonpath": "^1.0.1",
     "randexp": "^0.5.3"
   }
 }
diff --git a/src/api/format.js b/src/api/format.js
index 8d752c0a1ed95530da211a0a73ae311a012c6e89..cedfeecb699dccebdbac23f8fc91793b3f3ff6a8 100644
--- a/src/api/format.js
+++ b/src/api/format.js
@@ -14,7 +14,9 @@ const registry = new Registry();
 function formatAPI(nameOrFormatMap, callback) {
   if (typeof nameOrFormatMap === 'undefined') {
     return registry.list();
-  } else if (typeof nameOrFormatMap === 'string') {
+  }
+
+  if (typeof nameOrFormatMap === 'string') {
     if (typeof callback === 'function') {
       registry.register(nameOrFormatMap, callback);
     } else if (callback === null || callback === false) {
diff --git a/src/api/option.js b/src/api/option.js
index e014d608c0d361b87188796f956e02c29f6550c2..97bb5920332f24ceedbbc9f8b235232b18df6cf8 100644
--- a/src/api/option.js
+++ b/src/api/option.js
@@ -9,8 +9,12 @@ const registry = new OptionRegistry();
  * @param nameOrOptionMap
  * @returns {any}
  */
-function optionAPI(nameOrOptionMap) {
+function optionAPI(nameOrOptionMap, optionalValue) {
   if (typeof nameOrOptionMap === 'string') {
+    if (typeof optionalValue !== 'undefined') {
+      return registry.register(nameOrOptionMap, optionalValue);
+    }
+
     return registry.get(nameOrOptionMap);
   }
 
diff --git a/src/core/random.js b/src/core/random.js
index 0ea6faffdafdc36e28b277314ed56454e6aadbbe..add5d1f0f9bec6ed9c97df89242da8ec4e055cdb 100644
--- a/src/core/random.js
+++ b/src/core/random.js
@@ -1,7 +1,7 @@
 import RandExp from 'randexp';
 
 import optionAPI from '../api/option';
-import env from '../core/constants';
+import env from './constants';
 
 function getRandomInteger(min, max) {
   min = typeof min === 'undefined' ? env.MIN_INTEGER : min;
@@ -15,8 +15,7 @@ function _randexp(value) {
   RandExp.prototype.max = optionAPI('defaultRandExpMax');
 
   // same implementation as the original except using our random
-  RandExp.prototype.randInt = (a, b) =>
-    a + Math.floor(optionAPI('random')() * (1 + (b - a)));
+  RandExp.prototype.randInt = (a, b) => a + Math.floor(optionAPI('random')() * (1 + (b - a)));
 
   const re = new RandExp(value);
 
diff --git a/src/core/run.js b/src/core/run.js
index 07979b36d5d22629973dc055d783dc0e46b6bbca..d53f73b0f70d90d68ee05e2944eb21baf32b1cf9 100644
--- a/src/core/run.js
+++ b/src/core/run.js
@@ -83,7 +83,7 @@ function resolve(obj, data, values, property) {
 // TODO provide types
 function run(refs, schema, container) {
   try {
-    const result = traverse(utils.merge({}, schema), [], function reduce(sub, maxReduceDepth, parentSchemaPath) {
+    const result = traverse(utils.clone(schema), [], function reduce(sub, maxReduceDepth, parentSchemaPath) {
       if (typeof maxReduceDepth === 'undefined') {
         maxReduceDepth = random.number(1, 3);
       }
@@ -163,8 +163,18 @@ function run(refs, schema, container) {
         return {
           thunk() {
             const copy = utils.omitProps(sub, ['anyOf', 'oneOf']);
-
-            utils.merge(copy, random.pick(mix));
+            const fixed = random.pick(mix);
+            utils.merge(copy, fixed);
+
+            if (sub.oneOf) {
+              mix.forEach(omit => {
+                if (omit !== fixed && omit.required) {
+                  omit.required.forEach(key => {
+                    delete copy.properties[key];
+                  });
+                }
+              });
+            }
 
             return copy;
           },
diff --git a/src/core/traverse.js b/src/core/traverse.js
index 43c100d7b205066e318804024d61197211dec951..fd3488653cad9416b2d02ee42adb1c11cb726996 100644
--- a/src/core/traverse.js
+++ b/src/core/traverse.js
@@ -80,7 +80,7 @@ function traverse(schema, path, resolve, rootSchema) {
         return types[type](schema, path, resolve, traverse);
       } catch (e) {
         if (typeof e.path === 'undefined') {
-          throw new ParseError(e.message, path);
+          throw new ParseError(e.stack, path);
         }
         throw e;
       }
diff --git a/src/core/utils.js b/src/core/utils.js
index d6d56043a795ff695edde4df01090af1c7df6bbb..c0146b132045e183cb53fce60f9207a49ebf20c8 100644
--- a/src/core/utils.js
+++ b/src/core/utils.js
@@ -1,5 +1,5 @@
 import optionAPI from '../api/option';
-import env from '../core/constants';
+import env from './constants';
 import random from './random';
 
 function getSubAttribute(obj, dotSeparatedKey) {
@@ -133,7 +133,11 @@ function typecast(type, schema, callback) {
       const max = Math.min(params.maxLength || Infinity, Infinity);
 
       while (value.length < min) {
-        value += ` ${value}`;
+        if (!schema.pattern) {
+          value += `${random.pick([' ', '/', '_', '-', '+', '=', '@', '^'])}${value}`;
+        } else {
+          value += random.randexp(schema.pattern);
+        }
       }
 
       if (value.length > max) {
@@ -143,7 +147,7 @@ function typecast(type, schema, callback) {
       switch (schema.format) {
         case 'date-time':
         case 'datetime':
-          value = new Date(value).toISOString();
+          value = new Date(value).toISOString().replace(/([0-9])0+Z$/, '$1Z');
           break;
 
         case 'date':
@@ -151,7 +155,7 @@ function typecast(type, schema, callback) {
           break;
 
         case 'time':
-          value = new Date(value).toISOString().substr(11);
+          value = new Date(`1969-01-01 ${value}`).toISOString().substr(11);
           break;
 
         default:
@@ -188,6 +192,21 @@ function merge(a, b) {
   return a;
 }
 
+function clone(obj) {
+  if (!obj || typeof obj !== 'object') {
+    return obj;
+  }
+
+  if (Array.isArray(obj)) {
+    return obj.map(x => clone(x));
+  }
+
+  return Object.keys(obj).reduce((prev, cur) => {
+    prev[cur] = clone(obj[cur]);
+    return prev;
+  }, {});
+}
+
 function short(schema) {
   const s = JSON.stringify(schema);
   const l = JSON.stringify(schema, null, 2);
@@ -207,6 +226,7 @@ function anyValue() {
     undefined,
     [],
     {},
+    // FIXME: use built-in random?
     Math.random(),
     Math.random().toString(36).substr(2),
   ]);
@@ -294,7 +314,7 @@ function omitProps(obj, props) {
       if (Array.isArray(obj[k])) {
         copy[k] = obj[k].slice();
       } else {
-        copy[k] = typeof obj[k] === 'object'
+        copy[k] = obj[k] instanceof Object
           ? merge({}, obj[k])
           : obj[k];
       }
@@ -322,6 +342,7 @@ export default {
   omitProps,
   typecast,
   merge,
+  clone,
   short,
   notValue,
   anyValue,
diff --git a/src/generators/thunk.js b/src/generators/thunk.js
index 99523c8b88a93ba478301d2880defe48d595487a..ab50a6aa55071b04494b9f38804cc80977ae4fd0 100644
--- a/src/generators/thunk.js
+++ b/src/generators/thunk.js
@@ -1,4 +1,4 @@
-import words from '../generators/words';
+import words from './words';
 import random from '../core/random';
 
 /**
diff --git a/src/types/array.js b/src/types/array.js
index cd5f6a3a3c8571b0ca5f11e43f52667ce01883cd..c1b63e3ac9196e8c1a0b9edfe38a5518094a9bb8 100644
--- a/src/types/array.js
+++ b/src/types/array.js
@@ -14,7 +14,11 @@ function unique(path, items, value, sample, resolve, traverseCallback) {
     if (seen.indexOf(json) === -1) {
       seen.push(json);
       tmp.push(obj);
+
+      return true;
     }
+
+    return false;
   }
 
   items.forEach(walk);
@@ -23,10 +27,11 @@ function unique(path, items, value, sample, resolve, traverseCallback) {
   let limit = 100;
 
   while (tmp.length !== items.length) {
-    walk(traverseCallback(value.items || sample, path, resolve));
+    if (!walk(traverseCallback(value.items || sample, path, resolve))) {
+      limit -= 1;
+    }
 
     if (!limit) {
-      limit -= 1;
       break;
     }
   }
@@ -76,14 +81,14 @@ function arrayType(value, path, resolve, traverseCallback) {
   }
 
   const optionalsProbability = optionAPI('alwaysFakeOptionals') === true ? 1.0 : optionAPI('optionalsProbability');
-  const fixedProbabilities = optionAPI('fixedProbabilities') || false;
+  const fixedProbabilities = optionAPI('alwaysFakeOptionals') || optionAPI('fixedProbabilities') || false;
 
   let length = random.number(minItems, maxItems, 1, 5);
 
   if (optionalsProbability !== false) {
-    length = fixedProbabilities
+    length = Math.max(fixedProbabilities
       ? Math.round((maxItems || length) * optionalsProbability)
-      : Math.abs(random.number(minItems, maxItems) * optionalsProbability);
+      : Math.abs(random.number(minItems, maxItems) * optionalsProbability), minItems || 0);
   }
 
   // TODO below looks bad. Should additionalItems be copied as-is?
diff --git a/src/types/null.js b/src/types/null.js
index 9362f837fb5b88674dae34bbf792ec2a24c72c16..9e9bbb20f6b8bee7396f42942b4caa62c1d61c8e 100644
--- a/src/types/null.js
+++ b/src/types/null.js
@@ -3,4 +3,3 @@ import nullGenerator from '../generators/null';
 const nullType = nullGenerator;
 
 export default nullType;
-
diff --git a/src/types/number.js b/src/types/number.js
index ea5e31550878142e6d68e4f56fcba85ceb2aedb8..7eeafffe65bfe21d3c095db4511411d2bd12755c 100644
--- a/src/types/number.js
+++ b/src/types/number.js
@@ -45,7 +45,6 @@ function numberType(value) {
       fix = (num / multipleOf) % 1;
     } while (fix !== 0);
 
-
     // FIXME: https://github.com/json-schema-faker/json-schema-faker/issues/379
 
     return num;
diff --git a/src/types/object.js b/src/types/object.js
index c71faf5ee7e6402ecc3abef703bfe545083d8651..c5add7359c812d84aff1185fe4db39eec0a5fb6e 100644
--- a/src/types/object.js
+++ b/src/types/object.js
@@ -2,7 +2,6 @@ import random from '../core/random';
 import words from '../generators/words';
 import utils from '../core/utils';
 import optionAPI from '../api/option';
-import ParseError from '../core/error';
 
 // fallback generator
 const anyType = { type: ['string', 'number', 'integer', 'boolean'] };
@@ -13,7 +12,7 @@ function objectType(value, path, resolve, traverseCallback) {
 
   const properties = value.properties || {};
   const patternProperties = value.patternProperties || {};
-  const requiredProperties = (value.required || []).slice();
+  const requiredProperties = typeof value.required === 'boolean' ? [] : (value.required || []).slice();
   const allowsAdditional = value.additionalProperties !== false;
 
   const propertyKeys = Object.keys(properties);
@@ -26,12 +25,12 @@ function objectType(value, path, resolve, traverseCallback) {
 
   const additionalProperties = allowsAdditional // eslint-disable-line
     ? (value.additionalProperties === true ? anyType : value.additionalProperties)
-    : null;
+    : value.additionalProperties;
 
-  if (!allowsAdditional &&
-    propertyKeys.length === 0 &&
-    patternPropertyKeys.length === 0 &&
-    utils.hasProperties(value, 'minProperties', 'maxProperties', 'dependencies', 'required')
+  if (!allowsAdditional
+    && propertyKeys.length === 0
+    && patternPropertyKeys.length === 0
+    && utils.hasProperties(value, 'minProperties', 'maxProperties', 'dependencies', 'required')
   ) {
     // just nothing
     return {};
@@ -48,23 +47,23 @@ function objectType(value, path, resolve, traverseCallback) {
   }
 
   const optionalsProbability = optionAPI('alwaysFakeOptionals') === true ? 1.0 : optionAPI('optionalsProbability');
-  const fixedProbabilities = optionAPI('fixedProbabilities') || false;
+  const fixedProbabilities = optionAPI('alwaysFakeOptionals') || optionAPI('fixedProbabilities') || false;
   const ignoreProperties = optionAPI('ignoreProperties') || [];
 
   const min = Math.max(value.minProperties || 0, requiredProperties.length);
-  const max = Math.min(value.maxProperties || allProperties.length, allProperties.length);
+  const max = value.maxProperties || (allProperties.length + random.number(1, 5));
 
   let neededExtras = Math.max(0, min - requiredProperties.length);
 
   if (allProperties.length === 1 && !requiredProperties.length) {
-    neededExtras = random.number(neededExtras, allProperties.length + (max - min));
+    neededExtras = random.number(neededExtras, allProperties.length + (allProperties.length - min));
   }
 
   if (optionalsProbability !== false) {
     if (fixedProbabilities === true) {
-      neededExtras = Math.round((min - requiredProperties.length) + (optionalsProbability * (max - min)));
+      neededExtras = Math.round((min - requiredProperties.length) + (optionalsProbability * (allProperties.length - min)));
     } else {
-      neededExtras = random.number(min - requiredProperties.length, optionalsProbability * (max - min));
+      neededExtras = random.number(min - requiredProperties.length, optionalsProbability * (allProperties.length - min));
     }
   }
 
@@ -75,6 +74,35 @@ function objectType(value, path, resolve, traverseCallback) {
 
   // properties are read from right-to-left
   const _props = requiredProperties.concat(extraProperties).slice(0, max);
+  const _defns = [];
+
+  if (value.dependencies) {
+    Object.keys(value.dependencies).forEach(prop => {
+      const _required = value.dependencies[prop];
+
+      if (_props.indexOf(prop) !== -1) {
+        if (Array.isArray(_required)) {
+          // property-dependencies
+          _required.forEach(sub => {
+            if (_props.indexOf(sub) === -1) {
+              _props.push(sub);
+            }
+          });
+        } else {
+          _defns.push(_required);
+        }
+      }
+    });
+
+    // schema-dependencies
+    if (_defns.length) {
+      delete value.dependencies;
+
+      return traverseCallback({
+        allOf: _defns.concat(value),
+      }, path.concat(['properties']), resolve);
+    }
+  }
 
   const skipped = [];
   const missing = [];
@@ -89,32 +117,40 @@ function objectType(value, path, resolve, traverseCallback) {
       }
     }
 
-    // first ones are the required properies
-    if (properties[key]) {
+    if (additionalProperties === false) {
+      if (requiredProperties.indexOf(key) !== -1) {
+        props[key] = properties[key];
+      }
+    } else if (properties[key]) {
       props[key] = properties[key];
-    } else {
-      let found;
+    }
+
+    let found;
 
-      // then try patternProperties
-      patternPropertyKeys.forEach(_key => {
-        if (key.match(new RegExp(_key))) {
-          found = true;
+    // then try patternProperties
+    patternPropertyKeys.forEach(_key => {
+      if (key.match(new RegExp(_key))) {
+        found = true;
+
+        if (props[key]) {
+          utils.merge(props[key], patternProperties[_key]);
+        } else {
           props[random.randexp(key)] = patternProperties[_key];
         }
-      });
+      }
+    });
 
-      if (!found) {
-        // try patternProperties again,
-        const subschema = patternProperties[key] || additionalProperties;
+    if (!found) {
+      // try patternProperties again,
+      const subschema = patternProperties[key] || additionalProperties;
 
-        // FIXME: allow anyType as fallback when no subschema is given?
+      // FIXME: allow anyType as fallback when no subschema is given?
 
-        if (subschema) {
-          // otherwise we can use additionalProperties?
-          props[patternProperties[key] ? random.randexp(key) : key] = subschema;
-        } else {
-          missing.push(key);
-        }
+      if (subschema && additionalProperties !== false) {
+        // otherwise we can use additionalProperties?
+        props[patternProperties[key] ? random.randexp(key) : key] = properties[key] || subschema;
+      } else {
+        missing.push(key);
       }
     }
   });
@@ -125,6 +161,9 @@ function objectType(value, path, resolve, traverseCallback) {
   // discard already ignored props if they're not required to be filled...
   let current = Object.keys(props).length + (fillProps ? 0 : skipped.length);
 
+  // generate dynamic suffix for additional props...
+  const hash = suffix => random.randexp(`_?[_a-f\\d]{1,3}${suffix ? '\\$?' : ''}`);
+
   function get() {
     let one;
 
@@ -173,7 +212,7 @@ function objectType(value, path, resolve, traverseCallback) {
           current += 1;
         }
       } else {
-        const word = get() || (words(1) + random.randexp('[a-f\\d]{1,3}'));
+        const word = get() || (words(1) + hash());
 
         if (!props[word]) {
           props[word] = additionalProperties || anyType;
@@ -186,6 +225,7 @@ function objectType(value, path, resolve, traverseCallback) {
       const _key = patternPropertyKeys[i];
       const word = random.randexp(_key);
 
+
       if (!props[word]) {
         props[word] = patternProperties[_key];
         current += 1;
@@ -193,18 +233,16 @@ function objectType(value, path, resolve, traverseCallback) {
     }
   }
 
-  if (!allowsAdditional && current < min) {
-    if (missing.length) {
-      throw new ParseError(`properties '${
-        missing.join(', ')
-      }' were not found while additionalProperties is false:\n${
-        utils.short(value)
-      }`, path);
-    }
+  // fill up-to this value and no more!
+  const maximum = random.number(min, max);
+
+  for (; current < maximum && additionalProperties;) {
+    const word = words(1) + hash(true);
 
-    throw new ParseError(`properties constraints were too strong to successfully generate a valid object for:\n${
-      utils.short(value)
-    }`, path);
+    if (!props[word]) {
+      props[word] = additionalProperties;
+      current += 1;
+    }
   }
 
   return traverseCallback(props, path.concat(['properties']), resolve);
diff --git a/tests/schema/core/dependencies.json b/tests/schema/core/dependencies.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc0086923fc7e65ad311bed894f3d864a5093894
--- /dev/null
+++ b/tests/schema/core/dependencies.json
@@ -0,0 +1,69 @@
+[
+  {
+    "description": "dependencies support",
+    "tests": [
+      {
+        "description": "should handle property-dependencies",
+        "schema": {
+          "type": "object",
+          "properties": {
+            "name": {
+              "type": "string"
+            },
+            "credit_card": {
+              "type": "number"
+            },
+            "billing_address": {
+              "type": "string"
+            }
+          },
+          "required": [
+            "name"
+          ],
+          "dependencies": {
+            "credit_card": [
+              "billing_address"
+            ]
+          }
+        },
+        "valid": true,
+        "set": {
+          "alwaysFakeOptionals": true
+        }
+      },
+      {
+        "description": "should handle schema-dependencies",
+        "schema": {
+          "type": "object",
+          "properties": {
+            "name": {
+              "type": "string"
+            },
+            "credit_card": {
+              "type": "number"
+            }
+          },
+          "required": [
+            "name"
+          ],
+          "dependencies": {
+            "credit_card": {
+              "properties": {
+                "billing_address": {
+                  "type": "string"
+                }
+              },
+              "required": [
+                "billing_address"
+              ]
+            }
+          }
+        },
+        "valid": true,
+        "set": {
+          "alwaysFakeOptionals": true
+        }
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-379.json b/tests/schema/core/issues/issue-379.json
index cd3051d9ccbdbcca7d55f446171286efef638707..6740930e5cf0ef4f09f87079759d5b77de12843e 100644
--- a/tests/schema/core/issues/issue-379.json
+++ b/tests/schema/core/issues/issue-379.json
@@ -18,9 +18,8 @@
         "multipleOf": 0.01
       },
       "seed": 0.06559633646612273,
-      "equal": 13119267.29,
-      "skip": true,
-      "valid": true
+      "equal": 13119267.290000001,
+      "valid": false
     }
   ]
 }
diff --git a/tests/schema/core/issues/issue-386.json b/tests/schema/core/issues/issue-386.json
index 65acbe24bff58f1428ad797c5da2d8a923666f4d..ae499a8b0d24384f28d2bd270c9a672cb3700436 100644
--- a/tests/schema/core/issues/issue-386.json
+++ b/tests/schema/core/issues/issue-386.json
@@ -60,9 +60,8 @@
           "additionalProperties": false
         },
         "set": {
-          "optionalsProbability": 1
+          "alwaysFakeOptionals": true
         },
-        "skip": true,
         "valid": true
       }
     ]
diff --git a/tests/schema/core/issues/issue-486.json b/tests/schema/core/issues/issue-486.json
new file mode 100644
index 0000000000000000000000000000000000000000..9ea4aae523160fab612891347dea4bdfae4f9a0d
--- /dev/null
+++ b/tests/schema/core/issues/issue-486.json
@@ -0,0 +1,26 @@
+[
+  {
+    "description": "pattern constraints",
+    "tests": [
+      {
+        "description": "should fullfil minLength/maxLength constraints",
+        "schema": {
+          "type": "string",
+          "minLength": 8,
+          "maxLength": 20,
+          "pattern": "^[a-zA-Z0-9_]+$"
+        },
+        "valid": true
+      },
+      {
+        "description": "would fail on complex patterns",
+        "schema": {
+          "type": "string",
+          "pattern": "^A[CD]{1,6}B$",
+          "minLength": 6
+        },
+        "throws": "String does not match pattern"
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-489.json b/tests/schema/core/issues/issue-489.json
new file mode 100644
index 0000000000000000000000000000000000000000..8f7578526db397db87ca4bbb38d7d443e153a68a
--- /dev/null
+++ b/tests/schema/core/issues/issue-489.json
@@ -0,0 +1,55 @@
+[
+  {
+    "description": "support consider patternProperties",
+    "tests": [
+      {
+        "description": "ensure first schema passes",
+        "schema": {
+          "$schema": "http://json-schema.org/draft-04/schema#",
+          "patternProperties": {
+            "test": {
+              "type": "null"
+            }
+          },
+          "properties": {
+            "test": {
+              "title": "short description"
+            }
+          },
+          "required": ["test"]
+        },
+        "valid": true
+      },
+      {
+        "description": "merge both properties definitions",
+        "schema": {
+          "$schema": "http://json-schema.org/draft-04/schema#",
+          "patternProperties": {
+            ".*_int$": {
+              "type": "integer"
+            }
+          },
+          "properties": {
+            "big_int": {
+              "title": "short description",
+              "minimum": 100
+            },
+            "normal_int": {
+              "title": "short description"
+            },
+            "small_int": {
+              "title": "short description",
+              "maximum": 100
+            }
+          },
+          "required": [
+            "big_int",
+            "normal_int",
+            "small_int"
+          ]
+        },
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-494.json b/tests/schema/core/issues/issue-494.json
new file mode 100644
index 0000000000000000000000000000000000000000..489bf020e5c9275a0be004e1b848c4b858ef0454
--- /dev/null
+++ b/tests/schema/core/issues/issue-494.json
@@ -0,0 +1,67 @@
+[
+  {
+    "description": "will use alwaysFakeOptionals",
+    "tests": [
+      {
+        "description": "should work if enabled",
+        "schema": {
+          "account-response": {
+            "title": "Account Response",
+            "type": "object",
+            "properties": {
+              "current": {
+                "type": "array",
+                "items": {
+                  "$ref": "#/definitions/current-account"
+                }
+              },
+              "escrow": {
+                "type": "array",
+                "items": {
+                  "$ref": "#/definitions/current-account"
+                }
+              }
+            },
+            "required": [
+              "current"
+            ]
+          },
+          "definitions": {
+            "current-account": {
+              "title": "Current Account",
+              "type": "object",
+              "properties": {
+                "number": {
+                  "type": "string"
+                },
+                "name": {
+                  "type": "string"
+                },
+                "balance": {
+                  "type": "number"
+                },
+                "currency": {
+                  "type": "string"
+                }
+              },
+              "required": [
+                "number",
+                "name",
+                "balance",
+                "currency"
+              ]
+            }
+          }
+        },
+        "set": {
+          "alwaysFakeOptionals": true
+        },
+        "notEmpty": [
+          "account-response.current",
+          "account-response.escrow"
+        ],
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-498.json b/tests/schema/core/issues/issue-498.json
new file mode 100644
index 0000000000000000000000000000000000000000..c77c342117658e962625a8450b543c65b4c3d98b
--- /dev/null
+++ b/tests/schema/core/issues/issue-498.json
@@ -0,0 +1,26 @@
+[
+  {
+    "description": "support consider patternProperties",
+    "tests": [
+      {
+        "description": "ensure first schema passes",
+        "schema": {
+          "required": [
+            "longitude"
+          ],
+          "type": "object",
+          "properties": {
+            "longitude": {
+              "title": "Longitude",
+              "type": "string",
+              "format": "decimal"
+            }
+          }
+        },
+        "set": {
+          "failOnInvalidFormat": false
+        }
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-502.json b/tests/schema/core/issues/issue-502.json
new file mode 100644
index 0000000000000000000000000000000000000000..176ca2b600bd827c5ccbe21c866256e74a972fef
--- /dev/null
+++ b/tests/schema/core/issues/issue-502.json
@@ -0,0 +1,50 @@
+[
+  {
+    "description": "will use alwaysFakeOptionals (regression)",
+    "tests": [
+      {
+        "description": "will fix #502",
+        "schema": {
+          "title": "Forum",
+          "type": "object",
+          "properties": {
+            "Id": {
+              "type": "string"
+            },
+            "Topics": {
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/Topic"
+              }
+            }
+          },
+          "definitions": {
+            "Topic": {
+              "type": "object",
+              "properties": {
+                "Id": {
+                  "type": "string"
+                },
+                "Posts": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/definitions/Post"
+                  }
+                }
+              }
+            },
+            "Post": {
+              "type": "object",
+              "properties": {
+                "Id": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        },
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-504.json b/tests/schema/core/issues/issue-504.json
new file mode 100644
index 0000000000000000000000000000000000000000..df424470cd4f47a826e3380855f246836acf8579
--- /dev/null
+++ b/tests/schema/core/issues/issue-504.json
@@ -0,0 +1,27 @@
+[
+  {
+    "description": "pattern and min/max length constraints",
+    "tests": [
+      {
+        "description": "should support minLength",
+        "schema": {
+          "type": "object",
+          "properties": {
+            "rodo": {
+              "type": "string"
+            }
+          },
+          "required": [
+            "rodo"
+          ],
+          "minProperties": 1,
+          "maxProperties": 3,
+          "additionalProperties": {
+            "type": "boolean"
+          }
+        },
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-506.json b/tests/schema/core/issues/issue-506.json
new file mode 100644
index 0000000000000000000000000000000000000000..6a3974a2870f34df2446c910d8d6fce02ae7cca4
--- /dev/null
+++ b/tests/schema/core/issues/issue-506.json
@@ -0,0 +1,31 @@
+[
+  {
+    "description": "about uniqueItems and enum",
+    "tests": [
+      {
+        "description": "should not take forever",
+        "schema": {
+          "type": "object",
+          "properties": {
+            "test": {
+              "type": "array",
+              "items": {
+                "type": "string",
+                "enum": [
+                  "a",
+                  "b",
+                  "c",
+                  "d",
+                  "e"
+                ]
+              },
+              "maxItems": 10,
+              "uniqueItems": true
+            }
+          }
+        },
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/issues/issue-508.json b/tests/schema/core/issues/issue-508.json
new file mode 100644
index 0000000000000000000000000000000000000000..043028f3a63f0d7f3aaa3120f34a5b1a6b0f6837
--- /dev/null
+++ b/tests/schema/core/issues/issue-508.json
@@ -0,0 +1,22 @@
+[
+  {
+    "description": "null issues",
+    "tests": [
+      {
+        "description": "should not iterate nulls",
+        "schema": {
+          "anyOf": [
+            {
+              "type": "boolean"
+            },
+            {
+              "type": "null"
+            }
+          ],
+          "default": null
+        },
+        "valid": true
+      }
+    ]
+  }
+]
diff --git a/tests/schema/core/option/failOnInvalidType.js b/tests/schema/core/option/failOnInvalidType.js
index c1d45d76a9da596c9b927f6aec891540a830f31d..5470f91ff5e1b0fdf4822ed6b0a4414a26552774 100644
--- a/tests/schema/core/option/failOnInvalidType.js
+++ b/tests/schema/core/option/failOnInvalidType.js
@@ -5,4 +5,3 @@ module.exports = {
     });
   },
 };
-
diff --git a/tests/schema/core/option/random.js b/tests/schema/core/option/random.js
index 51de6ffedfe1322b38584d1241cd39320b253fc2..6fba248d60247e41cbfca1e4824687ce7fd8cdfc 100644
--- a/tests/schema/core/option/random.js
+++ b/tests/schema/core/option/random.js
@@ -2,8 +2,6 @@ const seedrandom = require('seedrandom');
 
 module.exports = {
   register(jsf) {
-    return jsf.option({
-      random: seedrandom('some seed'),
-    });
+    return jsf.option('random', seedrandom('some seed'));
   },
 };
diff --git a/tests/schema/core/option/random.json b/tests/schema/core/option/random.json
index cce07cdfae7cfbb782c7e0b704b1dcac312a18ec..e126961c8d3c9285559f8c462a5768880e1c39be 100644
--- a/tests/schema/core/option/random.json
+++ b/tests/schema/core/option/random.json
@@ -23,9 +23,9 @@
         },
         "valid": true,
         "equal": {
-          "a": 93,
-          "b": "enim veniam",
-          "c": "ff353"
+          "a": 71,
+          "b": "do cupidatat",
+          "c": "wj382"
         },
         "repeat": 1,
         "require": "core/option/random"
diff --git a/tests/schema/core/option/useDefaultValue.js b/tests/schema/core/option/useDefaultValue.js
index 9150c32ca6d1a4032f331e54586f08412eab7b8d..fe027ba0ec3f022f46ac41d7233b99c878c892fe 100644
--- a/tests/schema/core/option/useDefaultValue.js
+++ b/tests/schema/core/option/useDefaultValue.js
@@ -5,4 +5,3 @@ module.exports = {
     });
   },
 };
-
diff --git a/tests/schema/core/option/useExamplesValue.js b/tests/schema/core/option/useExamplesValue.js
index 52964df691f8b89bd190427efbeb15295b2e17c0..4ad2e79cdfbe839655529e1a6f0c972ded5d34ef 100644
--- a/tests/schema/core/option/useExamplesValue.js
+++ b/tests/schema/core/option/useExamplesValue.js
@@ -5,4 +5,3 @@ module.exports = {
     });
   },
 };
-
diff --git a/tests/schema/core/refs/sync.json b/tests/schema/core/refs/sync.json
index 42b8596430aaf4c13df933e2f7426b94a51c1d7e..156f12378ed24fa35d182614e45f1be341376a11 100644
--- a/tests/schema/core/refs/sync.json
+++ b/tests/schema/core/refs/sync.json
@@ -24,6 +24,9 @@
             }
           }
         },
+        "FIXME": "this eventually fails, but because other is resolved to undefined; it just happen when repeating too much (too many requests?)",
+        "_repeat": 100,
+        "_only": true,
         "valid": true
       },
       {
diff --git a/tests/schema/core/types/object.json b/tests/schema/core/types/object.json
index 01ba47f89f991ac9c1f4774fe117a9b304241684..433a326699c7762667256fb44b594e4981636eff 100644
--- a/tests/schema/core/types/object.json
+++ b/tests/schema/core/types/object.json
@@ -269,13 +269,13 @@
           "type": "object",
           "properties": {
             "$count": {
-                "type": "string"
+              "type": "string"
             }
           },
           "minProperties": 20,
           "additionalProperties": false
         },
-        "throws": "properties constraints were too strong to successfully generate a valid object for:\n[\\s\\S]+? in \\/"
+        "throws": "properties '\\$count' were not found while additionalProperties is false"
       },
       {
         "description": "should handle inferred type (when possible)",
diff --git a/tests/schema/core/types/string.json b/tests/schema/core/types/string.json
index 6d29ab93f5c524c8f86a49b09039501942120f69..612bdcc1f74872018fdbf49cd62616473aafcb33 100644
--- a/tests/schema/core/types/string.json
+++ b/tests/schema/core/types/string.json
@@ -114,7 +114,7 @@
           },
           "required": ["test"]
         },
-        "throws": "Error: unknown registry key .+? in \\/properties\\/test"
+        "throws": "Error: unknown registry key .+?"
       },
       {
         "description": "should validate custom formats",
diff --git a/tests/schema/helpers.js b/tests/schema/helpers.js
index 137c0164cc4ba726cb61770c4e3d6b88a8eba72c..9e9bfdf767d034672bb6a095c07edc51b060dd7a 100644
--- a/tests/schema/helpers.js
+++ b/tests/schema/helpers.js
@@ -78,6 +78,16 @@ export function tryTest(test, refs, schema) {
       expect(sample.length).to.eql(test.length);
     }
 
+    if (test.notEmpty) {
+      test.notEmpty.forEach(x => {
+        const value = pick(sample, x);
+
+        if (value.length === 0) {
+          throw new Error(`${x} should not be empty`);
+        }
+      });
+    }
+
     if (test.hasProps) {
       test.hasProps.forEach(prop => {
         if (Array.isArray(sample)) {
@@ -108,12 +118,16 @@ export function tryTest(test, refs, schema) {
   }).catch(error => {
     if (typeof test.throws === 'string') {
       expect(error).to.match(new RegExp(test.throws, 'im'));
+      return;
     }
 
     if (typeof test.throws === 'boolean') {
       if (test.throws !== true) {
         throw error;
       }
+      return;
     }
+
+    throw error;
   });
 }
diff --git a/tests/schema/main.spec.js b/tests/schema/main.spec.js
index c959318019ce102d99447ba2494d39068954ccc9..0dba88bcbdd09cdc319ba4075f4ded1a3dcec854 100644
--- a/tests/schema/main.spec.js
+++ b/tests/schema/main.spec.js
@@ -1,11 +1,21 @@
-import { jsf, pick, tryTest, getTests } from './helpers';
+import {
+  jsf, pick, tryTest, getTests,
+} from './helpers';
 
 const { only, all } = getTests(__dirname);
 
 /* global describe, it */
 
+const seeds = [];
+
+function seed() {
+  const value = Math.random();
+  seeds.push(value);
+  return value;
+}
+
 (only.length ? only : all).forEach(suite => {
-  describe(`${suite.description} (${suite.file.replace(`${__dirname}/`, '')})`, () => {
+  describe(`${suite.description} (${suite.file.replace(`${process.cwd()}/`, '')})`, () => {
     suite.tests.forEach(test => {
       it(test.description, () => {
         jsf.option(jsf.option.getDefaults());
@@ -14,11 +24,9 @@ const { only, all } = getTests(__dirname);
           jsf.option(test.set);
         }
 
-        if (test.seed) {
-          jsf.option({
-            random: () => test.seed,
-          });
-        }
+        jsf.option({
+          random: () => ((test.seed && (Array.isArray(test.seed) ? test.seed.shift() : test.seed)) || seed()),
+        });
 
         if (test.require) {
           require(`./${test.require}`).register(jsf);
@@ -48,7 +56,11 @@ const { only, all } = getTests(__dirname);
           nth -= 1;
         }
 
-        return Promise.all(tasks);
+        return Promise.all(tasks).catch(e => {
+          // FIXME: find a way to debug this
+          console.log('---> Used seeds:', seeds.slice(-10).join(', ') || test.seed);
+          throw e;
+        });
       }).timeout(process.CI ? 30000 : 10000);
     });
   });