Skip to content

Commit e514ce3

Browse files
committed
Tests for thrown errors
1 parent 37b0b8c commit e514ce3

File tree

6 files changed

+198
-35
lines changed

6 files changed

+198
-35
lines changed

src/Transpiler.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -724,14 +724,9 @@ export class LuaTranspiler {
724724
result = `${lhs}=${lhs}>>${rhs}`;
725725
break;
726726
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
727-
result = `${lhs}>>>${rhs}`;
728-
break;
727+
throw new TranspileError("Bitwise operator >>> not supported", node);
729728
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
730-
if (tsHelper.hasSetAccessor(node.left, this.checker)) {
731-
return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, `${lhs}>>>${rhs}`);
732-
}
733-
result = `${lhs}=${lhs}>>>${rhs}`;
734-
break;
729+
throw new TranspileError("Bitwise operator >>> not supported", node);
735730
}
736731
}
737732

@@ -864,7 +859,8 @@ export class LuaTranspiler {
864859
case ts.SyntaxKind.MinusMinusToken:
865860
return `${operand}=${operand}-1`;
866861
default:
867-
throw new TranspileError("Unsupported unary postfix: " + tsHelper.enumName(node.kind, ts.SyntaxKind),
862+
const operator = tsHelper.enumName(node.operator, ts.SyntaxKind);
863+
throw new TranspileError("Unsupported unary postfix: " + operator,
868864
node);
869865
}
870866
}
@@ -881,7 +877,8 @@ export class LuaTranspiler {
881877
case ts.SyntaxKind.MinusToken:
882878
return `-${operand}`;
883879
default:
884-
throw new TranspileError("Unsupported unary prefix: " + tsHelper.enumName(node.kind, ts.SyntaxKind),
880+
const operator = tsHelper.enumName(node.operator, ts.SyntaxKind);
881+
throw new TranspileError("Unsupported unary prefix: " + operator,
885882
node);
886883
}
887884
}
@@ -1121,7 +1118,7 @@ export class LuaTranspiler {
11211118
if (translation[identifier.escapedText as string]) {
11221119
return `math.${translation[identifier.escapedText as string]}`;
11231120
} else {
1124-
throw new TranspileError(`Unsupported math property ${identifier.escapedText}.`, identifier);
1121+
throw new TranspileError(`Unsupported math property: ${identifier.escapedText}.`, identifier);
11251122
}
11261123
}
11271124

@@ -1207,7 +1204,7 @@ export class LuaTranspiler {
12071204
}
12081205
} else {
12091206
throw new TranspileError(
1210-
"Unsupported variable declaration type " + tsHelper.enumName(node.name.kind, ts.SyntaxKind),
1207+
"Unsupported variable declaration type: " + tsHelper.enumName(node.name.kind, ts.SyntaxKind),
12111208
node
12121209
);
12131210
}
@@ -1513,7 +1510,8 @@ export class LuaTranspiler {
15131510
const expression = this.transpileExpression(element.initializer);
15141511
properties.push(`${name} = ${expression}`);
15151512
} else {
1516-
throw new TranspileError(`Encountered unsupported object literal element ${element.kind}.`, node);
1513+
const elementKind = tsHelper.enumName(element.kind, ts.SyntaxKind);
1514+
throw new TranspileError(`Encountered unsupported object literal element: ${elementKind}.`, node);
15171515
}
15181516
});
15191517

test/src/util.ts

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,25 @@ import * as path from "path";
33

44
import { Expect } from "alsatian";
55

6-
import { LuaTranspiler, TranspileError, LuaTarget } from "../../src/Transpiler";
6+
import { LuaTarget, LuaTranspiler, TranspileError } from "../../src/Transpiler";
77
import { CompilerOptions } from "../../src/CommandLineParser";
88

