@@ -2,107 +2,106 @@ import * as ts from "typescript";
22import { InvalidForRangeCall } from "../../../src/transformation/utils/errors" ;
33import * as util from "../../util" ;
44
5+ const createForRangeDeclaration = ( args = "i: number, j: number, k?: number" , returns = "number[]" ) => `
6+ /** @forRange */
7+ declare function luaRange(${ args } ): ${ returns } ;
8+ ` ;
9+
510test . each ( [
6- { args : [ 1 , 10 ] , expectResult : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] } ,
7- { args : [ 1 , 10 , 2 ] , expectResult : [ 1 , 3 , 5 , 7 , 9 ] } ,
8- { args : [ 10 , 1 , - 1 ] , expectResult : [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] } ,
9- { args : [ 10 , 1 , - 2 ] , expectResult : [ 10 , 8 , 6 , 4 , 2 ] } ,
10- ] ) ( "@forRange loop" , ( { args, expectResult } ) => {
11- const tsHeader = "/** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[];" ;
12- const code = `
13- const results: number[] = [];
11+ { args : [ 1 , 10 ] , results : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] } ,
12+ { args : [ 1 , 10 , 2 ] , results : [ 1 , 3 , 5 , 7 , 9 ] } ,
13+ { args : [ 10 , 1 , - 1 ] , results : [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] } ,
14+ { args : [ 10 , 1 , - 2 ] , results : [ 10 , 8 , 6 , 4 , 2 ] } ,
15+ ] ) ( "usage in for...of loop" , ( { args, results } ) => {
16+ util . testModule `
17+ ${ createForRangeDeclaration ( ) }
18+ export const results: number[] = [];
19+
1420 for (const i of luaRange(${ args } )) {
1521 results.push(i);
1622 }
17- return JSONStringify(results);` ;
18-
19- const result = util . transpileAndExecute ( code , undefined , undefined , tsHeader ) ;
20- expect ( JSON . parse ( result ) ) . toEqual ( expectResult ) ;
21- } ) ;
22-
23- test ( "invalid non-ambient @forRange function" , ( ) => {
24- const code = `
25- /** @forRange **/ function luaRange(i: number, j: number, k?: number): number[] { return []; }
26- for (const i of luaRange(1, 10, 2)) {}` ;
27-
28- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
29- InvalidForRangeCall (
30- ts . createEmptyStatement ( ) ,
31- "@forRange function can only be used as an iterable in a for...of loop."
32- ) . message
33- ) ;
34- } ) ;
35-
36- test . each ( [ [ 1 ] , [ 1 , 2 , 3 , 4 ] ] ) ( "invalid @forRange argument count" , args => {
37- const code = `
38- /** @forRange **/ declare function luaRange(...args: number[]): number[] { return []; }
39- for (const i of luaRange(${ args } )) {}` ;
40-
41- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
42- InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange function must take 2 or 3 arguments." ) . message
43- ) ;
44- } ) ;
45-
46- test ( "invalid @forRange control variable" , ( ) => {
47- const code = `
48- /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[];
49- let i: number;
50- for (i of luaRange(1, 10, 2)) {}` ;
51-
52- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
53- InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange loop must declare its own control variable." ) . message
54- ) ;
23+ `
24+ . setReturnExport ( "results" )
25+ . expectToEqual ( results ) ;
5526} ) ;
5627
57- test ( "invalid @forRange argument type" , ( ) => {
58- const code = `
59- /** @forRange **/ declare function luaRange(i: string, j: number): number[] { return []; }
60- for (const i of luaRange("foo", 2)) {}` ;
61-
62- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
63- InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange arguments must be number types." ) . message
64- ) ;
65- } ) ;
66-
67- test ( "invalid @forRange destructuring" , ( ) => {
68- const code = `
69- /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[][];
70- for (const [i] of luaRange(1, 10, 2)) {}` ;
71-
72- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
73- InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange loop cannot use destructuring." ) . message
74- ) ;
75- } ) ;
76-
77- test ( "invalid @forRange return type" , ( ) => {
78- const code = `
79- /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): string[];
80- for (const i of luaRange(1, 10)) {}` ;
81-
82- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
83- InvalidForRangeCall (
84- ts . createEmptyStatement ( ) ,
85- "@forRange function must return Iterable<number> or Array<number>."
86- ) . message
87- ) ;
88- } ) ;
89-
90- test . each ( [
91- "const range = luaRange(1, 10);" ,
92- "console.log(luaRange);" ,
93- "luaRange.call(null, 0, 0, 0);" ,
94- "let array = [0, luaRange, 1];" ,
95- "const call: any; call(luaRange);" ,
96- "for (const i of [...luaRange(1, 10)]) {}" ,
97- ] ) ( "invalid @forRange reference (%p)" , statement => {
98- const code = `
99- /** @forRange **/ declare function luaRange(i: number, j: number, k?: number): number[];
100- ${ statement } ` ;
101-
102- expect ( ( ) => util . transpileString ( code ) ) . toThrow (
103- InvalidForRangeCall (
104- ts . createEmptyStatement ( ) ,
105- "@forRange function can only be used as an iterable in a for...of loop."
106- ) . message
107- ) ;
28+ describe ( "invalid usage" , ( ) => {
29+ test ( "non-ambient declaration" , ( ) => {
30+ util . testModule `
31+ /** @forRange */
32+ function luaRange() {}
33+ ` . expectToHaveDiagnosticOfError (
34+ InvalidForRangeCall (
35+ ts . createEmptyStatement ( ) ,
36+ "@forRange function can only be used as an iterable in a for...of loop."
37+ )
38+ ) ;
39+ } ) ;
40+
41+ test . each ( [ [ 1 ] , [ 1 , 2 , 3 , 4 ] ] ) ( "argument count" , args => {
42+ util . testModule `
43+ ${ createForRangeDeclaration ( "...args: number[]" ) }
44+ for (const i of luaRange(${ args } )) {}
45+ ` . expectToHaveDiagnosticOfError (
46+ InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange function must take 2 or 3 arguments." )
47+ ) ;
48+ } ) ;
49+
50+ test ( "non-declared loop variable" , ( ) => {
51+ util . testModule `
52+ ${ createForRangeDeclaration ( ) }
53+ let i: number;
54+ for (i of luaRange(1, 10, 2)) {}
55+ ` . expectToHaveDiagnosticOfError (
56+ InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange loop must declare its own control variable." )
57+ ) ;
58+ } ) ;
59+
60+ test ( "argument types" , ( ) => {
61+ util . testModule `
62+ ${ createForRangeDeclaration ( "i: string, j: number" ) }
63+ for (const i of luaRange("foo", 2)) {}
64+ ` . expectToHaveDiagnosticOfError (
65+ InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange arguments must be number types." )
66+ ) ;
67+ } ) ;
68+
69+ test ( "variable destructuring" , ( ) => {
70+ util . testModule `
71+ ${ createForRangeDeclaration ( undefined , "number[][]" ) }
72+ for (const [i] of luaRange(1, 10, 2)) {}
73+ ` . expectToHaveDiagnosticOfError (
74+ InvalidForRangeCall ( ts . createEmptyStatement ( ) , "@forRange loop cannot use destructuring." )
75+ ) ;
76+ } ) ;
77+
78+ test ( "return type" , ( ) => {
79+ util . testModule `
80+ ${ createForRangeDeclaration ( undefined , "string[]" ) }
81+ for (const i of luaRange(1, 10)) {}
82+ ` . expectToHaveDiagnosticOfError (
83+ InvalidForRangeCall (
84+ ts . createEmptyStatement ( ) ,
85+ "@forRange function must return Iterable<number> or Array<number>."
86+ )
87+ ) ;
88+ } ) ;
89+
90+ test . each ( [
91+ "const range = luaRange(1, 10);" ,
92+ "luaRange.call(null, 0, 0, 0);" ,
93+ "let array = [0, luaRange, 1];" ,
94+ "const call = undefined as any; call(luaRange);" ,
95+ "for (const i of [...luaRange(1, 10)]) {}" ,
96+ ] ) ( "reference (%p)" , statement => {
97+ util . testModule `
98+ ${ createForRangeDeclaration ( ) }
99+ ${ statement }
100+ ` . expectToHaveDiagnosticOfError (
101+ InvalidForRangeCall (
102+ ts . createEmptyStatement ( ) ,
103+ "@forRange function can only be used as an iterable in a for...of loop."
104+ )
105+ ) ;
106+ } ) ;
108107} ) ;
0 commit comments