Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#23 basic checker tests #36

Merged
merged 4 commits into from
Mar 2, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions lib/checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@ function addOutputMessage({ type = "info", id = -1, text = "?", node = {}, } =
outputMessages.push({ type, id, text: textWithLoc, });
}

function check(code) {
function check(code, {verbose=true}) {
var ast = babylon.parse(code);

multipass: for (let passCount = 1; passCount <= PASS_LIMIT; passCount++) {
Expand Down Expand Up @@ -1958,14 +1958,16 @@ function check(code) {
break;
}

for (let msg of outputMessages) {
if (msg.type == "error") {
console.error(msg.text);
}
else {
console.log(msg.text);
if (verbose){
for (let msg of outputMessages) {
if (msg.type == "error") {
console.error(msg.text);
}
else {
console.log(msg.text);
}
}
}

return ast;
return {ast, outputMessages};
}
125 changes: 119 additions & 6 deletions tests/tests.checker.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,131 @@
"use strict";
var path = require("path");
var Typl = require(path.join(__dirname,"..","lib"));

QUnit.test( "Checker: API", function test(assert){
assert.expect( 1 );
assert.ok( _isFunction( Typl.Checker.check ), "check(..)" );
} );

QUnit.test( "Checker: #6 number sub-types", function test(assert){
assert.expect(2);
let code = `var a = int\`3\`;
a = 4; // error, can't assign number to int

var b = 5;
b = int\`6\`; // no error

var c = finite\`7\`;
b = c; // no error
c = b; // error can't assign number to finite`

assert.ok( _isFunction( Checker.check ), "check(..)" );
let {outputMessages} = Typl.Checker. check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 5, 'total output length');
assert.equal(errors.length, 2, 'num errors');
} );

QUnit.test( "Checker: check(..)", function test(assert){
var rExpected = undefined;
QUnit.test( "Checker: #7 enforce bool type check in conditionals", function test(assert){
assert.expect(2);
let code = `var i = 3 > 9; // becomes bool but with error
function foo(){
return "ddd"; // foo returns string
}

function bar(){
return "d" + 3 > 9;
}

if(i){} // pass
while(i){} // pass
do{} while(i) // pass
let a = i ? 1 : 0; // pass

if(foo()){} // error
while(foo()){} // error
do{} while(foo()) // error
let b = foo() ? 1 : 0; // error`

var rActual = Checker.check("var x;");
let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 18, 'total output length');
assert.equal(errors.length, 6, 'num errors');
} );

assert.expect( 1 );
assert.strictEqual( rActual, rActual, "check(..)" );
QUnit.test( "Checker: #8 any", function test(assert){
assert.expect(2);
let code = `var a = any\`\`;
a = "hello"; // OK
a = 1; // also OK because a is still type any
var b = a + 2; // error: mixed operand types: any and number`

let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 16, 'total output length');
assert.equal(errors.length, 1, 'num errors');
} );

QUnit.test( "Checker: #9 undef", function test(assert){
assert.expect(2);
let code = `var a;
var b = a + 1; // error: mixed operand types

a = 2; // no error, overwrites a to type number
b = a + 2; // no error

var c = undefined;
c = 3; // no error, overwrites c to type number

var d = undef\`\`;
d = 4; // error, d is already tagged-type of undef`

let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 24, 'total output length');
assert.equal(errors.length, 2, 'num errors');
} );


QUnit.test( "Checker: #17 Narrower number type inference", function test(assert){
assert.expect(2);
let code = `var x = 3; // infer 'int'
var y = 3.14; // infer 'finite'
var z = NaN; // infer 'number'

x = 2.2 // error, expected int, got number
y = NaN // error, expected finite, got number
z = "a" // error, expected number, found string`

let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 29, 'total output length');
assert.equal(errors.length, 3, 'num errors');
} );

QUnit.test( "Checker: #33 Treat IIFE as a validated call-expression", function test(assert){
assert.expect(2);
let code = `var y = (function foo(x = number){
return String(x);
})(true);`

let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 32, 'total output length');
assert.equal(errors.length, 1, 'num errors');
} );

QUnit.test( "Checker: #34 check tagged-type simple literals", function test(assert){
assert.expect(2);
let code = `int\`3.1\` // should report an error
finite\`3.1\` // OK
bool\`${true}\` // OK
bool\`true\` // OK
bool\`ok\` // error`

let {outputMessages} = Typl.Checker.check(code, {verbose:false});
let errors = outputMessages.filter(m => m.type == "error")
assert.equal(outputMessages.length, 34, 'total output length');
assert.equal(errors.length, 2, 'num errors');
} );


Expand Down