tc39_test.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. package goja
  2. import (
  3. "errors"
  4. "fmt"
  5. "gopkg.in/yaml.v2"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "sort"
  10. "strings"
  11. "sync"
  12. "testing"
  13. "time"
  14. )
  15. const (
  16. tc39BASE = "testdata/test262"
  17. )
  18. var (
  19. invalidFormatError = errors.New("Invalid file format")
  20. ignorableTestError = newSymbol(stringEmpty)
  21. sabStub = MustCompile("sabStub.js", `
  22. Object.defineProperty(this, "SharedArrayBuffer", {
  23. get: function() {
  24. throw IgnorableTestError;
  25. }
  26. });`,
  27. false)
  28. )
  29. var (
  30. skipList = map[string]bool{
  31. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-8.js": true, // timezone
  32. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-9.js": true, // timezone
  33. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js": true, // timezone
  34. // \u{xxxxx}
  35. "test/annexB/built-ins/escape/escape-above-astral.js": true,
  36. "test/built-ins/RegExp/prototype/source/value-u.js": true,
  37. // SharedArrayBuffer
  38. "test/built-ins/ArrayBuffer/prototype/slice/this-is-sharedarraybuffer.js": true,
  39. // class
  40. "test/language/statements/class/subclass/builtin-objects/Symbol/symbol-valid-as-extends-value.js": true,
  41. "test/language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js": true,
  42. "test/language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js": true,
  43. "test/language/statements/class/subclass/builtin-objects/WeakSet/regular-subclassing.js": true,
  44. "test/language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js": true,
  45. "test/language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js": true,
  46. "test/language/statements/class/subclass/builtin-objects/Map/super-must-be-called.js": true,
  47. "test/language/statements/class/subclass/builtin-objects/Map/regular-subclassing.js": true,
  48. "test/language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js": true,
  49. "test/language/statements/class/subclass/builtin-objects/Set/regular-subclassing.js": true,
  50. "test/language/statements/class/subclass/builtin-objects/Object/replacing-prototype.js": true,
  51. "test/language/statements/class/subclass/builtin-objects/Object/regular-subclassing.js": true,
  52. "test/built-ins/Array/prototype/concat/Array.prototype.concat_non-array.js": true,
  53. "test/language/statements/class/subclass/builtin-objects/Array/length.js": true,
  54. "test/language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js": true,
  55. "test/language/statements/class/subclass/builtin-objects/TypedArray/regular-subclassing.js": true,
  56. "test/language/statements/class/subclass/builtin-objects/DataView/super-must-be-called.js": true,
  57. "test/language/statements/class/subclass/builtin-objects/DataView/regular-subclassing.js": true,
  58. "test/language/statements/class/subclass/builtin-objects/String/super-must-be-called.js": true,
  59. "test/language/statements/class/subclass/builtin-objects/String/regular-subclassing.js": true,
  60. "test/language/statements/class/subclass/builtin-objects/String/length.js": true,
  61. "test/language/statements/class/subclass/builtin-objects/Date/super-must-be-called.js": true,
  62. "test/language/statements/class/subclass/builtin-objects/Date/regular-subclassing.js": true,
  63. "test/language/statements/class/subclass/builtin-objects/Number/super-must-be-called.js": true,
  64. "test/language/statements/class/subclass/builtin-objects/Number/regular-subclassing.js": true,
  65. "test/language/statements/class/subclass/builtin-objects/Function/super-must-be-called.js": true,
  66. "test/language/statements/class/subclass/builtin-objects/Function/regular-subclassing.js": true,
  67. "test/language/statements/class/subclass/builtin-objects/Function/instance-name.js": true,
  68. "test/language/statements/class/subclass/builtin-objects/Function/instance-length.js": true,
  69. "test/language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called.js": true,
  70. "test/language/statements/class/subclass/builtin-objects/Boolean/regular-subclassing.js": true,
  71. "test/language/statements/class/subclass/builtin-objects/NativeError/URIError-super.js": true,
  72. "test/language/statements/class/subclass/builtin-objects/NativeError/URIError-name.js": true,
  73. "test/language/statements/class/subclass/builtin-objects/NativeError/URIError-message.js": true,
  74. "test/language/statements/class/subclass/builtin-objects/NativeError/TypeError-super.js": true,
  75. "test/language/statements/class/subclass/builtin-objects/NativeError/TypeError-name.js": true,
  76. "test/language/statements/class/subclass/builtin-objects/NativeError/TypeError-message.js": true,
  77. "test/language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-super.js": true,
  78. "test/language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-name.js": true,
  79. "test/language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-message.js": true,
  80. "test/language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-super.js": true,
  81. "test/language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-name.js": true,
  82. "test/language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-message.js": true,
  83. "test/language/statements/class/subclass/builtin-objects/NativeError/RangeError-super.js": true,
  84. "test/language/statements/class/subclass/builtin-objects/NativeError/RangeError-name.js": true,
  85. "test/language/statements/class/subclass/builtin-objects/NativeError/RangeError-message.js": true,
  86. "test/language/statements/class/subclass/builtin-objects/NativeError/EvalError-super.js": true,
  87. "test/language/statements/class/subclass/builtin-objects/NativeError/EvalError-name.js": true,
  88. "test/language/statements/class/subclass/builtin-objects/NativeError/EvalError-message.js": true,
  89. "test/language/statements/class/subclass/builtin-objects/Error/super-must-be-called.js": true,
  90. "test/language/statements/class/subclass/builtin-objects/Error/regular-subclassing.js": true,
  91. "test/language/statements/class/subclass/builtin-objects/Error/message-property-assignment.js": true,
  92. "test/language/statements/class/subclass/builtin-objects/Array/super-must-be-called.js": true,
  93. "test/language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js": true,
  94. "test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js": true,
  95. "test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js": true,
  96. "test/language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js": true,
  97. "test/language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js": true,
  98. "test/built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js": true,
  99. "test/built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js": true,
  100. "test/language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.js": true,
  101. "test/language/statements/class/subclass/builtin-objects/RegExp/regular-subclassing.js": true,
  102. "test/language/statements/class/subclass/builtin-objects/RegExp/lastIndex.js": true,
  103. // object literals
  104. "test/built-ins/Array/from/source-object-iterator-1.js": true,
  105. "test/built-ins/Array/from/source-object-iterator-2.js": true,
  106. "test/built-ins/TypedArray/prototype/fill/fill-values-conversion-once.js": true,
  107. "test/built-ins/TypedArrays/of/this-is-not-constructor.js": true,
  108. "test/built-ins/TypedArrays/of/argument-number-value-throws.js": true,
  109. "test/built-ins/TypedArrays/from/this-is-not-constructor.js": true,
  110. "test/built-ins/TypedArrays/from/set-value-abrupt-completion.js": true,
  111. "test/built-ins/TypedArrays/from/property-abrupt-completion.js": true,
  112. "test/built-ins/TypedArray/of/this-is-not-constructor.js": true,
  113. "test/built-ins/TypedArray/from/this-is-not-constructor.js": true,
  114. "test/built-ins/DataView/custom-proto-access-throws.js": true,
  115. "test/built-ins/DataView/custom-proto-access-throws-sab.js": true,
  116. "test/built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js": true,
  117. "test/built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js": true,
  118. "test/built-ins/Array/prototype/splice/property-traps-order-with-species.js": true,
  119. "test/built-ins/Date/prototype/toJSON/invoke-abrupt.js": true,
  120. "test/built-ins/String/prototype/indexOf/position-tointeger-errors.js": true,
  121. "test/built-ins/String/prototype/indexOf/position-tointeger-toprimitive.js": true,
  122. "test/built-ins/String/prototype/indexOf/position-tointeger-wrapped-values.js": true,
  123. "test/built-ins/String/prototype/indexOf/searchstring-tostring-errors.js": true,
  124. "test/built-ins/String/prototype/indexOf/searchstring-tostring-toprimitive.js": true,
  125. "test/built-ins/String/prototype/indexOf/searchstring-tostring-wrapped-values.js": true,
  126. "test/built-ins/String/prototype/split/separator-undef-limit-zero.js": true,
  127. "test/built-ins/String/prototype/trimEnd/this-value-object-cannot-convert-to-primitive-err.js": true,
  128. "test/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-call-err.js": true,
  129. "test/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-meth-err.js": true,
  130. "test/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-meth-priority.js": true,
  131. "test/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-returns-object-err.js": true,
  132. "test/built-ins/String/prototype/trimEnd/this-value-object-tostring-call-err.js": true,
  133. "test/built-ins/String/prototype/trimEnd/this-value-object-tostring-meth-err.js": true,
  134. "test/built-ins/String/prototype/trimEnd/this-value-object-tostring-meth-priority.js": true,
  135. "test/built-ins/String/prototype/trimEnd/this-value-object-tostring-returns-object-err.js": true,
  136. "test/built-ins/String/prototype/trimEnd/this-value-object-valueof-call-err.js": true,
  137. "test/built-ins/String/prototype/trimEnd/this-value-object-valueof-meth-err.js": true,
  138. "test/built-ins/String/prototype/trimEnd/this-value-object-valueof-meth-priority.js": true,
  139. "test/built-ins/String/prototype/trimEnd/this-value-object-valueof-returns-object-err.js": true,
  140. "test/built-ins/String/prototype/trimStart/this-value-object-cannot-convert-to-primitive-err.js": true,
  141. "test/built-ins/String/prototype/trimStart/this-value-object-toprimitive-call-err.js": true,
  142. "test/built-ins/String/prototype/trimStart/this-value-object-toprimitive-meth-err.js": true,
  143. "test/built-ins/String/prototype/trimStart/this-value-object-toprimitive-meth-priority.js": true,
  144. "test/built-ins/String/prototype/trimStart/this-value-object-toprimitive-returns-object-err.js": true,
  145. "test/built-ins/String/prototype/trimStart/this-value-object-tostring-call-err.js": true,
  146. "test/built-ins/String/prototype/trimStart/this-value-object-tostring-meth-err.js": true,
  147. "test/built-ins/String/prototype/trimStart/this-value-object-tostring-meth-priority.js": true,
  148. "test/built-ins/String/prototype/trimStart/this-value-object-tostring-returns-object-err.js": true,
  149. "test/built-ins/String/prototype/trimStart/this-value-object-valueof-call-err.js": true,
  150. "test/built-ins/String/prototype/trimStart/this-value-object-valueof-meth-err.js": true,
  151. "test/built-ins/String/prototype/trimStart/this-value-object-valueof-meth-priority.js": true,
  152. "test/built-ins/String/prototype/trimStart/this-value-object-valueof-returns-object-err.js": true,
  153. "test/built-ins/TypedArray/prototype/sort/sort-tonumber.js": true,
  154. "test/built-ins/TypedArrayConstructors/from/property-abrupt-completion.js": true,
  155. "test/built-ins/TypedArrayConstructors/from/set-value-abrupt-completion.js": true,
  156. "test/built-ins/TypedArrayConstructors/from/this-is-not-constructor.js": true,
  157. "test/built-ins/TypedArrayConstructors/of/argument-number-value-throws.js": true,
  158. "test/built-ins/TypedArrayConstructors/of/this-is-not-constructor.js": true,
  159. "test/built-ins/Array/prototype/flatMap/array-like-objects.js": true,
  160. "test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js": true,
  161. "test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js": true,
  162. "test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js": true,
  163. "test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js": true,
  164. "test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js": true,
  165. "test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js": true,
  166. "test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js": true,
  167. // arrow-function
  168. "test/built-ins/Object/prototype/toString/proxy-function.js": true,
  169. "test/built-ins/Array/prototype/pop/throws-with-string-receiver.js": true,
  170. "test/built-ins/Array/prototype/push/throws-with-string-receiver.js": true,
  171. "test/built-ins/Array/prototype/shift/throws-with-string-receiver.js": true,
  172. "test/built-ins/Array/prototype/unshift/throws-with-string-receiver.js": true,
  173. "test/built-ins/Date/prototype/toString/non-date-receiver.js": true,
  174. "test/built-ins/Number/prototype/toExponential/range.js": true,
  175. "test/built-ins/Number/prototype/toFixed/range.js": true,
  176. "test/built-ins/Number/prototype/toPrecision/range.js": true,
  177. // template strings
  178. "test/built-ins/String/raw/zero-literal-segments.js": true,
  179. "test/built-ins/String/raw/template-substitutions-are-appended-on-same-index.js": true,
  180. "test/built-ins/String/raw/special-characters.js": true,
  181. "test/built-ins/String/raw/return-the-string-value-from-template.js": true,
  182. "test/built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js": true,
  183. // restricted unicode regexp syntax
  184. "test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js": true,
  185. "test/built-ins/RegExp/unicode_restricted_octal_escape.js": true,
  186. "test/built-ins/RegExp/unicode_restricted_incomple_quantifier.js": true,
  187. "test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js": true,
  188. "test/built-ins/RegExp/unicode_restricted_identity_escape_x.js": true,
  189. "test/built-ins/RegExp/unicode_restricted_identity_escape_u.js": true,
  190. "test/built-ins/RegExp/unicode_restricted_identity_escape_c.js": true,
  191. "test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js": true,
  192. "test/built-ins/RegExp/unicode_restricted_identity_escape.js": true,
  193. "test/built-ins/RegExp/unicode_restricted_brackets.js": true,
  194. "test/built-ins/RegExp/unicode_restricted_character_class_escape.js": true,
  195. "test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js": true,
  196. // regexp named groups
  197. "test/built-ins/RegExp/prototype/Symbol.replace/named-groups-fn.js": true,
  198. "test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-err.js": true,
  199. "test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop-err.js": true,
  200. "test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups-prop.js": true,
  201. "test/built-ins/RegExp/prototype/Symbol.replace/result-coerce-groups.js": true,
  202. "test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-err.js": true,
  203. "test/built-ins/RegExp/prototype/Symbol.replace/result-get-groups-prop-err.js": true,
  204. // Because goja parser works in UTF-8 it is not possible to pass strings containing invalid UTF-16 code points.
  205. // This is mitigated by escaping them as \uXXXX, however because of this the RegExp source becomes
  206. // `\uXXXX` instead of `<the actual UTF-16 code point of XXXX>`.
  207. // The resulting RegExp will work exactly the same, but it causes these two tests to fail.
  208. "test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js": true,
  209. "test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js": true,
  210. // Promise
  211. "test/built-ins/Symbol/species/builtin-getter-name.js": true,
  212. // x ** y
  213. "test/built-ins/Array/prototype/pop/clamps-to-integer-limit.js": true,
  214. "test/built-ins/Array/prototype/pop/length-near-integer-limit.js": true,
  215. "test/built-ins/Array/prototype/push/clamps-to-integer-limit.js": true,
  216. "test/built-ins/Array/prototype/push/length-near-integer-limit.js": true,
  217. "test/built-ins/Array/prototype/push/throws-if-integer-limit-exceeded.js": true,
  218. "test/built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js": true,
  219. "test/built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js": true,
  220. "test/built-ins/Array/prototype/slice/length-exceeding-integer-limit.js": true,
  221. "test/built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js": true,
  222. "test/built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js": true,
  223. "test/built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js": true,
  224. "test/built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js": true,
  225. "test/built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded.js": true,
  226. "test/built-ins/Array/prototype/unshift/clamps-to-integer-limit.js": true,
  227. "test/built-ins/Array/prototype/unshift/length-near-integer-limit.js": true,
  228. "test/built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js": true,
  229. "test/built-ins/String/prototype/split/separator-undef-limit-custom.js": true,
  230. // block-scoped vars
  231. "test/built-ins/Array/prototype/sort/stability-11-elements.js": true,
  232. "test/built-ins/Array/prototype/sort/stability-2048-elements.js": true,
  233. "test/built-ins/Array/prototype/sort/stability-5-elements.js": true,
  234. "test/built-ins/Array/prototype/sort/stability-513-elements.js": true,
  235. "test/built-ins/Date/parse/time-value-maximum-range.js": true,
  236. "test/built-ins/Date/parse/without-utc-offset.js": true,
  237. "test/built-ins/Date/parse/zero.js": true,
  238. "test/built-ins/Date/prototype/toDateString/format.js": true,
  239. "test/built-ins/Date/prototype/toString/format.js": true,
  240. "test/built-ins/Date/prototype/toTimeString/format.js": true,
  241. "test/built-ins/Date/prototype/toUTCString/format.js": true,
  242. "test/built-ins/Number/prototype/toString/a-z.js": true,
  243. "test/built-ins/RegExp/named-groups/functional-replace-global.js": true,
  244. "test/built-ins/RegExp/named-groups/functional-replace-non-global.js": true,
  245. "test/built-ins/RegExp/prototype/Symbol.replace/poisoned-stdlib.js": true,
  246. "test/built-ins/TypedArray/prototype/sort/stability.js": true,
  247. "test/annexB/built-ins/RegExp/prototype/compile/this-cross-realm-instance.js": true,
  248. "test/annexB/built-ins/RegExp/prototype/compile/this-subclass-instance.js": true,
  249. "test/built-ins/Array/prototype/flatMap/proxy-access-count.js": true,
  250. "test/built-ins/Array/prototype/flat/proxy-access-count.js": true,
  251. // generators
  252. "test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js": true,
  253. }
  254. featuresBlackList = []string{
  255. "arrow-function",
  256. "BigInt",
  257. "generators",
  258. "String.prototype.replaceAll",
  259. }
  260. es6WhiteList = map[string]bool{}
  261. es6IdWhiteList = []string{
  262. "8.1.2.1",
  263. "9.5",
  264. "12.9.3",
  265. "12.9.4",
  266. "19.1",
  267. "19.2",
  268. "19.3",
  269. "19.4",
  270. "19.5",
  271. "20.1",
  272. "20.2",
  273. "20.3",
  274. "21.1",
  275. "21.2",
  276. "22.1",
  277. "22.2",
  278. "23.1",
  279. "23.2",
  280. "23.3",
  281. "23.4",
  282. "24.1",
  283. "24.2",
  284. "24.3",
  285. "25.1.2",
  286. "26.1",
  287. "26.2",
  288. "B.2.1",
  289. "B.2.2",
  290. }
  291. esIdPrefixWhiteList = []string{
  292. "sec-array",
  293. "sec-%typedarray%",
  294. "sec-string",
  295. "sec-date",
  296. "sec-number",
  297. "sec-math",
  298. "sec-arraybuffer-length",
  299. "sec-arraybuffer",
  300. "sec-regexp",
  301. "sec-string.prototype.trimLeft",
  302. "sec-string.prototype.trimRight",
  303. "sec-object.getownpropertydescriptors",
  304. }
  305. )
  306. type tc39Test struct {
  307. name string
  308. f func(t *testing.T)
  309. }
  310. type tc39BenchmarkItem struct {
  311. name string
  312. duration time.Duration
  313. }
  314. type tc39BenchmarkData []tc39BenchmarkItem
  315. type tc39TestCtx struct {
  316. base string
  317. t *testing.T
  318. prgCache map[string]*Program
  319. prgCacheLock sync.Mutex
  320. enableBench bool
  321. benchmark tc39BenchmarkData
  322. benchLock sync.Mutex
  323. testQueue []tc39Test
  324. }
  325. type TC39MetaNegative struct {
  326. Phase, Type string
  327. }
  328. type tc39Meta struct {
  329. Negative TC39MetaNegative
  330. Includes []string
  331. Flags []string
  332. Features []string
  333. Es5id string
  334. Es6id string
  335. Esid string
  336. }
  337. func (m *tc39Meta) hasFlag(flag string) bool {
  338. for _, f := range m.Flags {
  339. if f == flag {
  340. return true
  341. }
  342. }
  343. return false
  344. }
  345. func parseTC39File(name string) (*tc39Meta, string, error) {
  346. f, err := os.Open(name)
  347. if err != nil {
  348. return nil, "", err
  349. }
  350. defer f.Close()
  351. b, err := ioutil.ReadAll(f)
  352. if err != nil {
  353. return nil, "", err
  354. }
  355. str := string(b)
  356. metaStart := strings.Index(str, "/*---")
  357. if metaStart == -1 {
  358. return nil, "", invalidFormatError
  359. } else {
  360. metaStart += 5
  361. }
  362. metaEnd := strings.Index(str, "---*/")
  363. if metaEnd == -1 || metaEnd <= metaStart {
  364. return nil, "", invalidFormatError
  365. }
  366. var meta tc39Meta
  367. err = yaml.Unmarshal([]byte(str[metaStart:metaEnd]), &meta)
  368. if err != nil {
  369. return nil, "", err
  370. }
  371. if meta.Negative.Type != "" && meta.Negative.Phase == "" {
  372. return nil, "", errors.New("negative type is set, but phase isn't")
  373. }
  374. return &meta, str, nil
  375. }
  376. func (*tc39TestCtx) detachArrayBuffer(call FunctionCall) Value {
  377. if obj, ok := call.Argument(0).(*Object); ok {
  378. if buf, ok := obj.self.(*arrayBufferObject); ok {
  379. buf.detach()
  380. return _undefined
  381. }
  382. }
  383. panic(typeError("detachArrayBuffer() is called with incompatible argument"))
  384. }
  385. func (*tc39TestCtx) throwIgnorableTestError(FunctionCall) Value {
  386. panic(ignorableTestError)
  387. }
  388. func (ctx *tc39TestCtx) runTC39Test(name, src string, meta *tc39Meta, t testing.TB) {
  389. defer func() {
  390. if x := recover(); x != nil {
  391. panic(fmt.Sprintf("panic while running %s: %v", name, x))
  392. }
  393. }()
  394. vm := New()
  395. _262 := vm.NewObject()
  396. _262.Set("detachArrayBuffer", ctx.detachArrayBuffer)
  397. _262.Set("createRealm", ctx.throwIgnorableTestError)
  398. vm.Set("$262", _262)
  399. vm.Set("IgnorableTestError", ignorableTestError)
  400. vm.Set("print", t.Log)
  401. vm.RunProgram(sabStub)
  402. err, early := ctx.runTC39Script(name, src, meta.Includes, vm)
  403. if err != nil {
  404. if meta.Negative.Type == "" {
  405. if err, ok := err.(*Exception); ok {
  406. if err.Value() == ignorableTestError {
  407. t.Skip("Test threw IgnorableTestError")
  408. }
  409. }
  410. t.Fatalf("%s: %v", name, err)
  411. } else {
  412. if (meta.Negative.Phase == "early" || meta.Negative.Phase == "parse") && !early || meta.Negative.Phase == "runtime" && early {
  413. t.Fatalf("%s: error %v happened at the wrong phase (expected %s)", name, err, meta.Negative.Phase)
  414. }
  415. var errType string
  416. switch err := err.(type) {
  417. case *Exception:
  418. if o, ok := err.Value().(*Object); ok {
  419. if c := o.Get("constructor"); c != nil {
  420. if c, ok := c.(*Object); ok {
  421. errType = c.Get("name").String()
  422. } else {
  423. t.Fatalf("%s: error constructor is not an object (%v)", name, o)
  424. }
  425. } else {
  426. t.Fatalf("%s: error does not have a constructor (%v)", name, o)
  427. }
  428. } else {
  429. t.Fatalf("%s: error is not an object (%v)", name, err.Value())
  430. }
  431. case *CompilerSyntaxError:
  432. errType = "SyntaxError"
  433. case *CompilerReferenceError:
  434. errType = "ReferenceError"
  435. default:
  436. t.Fatalf("%s: error is not a JS error: %v", name, err)
  437. }
  438. if errType != meta.Negative.Type {
  439. vm.vm.prg.dumpCode(t.Logf)
  440. t.Fatalf("%s: unexpected error type (%s), expected (%s)", name, errType, meta.Negative.Type)
  441. }
  442. }
  443. } else {
  444. if meta.Negative.Type != "" {
  445. vm.vm.prg.dumpCode(t.Logf)
  446. t.Fatalf("%s: Expected error: %v", name, err)
  447. }
  448. }
  449. if vm.vm.sp != 0 {
  450. t.Fatalf("sp: %d", vm.vm.sp)
  451. }
  452. if l := len(vm.vm.iterStack); l > 0 {
  453. t.Fatalf("iter stack is not empty: %d", l)
  454. }
  455. }
  456. func (ctx *tc39TestCtx) runTC39File(name string, t testing.TB) {
  457. if skipList[name] {
  458. t.Skip("Excluded")
  459. }
  460. p := path.Join(ctx.base, name)
  461. meta, src, err := parseTC39File(p)
  462. if err != nil {
  463. //t.Fatalf("Could not parse %s: %v", name, err)
  464. t.Errorf("Could not parse %s: %v", name, err)
  465. return
  466. }
  467. if meta.Es5id == "" {
  468. skip := true
  469. //t.Logf("%s: Not ES5, skipped", name)
  470. if es6WhiteList[name] {
  471. skip = false
  472. } else {
  473. if meta.Es6id != "" {
  474. for _, prefix := range es6IdWhiteList {
  475. if strings.HasPrefix(meta.Es6id, prefix) &&
  476. (len(meta.Es6id) == len(prefix) || meta.Es6id[len(prefix)] == '.') {
  477. skip = false
  478. break
  479. }
  480. }
  481. }
  482. }
  483. if skip {
  484. if meta.Esid != "" {
  485. for _, prefix := range esIdPrefixWhiteList {
  486. if strings.HasPrefix(meta.Esid, prefix) &&
  487. (len(meta.Esid) == len(prefix) || meta.Esid[len(prefix)] == '.') {
  488. skip = false
  489. break
  490. }
  491. }
  492. }
  493. }
  494. if skip {
  495. t.Skip("Not ES5")
  496. }
  497. for _, feature := range meta.Features {
  498. for _, bl := range featuresBlackList {
  499. if feature == bl {
  500. t.Skip("Blacklisted feature")
  501. }
  502. }
  503. }
  504. }
  505. var startTime time.Time
  506. if ctx.enableBench {
  507. startTime = time.Now()
  508. }
  509. hasRaw := meta.hasFlag("raw")
  510. if hasRaw || !meta.hasFlag("onlyStrict") {
  511. //log.Printf("Running normal test: %s", name)
  512. t.Logf("Running normal test: %s", name)
  513. ctx.runTC39Test(name, src, meta, t)
  514. }
  515. if !hasRaw && !meta.hasFlag("noStrict") {
  516. //log.Printf("Running strict test: %s", name)
  517. t.Logf("Running strict test: %s", name)
  518. ctx.runTC39Test(name, "'use strict';\n"+src, meta, t)
  519. }
  520. if ctx.enableBench {
  521. ctx.benchLock.Lock()
  522. ctx.benchmark = append(ctx.benchmark, tc39BenchmarkItem{
  523. name: name,
  524. duration: time.Since(startTime),
  525. })
  526. ctx.benchLock.Unlock()
  527. }
  528. }
  529. func (ctx *tc39TestCtx) init() {
  530. ctx.prgCache = make(map[string]*Program)
  531. }
  532. func (ctx *tc39TestCtx) compile(base, name string) (*Program, error) {
  533. ctx.prgCacheLock.Lock()
  534. defer ctx.prgCacheLock.Unlock()
  535. prg := ctx.prgCache[name]
  536. if prg == nil {
  537. fname := path.Join(base, name)
  538. f, err := os.Open(fname)
  539. if err != nil {
  540. return nil, err
  541. }
  542. defer f.Close()
  543. b, err := ioutil.ReadAll(f)
  544. if err != nil {
  545. return nil, err
  546. }
  547. str := string(b)
  548. prg, err = Compile(name, str, false)
  549. if err != nil {
  550. return nil, err
  551. }
  552. ctx.prgCache[name] = prg
  553. }
  554. return prg, nil
  555. }
  556. func (ctx *tc39TestCtx) runFile(base, name string, vm *Runtime) error {
  557. prg, err := ctx.compile(base, name)
  558. if err != nil {
  559. return err
  560. }
  561. _, err = vm.RunProgram(prg)
  562. return err
  563. }
  564. func (ctx *tc39TestCtx) runTC39Script(name, src string, includes []string, vm *Runtime) (err error, early bool) {
  565. early = true
  566. err = ctx.runFile(ctx.base, path.Join("harness", "assert.js"), vm)
  567. if err != nil {
  568. return
  569. }
  570. err = ctx.runFile(ctx.base, path.Join("harness", "sta.js"), vm)
  571. if err != nil {
  572. return
  573. }
  574. for _, include := range includes {
  575. err = ctx.runFile(ctx.base, path.Join("harness", include), vm)
  576. if err != nil {
  577. return
  578. }
  579. }
  580. var p *Program
  581. p, err = Compile(name, src, false)
  582. if err != nil {
  583. return
  584. }
  585. early = false
  586. _, err = vm.RunProgram(p)
  587. return
  588. }
  589. func (ctx *tc39TestCtx) runTC39Tests(name string) {
  590. files, err := ioutil.ReadDir(path.Join(ctx.base, name))
  591. if err != nil {
  592. ctx.t.Fatal(err)
  593. }
  594. for _, file := range files {
  595. if file.Name()[0] == '.' {
  596. continue
  597. }
  598. if file.IsDir() {
  599. ctx.runTC39Tests(path.Join(name, file.Name()))
  600. } else {
  601. fileName := file.Name()
  602. if strings.HasSuffix(fileName, ".js") && !strings.HasSuffix(fileName, "_FIXTURE.js") {
  603. name := path.Join(name, fileName)
  604. ctx.runTest(name, func(t *testing.T) {
  605. ctx.runTC39File(name, t)
  606. })
  607. }
  608. }
  609. }
  610. }
  611. func TestTC39(t *testing.T) {
  612. if testing.Short() {
  613. t.Skip()
  614. }
  615. if _, err := os.Stat(tc39BASE); err != nil {
  616. t.Skipf("If you want to run tc39 tests, download them from https://github.com/tc39/test262 and put into %s. The current working commit is ddfe24afe3043388827aa220ef623b8540958bbd. (%v)", tc39BASE, err)
  617. }
  618. // at 1ba3a7c4a93fc93b3d0d7e4146f59934a896837d
  619. // Tests ignored: 10,453, passed: 14,782
  620. // at ddfe24afe3043388827aa220ef623b8540958bbd
  621. // Tests ignored: 19,244, passed: 14,443
  622. ctx := &tc39TestCtx{
  623. base: tc39BASE,
  624. }
  625. ctx.init()
  626. //ctx.enableBench = true
  627. t.Run("tc39", func(t *testing.T) {
  628. ctx.t = t
  629. //ctx.runTC39File("test/language/types/number/8.5.1.js", t)
  630. //ctx.runTC39Tests("test/language")
  631. ctx.runTC39Tests("test/language/expressions")
  632. ctx.runTC39Tests("test/language/arguments-object")
  633. ctx.runTC39Tests("test/language/asi")
  634. ctx.runTC39Tests("test/language/directive-prologue")
  635. ctx.runTC39Tests("test/language/function-code")
  636. ctx.runTC39Tests("test/language/eval-code")
  637. ctx.runTC39Tests("test/language/global-code")
  638. ctx.runTC39Tests("test/language/identifier-resolution")
  639. ctx.runTC39Tests("test/language/identifiers")
  640. //ctx.runTC39Tests("test/language/literals") // octal sequences in strict mode
  641. ctx.runTC39Tests("test/language/punctuators")
  642. ctx.runTC39Tests("test/language/reserved-words")
  643. ctx.runTC39Tests("test/language/source-text")
  644. ctx.runTC39Tests("test/language/statements")
  645. ctx.runTC39Tests("test/language/types")
  646. ctx.runTC39Tests("test/language/white-space")
  647. ctx.runTC39Tests("test/built-ins")
  648. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/substr")
  649. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimLeft")
  650. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimRight")
  651. ctx.runTC39Tests("test/annexB/built-ins/escape")
  652. ctx.runTC39Tests("test/annexB/built-ins/unescape")
  653. ctx.runTC39Tests("test/annexB/built-ins/RegExp")
  654. ctx.flush()
  655. })
  656. if ctx.enableBench {
  657. sort.Slice(ctx.benchmark, func(i, j int) bool {
  658. return ctx.benchmark[i].duration > ctx.benchmark[j].duration
  659. })
  660. bench := ctx.benchmark
  661. if len(bench) > 50 {
  662. bench = bench[:50]
  663. }
  664. for _, item := range bench {
  665. fmt.Printf("%s\t%d\n", item.name, item.duration/time.Millisecond)
  666. }
  667. }
  668. }