OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Flags: --harmony-types | 5 // Flags: --harmony-types |
6 | 6 |
7 | 7 |
| 8 load("test/mjsunit/harmony/typesystem/typegen.js"); |
| 9 |
| 10 |
8 // In all the following functions, the size parameter (positive integer) | 11 // In all the following functions, the size parameter (positive integer) |
9 // denotes how many test cases will be tried. The variable test_size | 12 // denotes how many test cases will be tried. The variable test_size |
10 // controls execution time of this test. It should not be too high. | 13 // controls execution time of this test. It should not be too high. |
11 let test_size = 1000; | 14 let test_size = 1000; |
12 | 15 |
13 function CheckValid(type) { | |
14 // print("V:", type); | |
15 assertDoesNotThrow("'use types'; var x: " + type + ";"); | |
16 } | |
17 | |
18 function CheckInvalid(type) { | |
19 // print("I:", type); | |
20 assertThrows("'use types'; var x: " + type + ";", SyntaxError); | |
21 } | |
22 | |
23 // Parameters: | |
24 // multiplicity: positive integer | |
25 // generator: (size: positive integer, ...params: any[]) => Iterator<SomeType> | |
26 // transformations: [false | ((t: SomeType) => OtherType)] | |
27 // params: any[] | |
28 // | |
29 // A "test generator" object will have its "generator" generate tests, | |
30 // will transform each generated test with all of its "transformations" | |
31 // and will yield the results. false transformations will be ignored. | |
32 class TestGen { | |
33 constructor(multiplicity, generator, transformations, ...params) { | |
34 // Determines how often this generator will run, compared to other ones. | |
35 this.multiplicity = multiplicity; | |
36 // The generator function. It will be called with (size, ...params), | |
37 // for an appropriate size provided externally to method initialize. | |
38 this.generator = generator; | |
39 // The list of transformation functions, excluding false ones. | |
40 this.transformations = transformations.filter(f => f !== false); | |
41 // The optional parameters to be passed to the generator function. | |
42 this.params = params; | |
43 } | |
44 // Returns how many tests this test generator is expected to yield | |
45 // in a row. | |
46 weight() { | |
47 return this.multiplicity * this.transformations.length; | |
48 } | |
49 // Initialize the generator function. | |
50 initialize(size) { | |
51 this.factory = this.generator(size, ...this.params); | |
52 } | |
53 // Is the test generator exhausted? | |
54 exhausted() { | |
55 return this.factory === null; | |
56 } | |
57 // Return a generator that will yield up to weight tests. | |
58 // It returns an Iterator<OtherType>. | |
59 * [Symbol.iterator]() { | |
60 for (let i = 0; i < this.multiplicity; i++) { | |
61 let element = this.factory.next(); | |
62 if (element.done) { | |
63 this.factory = null; | |
64 return; | |
65 } | |
66 for (let f of this.transformations) yield f(element.value); | |
67 } | |
68 } | |
69 } | |
70 | |
71 // Parameters: | |
72 // size: positive integer | |
73 // generators: [false | string | TestGen] | |
74 // | |
75 // This generator function will yield up to size tests. It will iterate | |
76 // cyclically through the list of test generators. A string in this list | |
77 // behaves as a simple generator yielding just one test; a false value | |
78 // behaves as a generator yielding nothing. For every test generator in | |
79 // the list, this function will generate as many tests as its weight | |
80 // before proceeding to the next test generator. Once a generator is | |
81 // exhausted, it is ignored in subsequent iterations. | |
82 function* Generate(size, generators) { | |
83 let fixed = 0, flexible = 0; | |
84 for (let gen of generators) { | |
85 if (gen === false) continue; | |
86 if (typeof gen === "string") fixed++; | |
87 else flexible += gen.weight(); | |
88 } | |
89 if (fixed + flexible == 0) throw "Empty list of test generators"; | |
90 let remaining = 0; | |
91 for (let gen of generators) { | |
92 if (gen === false) continue; | |
93 if (typeof gen !== "string") { | |
94 let weight = 1 + gen.weight(); | |
95 gen.initialize(Math.ceil(size * weight / flexible)); | |
96 remaining++; | |
97 } | |
98 } | |
99 for (let once = true; true; once = false) { | |
100 if (remaining == 0) return; | |
101 for (let gen of generators) { | |
102 if (gen === false) continue; | |
103 if (typeof gen === "string") { | |
104 if (once) { | |
105 if (size-- <= 0) return; else yield gen; | |
106 } | |
107 continue; | |
108 } | |
109 if (gen.exhausted()) continue; | |
110 for (let test of gen) { | |
111 if (size-- <= 0) return; else yield test; | |
112 } | |
113 if (gen.exhausted()) remaining--; | |
114 } | |
115 } | |
116 } | |
117 | |
118 // Parameters: | |
119 // size: positive integer | |
120 // generators: [string | TestGen] | |
121 // | |
122 // This function will generate all tests yielded by Generate and will | |
123 // discard the results. It will normally be called with test generators | |
124 // whose transformation functions test for validity (e.g. CheckValid or | |
125 // CheckInvalid) and do not return anything interesting. | |
126 function Test(size, generators) { | |
127 for (let attempt of Generate(size, generators)) continue; | |
128 } | |
129 | |
130 | |
131 // In the rest, for each NonTerminal symbol in the parser grammar that we | |
132 // care to test, there are two generator functions (ValidNonTerminal and | |
133 // InvalidNonTerminal) yielding valid and non valid terms for this symbol. | |
134 // These functions are of the form to be passed to Generate. | |
135 // There is also a test (using the TestNonTerminal function). | |
136 | |
137 | |
138 // Primary types. | |
139 | |
140 function ValidPrimaryTypes(size, proper=false) { | |
141 return Generate(size, [ | |
142 "any", | |
143 "void", | |
144 "this", | |
145 new TestGen(1, ValidTypes, [ | |
146 t => "(" + t + ")" | |
147 ]), | |
148 new TestGen(1, ValidPrimaryTypes, [ | |
149 t => t + "[]", | |
150 t => t + "[][]", | |
151 t => "(" + t + "[])", | |
152 t => "(" + t + "[])[]", | |
153 ]), | |
154 proper && "number", | |
155 proper && "boolean", | |
156 proper && "string", | |
157 proper && "symbol" | |
158 ]); | |
159 } | |
160 | |
161 function InvalidPrimaryTypes(size, proper=false) { | |
162 return Generate(size, [ | |
163 // Undefined variable. Removed, this is a semantic error now. | |
164 // "whatever", | |
165 // Legal parenthesized parameter lists that are not types. | |
166 "()", "(a: number, b: string)", "(x, y, z)", | |
167 // Illegal types in legal places. | |
168 new TestGen(1, InvalidTypes, [ | |
169 t => "(" + t + ")" | |
170 ]), | |
171 new TestGen(1, InvalidPrimaryTypes, [ | |
172 t => t + "[]", | |
173 t => t + "[][]", | |
174 t => "(" + t + "[])", | |
175 t => "(" + t + "[])[]", | |
176 ]), | |
177 // Line terminator in arrays. | |
178 new TestGen(1, ValidTypes, [ | |
179 t => "(" + t + "\n[])" | |
180 ]) | |
181 ]); | |
182 } | |
183 | 16 |
184 (function TestPrimaryTypes(size) { | 17 (function TestPrimaryTypes(size) { |
185 Test(size, [ | 18 Test(size, [ |
186 new TestGen(4, ValidPrimaryTypes, [CheckValid], true), | 19 new TestGen(4, ValidPrimaryTypes, [CheckValid], true), |
187 new TestGen(1, InvalidPrimaryTypes, [CheckInvalid], true) | 20 new TestGen(1, InvalidPrimaryTypes, [CheckInvalid], true) |
188 ]); | 21 ]); |
189 })(test_size); | 22 })(test_size); |
190 | 23 |
191 | 24 |
192 // Intersection types. | |
193 | |
194 function ValidIntersectionTypes(size, proper=false) { | |
195 return Generate(size, [ | |
196 new TestGen(1, ValidPrimaryTypes, [ | |
197 !proper && (t => t), | |
198 t => t + " & " + t, | |
199 t => "(" + t + " & " + t + ") & " + t, | |
200 t => t + " & (" + t + " & " + t + ")", | |
201 t => t + " & " + t + " & " + t | |
202 ]) | |
203 ]); | |
204 } | |
205 | |
206 function InvalidIntersectionTypes(size, proper=false) { | |
207 return Generate(size, [ | |
208 // Illegal types in legal places. | |
209 new TestGen(4, InvalidPrimaryTypes, [ | |
210 !proper && (t => t), | |
211 t => t + " & " + t, | |
212 t => "(" + t + " & " + t + ") & " + t, | |
213 t => t + " & (" + t + " & " + t + ")", | |
214 t => t + " & " + t + " & " + t | |
215 ]), | |
216 // Right hand side is a function or constructor type. | |
217 new TestGen(1, ValidFunctionTypes, [t => "any & " + t], false), | |
218 new TestGen(1, ValidFunctionTypes, [t => "any & " + t], true) | |
219 ]); | |
220 } | |
221 | |
222 (function TestIntersectionTypes(size) { | 25 (function TestIntersectionTypes(size) { |
223 Test(size, [ | 26 Test(size, [ |
224 new TestGen(4, ValidIntersectionTypes, [CheckValid], true), | 27 new TestGen(4, ValidIntersectionTypes, [CheckValid], true), |
225 new TestGen(1, InvalidIntersectionTypes, [CheckInvalid], true) | 28 new TestGen(1, InvalidIntersectionTypes, [CheckInvalid], true) |
226 ]); | 29 ]); |
227 })(test_size); | 30 })(test_size); |
228 | 31 |
229 | 32 |
230 // Union types. | |
231 | |
232 function ValidUnionTypes(size, proper=false) { | |
233 return Generate(size, [ | |
234 new TestGen(1, ValidIntersectionTypes, [ | |
235 !proper && (t => t), | |
236 t => t + " | " + t, | |
237 t => "(" + t + " | " + t + ") | " + t, | |
238 t => t + " | (" + t + " | " + t + ")", | |
239 t => t + " | " + t + " | " + t | |
240 ]) | |
241 ]); | |
242 } | |
243 | |
244 function InvalidUnionTypes(size, proper=false) { | |
245 return Generate(size, [ | |
246 // Illegal types in legal places. | |
247 new TestGen(1, InvalidIntersectionTypes, [ | |
248 !proper && (t => t), | |
249 t => t + " | " + t, | |
250 t => "(" + t + " | " + t + ") | " + t, | |
251 t => t + " | (" + t + " | " + t + ")", | |
252 t => t + " | " + t + " | " + t | |
253 ]), | |
254 // Right hand side is a function or constructor type. | |
255 new TestGen(1, ValidFunctionTypes, [t => "any | " + t], false), | |
256 new TestGen(1, ValidFunctionTypes, [t => "any | " + t], true) | |
257 ]); | |
258 } | |
259 | |
260 (function TestUnionTypes(size) { | 33 (function TestUnionTypes(size) { |
261 Test(size, [ | 34 Test(size, [ |
262 new TestGen(4, ValidUnionTypes, [CheckValid], true), | 35 new TestGen(4, ValidUnionTypes, [CheckValid], true), |
263 new TestGen(1, InvalidUnionTypes, [CheckInvalid], true) | 36 new TestGen(1, InvalidUnionTypes, [CheckInvalid], true) |
264 ]); | 37 ]); |
265 })(test_size); | 38 })(test_size); |
266 | 39 |
267 | 40 |
268 // Function and constructor types. | |
269 | |
270 function ValidFunctionTypes(size, constr) { | |
271 let c = constr ? "new " : ""; | |
272 return Generate(size, [ | |
273 new TestGen(1, ValidTypes, [ | |
274 t => c + "() => " + t, | |
275 t => c + "(a: " + t + ") => " + t, | |
276 t => c + "(a:" + t + ", b?:" + t + ") => " + t, | |
277 t => c + "(a:" + t + ", b?:" + t + ", c) => " + t, | |
278 t => c + "(a:" + t + ", b?:" + t + ", c?) => " + t, | |
279 t => c + "(a:" + t + ", b:" + t + ", c, ...d) => " + t, | |
280 t => c + "(a:" + t + ", b:" + t + ", c, ...d) => " + t, | |
281 t => c + "(a:" + t + ", b:" + t + ", c, ...d: string[]) => " + t | |
282 ]) | |
283 ]); | |
284 } | |
285 | |
286 function InvalidFunctionTypes(size, constr) { | |
287 let c = constr ? "new " : ""; | |
288 return Generate(size, [ | |
289 // Illegal types in legal places. | |
290 new TestGen(1, InvalidTypes, [ | |
291 t => c + "() => " + t, | |
292 t => c + "(a: " + t + ") => " + t, | |
293 t => c + "(a:" + t + ", b?:" + t + ") => " + t, | |
294 t => c + "(a:" + t + ", b?:" + t + ", c) => " + t, | |
295 t => c + "(a:" + t + ", b?:" + t + ", c?) => " + t, | |
296 t => c + "(a:" + t + ", b:" + t + ", c, ...d) => " + t, | |
297 t => c + "(a:" + t + ", b:" + t + ", c, ...d) => " + t, | |
298 t => c + "(a:" + t + ", b:" + t + ", c, ...d: string[]) => " + t | |
299 ]) | |
300 ]); | |
301 } | |
302 | |
303 (function TestFunctionAndConstructorTypes(size) { | 41 (function TestFunctionAndConstructorTypes(size) { |
304 Test(size, [ | 42 Test(size, [ |
305 new TestGen(4, ValidFunctionTypes, [CheckValid], false), | 43 new TestGen(4, ValidFunctionTypes, [CheckValid], false), |
306 new TestGen(1, InvalidFunctionTypes, [CheckInvalid], false), | 44 new TestGen(1, InvalidFunctionTypes, [CheckInvalid], false), |
307 new TestGen(4, ValidFunctionTypes, [CheckValid], true), | 45 new TestGen(4, ValidFunctionTypes, [CheckValid], true), |
308 new TestGen(1, InvalidFunctionTypes, [CheckInvalid], true) | 46 new TestGen(1, InvalidFunctionTypes, [CheckInvalid], true) |
309 ]); | 47 ]); |
310 })(test_size); | 48 })(test_size); |
311 | |
312 | |
313 // All simple types. | |
314 | |
315 function ValidTypes(size) { | |
316 return Generate(size, [ | |
317 new TestGen(3, ValidUnionTypes, [t => t]), | |
318 new TestGen(1, ValidFunctionTypes, [t => t], false), | |
319 ]); | |
320 } | |
321 | |
322 function InvalidTypes(size) { | |
323 return Generate(size, [ | |
324 new TestGen(3, InvalidUnionTypes, [t => t]), | |
325 new TestGen(1, InvalidFunctionTypes, [t => t], false), | |
326 ]); | |
327 } | |
OLD | NEW |