Repository: typestack/class-validator (ts)

Issue:
fix: forbidUnknownValues doesn't default to true when validatorOptions are undefined
### Description
0.14.0 is supposed to make `forbidUnknownValues` default to `true`. However, it only defaults to `true` when a `validatorOptions` object is passed.

**Minimal code-snippet showcasing the problem**
```ts
await validateOrReject({}); // resolves
await validateOrReject({}, {}); // rejects
```

### Expected behavior
`forbidUnknownValues` should default to `true` unless explicitly specified as `false`.

### Actual behavior
`forbidUnknownValues` continues to default to `false` when no `validatorOptions` object is specified.


Pull request description:
fix: forbidUnknownValues should default true when validatorOptions undefined
## Description
<!-- A clear and concise description what these changes does. -->
`forbidUnknownValues` is supposed to default to `true`. This wasn't the case when `validatorOptions` was `undefined`. This PR corrects that and adds a test for it. It also corrects some related code doc.

## Checklist
<!-- Replace  the [ ] with [x] to check the boxes. -->
- [x] the pull request title describes what this PR does (not a vague title like `Update index.md`)
- [x] the pull request targets the *default* branch of the repository (`develop`)
- [x] the code follows the established code style of the repository
  - `npm run prettier:check` passes
  - `npm run lint:check` passes
- [x] tests are added for the changes I made (if any source code was modified)
- [x] documentation added or updated
- [x] I have run the project locally and verified that there are no errors

### Fixes
<!-- If there is no issue being resolved, open one before creating this pull request. -->
<!-- If the PR doesn't fully resolve the issue, replace 'fixes' with 'references'. -->
fixes #1906


Patch:
diff --git a/src/validation/ValidationExecutor.ts b/src/validation/ValidationExecutor.ts
index 9d3d312..98d09fc 100644
--- a/src/validation/ValidationExecutor.ts
+++ b/src/validation/ValidationExecutor.ts
@@ -67,7 +67,7 @@ export class ValidationExecutor {
     );
     const groupedMetadatas = this.metadataStorage.groupByPropertyName(targetMetadatas);
 
-    if (this.validatorOptions && forbidUnknownValues && !targetMetadatas.length) {
+    if (forbidUnknownValues && !targetMetadatas.length) {
       const validationError = new ValidationError();
 
       if (
diff --git a/src/validation/ValidatorOptions.ts b/src/validation/ValidatorOptions.ts
index 0069cd4..f33d892 100644
--- a/src/validation/ValidatorOptions.ts
+++ b/src/validation/ValidatorOptions.ts
@@ -75,8 +75,9 @@ export interface ValidatorOptions {
    * Fails validation for objects unknown to class-validator. Defaults to true.
    *
    * For instance, since a plain empty object has no annotations used for validation:
-   * - `validate({})` // passes
+   * - `validate({})` // fails.
    * - `validate({}, { forbidUnknownValues: true })` // fails.
+   * - `validate({}, { forbidUnknownValues: false })` // passes.
    * - `validate(new SomeAnnotatedEmptyClass(), { forbidUnknownValues: true })` // passes.
    */
   forbidUnknownValues?: boolean;


Test patch:
diff --git a/test/functional/validator-options.spec.ts b/test/functional/validator-options.spec.ts
index b14fbf1..ed4b6f3 100644
--- a/test/functional/validator-options.spec.ts
+++ b/test/functional/validator-options.spec.ts
@@ -44,4 +44,43 @@ describe('validator options', () => {
       expect(errors.length).toEqual(0);
     });
   });
+
+  it(`should return error on unknown objects if no options object argument is passed`, () => {
+    const anonymousObject = { badKey: 'This should not pass.' };
+
+    return validator.validate(anonymousObject, undefined).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(anonymousObject);
+      expect(errors[0].property).toEqual(undefined);
+      expect(errors[0].value).toEqual(undefined);
+      expect(errors[0].children).toBeInstanceOf(Array);
+      expect(errors[0].constraints).toEqual({ unknownValue: 'an unknown value was passed to the validate function' });
+    });
+  });
+
+  it(`should return error on unknown objects if empty options object argument passed`, () => {
+    const anonymousObject = { badKey: 'This should not pass.' };
+
+    return validator.validate(anonymousObject, {}).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(anonymousObject);
+      expect(errors[0].property).toEqual(undefined);
+      expect(errors[0].value).toEqual(undefined);
+      expect(errors[0].children).toBeInstanceOf(Array);
+      expect(errors[0].constraints).toEqual({ unknownValue: 'an unknown value was passed to the validate function' });
+    });
+  });
+
+  it(`should return error on unknown objects if options object argument passed with forbidUnknownValues undefined`, () => {
+    const anonymousObject = { badKey: 'This should not pass.' };
+
+    return validator.validate(anonymousObject, { forbidUnknownValues: undefined }).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(anonymousObject);
+      expect(errors[0].property).toEqual(undefined);
+      expect(errors[0].value).toEqual(undefined);
+      expect(errors[0].children).toBeInstanceOf(Array);
+      expect(errors[0].constraints).toEqual({ unknownValue: 'an unknown value was passed to the validate function' });
+    });
+  });
 });