-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Rewrite - type-appropriate assertions and better diffs. (#341)
BREAKING CHANGE: Many assertions are now only usable with types they make sense for. This should probably not break much code, but also probably will. Not entirely sure about the repercussions these changes will have. Some rarely used assertions have been removed (e.g. between). Some have been added: Support for Results, Maps, Sets and Errors. Recursions in asserted values are now recognized and in most cases even correctly compared (excluding maps and sets). Error messages are now much more informational and dare I say beautiful, since the new implementation is based on an in-depth diffing algorithm based on value equality.
- Loading branch information
Hannes Leutloff
authored
May 6, 2021
1 parent
5557f62
commit f6c430f
Showing
407 changed files
with
13,693 additions
and
6,074 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { CommonAssertions } from './CommonAssertions'; | ||
|
||
type AssertThatForAny = <TAny>(actual: TAny) => { | ||
is: CommonAssertions<TAny> & { | ||
not: CommonAssertions<TAny>; | ||
}; | ||
}; | ||
|
||
export type { | ||
AssertThatForAny | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Type } from '../../types/Type'; | ||
|
||
interface CommonAssertions<TAny> { | ||
equalTo: (expected: TAny) => void; | ||
identicalTo: (expected: TAny) => void; | ||
sameJsonAs: (expected: TAny) => void; | ||
|
||
falsy: () => void; | ||
truthy: () => void; | ||
|
||
null: () => void; | ||
undefined: () => void; | ||
true: () => void; | ||
false: () => void; | ||
|
||
ofType: (expected: Type) => void; | ||
} | ||
|
||
export type { | ||
CommonAssertions | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { compare } from '../../comparisons/typeAware/compare'; | ||
import { dispel } from '../../dispel/dispel'; | ||
import { isEqualDiff } from '../../diffs/EqualDiff'; | ||
import { prettyPrint } from '../../prettyPrint/typeAware/prettyPrint'; | ||
import { prettyPrintDiff } from '../../prettyPrint/typeAware/prettyPrintDiff'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsEqualToExpected = function ( | ||
actual: any, | ||
expected: any | ||
): Result<undefined, AssertionFailed> { | ||
const diff = compare(dispel(actual), dispel(expected)); | ||
|
||
if (isEqualDiff(diff)) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The values are not equal.', | ||
expected: prettyPrint(expected), | ||
actual: prettyPrint(actual), | ||
diff: prettyPrintDiff(diff) | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsEqualToExpected | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { compare } from '../../comparisons/typeAware/compare'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsFalse = function ( | ||
actual: any | ||
): Result<undefined, AssertionFailed> { | ||
const diff = compare(actual, false); | ||
|
||
if (diff.cost === 0) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The value is not false.' | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsFalse | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { prettyPrint } from '../../prettyPrint/typeAware/prettyPrint'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsFalsy = function ( | ||
actual: any | ||
): Result<undefined, AssertionFailed> { | ||
if (!actual) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The value is not falsy.', | ||
actual: prettyPrint(actual) | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsFalsy | ||
}; |
19 changes: 19 additions & 0 deletions
19
lib/assertions/forAny/assertActualIsIdenticalToExpected.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsIdenticalToExpected = function ( | ||
actual: any, | ||
expected: any | ||
): Result<undefined, AssertionFailed> { | ||
if (actual === expected) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The values are not identical.' | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsIdenticalToExpected | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { compare } from '../../comparisons/typeAware/compare'; | ||
import { dispel } from '../../dispel/dispel'; | ||
import { isEqualDiff } from '../../diffs/EqualDiff'; | ||
import { prettyPrint } from '../../prettyPrint/typeAware/prettyPrint'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotEqualToExpected = function ( | ||
actual: any, | ||
expected: any | ||
): Result<undefined, AssertionFailed> { | ||
const diff = compare(dispel(actual), dispel(expected)); | ||
|
||
if (!isEqualDiff(diff)) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The values are equal.', | ||
expected: `Not to equal:\n${prettyPrint(expected)}` | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsNotEqualToExpected | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { compare } from '../../comparisons/typeAware/compare'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotFalse = function ( | ||
actual: any | ||
): Result<undefined, AssertionFailed> { | ||
const diff = compare(actual, true); | ||
|
||
if (diff.cost === 0) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The value is false.' | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsNotFalse | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { prettyPrint } from '../../prettyPrint/typeAware/prettyPrint'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotFalsy = function ( | ||
actual: any | ||
): Result<undefined, AssertionFailed> { | ||
if (actual) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The value is falsy.', | ||
actual: prettyPrint(actual) | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsNotFalsy | ||
}; |
19 changes: 19 additions & 0 deletions
19
lib/assertions/forAny/assertActualIsNotIdenticalToExpected.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotIdenticalToExpected = function ( | ||
actual: any, | ||
expected: any | ||
): Result<undefined, AssertionFailed> { | ||
if (actual !== expected) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The values are identical.' | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsNotIdenticalToExpected | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { AssertionFailed } from '../../errors'; | ||
import { error, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotNull = function ( | ||
actual: any | ||
): Result<undefined, AssertionFailed> { | ||
if (actual !== null) { | ||
return value(); | ||
} | ||
|
||
return error(new AssertionFailed({ | ||
message: 'The value is null.' | ||
})); | ||
}; | ||
|
||
export { | ||
assertActualIsNotNull | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import { isArray } from '../../types/isArray'; | ||
import { isBoolean } from '../../types/isBoolean'; | ||
import { isFunction } from '../../types/isFunction'; | ||
import { isMap } from '../../types/isMap'; | ||
import { isNull } from '../../types/isNull'; | ||
import { isNumber } from '../../types/isNumber'; | ||
import { isObject } from '../../types/isObject'; | ||
import { isSet } from '../../types/isSet'; | ||
import { isString } from '../../types/isString'; | ||
import { isSymbol } from '../../types/isSymbol'; | ||
import { isUndefined } from '../../types/isUndefined'; | ||
import { prettyPrint } from '../../prettyPrint/typeAware/prettyPrint'; | ||
import { Type } from '../../types/Type'; | ||
import { AssertionFailed, InvalidOperation } from '../../errors'; | ||
import { error, isError, isResult, Result, value } from 'defekt'; | ||
|
||
const assertActualIsNotOfType = function ( | ||
actual: any, | ||
expected: Type | ||
): Result<undefined, AssertionFailed> { | ||
switch (expected) { | ||
case 'array': { | ||
if (isArray(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type array.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'boolean': { | ||
if (isBoolean(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type boolean.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'error': { | ||
if (isError(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type error.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'function': { | ||
if (isFunction(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type function.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'map': { | ||
if (isMap(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type map.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'null': { | ||
if (isNull(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type null.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'number': { | ||
if (isNumber(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type number.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'result': { | ||
if (isResult(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type result.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'set': { | ||
if (isSet(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type set.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'string': { | ||
if (isString(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type string.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'symbol': { | ||
if (isSymbol(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type symbol.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'undefined': { | ||
if (isUndefined(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type undefined.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
case 'object': { | ||
if (isObject(actual)) { | ||
return error(new AssertionFailed({ | ||
message: 'The value is of type object.', | ||
actual: prettyPrint(actual) | ||
})); | ||
} | ||
break; | ||
} | ||
default: { | ||
throw new InvalidOperation(); | ||
} | ||
} | ||
|
||
return value(); | ||
}; | ||
|
||
export { | ||
assertActualIsNotOfType | ||
}; |
Oops, something went wrong.