Increase test coverage (#4742)
* Add tests for path type inferers * Add test for babel-types.valueToNode * Add tests for babel-types.toKeyAlias * Add tests for babel-types.toStatement * Add tests for babel-types.toExpression * Lint fixes in babel-traverse/test/inference
This commit is contained in:
committed by
Daniel Tschinder
parent
beda884f41
commit
fd4667e649
@@ -137,7 +137,13 @@ function Func() {
|
||||
return t.genericTypeAnnotation(t.identifier("Function"));
|
||||
}
|
||||
|
||||
export { Func as Function, Func as Class };
|
||||
export {
|
||||
Func as FunctionExpression,
|
||||
Func as ArrowFunctionExpression,
|
||||
Func as FunctionDeclaration,
|
||||
Func as ClassExpression,
|
||||
Func as ClassDeclaration
|
||||
};
|
||||
|
||||
export function CallExpression() {
|
||||
return resolveCall(this.get("callee"));
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
let traverse = require("../lib").default;
|
||||
let assert = require("assert");
|
||||
let parse = require("babylon").parse;
|
||||
import traverse from "../lib";
|
||||
import assert from "assert";
|
||||
import { parse } from "babylon";
|
||||
import * as t from "babel-types";
|
||||
|
||||
function getPath(code) {
|
||||
let ast = parse(code);
|
||||
const ast = parse(code, {plugins: ["flow", "asyncGenerators"]});
|
||||
let path;
|
||||
traverse(ast, {
|
||||
Program: function (_path) {
|
||||
@@ -17,40 +18,160 @@ function getPath(code) {
|
||||
describe("inference", function () {
|
||||
describe("baseTypeStrictlyMatches", function () {
|
||||
it("it should work with null", function () {
|
||||
let path = getPath("var x = null; x === null").get("body")[1].get("expression");
|
||||
let left = path.get("left");
|
||||
let right = path.get("right");
|
||||
let strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
const path = getPath("var x = null; x === null").get("body")[1].get("expression");
|
||||
const left = path.get("left");
|
||||
const right = path.get("right");
|
||||
const strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
|
||||
assert.ok(strictMatch, "null should be equal to null");
|
||||
});
|
||||
|
||||
it("it should work with numbers", function () {
|
||||
let path = getPath("var x = 1; x === 2").get("body")[1].get("expression");
|
||||
let left = path.get("left");
|
||||
let right = path.get("right");
|
||||
let strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
const path = getPath("var x = 1; x === 2").get("body")[1].get("expression");
|
||||
const left = path.get("left");
|
||||
const right = path.get("right");
|
||||
const strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
|
||||
assert.ok(strictMatch, "null should be equal to null");
|
||||
assert.ok(strictMatch, "number should be equal to number");
|
||||
});
|
||||
|
||||
it("it should bail when type changes", function () {
|
||||
let path = getPath("var x = 1; if (foo) x = null;else x = 3; x === 2").get("body")[2].get("expression");
|
||||
let left = path.get("left");
|
||||
let right = path.get("right");
|
||||
const path = getPath("var x = 1; if (foo) x = null;else x = 3; x === 2").get("body")[2].get("expression");
|
||||
const left = path.get("left");
|
||||
const right = path.get("right");
|
||||
|
||||
let strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
const strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
|
||||
assert.ok(!strictMatch, "type might change in if statement");
|
||||
});
|
||||
|
||||
it("it should differentiate between null and undefined", function () {
|
||||
let path = getPath("var x; x === null").get("body")[1].get("expression");
|
||||
let left = path.get("left");
|
||||
let right = path.get("right");
|
||||
let strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
const path = getPath("var x; x === null").get("body")[1].get("expression");
|
||||
const left = path.get("left");
|
||||
const right = path.get("right");
|
||||
const strictMatch = left.baseTypeStrictlyMatches(right);
|
||||
|
||||
assert.ok(!strictMatch, "null should not match undefined");
|
||||
});
|
||||
});
|
||||
describe("getTypeAnnotation", function () {
|
||||
it("should infer from type cast", function () {
|
||||
const path = getPath("(x: number)").get("body")[0].get("expression");
|
||||
assert.ok(t.isNumberTypeAnnotation(path.getTypeAnnotation()), "should be number");
|
||||
|
||||
});
|
||||
it("should infer string from template literal", function () {
|
||||
const path = getPath("`hey`").get("body")[0].get("expression");
|
||||
assert.ok(t.isStringTypeAnnotation(path.getTypeAnnotation()), "should be string");
|
||||
});
|
||||
it("should infer number from +x", function () {
|
||||
const path = getPath("+x").get("body")[0].get("expression");
|
||||
assert.ok(t.isNumberTypeAnnotation(path.getTypeAnnotation()), "should be number");
|
||||
});
|
||||
it("should infer T from new T", function () {
|
||||
const path = getPath("new T").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "T", "should be T");
|
||||
});
|
||||
it("should infer number from ++x", function () {
|
||||
const path = getPath("++x").get("body")[0].get("expression");
|
||||
assert.ok(t.isNumberTypeAnnotation(path.getTypeAnnotation()), "should be number");
|
||||
});
|
||||
it("should infer number from --x", function () {
|
||||
const path = getPath("--x").get("body")[0].get("expression");
|
||||
assert.ok(t.isNumberTypeAnnotation(path.getTypeAnnotation()), "should be number");
|
||||
});
|
||||
it("should infer void from void x", function () {
|
||||
const path = getPath("void x").get("body")[0].get("expression");
|
||||
assert.ok(t.isVoidTypeAnnotation(path.getTypeAnnotation()), "should be void");
|
||||
});
|
||||
it("should infer string from typeof x", function () {
|
||||
const path = getPath("typeof x").get("body")[0].get("expression");
|
||||
assert.ok(t.isStringTypeAnnotation(path.getTypeAnnotation()), "should be string");
|
||||
});
|
||||
it("should infer boolean from !x", function () {
|
||||
const path = getPath("!x").get("body")[0].get("expression");
|
||||
assert.ok(t.isBooleanTypeAnnotation(path.getTypeAnnotation()), "should be boolean");
|
||||
});
|
||||
it("should infer type of sequence expression", function () {
|
||||
const path = getPath("a,1").get("body")[0].get("expression");
|
||||
assert.ok(t.isNumberTypeAnnotation(path.getTypeAnnotation()), "should be number");
|
||||
});
|
||||
it("should infer type of logical expression", function () {
|
||||
const path = getPath("'a' && 1").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isUnionTypeAnnotation(type), "should be a union");
|
||||
assert.ok(t.isStringTypeAnnotation(type.types[0]), "first type in union should be string");
|
||||
assert.ok(t.isNumberTypeAnnotation(type.types[1]), "second type in union should be number");
|
||||
});
|
||||
it("should infer type of conditional expression", function () {
|
||||
const path = getPath("q ? true : 0").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isUnionTypeAnnotation(type), "should be a union");
|
||||
assert.ok(t.isBooleanTypeAnnotation(type.types[0]), "first type in union should be boolean");
|
||||
assert.ok(t.isNumberTypeAnnotation(type.types[1]), "second type in union should be number");
|
||||
});
|
||||
it("should infer RegExp from RegExp literal", function () {
|
||||
const path = getPath("/.+/").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "RegExp", "should be RegExp");
|
||||
});
|
||||
it("should infer Object from object expression", function () {
|
||||
const path = getPath("({ a: 5 })").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "Object", "should be Object");
|
||||
});
|
||||
it("should infer Array from array expression", function () {
|
||||
const path = getPath("[ 5 ]").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "Array", "should be Array");
|
||||
});
|
||||
it("should infer Function from function", function () {
|
||||
const path = getPath("(function (): string {})").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "Function", "should be Function");
|
||||
});
|
||||
it("should infer call return type using function", function () {
|
||||
const path = getPath("(function (): string {})()").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isStringTypeAnnotation(type), "should be string");
|
||||
});
|
||||
it("should infer call return type using async function", function () {
|
||||
const path = getPath("(async function (): string {})()").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "Promise", "should be Promise");
|
||||
});
|
||||
it("should infer call return type using async generator function", function () {
|
||||
const path = getPath("(async function * (): string {})()").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "AsyncIterator", "should be AsyncIterator");
|
||||
});
|
||||
it("should infer number from x/y", function () {
|
||||
const path = getPath("x/y").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isNumberTypeAnnotation(type), "should be number");
|
||||
});
|
||||
it("should infer boolean from x instanceof y", function () {
|
||||
const path = getPath("x instanceof y").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isBooleanTypeAnnotation(type), "should be boolean");
|
||||
});
|
||||
it("should infer number from 1 + 2", function () {
|
||||
const path = getPath("1 + 2").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isNumberTypeAnnotation(type), "should be number");
|
||||
});
|
||||
it("should infer string|number from x + y", function () {
|
||||
const path = getPath("x + y").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isUnionTypeAnnotation(type), "should be a union");
|
||||
assert.ok(t.isStringTypeAnnotation(type.types[0]), "first type in union should be string");
|
||||
assert.ok(t.isNumberTypeAnnotation(type.types[1]), "second type in union should be number");
|
||||
});
|
||||
it("should infer type of tagged template literal", function () {
|
||||
const path = getPath("(function (): RegExp {}) `hey`").get("body")[0].get("expression");
|
||||
const type = path.getTypeAnnotation();
|
||||
assert.ok(t.isGenericTypeAnnotation(type) && type.id.name === "RegExp", "should be RegExp");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
147
packages/babel-types/test/converters.js
Normal file
147
packages/babel-types/test/converters.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as t from "../lib";
|
||||
import { assert } from "chai";
|
||||
|
||||
describe("converters", function () {
|
||||
describe("valueToNode", function () {
|
||||
it("number", function () {
|
||||
assert.deepEqual(t.valueToNode(Math.PI), t.numericLiteral(Math.PI));
|
||||
assert.deepEqual(t.valueToNode(-Infinity), t.numericLiteral(-Infinity));
|
||||
assert.deepEqual(t.valueToNode(NaN), t.numericLiteral(NaN));
|
||||
});
|
||||
it("string", function () {
|
||||
assert.deepEqual(t.valueToNode("This is a \"string\""), t.stringLiteral("This is a \"string\""));
|
||||
});
|
||||
it("boolean", function () {
|
||||
assert.deepEqual(t.valueToNode(true), t.booleanLiteral(true));
|
||||
assert.deepEqual(t.valueToNode(false), t.booleanLiteral(false));
|
||||
});
|
||||
it("null", function () {
|
||||
assert.deepEqual(t.valueToNode(null), t.nullLiteral());
|
||||
});
|
||||
it("undefined", function () {
|
||||
assert.deepEqual(t.valueToNode(undefined), t.identifier("undefined"));
|
||||
});
|
||||
it("RegExp", function () {
|
||||
assert.deepEqual(t.valueToNode(/abc.+/gm), t.regExpLiteral("abc.+", "gm"));
|
||||
});
|
||||
it("array", function () {
|
||||
assert.deepEqual(t.valueToNode([1, "a"]), t.arrayExpression([t.numericLiteral(1), t.stringLiteral("a")]));
|
||||
});
|
||||
it("object", function () {
|
||||
assert.deepEqual(t.valueToNode({
|
||||
a: 1,
|
||||
"b c": 2
|
||||
}), t.objectExpression([
|
||||
t.objectProperty(t.identifier("a"), t.numericLiteral(1)),
|
||||
t.objectProperty(t.stringLiteral("b c"), t.numericLiteral(2))
|
||||
]));
|
||||
});
|
||||
it("throws if cannot convert", function () {
|
||||
assert.throws(function () {
|
||||
t.valueToNode(Object);
|
||||
});
|
||||
assert.throws(function () {
|
||||
t.valueToNode(Symbol());
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("toKeyAlias", function () {
|
||||
beforeEach(function () {
|
||||
// make tests deterministic
|
||||
t.toKeyAlias.uid = 0;
|
||||
});
|
||||
it("doesn't change string literals", function () {
|
||||
assert.equal(t.toKeyAlias(t.objectProperty(t.stringLiteral("a"), t.nullLiteral())), "\"a\"");
|
||||
});
|
||||
it("wraps around at Number.MAX_SAFE_INTEGER", function () {
|
||||
assert.equal(t.toKeyAlias(t.objectMethod("method", t.identifier("a"), [], t.blockStatement([]))), "0");
|
||||
});
|
||||
});
|
||||
describe("toStatement", function () {
|
||||
it("noop on statements", function () {
|
||||
const node = t.emptyStatement();
|
||||
assert.equal(t.toStatement(node), node);
|
||||
t.assertEmptyStatement(node);
|
||||
});
|
||||
it("mutate class expression to declaration", function () {
|
||||
const node = t.classExpression(t.identifier("A"), null, t.classBody([]), []);
|
||||
t.toStatement(node);
|
||||
t.assertClassDeclaration(node);
|
||||
});
|
||||
it("fail if class expression has no id", function () {
|
||||
const node = t.classExpression(null, null, t.classBody([]), []);
|
||||
assert.throws(function() {
|
||||
t.toStatement(node);
|
||||
});
|
||||
assert.strictEqual(t.toStatement(node, /* ignore = */ true), false);
|
||||
t.assertClassExpression(node);
|
||||
});
|
||||
it("mutate function expression to declaration", function () {
|
||||
const node = t.functionExpression(t.identifier("A"), [], t.blockStatement([]));
|
||||
t.toStatement(node);
|
||||
t.assertFunctionDeclaration(node);
|
||||
});
|
||||
it("fail if function expression has no id", function () {
|
||||
const node = t.functionExpression(null, [], t.blockStatement([]));
|
||||
assert.throws(function() {
|
||||
t.toStatement(node);
|
||||
});
|
||||
assert.strictEqual(t.toStatement(node, /* ignore = */ true), false);
|
||||
t.assertFunctionExpression(node);
|
||||
});
|
||||
it("assignment expression", function () {
|
||||
const node = t.assignmentExpression("+=", t.identifier("x"), t.numericLiteral(1));
|
||||
t.assertExpressionStatement(t.toStatement(node));
|
||||
t.assertAssignmentExpression(node);
|
||||
});
|
||||
it("fail if cannot convert node type", function () {
|
||||
const node = t.yieldExpression(t.identifier("foo"));
|
||||
assert.throws(function() {
|
||||
t.toStatement(node);
|
||||
});
|
||||
assert.strictEqual(t.toStatement(node, /* ignore = */ true), false);
|
||||
t.assertYieldExpression(node);
|
||||
});
|
||||
});
|
||||
describe("toExpression", function () {
|
||||
it("noop on expressions", function () {
|
||||
const node = t.identifier("a");
|
||||
assert.equal(t.toExpression(node), node);
|
||||
t.assertIdentifier(node);
|
||||
});
|
||||
it("mutate class declaration to expression", function () {
|
||||
const node = t.classDeclaration(t.identifier("A"), null, t.classBody([]), []);
|
||||
t.toExpression(node);
|
||||
t.assertClassExpression(node);
|
||||
});
|
||||
it("mutate function declaration to expression", function () {
|
||||
const node = t.functionDeclaration(t.identifier("A"), [], t.blockStatement([]));
|
||||
t.toExpression(node);
|
||||
t.assertFunctionExpression(node);
|
||||
});
|
||||
it("mutate object method to expression", function () {
|
||||
const node = t.objectMethod("method", t.identifier("A"), [], t.blockStatement([]));
|
||||
t.toExpression(node);
|
||||
t.assertFunctionExpression(node);
|
||||
});
|
||||
it("mutate class method to expression", function () {
|
||||
const node = t.classMethod("constructor", t.identifier("A"), [], t.blockStatement([]));
|
||||
t.toExpression(node);
|
||||
t.assertFunctionExpression(node);
|
||||
});
|
||||
it("expression statement", function () {
|
||||
const inner = t.yieldExpression(t.identifier("foo"));
|
||||
const node = t.expressionStatement(inner);
|
||||
t.assertYieldExpression(t.toExpression(node));
|
||||
assert.equal(t.toExpression(node), inner);
|
||||
t.assertExpressionStatement(node);
|
||||
});
|
||||
it("fail if cannot convert node type", function () {
|
||||
const node = t.program([]);
|
||||
assert.throws(function() {
|
||||
t.toExpression(node);
|
||||
});
|
||||
t.assertProgram(node);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user