Skip to content

Commit

Permalink
Add NullOrAssert to allow any assert to be nullable
Browse files Browse the repository at this point in the history
  • Loading branch information
Ricardo Lopes authored and franciscocardoso committed Jan 31, 2023
1 parent d916e15 commit c736b90
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 1 deletion.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The following set of extra asserts are provided by this package:
- [Iso3166Country](#iso3166country) (requires `isoc`)
- [Json](#json)
- [NotEmpty](#notempty)
- [NullOr](#nullor)
- [NullOrDate](#nullordate)
- [NullOrBoolean](#nullorboolean)
- [NullOrString](#nullorstring)
Expand Down Expand Up @@ -196,6 +197,9 @@ Tests if the value is valid json.
### NotEmpty
Tests if the value is not an empty (empty object, empty array, empty string, etc).

### NullOr
Tests if the value is a `null` or validates agains the assert received as an argument.

### NullOrBoolean
Tests if the value is a `null` or `boolean`.

Expand Down Expand Up @@ -264,6 +268,13 @@ if (true !== violation) {
console.log('"foo" is not a valid IP. Violation:', violation[0].show());
// => "foo" is not a valid IP. Violation: { assert: 'Ip', value: 'foo' }
}

// Make the validation nullable.
violation = validator.validate(null, is.nullOr(is.ip()));

if (true === violation) {
console.log('null is null or a valid IP'); // => null is null or a valid IP
}
```

## Tests
Expand Down
41 changes: 41 additions & 0 deletions src/asserts/null-or-assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

/**
* Export `NullOrAssert`.
*/

module.exports = function nullOrAssert(assert) {
/**
* Class name.
*/

this.__class__ = 'NullOr';

if (typeof assert !== 'object') {
throw new Error('Assert must be an object.');
}

if (typeof assert.validate !== 'function') {
throw new Error('Assert must have a validate function.');
}

/**
* Nullable assert.
*/

this.assert = assert;

/**
* Validation algorithm.
*/

this.validate = value => {
if (value === null) {
return true;
}

return this.assert.validate(value);
};

return this;
};
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const Ip = require('./asserts/ip-assert.js');
const Iso3166Country = require('./asserts/iso-3166-country-assert.js');
const Json = require('./asserts/json-assert.js');
const NotEmpty = require('./asserts/not-empty-assert.js');
const NullOr = require('./asserts/null-or-assert.js');
const NullOrBoolean = require('./asserts/null-or-boolean-assert.js');
const NullOrDate = require('./asserts/null-or-date-assert.js');
const NullOrString = require('./asserts/null-or-string-assert.js');
Expand Down Expand Up @@ -73,6 +74,7 @@ module.exports = {
Iso3166Country,
Json,
NotEmpty,
NullOr,
NullOrBoolean,
NullOrDate,
NullOrString,
Expand Down
100 changes: 100 additions & 0 deletions test/asserts/null-or-assert.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use strict';

/**
* Module dependencies.
*/

const { Assert: BaseAssert, Violation } = require('validator.js');
const NullOrAssert = require('../../src/asserts/null-or-assert');
const UuidAssert = require('../../src/asserts/uuid-assert');

/**
* Extend `Assert` with `NullOrAssert`.
*/

const Assert = BaseAssert.extend({
NullOr: NullOrAssert,
Uuid: UuidAssert
});

/**
* Test `NullOrAssert`.
*/

describe('NullOrAssert', () => {
it('should throw an error if the specified assert is missing', () => {
try {
Assert.nullOr('foo').validate();

fail();
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect(e.message).toBe('Assert must be an object.');
}
});

it('should throw an error if the specified assert is not valid', () => {
try {
Assert.nullOr('foo').validate('bar');

fail();
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect(e.message).toBe('Assert must be an object.');
}
});

it('should throw an error if the specified assert has no `validate` function', () => {
try {
Assert.nullOr({}).validate(123);

fail();
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect(e.message).toBe('Assert must have a validate function.');
}
});

it('should throw an error if the specified assert has a `validate` property that is not a function', () => {
try {
Assert.nullOr({ validate: true }).validate(123);

fail();
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect(e.message).toBe('Assert must have a validate function.');
}
});

it('should throw an error if the value is not null and is not valid for the specified assert', () => {
try {
Assert.nullOr(Assert.string()).validate(123);

fail();
} catch (e) {
expect(e).toBeInstanceOf(Violation);
expect(e.show().assert).toBe('IsString');
expect(e.violation.value).toBe('must_be_a_string');
}
});

it('should include the arguments of the specified assert', () => {
try {
Assert.nullOr(Assert.uuid(4)).validate('foobar');

fail();
} catch (e) {
expect(e).toBeInstanceOf(Object);
expect(e.show().assert).toBe('Uuid');
expect(e.violation.version).toBe(4);
}
});

it('should accept a null value', () => {
Assert.nullOr(Assert.string()).validate(null);
});

it('should accept a value that is valid for the specified assert', () => {
Assert.nullOr(Assert.string()).validate('foobar');
});
});
3 changes: 2 additions & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('validator.js-asserts', () => {
it('should export all asserts', () => {
const assertNames = Object.keys(asserts);

expect(assertNames).toHaveLength(37);
expect(assertNames).toHaveLength(38);
expect(assertNames).toEqual(
expect.arrayContaining([
'AbaRoutingNumber',
Expand Down Expand Up @@ -43,6 +43,7 @@ describe('validator.js-asserts', () => {
'Iso3166Country',
'Json',
'NotEmpty',
'NullOr',
'NullOrBoolean',
'NullOrDate',
'NullOrString',
Expand Down

0 comments on commit c736b90

Please sign in to comment.