Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
Add commands for v1.1 (#12)
Browse files Browse the repository at this point in the history
* Add instanceof
* Add equality functions
* Add inequality operators
  • Loading branch information
esdmr authored Sep 5, 2021
1 parent 579a253 commit fac1734
Show file tree
Hide file tree
Showing 12 changed files with 434 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-dogs-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@esdmr/assert": minor
---

Add equality operators: `isEqual`, `isNotEqual`.
5 changes: 5 additions & 0 deletions .changeset/chatty-peas-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@esdmr/assert": minor
---

Add inequality operators: `isGreater`, `isGreaterOrEqual`, `isLess`, `isLessOrEqual`.
5 changes: 5 additions & 0 deletions .changeset/long-pens-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@esdmr/assert": minor
---

New function `isInstanceOf`.
21 changes: 21 additions & 0 deletions examples/v1.1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as assert from '@esdmr/assert';

export function parseConfig (json: unknown) {
try {
assert.isObject(json);
assert.isNotNull(json);
assert.isBoolean(json.private, 'property "private"');
assert.isEqual(json.private, false, 'property "private"');
assert.isNumber(json.major, 'property "major"');
assert.isGreater(json.major, 0, 'property "major"');
assert.isNumber(json.minor, 'property "minor"');
assert.isGreaterOrEqual(json.minor, 0, 'property "minor"');
} catch (error) {
throw assert.wrap(error, 'Failed to parse config');
}

return {
major: json.major,
minor: json.minor,
};
}
54 changes: 50 additions & 4 deletions src/assert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AssertionError, WrappedError } from './errors.js';
import { DEFAULT_MESSAGE } from './messages.js';
import { format } from './utils.js';
import * as messages from './messages.js';
import { addDetail, format } from './utils.js';

