Skip to content

Commit a2fb82c

Browse files
authored
Add unit tests for Runtime and fix validateObject(#59)
1 parent de0f387 commit a2fb82c

13 files changed

+54
-13
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"build:atBabelCore": "rollup -c --environment target:atBabelCore",
1010
"build:dts": "tsc src-transpiler/index.mjs --outDir types/transpiler --allowJs --declaration --emitDeclarationOnly --target esnext",
1111
"build:types": "npm run build:dts && rollup -c --environment target:types",
12-
"test": "npm run test:update && node test.mjs",
12+
"test": "npm run test:update && node test.mjs && node test_runtime.mjs",
1313
"test:update": "node gen_tests.mjs > test/typechecking.json",
1414
"lint": "eslint --ext .js,.mjs,.cjs src-transpiler src-runtime",
1515
"docs": "echo todo docs using jsdoc"

src-runtime/assertType.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {validateType } from "./validateType.mjs";
88
* @param {string} loc - String like `BoundingBox#compute`
99
* @param {string} name - Name of the argument
1010
* @param {boolean} critical - Only `false` for unions.
11-
* @returns {boolean} - Boolean indicating if a type is correct.
11+
* @returns {boolean} Boolean indicating if a type is correct.
1212
*/
1313
export function assertType(value, expect, loc, name, critical = true) {
1414
if (!expect) {

src-runtime/validateArray.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {typecheckEvery} from "./typecheckEvery.mjs";
66
* @param {string} loc - String like `BoundingBox#compute`
77
* @param {string} name - Name of the argument
88
* @param {boolean} critical - Only `false` for unions.
9-
* @returns {boolean} - Boolean indicating if a type is correct.
9+
* @returns {boolean} Boolean indicating if a type is correct.
1010
*/
1111
function validateArray(value, expect, loc, name, critical) {
1212
if (value && value instanceof Array) {

src-runtime/validateMap.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {typecheckWarn} from "./typecheckWarn.mjs";
77
* @param {string} loc - String like `BoundingBox#compute`
88
* @param {string} name - Name of the argument
99
* @param {boolean} critical - Only `false` for unions.
10-
* @returns {boolean} - Boolean indicating if a type is correct.
10+
* @returns {boolean} Boolean indicating if a type is correct.
1111
*/
1212
function validateMap(value, expect, loc, name, critical) {
1313
const {key, val} = expect;

src-runtime/validateObject.mjs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
import {assertType } from "./assertType.mjs";
22
import {typecheckOptions} from "./typecheckOptions.mjs";
33
import {typecheckWarn } from "./typecheckWarn.mjs";
4+
/**
5+
* Did you ever heard of Anakandavada, the doctrine of manifoldness of reality?
6+
* 1) Check: typeof value === 'object'
7+
* 2) Check: value instanceof Object
8+
* 3) Check (1) *and* (2)
9+
* 4) neither
10+
* You may ponder to either use (1) or (2), but only (3) is right, because:
11+
* 1) Fails for functions, every function is also an object: Math.sqrt.test = "Hai"
12+
* 2) Fails for prototype-less objects: Object.create(null) instanceof Object === false.
13+
* @param {*} value - The actual value that we need to validate.
14+
* @returns {boolean} Boolean indicating if value is an object.
15+
*/
16+
function isObject(value) {
17+
return value instanceof Object || typeof value === 'object';
18+
}
419
/**
520
* @param {*} value - The actual value that we need to validate.
621
* @param {*} properties - The properties.
722
* @param {string} loc - String like `BoundingBox#compute`
823
* @param {string} name - Name of the argument
924
* @param {boolean} critical - Only `false` for unions.
10-
* @returns {boolean} - Boolean indicating if a type is correct.
25+
* @returns {boolean} Boolean indicating if a type is correct.
1126
*/
1227
function validateObject(value, properties, loc, name, critical) {
13-
if (!(value instanceof Object)) {
28+
if (!isObject(value)) {
1429
return false;
1530
}
1631
if (properties && Object.keys(properties).length) {
@@ -38,6 +53,6 @@ function validateObject(value, properties, loc, name, critical) {
3853
);
3954
});
4055
}
41-
return value instanceof Object;
56+
return true;
4257
}
4358
export {validateObject};

src-runtime/validateRecord.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {typecheckWarn} from "./typecheckWarn.mjs";
66
* @param {string} loc - String like `BoundingBox#compute`
77
* @param {string} name - Name of the argument
88
* @param {boolean} critical - Only `false` for unions.
9-
* @returns {boolean} - Boolean indicating if a type is correct.
9+
* @returns {boolean} Boolean indicating if a type is correct.
1010
*/
1111
function validateRecord(value, expect, loc, name, critical) {
1212
const {key, val} = expect;

src-runtime/validateSet.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {typecheckWarn} from "./typecheckWarn.mjs";
66
* @param {string} loc - String like `BoundingBox#compute`
77
* @param {string} name - Name of the argument
88
* @param {boolean} critical - Only `false` for unions.
9-
* @returns {boolean} - Boolean indicating if a type is correct.
9+
* @returns {boolean} Boolean indicating if a type is correct.
1010
*/
1111
function validateSet(value, expect, loc, name, critical) {
1212
if (!(value instanceof Set)) {

src-runtime/validateTuple.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {assertType} from "./assertType.mjs";
55
* @param {string} loc - String like `BoundingBox#compute`
66
* @param {string} name - Name of the argument
77
* @param {boolean} critical - Only `false` for unions.
8-
* @returns {boolean} - Boolean indicating if a type is correct.
8+
* @returns {boolean} Boolean indicating if a type is correct.
99
*/
1010
function validateTuple(value, expect, loc, name, critical) {
1111
if (!value) {

src-runtime/validateType.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const props16 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
3333
* @param {string} loc - String like `BoundingBox#compute`
3434
* @param {string} name - Name of the argument.
3535
* @param {boolean} critical - Only false for unions.
36-
* @returns {boolean} - Returns wether `value` is in the shape of `expect`.
36+
* @returns {boolean} Returns wether `value` is in the shape of `expect`.
3737
*/
3838
function validateType(value, expect, loc, name, critical = true) {
3939
if (typeof expect === 'string') {

src-runtime/validateTypedef.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {validateType} from "./validateType.mjs";
66
* @param {string} loc - String like `BoundingBox#compute`
77
* @param {string} name - Name of the argument
88
* @param {boolean} critical - Only `false` for unions.
9-
* @returns {boolean} - Boolean indicating if a type is correct.
9+
* @returns {boolean} Boolean indicating if a type is correct.
1010
*/
1111
function validateTypedef(value, expect, loc, name, critical) {
1212
if (expect.optional && value === undefined) {

src-runtime/validateUnion.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {assertType} from "./assertType.mjs";
55
* @param {string} loc - String like `BoundingBox#compute`
66
* @param {string} name - Name of the argument
77
* @param {boolean} critical - Only `false` for unions.
8-
* @returns {boolean} - Boolean indicating if a type is correct.
8+
* @returns {boolean} Boolean indicating if a type is correct.
99
*/
1010
function validateUnion(value, expect, loc, name, critical) {
1111
return expect.members.some(member => assertType(

test/typechecking.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@
7171
"input": "./test/typechecking/typedef-new-input.mjs",
7272
"output": "./test/typechecking/typedef-new-output.mjs"
7373
},
74+
{
75+
"input": "./test/typechecking/typedef-overwrite-input.mjs",
76+
"output": "./test/typechecking/typedef-overwrite-output.mjs"
77+
},
7478
{
7579
"input": "./test/typechecking/typedef-promise-input.mjs",
7680
"output": "./test/typechecking/typedef-promise-output.mjs"

test_runtime.mjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {validateType} from './src-runtime/validateType.mjs';
2+
// We expect all functions to return true.
3+
const tests = [
4+
() => validateType({}, {type: 'object', optional: false}, 'loc', 'name', true),
5+
// There is no type distinction between a "normal" and "prototype-less" object
6+
() => validateType(Object.create(null), {type: 'object', optional: false}, 'loc', 'name', true),
7+
// Every function is also an object
8+
() => validateType(Math.sqrt, {type: 'object', optional: false}, 'loc', 'name', true),
9+
() => validateType(new Date(), {type: 'object', optional: false}, 'loc', 'name', true),
10+
() => validateType(1, {type: 'object', optional: false}, 'loc', 'name', true) === false,
11+
() => validateType('nope', {type: 'object', optional: false}, 'loc', 'name', true) === false,
12+
() => validateType(Symbol('nope'), {type: 'object', optional: false}, 'loc', 'name', true) === false,
13+
];
14+
let errors = 0;
15+
for (const test of tests) {
16+
const ret = test();
17+
if (!ret) {
18+
console.error("Test failed: " + test);
19+
errors++;
20+
}
21+
}
22+
process.exit(errors); // 0 means success

0 commit comments

Comments
 (0)