9-
import {lauxlib, lua, lualib, to_luastring, to_jsstring } from "fengari";
9+
import {lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari";
1010

1111
const fs = require("fs");
1212

1313
const libSource = fs.readFileSync(path.join(path.dirname(require.resolve('typescript')), 'lib.d.ts')).toString();
1414

1515
export function transpileString(str: string, options: CompilerOptions = { dontRequireLuaLib: true, luaTarget: LuaTarget.Lua53 }): string {
16-
let compilerHost = {
16+
const compilerHost = {
17+
directoryExists: () => true,
18+
fileExists: (fileName): boolean => true,
19+
getCanonicalFileName: fileName => fileName,
20+
getCurrentDirectory: () => "",
21+
getDefaultLibFileName: () => "lib.d.ts",
22+
getDirectories: () => [],
23+
getNewLine: () => "\n",
24+
1725
getSourceFile: (filename, languageVersion) => {
1826
if (filename === "file.ts") {
1927
return ts.createSourceFile(filename, str, ts.ScriptTarget.Latest, false);
@@ -23,35 +31,31 @@ export function transpileString(str: string, options: CompilerOptions = { dontRe
2331
}
2432
return undefined;
2533
},
26-
writeFile: (name, text, writeByteOrderMark) => {
27-
// we dont care about the js output
28-
},
29-
getDefaultLibFileName: () => "lib.d.ts",
30-
useCaseSensitiveFileNames: () => false,
31-
getCanonicalFileName: fileName => fileName,
32-
getCurrentDirectory: () => "",
33-
getNewLine: () => "\n",
34-
fileExists: (fileName): boolean => true,
34+
3535
readFile: () => "",
36-
directoryExists: () => true,
37-
getDirectories: () => []
36+
37+
useCaseSensitiveFileNames: () => false,
38+
// Don't write output
39+
writeFile: (name, text, writeByteOrderMark) => null,
3840
};
39-
let program = ts.createProgram(["file.ts"], options, compilerHost);
41+
const program = ts.createProgram(["file.ts"], options, compilerHost);
4042

41-
const result = LuaTranspiler.transpileSourceFile(program.getSourceFile("file.ts"), program.getTypeChecker(), options);
43+
const result = LuaTranspiler.transpileSourceFile(program.getSourceFile("file.ts"),
44+
program.getTypeChecker(),
45+
options);
4246
return result.trim();
4347
}
4448

45-
export function transpileFile(path: string): string {
46-
const program = ts.createProgram([path], {});
49+
export function transpileFile(filePath: string): string {
50+
const program = ts.createProgram([filePath], {});
4751
const checker = program.getTypeChecker();
4852

4953
// Output errors
50-
const diagnostics = ts.getPreEmitDiagnostics(program).filter(diag => diag.code != 6054);
51-
diagnostics.forEach(diagnostic => console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`));
54+
const diagnostics = ts.getPreEmitDiagnostics(program).filter(diag => diag.code !== 6054);
55+
diagnostics.forEach(diagnostic => console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`));
5256

5357
const options: ts.CompilerOptions = { dontRequireLuaLib: true };
54-
const result = LuaTranspiler.transpileSourceFile(program.getSourceFile(path), checker, options);
58+
const result = LuaTranspiler.transpileSourceFile(program.getSourceFile(filePath), checker, options);
5559
return result.trim();
5660
}
5761

@@ -98,6 +102,13 @@ export function expectCodeEqual(code1: string, code2: string) {
98102
Expect(c1).toBe(c2);
99103
}
100104

105+
// Get a mock transpiler to use for testing
106+
export function makeTestTranspiler(target: LuaTarget = LuaTarget.Lua53) {
107+
return new LuaTranspiler({} as ts.TypeChecker,
108+
{ dontRequireLuaLib: true, luaTarget: target } as any,
109+
{ statements: [] } as any as ts.SourceFile);
110+
}
111+
101112
const tslualib = fs.readFileSync("dist/lualib/typescript.lua") + "\n";
102113

103114
const jsonlib = fs.readFileSync("test/src/json.lua") + "\n";
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ClassB = ClassB or ClassA.new()
2+
ClassB.__index = ClassB
3+
ClassB.__base = ClassA
4+
function ClassB.new(construct, ...)
5+
local instance = setmetatable({}, ClassB)
6+
if construct and ClassB.constructor then ClassB.constructor(instance, ...) end
7+
return instance
8+
end
9+
function ClassB.constructor(self)
10+
self.__base.constructor(self)
11+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare class ClassA {}
2+
class ClassB extends ClassA {
3+
public constructor() {
4+
super();
5+
}
6+
}

test/unit/expressions.spec.ts

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,19 @@ export class ExpressionTests {
116116
@TestCase("a<<=b", "a=a<<b")
117117
@TestCase("a>>b", "a>>b")
118118
@TestCase("a>>=b", "a=a>>b")
119-
@TestCase("a>>>b", "a>>>b")
120-
@TestCase("a>>>=b", "a=a>>>b")
121119
@Test("Bitop [5.3]")
122120
public bitOperatorOverride53(input: string, lua: string) {
123121
Expect(util.transpileString(input, { luaTarget: "5.3", dontRequireLuaLib: true })).toBe(lua);
124122
}
125123

124+
@TestCase("a>>>b")
125+
@TestCase("a>>>=b")
126+
@Test("Unsupported bitop 5.3")
127+
public bitOperatorOverride53Unsupported(input: string) {
128+
Expect(() => util.transpileString(input, { luaTarget: "5.3", dontRequireLuaLib: true }))
129+
.toThrowError(Error, "Bitwise operator >>> not supported");
130+
}
131+
126132
@TestCase("1+1", "1+1")
127133
@TestCase("-1+1", "-1+1")
128134
@TestCase("1*30+4", "(1*30)+4")
@@ -281,4 +287,119 @@ export class ExpressionTests {
281287
// Assert
282288
Expect(result).toBe(expected);
283289
}
290+
291+
// ====================================
292+
// Test expected errors
293+
// ====================================
294+
295+
@Test("Unknown unary postfix error")
296+
public unknownUnaryPostfixError() {
297+
const transpiler = util.makeTestTranspiler();
298+
299+
const mockExpression: any = {
300+
operand: ts.createLiteral(false),
301+
operator: ts.SyntaxKind.AsteriskToken,
302+
};
303+
304+
Expect(() => transpiler.transpilePostfixUnaryExpression(mockExpression as ts.PostfixUnaryExpression))
305+
.toThrowError(Error, "Unsupported unary postfix: AsteriskToken");
306+
}
307+
308+
@Test("Unknown unary postfix error")
309+
public unknownUnaryPrefixError() {
310+
const transpiler = util.makeTestTranspiler();
311+
312+
const mockExpression: any = {
313+
operand: ts.createLiteral(false),
314+
operator: ts.SyntaxKind.AsteriskToken,
315+
};
316+
317+
Expect(() => transpiler.transpilePrefixUnaryExpression(mockExpression as ts.PrefixUnaryExpression))
318+
.toThrowError(Error, "Unsupported unary prefix: AsteriskToken");
319+
}
320+
321+
@Test("Incompatible fromCodePoint expression error")
322+
public incompatibleFromCodePointExpression() {
323+
const transpiler = util.makeTestTranspiler(LuaTarget.LuaJIT);
324+
325+
const identifier = ts.createIdentifier("fromCodePoint");
326+
Expect(() => transpiler.transpileStringExpression(identifier))
327+
.toThrowError(Error, "Unsupported string property fromCodePoint is only supported for lua 5.3.");
328+
}
329+
330+
@Test("Unknown string expression error")
331+
public unknownStringExpression() {
332+
const transpiler = util.makeTestTranspiler(LuaTarget.LuaJIT);
333+
334+
const identifier = ts.createIdentifier("abcd");
335+
Expect(() => transpiler.transpileStringExpression(identifier))
336+
.toThrowError(Error, "Unsupported string property abcd.");
337+
}
338+
339+
@Test("Unsupported array function error")
340+
public unsupportedArrayFunctionError() {
341+
const transpiler = util.makeTestTranspiler();
342+
343+
const mockNode: any = {
344+
arguments: [],
345+
caller: ts.createLiteral(false),
346+
expression: {name: ts.createIdentifier("unknownFunction"), expression: ts.createLiteral(false)},
347+
};
348+
349+
Expect(() => transpiler.transpileArrayCallExpression(mockNode as ts.CallExpression))
350+
.toThrowError(Error, "Unsupported array function: unknownFunction");
351+
}
352+
353+
@Test("Unsupported array property error")
354+
public unsupportedArrayPropertyError() {
355+
const transpiler = util.makeTestTranspiler();
356+
357+
const mockNode: any = {
358+
name: ts.createIdentifier("unknownProperty"),
359+
};
360+
361+
Expect(() => transpiler.transpileArrayProperty(mockNode as ts.PropertyAccessExpression))
362+
.toThrowError(Error, "Unsupported array property: unknownProperty");
363+
}
364+
365+
@Test("Unsupported math property error")
366+
public unsupportedMathPropertyError() {
367+
const transpiler = util.makeTestTranspiler();
368+
369+
Expect(() => transpiler.transpileMathExpression(ts.createIdentifier("unknownProperty")))
370+
.toThrowError(Error, "Unsupported math property: unknownProperty.");
371+
}
372+
373+
@Test("Unsupported variable declaration type error")
374+
public unsupportedVariableDeclarationType() {
375+
const transpiler = util.makeTestTranspiler();
376+
377+
const mockNode: any = {name: ts.createLiteral(false)};
378+
379+
Expect(() => transpiler.transpileVariableDeclaration(mockNode as ts.VariableDeclaration))
380+
.toThrowError(Error, "Unsupported variable declaration type: FalseKeyword");
381+
}
382+
383+
@Test("Class without name error")
384+
public classWithoutNameError() {
385+
const transpiler = util.makeTestTranspiler();
386+
387+
Expect(() => transpiler.transpileClass({} as ts.ClassDeclaration))
388+
.toThrowError(Error, "Unexpected Error: Node has no Name");
389+
}
390+
391+
@Test("Unsupported object literal element error")
392+
public unsupportedObjectLiteralElementError() {
393+
const transpiler = util.makeTestTranspiler();
394+
395+
const mockObject: any = {
396+
properties: [{
397+
kind: ts.SyntaxKind.FalseKeyword,
398+
name: ts.createIdentifier("testProperty"),
399+
}],
400+
};
401+
402+
Expect(() => transpiler.transpileObjectLiteral(mockObject as ts.ObjectLiteralExpression))
403+
.toThrowError(Error, "Encountered unsupported object literal element: FalseKeyword.");
404+
}
284405
}

test/unit/modules.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Expect, Test, TestCase } from "alsatian";
2+
import * as ts from "typescript";
3+
import { LuaTarget, LuaTranspiler } from "../../src/Transpiler";
24
import * as util from "../src/util";
35

46
export class LuaModuleTests {
@@ -18,4 +20,18 @@ export class LuaModuleTests {
1820
// Assert
1921
Expect(lua).toBe(`require("typescript_lualib")`);
2022
}
23+
24+
@Test("Import named bindings exception")
25+
public namedBindigsException() {
26+
const transpiler = util.makeTestTranspiler();
27+
28+
const mockDeclaration: any = {
29+
importClause: {namedBindings: {}},
30+
kind: ts.SyntaxKind.ImportDeclaration,
31+
moduleSpecifier: ts.createLiteral("test"),
32+
};
33+
34+
Expect(() => transpiler.transpileImport(mockDeclaration as ts.ImportDeclaration))
35+
.toThrowError(Error, "Unsupported import type.");
36+
}
2137
}

0 commit comments

Comments
 (0)