/**
* Asserts that a given condition is true.
Expand All @@ -12,7 +12,7 @@ import { format } from './utils.js';
*/
export function assert (
condition: boolean,
message = DEFAULT_MESSAGE,
message = messages.DEFAULT_MESSAGE,
...args: unknown[]
): asserts condition {
if (!condition) {
Expand All @@ -30,8 +30,54 @@ export function assert (
*/
export function wrap (
thrownValue: unknown,
message = DEFAULT_MESSAGE,
message = messages.DEFAULT_MESSAGE,
...args: unknown[]
) {
return new WrappedError(format(message, ...args), thrownValue);
}

/**
* Asserts that the given value is strictly equal to the given expected value.
*
* @param value - Value to assert.
* @param expectedValue
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isEqual<T> (
value: T,
expectedValue: T,
detail?: string,
...args: unknown[]
) {
if (value !== expectedValue) {
throw new AssertionError(format(
addDetail(messages.NOT_EQUAL, detail),
expectedValue,
...args,
));
}
}

/**
* Asserts that the given value is not strictly equal to the given (un)expected value.
*
* @param value - Value to assert.
* @param expectedValue
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isNotEqual<T> (
value: T,
expectedValue: T,
detail?: string,
...args: unknown[]
) {
if (value === expectedValue) {
throw new AssertionError(format(
addDetail(messages.IS_EQUAL, detail),
expectedValue,
...args,
));
}
}
7 changes: 7 additions & 0 deletions src/messages.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
export const DEFAULT_MESSAGE = 'Assertion failed';
export const IS_EQUAL = 'Value is equal to {}';
export const IS_NAN = 'Value is NaN';
export const IS_NULL = 'Value is null';
export const IS_NULLABLE = 'Value is nullable';
export const IS_UNDEFINED = 'Value is undefined';
export const NOT_BIGINT = 'Value is not a big integer';
export const NOT_BOOLEAN = 'Value is not a boolean';
export const NOT_EQUAL = 'Value is not equal to {}';
export const NOT_FINITE = 'Value is not finite';
export const NOT_FUNCTION = 'Value is not a function';
export const NOT_GREATER = 'Value is not greater than {}';
export const NOT_GREATER_OR_EQUAL = 'Value is not greater than or equal to {}';
export const NOT_INSTANCE_OF = 'Value is not an instance of {}';
export const NOT_INTEGER = 'Value is not an integer';
export const NOT_LESS = 'Value is not less than {}';
export const NOT_LESS_OR_EQUAL = 'Value is not less than or equal to {}';
export const NOT_NUMBER = 'Value is not a number';
export const NOT_OBJECT = 'Value is not an object';
export const NOT_POSITIVE = 'Value is not positive';
Expand Down
94 changes: 94 additions & 0 deletions src/numbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,97 @@ export function isSafeInteger (value: number, detail?: string, ...args: unknown[
));
}
}

/**
* Asserts that the given value is greater than the given minimum value.
*
* @param value - Value to assert.
* @param minimum
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isGreater (
value: number,
minimum: number,
detail?: string,
...args: unknown[]
) {
if (value <= minimum) {
throw new RangeError(format(
addDetail(messages.NOT_GREATER, detail),
minimum,
...args,
));
}
}

/**
* Asserts that the given value is greater than or equal to the given minimum
* value.
*
* @param value - Value to assert.
* @param minimum
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isGreaterOrEqual (
value: number,
minimum: number,
detail?: string,
...args: unknown[]
) {
if (value < minimum) {
throw new RangeError(format(
addDetail(messages.NOT_GREATER_OR_EQUAL, detail),
minimum,
...args,
));
}
}

/**
* Asserts that the given value is less than the given maximum value.
*
* @param value - Value to assert.
* @param maximum
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isLess (
value: number,
maximum: number,
detail?: string,
...args: unknown[]
) {
if (value >= maximum) {
throw new RangeError(format(
addDetail(messages.NOT_LESS, detail),
maximum,
...args,
));
}
}

/**
* Asserts that the given value is less than or equal to the given maximum
* value.
*
* @param value - Value to assert.
* @param maximum
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isLessOrEqual (
value: number,
maximum: number,
detail?: string,
...args: unknown[]
) {
if (value > maximum) {
throw new RangeError(format(
addDetail(messages.NOT_LESS_OR_EQUAL, detail),
maximum,
...args,
));
}
}
29 changes: 29 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export type FunctionLike =
/** @public */
export type ObjectLike = Record<string, unknown>;

/** @public */
export type TypedConstructor<T> =
| (new (...args: unknown[]) => T)
| (abstract new (...args: unknown[]) => T);

/**
* Asserts that the given value is a big integer.
*
Expand Down Expand Up @@ -73,6 +78,30 @@ export function isFunction (
}
}

/**
* Asserts that the given value is an instance of a constructor.
*
* @public
* @param value - Value to assert.
* @param Constructor - The constructor to check value with.
* @param detail - Extra description.
* @param args - Format arguments.
*/
export function isInstanceOf<T> (
value: unknown,
Constructor: TypedConstructor<T>,
detail?: string,
...args: unknown[]
): asserts value is T {
if (!(value instanceof Constructor)) {
throw new TypeError(format(
addDetail(messages.NOT_INSTANCE_OF, detail),
Constructor.name,
...args,
));
}
}

/**
* Asserts that the given value is a number.
*
Expand Down
76 changes: 67 additions & 9 deletions test/assert.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,93 @@
import { test } from 'tap';
import { testFormat } from './test-util/format.js';
import { assert, wrap } from '#src/assert.js';
import { testDetail, testFormat } from '#test/test-util/format.js';
import * as assert from '#src/assert.js';
import { AssertionError, WrappedError } from '#src/errors.js';
import { DEFAULT_MESSAGE } from '#src/messages.js';
import * as messages from '#src/messages.js';
import { format } from '#src/utils.js';

await test('assert', async (t) => {
t.doesNotThrow(
() => {
assert(true, 'This should not throw');
assert.assert(true, 'This should not throw');
},
'expected to not throw if condition is true',
);

t.throws(
() => {
assert(false);
assert.assert(false);
},
new AssertionError(DEFAULT_MESSAGE),
new AssertionError(messages.DEFAULT_MESSAGE),
'expected to throw the default message if condition is false',
);

await testFormat(t, (...args) => {
assert(false, ...args);
assert.assert(false, ...args);
}, (message: string) => new AssertionError(message));
});

await test('wrap', async (t) => {
t.strictSame(wrap('value'), wrap('value', DEFAULT_MESSAGE),
t.strictSame(assert.wrap('value'), assert.wrap('value', messages.DEFAULT_MESSAGE),
'expected to use the default message if not given one');

await testFormat(t, (...args) => {
throw wrap('value', ...args);
throw assert.wrap('value', ...args);
}, (message: string) => new WrappedError(message, 'value'));
});

await test('isEqual', async (t) => {
t.doesNotThrow(
() => {
assert.isEqual(0, 0);
},
'expected not to throw for equal values',
);

t.throws(
() => {
assert.isEqual(true, false);
},
new AssertionError(format(messages.NOT_EQUAL, false)),
'expected to throw for not equal values',
);

t.throws(
() => {
assert.isEqual<number | boolean>(0, false);
},
new AssertionError(format(messages.NOT_EQUAL, false)),
'expected to throw for not equal types with same value',
);

await testDetail(t, (...args) => {
assert.isEqual(true, false, ...args);
}, (message: string) => new AssertionError(message), format(messages.NOT_EQUAL, false));
});

await test('isNotEqual', async (t) => {
t.throws(
() => {
assert.isNotEqual(0, 0);
},
new AssertionError(format(messages.IS_EQUAL, 0)),
'expected to throw for equal values',
);

t.doesNotThrow(
() => {
assert.isNotEqual(true, false);
},
'expected to not throw for not equal values',
);

t.doesNotThrow(
() => {
assert.isNotEqual<number | boolean>(0, false);
},
'expected to not throw for not equal types with same value',
);

await testDetail(t, (...args) => {
assert.isNotEqual(false, false, ...args);
}, (message: string) => new AssertionError(message), format(messages.IS_EQUAL, false));
});
2 changes: 1 addition & 1 deletion test/nullables.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test } from 'tap';
import { testDetail } from './test-util/format.js';
import { testDetail } from '#test/test-util/format.js';
import * as nullables from '#src/nullables.js';
import * as messages from '#src/messages.js';

Expand Down
Loading

0 comments on commit fac1734

Please sign in to comment.