UNPKG

@assertive-ts/core

Version:

A type-safe fluent assertion library

517 lines (473 loc) 13.7 kB
import { Assertion } from "./Assertion"; import { isHighInclusiveOptions, isInclusiveOptions, isLowInclusiveOptions } from "./helpers/guards"; import { AssertionError } from "assert"; export interface BaseBetweenOptions { range: [number, number]; } export interface CloseToOptions { value: number; withOffset: number; } export interface InclusiveBetweenOptions extends BaseBetweenOptions { inclusive: boolean; } export interface LowInclusiveBetweenOptions extends BaseBetweenOptions { lowInclusive: boolean; } export interface HighInclusiveBetweenOptions extends BaseBetweenOptions { highInclusive: boolean; } export type BetweenOptions = | BaseBetweenOptions | InclusiveBetweenOptions | LowInclusiveBetweenOptions | HighInclusiveBetweenOptions; /** * Encapsulates assertion methods applicable to values of type number */ export class NumberAssertion extends Assertion<number> { public constructor(actual: number) { super(actual); } /** * Check if the number is zero. * * @example * ``` * expect(0).toBeZero(); * ``` * * @returns the assertion instance */ public toBeZero(): this { const error = new AssertionError({ actual: this.actual, expected: 0, message: `Expected <${this.actual}> to be zero`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be zero", }); return this.execute({ assertWhen: this.actual === 0, error, invertedError, }); } /** * Check if the number is positive. That is, when the number is greater than * zero. * * @example * ``` * expect(10).toBePositive(); * ``` * * @returns the assertion instance */ public toBePositive(): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be positive`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be positive", }); return this.execute({ assertWhen: this.actual > 0, error, invertedError, }); } /** * Check if the number is negative. That is, when the number is less than * zero. * * @example * ``` * expect(-10).toBeNegative(); * ``` * * @returns the assertion instance */ public toBeNegative(): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be negative`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be negative", }); return this.execute({ assertWhen: this.actual < 0, error, invertedError, }); } /** * Check if the number is finite. That is, when the number is not a * JavaScript's `Infinity` value. Keep in mind that this includes * positive and negative infinity. * * @example * ``` * expect(0).toBeFinite(); * expect(-10).toBeFinite(); * expect(10).toBeFinite(); * ``` * * @returns the assertion instance */ public toBeFinite(): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be finite`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be finite", }); return this.execute({ assertWhen: isFinite(this.actual), error, invertedError, }); } /** * Check if the number is `NaN`. That is only when the number is JavaScript's * `NaN` value. * * @example * ``` * expect(NaN).toBeNaN(); * expect(0/0).toBeNaN(); * ``` * * @returns the assertion instance */ public toBeNaN(): this { const error = new AssertionError({ actual: this.actual, expected: NaN, message: `Expected <${this.actual}> to be NaN`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be NaN", }); return this.execute({ assertWhen: isNaN(this.actual), error, invertedError, }); } /** * Check if the number is even. That is, when the number is divisible by 2. * * @example * ``` * expect(50).toBeEven(); * expect(0).toBeEven(); * expect(-10).toBeEven(); * ``` * * @returns the assertion instance */ public toBeEven(): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be even`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be even", }); return this.execute({ assertWhen: this.actual % 2 === 0, error, invertedError, }); } /** * Check if the number is odd. That is, when the number is not divisible by 2. * * @example * ``` * expect(-13).toBeOdd(); * expect(17).toBeOdd(); * ``` * * @returns the assertion instance */ public toBeOdd(): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be odd`, }); const invertedError = new AssertionError({ actual: this.actual, message: "Expected the value NOT to be odd", }); return this.execute({ assertWhen: this.actual % 2 === 1, error, invertedError, }); } /** * Check if the number is between the specified bounds. By default, the * bounds are exclusive, but the options allow to set the high, low, or both * limits as inclusive * * @example * ``` * expect(0).toBeBetween({ * range: [-1, 1], * }); * * expect(-1).toBeBetween({ * range: [-1, 1], * lowInclusive: true, * }); * * expect(1).toBeBetween({ * range: [-1, 1], * highInclusive: true, * }); * * expect(0).toBeBetween({ * range: [0, 0], * inclusive: true, * }); * ``` * * @param options an object of type {@link BetweenOptions} where the `range` * property defines the bounds, so it's always required. Use * `inclusive: true` to make both limits inclusive. Or you can * selectively make low or high limits inclusive using * `lowInclusive: true` or `highInclusive: true`, respectively * @returns the assertion instance */ public toBeBetween(options: BetweenOptions): this { const [min, max] = options.range; if (isInclusiveOptions(options)) { const rangeText = options.inclusive ? `[${min}, ${max}]` : `(${min}, ${max})`; const inclusiveError = new AssertionError({ actual: this.actual, expected: options, message: `Expected <${this.actual}> to be between ${rangeText} range` }); const inclusiveInvertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be between ${rangeText} range` }); return this.execute({ assertWhen: options.inclusive ? this.actual >= min && this.actual <= max : this.actual > min && this.actual < max, error: inclusiveError, invertedError: inclusiveInvertedError, }); } if (isLowInclusiveOptions(options)) { const rangeText = options.lowInclusive ? `[${min}, ${max})` : `(${min}, ${max})`; const lowInclusiveError = new AssertionError({ actual: this.actual, expected: options, message: `Expected <${this.actual}> to be between ${rangeText} range`, }); const lowInclusiveErrorInvertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be between ${rangeText} range`, }); return this.execute({ assertWhen: options.lowInclusive ? this.actual >= min && this.actual < max : this.actual > min && this.actual < max, error: lowInclusiveError, invertedError: lowInclusiveErrorInvertedError, }); } if (isHighInclusiveOptions(options)) { const rangeText = options.highInclusive ? `(${min}, ${max}]` : `(${min}, ${max})`; const highInclusiveError = new AssertionError({ actual: this.actual, expected: options, message: `Expected <${this.actual}> to be between ${rangeText} range`, }); const highInclusiveErrorInvertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be between ${rangeText} range`, }); return this.execute({ assertWhen: options.highInclusive ? this.actual > min && this.actual <= max : this.actual > min && this.actual < max, error: highInclusiveError, invertedError: highInclusiveErrorInvertedError, }); } const error = new AssertionError({ actual: this.actual, expected: options, message: `Expected <${this.actual}> to be between (${min}, ${max}) range`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be between (${min}, ${max}) range`, }); return this.execute({ assertWhen: this.actual > min && this.actual < max, error, invertedError, }); } /** * Check if the number value is close to the base value with certain offset. * This checks both limits min and max which are inclusive. * * @example * ``` * expect(-1).toBeCloseTo({ * value: 0, * withOffset: 1, * }); * * expect(1).toBeCloseTo({ * value: 0, * withOffset: 1, * }); * ``` * * @param options the object that contains the value (base number that value * should be close) and withOffset (min and max offset value) * * @returns the assertion instance */ public toBeCloseTo(options: CloseToOptions): this { const error = new AssertionError({ actual: this.actual, expected: options, message: `Expected <${this.actual}> to be close to <${options.value}> with offset <${options.withOffset}>`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be close to <${options.value}> with offset <${options.withOffset}>`, }); const { value, withOffset } = options; return this.execute({ assertWhen: this.actual <= value + withOffset && this.actual >= value - withOffset, error, invertedError, }); } /** * Check if the number value is greater than the defined value. * * @example * ``` * expect(5).toBeGreaterThan(3); * ``` * * @param value the value that number should be greater than * @returns the assertion instance */ public toBeGreaterThan(value: number): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be greater than <${value}>`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be greater than <${value}>`, }); return this.execute({ assertWhen: this.actual > value, error, invertedError, }); } /** * Check if the number value is greater than or equal to the defined value. * * @example * ``` * expect(5).toBeGreaterThanOrEqual(3); * expect(3).toBeGreaterThanOrEqual(3); * ``` * * @param value the value that number should be greater than or equal to * @returns the assertion instance */ public toBeGreaterThanOrEqual(value: number): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be greater than or equal to <${value}>`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be greater than or equal to <${value}>`, }); return this.execute({ assertWhen: this.actual >= value, error, invertedError, }); } /** * Check if the number value is less than the defined value. * * @example * ``` * expect(2).toBeLessThan(5); * ``` * * @example * @param value the value that number should be less than * @returns the assertion instance */ public toBeLessThan(value: number): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be less than <${value}>`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be less than <${value}>`, }); return this.execute({ assertWhen: this.actual < value, error, invertedError, }); } /** * Check if the number value is less than or equal to the defined value. * * @example * ``` * expect(2).toBeLessThanOrEqual(5); * expect(5).toBeLessThanOrEqual(5); * ``` * * @param value the value that number should be less than or equal to * @returns the assertion instance */ public toBeLessThanOrEqual(value: number): this { const error = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> to be less than or equal to <${value}>`, }); const invertedError = new AssertionError({ actual: this.actual, message: `Expected <${this.actual}> NOT to be less than or equal to <${value}>`, }); return this.execute({ assertWhen: this.actual <= value, error, invertedError, }); } }