| 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 | 
|---|