diff --git a/package.json b/package.json index 734b966..29ead9a 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "object" ], "dependencies": { - "@sindresorhus/is": "^0.2.0" + "@sindresorhus/is": "^0.3.0" }, "devDependencies": { "@types/node": "^8.0.31", diff --git a/source/lib/predicates/number.ts b/source/lib/predicates/number.ts new file mode 100644 index 0000000..b19ebc7 --- /dev/null +++ b/source/lib/predicates/number.ts @@ -0,0 +1,132 @@ +import * as is from '@sindresorhus/is'; +import { Predicate, Context } from './predicate'; + +export class NumberPredicate extends Predicate { + + constructor(context?: Context) { + super('number', context); + } + + /** + * Test a number to be in a specified range. + * + * @param start Start of the range. + * @param end End of the range. + */ + inRange(start: number, end: number) { + return this.addValidator({ + message: value => `Expected ${value} to be in range [${start}..${end}]`, + validator: value => is.inRange(value, [start, end]) + }); + } + + /** + * Test a number to be greater than the provided value. + * + * @param x Minimum value. + */ + greaterThan(x: number) { + return this.addValidator({ + message: value => `Expected ${value} to be greater than ${x}`, + validator: value => value > x + }); + } + + /** + * Test a number to be greater than or equal to the provided value. + * + * @param x Minimum value. + */ + greaterThanOrEqual(x: number) { + return this.addValidator({ + message: value => `Expected ${value} to be greater than or equal to ${x}`, + validator: value => value >= x + }); + } + + /** + * Test a number to be less than the provided value. + * + * @param x Maximum value. + */ + lessThan(x: number) { + return this.addValidator({ + message: value => `Expected ${value} to be less than ${x}`, + validator: value => value < x + }); + } + + /** + * Test a number to be less than or equal to the provided value. + * + * @param x Minimum value. + */ + lessThanOrEqual(x: number) { + return this.addValidator({ + message: value => `Expected ${value} to be less than or equal to ${x}`, + validator: value => value <= x + }); + } + + /** + * Test a number to be equal to a specified number. + * + * @param expected Expected value to match. + */ + equal(expected: number) { + return this.addValidator({ + message: value => `Expected ${value} to be equal to ${expected}`, + validator: value => value === expected + }); + } + + /** + * Test a number to be an integer. + */ + get integer() { + return this.addValidator({ + message: value => `Expected ${value} to be an integer`, + validator: value => is.integer(value) + }); + } + + /** + * Test a number to be finite. + */ + get finite() { + return this.addValidator({ + message: value => `Expected ${value} to be finite`, + validator: value => !is.infinite(value) + }); + } + + /** + * Test a number to be infinite. + */ + get infinite() { + return this.addValidator({ + message: value => `Expected ${value} to be infinite`, + validator: value => is.infinite(value) + }); + } + + /** + * Test a number to be positive. + */ + get positive() { + return this.addValidator({ + message: value => `Expected ${value} to be positive`, + validator: value => value > 0 + }); + } + + /** + * Test a number to be negative. + */ + get negative() { + return this.addValidator({ + message: value => `Expected ${value} to be negative`, + validator: value => value < 0 + }); + } +} diff --git a/source/ow.ts b/source/ow.ts index ae44740..20d1215 100644 --- a/source/ow.ts +++ b/source/ow.ts @@ -1,6 +1,7 @@ import { ArgumentError } from './lib/argument-error'; import { Predicate, validatorSymbol } from './lib/predicates/predicate'; import { StringPredicate } from './lib/predicates/string'; +import { NumberPredicate } from './lib/predicates/number'; export interface Ow { (value: any, predicate: Predicate): void; @@ -8,6 +9,10 @@ export interface Ow { * Test the value to be a string. */ string: StringPredicate; + /** + * Test the value to be a number. + */ + number: NumberPredicate; } const main = (value: any, predicate: Predicate) => { @@ -22,6 +27,9 @@ const main = (value: any, predicate: Predicate) => { Object.defineProperties(main, { string: { get: () => new StringPredicate() + }, + number: { + get: () => new NumberPredicate() } }); diff --git a/source/test/number.ts b/source/test/number.ts new file mode 100644 index 0000000..7f5f90f --- /dev/null +++ b/source/test/number.ts @@ -0,0 +1,75 @@ +import test from 'ava'; +import * as m from '..'; + +test('number', t => { + t.notThrows(() => m(1, m.number)); + t.throws(() => m('12', m.number), 'Expected argument to be of type `number` but received type `string`'); +}); + +test('number.inRange', t => { + t.notThrows(() => m(10, m.number.inRange(0, 20))); + t.notThrows(() => m(10, m.number.inRange(10, 20))); + t.notThrows(() => m(10, m.number.inRange(0, 10))); + t.throws(() => m(10, m.number.inRange(0, 9)), 'Expected 10 to be in range [0..9]'); + t.throws(() => m(10, m.number.inRange(11, 20)), 'Expected 10 to be in range [11..20]'); +}); + +test('number.greaterThan', t => { + t.notThrows(() => m(10, m.number.greaterThan(5))); + t.notThrows(() => m(10, m.number.greaterThan(9))); + t.throws(() => m(10, m.number.greaterThan(10)), 'Expected 10 to be greater than 10'); + t.throws(() => m(10, m.number.greaterThan(11)), 'Expected 10 to be greater than 11'); + t.throws(() => m(10, m.number.greaterThan(20)), 'Expected 10 to be greater than 20'); +}); + +test('number.greaterThanOrEqual', t => { + t.notThrows(() => m(10, m.number.greaterThanOrEqual(5))); + t.notThrows(() => m(10, m.number.greaterThanOrEqual(10))); + t.throws(() => m(10, m.number.greaterThanOrEqual(11)), 'Expected 10 to be greater than or equal to 11'); + t.throws(() => m(10, m.number.greaterThanOrEqual(20)), 'Expected 10 to be greater than or equal to 20'); +}); + +test('number.lessThan', t => { + t.notThrows(() => m(10, m.number.lessThan(20))); + t.notThrows(() => m(10, m.number.lessThan(11))); + t.throws(() => m(10, m.number.lessThan(10)), 'Expected 10 to be less than 10'); + t.throws(() => m(10, m.number.lessThan(9)), 'Expected 10 to be less than 9'); + t.throws(() => m(10, m.number.lessThan(0)), 'Expected 10 to be less than 0'); +}); + +test('number.lessThanOrEqual', t => { + t.notThrows(() => m(10, m.number.lessThanOrEqual(20))); + t.notThrows(() => m(10, m.number.lessThanOrEqual(10))); + t.throws(() => m(10, m.number.lessThanOrEqual(9)), 'Expected 10 to be less than or equal to 9'); + t.throws(() => m(10, m.number.lessThanOrEqual(0)), 'Expected 10 to be less than or equal to 0'); +}); + +test('number.equal', t => { + t.notThrows(() => m(10, m.number.equal(10))); + t.throws(() => m(10, m.number.equal(5)), 'Expected 10 to be equal to 5'); +}); + +test('number.integer', t => { + t.notThrows(() => m(10, m.number.integer)); + t.throws(() => m(10.1, m.number.integer), 'Expected 10.1 to be an integer'); +}); + +test('number.finite', t => { + t.notThrows(() => m(10, m.number.finite)); + t.throws(() => m(Infinity, m.number.finite), 'Expected Infinity to be finite'); +}); + +test('number.infinite', t => { + t.notThrows(() => m(Infinity, m.number.infinite)); + t.throws(() => m(10, m.number.infinite), 'Expected 10 to be infinite'); +}); + +test('number.positive', t => { + t.notThrows(() => m(1, m.number.positive)); + t.throws(() => m(-1, m.number.positive), 'Expected -1 to be positive'); +}); + +test('number.negative', t => { + t.notThrows(() => m(-1, m.number.negative)); + t.throws(() => m(1, m.number.negative), 'Expected 1 to be negative'); +});