From ddf9ab1a3b0d0183ff03ce55c22543b57c7e6284 Mon Sep 17 00:00:00 2001 From: Joao Madeiras Date: Sun, 10 Apr 2016 22:25:14 +0100 Subject: [PATCH 1/4] Add support for numeric timestamps on `DateAssert` --- src/asserts/date-assert.js | 10 +++++++++- test/asserts/date-assert_test.js | 31 +++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/asserts/date-assert.js b/src/asserts/date-assert.js index 97743ee..de1e1cc 100644 --- a/src/asserts/date-assert.js +++ b/src/asserts/date-assert.js @@ -46,8 +46,16 @@ export default function dateAssert({ format } = {}) { */ this.validate = value => { + if (typeof value === 'number') { + if (new Date(value).toString() === 'Invalid Date') { + throw new Violation(this, value); + } + + return true; + } + if (typeof value !== 'string' && Object.prototype.toString.call(value) !== '[object Date]') { - throw new Violation(this, value, { value: 'must_be_a_date_or_a_string' }); + throw new Violation(this, value, { value: 'must_be_a_date_or_a_string_or_a_number' }); } if (isNaN(Date.parse(value)) === true) { diff --git a/test/asserts/date-assert_test.js b/test/asserts/date-assert_test.js index 0ee7086..bf27555 100644 --- a/test/asserts/date-assert_test.js +++ b/test/asserts/date-assert_test.js @@ -20,8 +20,8 @@ const Assert = BaseAssert.extend({ */ describe('DateAssert', () => { - it('should throw an error if the input value is not a string or a date', () => { - const choices = [[], {}, 123]; + it('should throw an error if the input value is not a date or a string or a number', () => { + const choices = [[], {}]; choices.forEach(choice => { try { @@ -30,7 +30,7 @@ describe('DateAssert', () => { should.fail(); } catch (e) { e.should.be.instanceOf(Violation); - e.violation.value.should.equal('must_be_a_date_or_a_string'); + e.violation.value.should.equal('must_be_a_date_or_a_string_or_a_number'); } }); }); @@ -61,6 +61,17 @@ describe('DateAssert', () => { } }); + it('should throw an error if the input value is an invalid timestamp', () => { + try { + new Assert().Date().validate(-Number.MAX_VALUE); + + should.fail(); + } catch (e) { + e.should.be.instanceOf(Violation); + e.show().assert.should.equal('Date'); + } + }); + it('should throw an error if value does not pass strict validation', () => { try { new Assert().Date({ format: 'YYYY-MM-DD' }).validate('2000.12.30'); @@ -82,7 +93,7 @@ describe('DateAssert', () => { } }); - it('should accept a `Date`', () => { + it('should accept an instance of `Date`', () => { new Assert().Date().validate(new Date()); }); @@ -90,7 +101,15 @@ describe('DateAssert', () => { new Assert().Date({ format: 'YYYY-MM-DD' }).validate('2000-12-30'); }); - it('should accept a `string`', () => { - new Assert().Date().validate('2014-10-16'); + it('should accept a string date', () => { + new Assert().Date().validate('2016-04-23'); + }); + + it('should accept an ISO-8601 string date', () => { + new Assert().Date().validate('2016-04-23T00:51:18.570Z'); + }); + + it('should accept a numeric timestamp', () => { + new Assert().Date().validate(Date.now()); }); }); From 111755853aa7adc28cad4735ce1d6fb44d90974c Mon Sep 17 00:00:00 2001 From: Joao Madeiras Date: Wed, 27 Apr 2016 15:48:47 +0100 Subject: [PATCH 2/4] Add support for numeric timestamps on `NullOrDateAssert` --- README.md | 5 ++- src/asserts/null-or-date-assert.js | 27 +++++++++++----- test/asserts/null-or-date-assert_test.js | 40 ++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b10776d..888c6fa 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ The following set of extra asserts are provided by this package: - [Iso3166Country](#iso3166country) (requires `isoc`) - [Json](#json) - [NotEmpty](#notempty) -- [NullOrDate](#nullordate) +- [NullOrDate](#nullordate) (requires `moment` for format validation only) - [NullOrString](#nullorstring) - [Phone](#phone) (requires `google-libphonenumber`) - [PlainObject](#plainobject) @@ -152,6 +152,9 @@ Tests if the value is valid json. ### NotEmpty Tests if the value is not an empty (empty object, empty array, empty string, etc). +### NullOrDate +Tests if the value is a `null` or `date`. + ### NullOrString Tests if the value is a `null` or `string`, optionally within some boundaries. diff --git a/src/asserts/null-or-date-assert.js b/src/asserts/null-or-date-assert.js index 43db5ec..b9bf819 100644 --- a/src/asserts/null-or-date-assert.js +++ b/src/asserts/null-or-date-assert.js @@ -3,34 +3,45 @@ * Module dependencies. */ -import { Violation } from 'validator.js'; +import DateAssert from './date-assert'; +import { Assert as BaseAssert, Violation } from 'validator.js'; + +/** + * Extend Assert with `DateAssert`. + */ + +const Assert = BaseAssert.extend({ Date: DateAssert }); /** * Export `NullOrDateAssert`. */ -export default function nullOrDateAssert() { +export default function nullOrDateAssert({ format } = {}) { /** * Class name. */ this.__class__ = 'NullOrDate'; + /** + * Format to match the input. + */ + + this.format = format; + /** * Validation algorithm. */ this.validate = value => { - if (typeof value !== 'string' && value !== null && Object.prototype.toString.call(value) !== '[object Date]') { - throw new Violation(this, value, { value: 'must_be_null_or_a_date' }); - } - if (value === null) { return true; } - if (isNaN(Date.parse(value)) === true) { - throw new Violation(this, value); + try { + new Assert().Date({ format }).validate(value); + } catch (e) { + throw new Violation(this, value, { value: 'must_be_null_or_a_date_or_a_number' }); } return true; diff --git a/test/asserts/null-or-date-assert_test.js b/test/asserts/null-or-date-assert_test.js index ea2780b..ae629ca 100644 --- a/test/asserts/null-or-date-assert_test.js +++ b/test/asserts/null-or-date-assert_test.js @@ -20,8 +20,8 @@ const Assert = BaseAssert.extend({ */ describe('NullOrDateAssert', () => { - it('should throw an error if the input value is not a `null` or a date', () => { - const choices = [[], {}, 123]; + it('should throw an error if the input value is not a `null` or a date or a number', () => { + const choices = [[], {}]; choices.forEach(choice => { try { @@ -30,7 +30,7 @@ describe('NullOrDateAssert', () => { should.fail(); } catch (e) { e.should.be.instanceOf(Violation); - e.violation.value.should.equal('must_be_null_or_a_date'); + e.violation.value.should.equal('must_be_null_or_a_date_or_a_number'); } }); }); @@ -46,6 +46,28 @@ describe('NullOrDateAssert', () => { } }); + it('should throw an error if the input value is an invalid timestamp', () => { + try { + new Assert().NullOrDate().validate(-Number.MAX_VALUE); + + should.fail(); + } catch (e) { + e.should.be.instanceOf(Violation); + e.show().assert.should.equal('NullOrDate'); + } + }); + + it('should throw an error if value does not pass strict validation', () => { + try { + new Assert().NullOrDate({ format: 'YYYY-MM-DD' }).validate('2000.12.30'); + + should.fail(); + } catch (e) { + e.should.be.instanceOf(Violation); + e.show().assert.should.equal('NullOrDate'); + } + }); + it('should expose `assert` equal to `NullOrDate`', () => { try { new Assert().NullOrDate().validate({}); @@ -64,7 +86,19 @@ describe('NullOrDateAssert', () => { new Assert().NullOrDate().validate(new Date()); }); + it('should accept a correctly formatted date', () => { + new Assert().NullOrDate({ format: 'YYYY' }).validate('2000'); + }); + it('should accept a string', () => { new Assert().NullOrDate().validate('2014-10-16'); }); + + it('should accept an ISO-8601 string date', () => { + new Assert().NullOrDate().validate('2016-04-23T00:51:18.570Z'); + }); + + it('should accept a numeric timestamp', () => { + new Assert().NullOrDate().validate(Date.now()); + }); }); From f0dfa719c3bdc2b5d206c6c19679a19d563f7bf4 Mon Sep 17 00:00:00 2001 From: Joao Madeiras Date: Wed, 27 Apr 2016 16:07:00 +0100 Subject: [PATCH 3/4] Add support for numeric timestamps on `DateDiffGreaterThan` --- src/asserts/date-diff-greater-than-assert.js | 19 ++++++++++------- .../date-diff-greater-than-assert_test.js | 21 ++++++++++++++++++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/asserts/date-diff-greater-than-assert.js b/src/asserts/date-diff-greater-than-assert.js index 2d3c0bd..51b251a 100644 --- a/src/asserts/date-diff-greater-than-assert.js +++ b/src/asserts/date-diff-greater-than-assert.js @@ -3,9 +3,16 @@ * Module dependencies. */ -import { Violation } from 'validator.js'; +import DateAssert from './date-assert'; +import { Assert as BaseAssert, Violation } from 'validator.js'; import { assign } from 'lodash'; +/** + * Extend Assert with `DateAssert`. + */ + +const Assert = BaseAssert.extend({ Date: DateAssert }); + /** * Export `DateDiffGreaterThanAssert`. */ @@ -53,12 +60,10 @@ export default function dateDiffGreaterThanAssert(threshold, options) { */ this.validate = value => { - if (typeof value !== 'string' && Object.prototype.toString.call(value) !== '[object Date]') { - throw new Violation(this, value, { value: 'must_be_a_date_or_a_string' }); - } - - if (isNaN(Date.parse(value)) === true) { - throw new Violation(this, value, { absolute: this.absolute, asFloat: this.asFloat, fromDate: this.fromDate, threshold: this.threshold, unit: this.unit }); + try { + new Assert().Date().validate(value); + } catch (e) { + throw new Violation(this, value, { value: 'must_be_a_date_or_a_string_or_a_number' }); } let diff = moment(this.fromDate || Date.now()).diff(value, this.unit, this.asFloat); diff --git a/test/asserts/date-diff-greater-than-assert_test.js b/test/asserts/date-diff-greater-than-assert_test.js index 67dff6a..172d825 100644 --- a/test/asserts/date-diff-greater-than-assert_test.js +++ b/test/asserts/date-diff-greater-than-assert_test.js @@ -65,7 +65,7 @@ describe('DateDiffGreaterThanAssert', () => { should.fail(); } catch (e) { e.should.be.instanceOf(Violation); - e.violation.value.should.equal('must_be_a_date_or_a_string'); + e.violation.value.should.equal('must_be_a_date_or_a_string_or_a_number'); } }); }); @@ -81,6 +81,17 @@ describe('DateDiffGreaterThanAssert', () => { } }); + it('should throw an error if the input value is an invalid timestamp', () => { + try { + new Assert().DateDiffGreaterThan(10).validate(-Number.MAX_VALUE); + + should.fail(); + } catch (e) { + e.should.be.instanceOf(Violation); + e.show().assert.should.equal('DateDiffGreaterThan'); + } + }); + it('should throw an error if the diff between `now` and input date is equal to `threshold`', () => { const clock = sinon.useFakeTimers(0, 'Date'); @@ -243,6 +254,14 @@ describe('DateDiffGreaterThanAssert', () => { clock.restore(); }); + it('should accept a timestamp whose diff from `now` is greater than the threshold', () => { + const clock = sinon.useFakeTimers(0, 'Date'); + + new Assert().DateDiffGreaterThan(0).validate(-1); + + clock.restore(); + }); + it('should accept a date whose diff from `fromDate` is greater than the threshold', () => { new Assert().DateDiffGreaterThan(24, { asFloat: false, fromDate: new Date('1970-01-01 00:00:00'), unit: 'hours' }).validate(new Date('1969-12-30 00:00:00')); }); From 7d7dfad54c857a2a2a54f97b4bf512a77c73904b Mon Sep 17 00:00:00 2001 From: Joao Madeiras Date: Wed, 27 Apr 2016 16:11:23 +0100 Subject: [PATCH 4/4] Add support for numeric timestamps on `DateDiffLessThanAssert` --- src/asserts/date-diff-less-than-assert.js | 19 ++++++++++------- .../date-diff-less-than-assert_test.js | 21 ++++++++++++++++++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/asserts/date-diff-less-than-assert.js b/src/asserts/date-diff-less-than-assert.js index 533c002..081acc6 100644 --- a/src/asserts/date-diff-less-than-assert.js +++ b/src/asserts/date-diff-less-than-assert.js @@ -3,9 +3,16 @@ * Module dependencies. */ -import { Violation } from 'validator.js'; +import DateAssert from './date-assert'; +import { Assert as BaseAssert, Violation } from 'validator.js'; import { assign } from 'lodash'; +/** + * Extend Assert with `DateAssert`. + */ + +const Assert = BaseAssert.extend({ Date: DateAssert }); + /** * Export `DateDiffLessThanAssert`. */ @@ -53,12 +60,10 @@ export default function dateDiffLessThanAssert(threshold, options) { */ this.validate = value => { - if (typeof value !== 'string' && Object.prototype.toString.call(value) !== '[object Date]') { - throw new Violation(this, value, { value: 'must_be_a_date_or_a_string' }); - } - - if (isNaN(Date.parse(value)) === true) { - throw new Violation(this, value, { absolute: this.absolute, asFloat: this.asFloat, fromDate: this.fromDate, threshold: this.threshold, unit: this.unit }); + try { + new Assert().Date().validate(value); + } catch (e) { + throw new Violation(this, value, { value: 'must_be_a_date_or_a_string_or_a_number' }); } let diff = moment(this.fromDate || Date.now()).diff(value, this.unit, this.asFloat); diff --git a/test/asserts/date-diff-less-than-assert_test.js b/test/asserts/date-diff-less-than-assert_test.js index aa44414..aa23837 100644 --- a/test/asserts/date-diff-less-than-assert_test.js +++ b/test/asserts/date-diff-less-than-assert_test.js @@ -65,7 +65,7 @@ describe('DateDiffLessThanAssert', () => { should.fail(); } catch (e) { e.should.be.instanceOf(Violation); - e.violation.value.should.equal('must_be_a_date_or_a_string'); + e.violation.value.should.equal('must_be_a_date_or_a_string_or_a_number'); } }); }); @@ -81,6 +81,17 @@ describe('DateDiffLessThanAssert', () => { } }); + it('should throw an error if the input value is an invalid timestamp', () => { + try { + new Assert().DateDiffLessThan(10).validate(-Number.MAX_VALUE); + + should.fail(); + } catch (e) { + e.should.be.instanceOf(Violation); + e.show().assert.should.equal('DateDiffLessThan'); + } + }); + it('should throw an error if the diff between `now` and input date is equal to `threshold`', () => { const clock = sinon.useFakeTimers(0, 'Date'); @@ -255,6 +266,14 @@ describe('DateDiffLessThanAssert', () => { clock.restore(); }); + it('should accept a timestamp whose diff from `now` is less than the threshold', () => { + const clock = sinon.useFakeTimers(0, 'Date'); + + new Assert().DateDiffLessThan(1).validate(0); + + clock.restore(); + }); + it('should accept a date whose diff from `fromDate` is less than the threshold', () => { new Assert().DateDiffLessThan(24, { asFloat: false, fromDate: new Date('1970-01-01 09:00:00'), unit: 'hours' }).validate(new Date('1970-01-01 00:00:00')); });