tc39_test.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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. skipPrefixes prefixList
  31. skipList = map[string]bool{
  32. // timezone
  33. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-8.js": true,
  34. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-9.js": true,
  35. "test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js": true,
  36. // floating point date calculations
  37. "test/built-ins/Date/UTC/fp-evaluation-order.js": true,
  38. // quantifier integer limit in regexp
  39. "test/built-ins/RegExp/quantifier-integer-limit.js": true,
  40. // GetFunctionRealm
  41. "test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js": true,
  42. // Go 1.14 supports unicode 12
  43. "test/language/identifiers/start-unicode-13.0.0.js": true,
  44. "test/language/identifiers/start-unicode-13.0.0-escaped.js": true,
  45. "test/language/identifiers/start-unicode-14.0.0.js": true,
  46. "test/language/identifiers/start-unicode-14.0.0-escaped.js": true,
  47. "test/language/identifiers/part-unicode-13.0.0.js": true,
  48. "test/language/identifiers/part-unicode-13.0.0-escaped.js": true,
  49. "test/language/identifiers/part-unicode-14.0.0.js": true,
  50. "test/language/identifiers/part-unicode-14.0.0-escaped.js": true,
  51. // class
  52. "test/built-ins/Array/prototype/concat/Array.prototype.concat_non-array.js": true,
  53. "test/built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js": true,
  54. "test/built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js": true,
  55. "test/language/expressions/object/method-definition/name-invoke-ctor.js": true,
  56. "test/language/expressions/object/method.js": true,
  57. "test/language/expressions/object/setter-super-prop.js": true,
  58. "test/language/expressions/object/getter-super-prop.js": true,
  59. "test/language/expressions/delete/super-property.js": true,
  60. "test/language/statements/let/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  61. "test/language/statements/let/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  62. "test/language/statements/for/dstr/var-obj-ptrn-id-init-fn-name-class.js": true,
  63. "test/language/statements/for/dstr/var-ary-ptrn-elem-id-init-fn-name-class.js": true,
  64. "test/language/statements/for/dstr/let-ary-ptrn-elem-id-init-fn-name-class.js": true,
  65. "test/language/statements/for/dstr/let-obj-ptrn-id-init-fn-name-class.js": true,
  66. "test/language/statements/const/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  67. "test/language/statements/for/dstr/const-obj-ptrn-id-init-fn-name-class.js": true,
  68. "test/language/statements/const/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  69. "test/language/statements/for/dstr/const-ary-ptrn-elem-id-init-fn-name-class.js": true,
  70. "test/language/statements/variable/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  71. "test/language/statements/variable/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  72. "test/language/expressions/object/method-definition/name-name-prop-symbol.js": true,
  73. "test/language/expressions/function/dstr/dflt-obj-ptrn-id-init-fn-name-class.js": true,
  74. "test/language/expressions/function/dstr/dflt-ary-ptrn-elem-id-init-fn-name-class.js": true,
  75. "test/language/expressions/function/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  76. "test/language/expressions/function/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  77. "test/language/statements/function/dstr/dflt-ary-ptrn-elem-id-init-fn-name-class.js": true,
  78. "test/language/statements/function/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  79. "test/language/statements/function/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  80. "test/language/statements/function/dstr/dflt-obj-ptrn-id-init-fn-name-class.js": true,
  81. "test/language/expressions/arrow-function/scope-paramsbody-var-open.js": true,
  82. "test/language/expressions/arrow-function/scope-paramsbody-var-close.js": true,
  83. "test/language/expressions/arrow-function/scope-body-lex-distinct.js": true,
  84. "test/language/statements/for-of/dstr/var-ary-ptrn-elem-id-init-fn-name-class.js": true,
  85. "test/language/statements/for-of/dstr/var-obj-ptrn-id-init-fn-name-class.js": true,
  86. "test/language/statements/for-of/dstr/const-obj-ptrn-id-init-fn-name-class.js": true,
  87. "test/language/statements/for-of/dstr/let-obj-ptrn-id-init-fn-name-class.js": true,
  88. "test/language/statements/for-of/dstr/const-ary-ptrn-elem-id-init-fn-name-class.js": true,
  89. "test/language/statements/for-of/dstr/let-ary-ptrn-elem-id-init-fn-name-class.js": true,
  90. "test/language/statements/try/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  91. "test/language/statements/try/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  92. "test/language/expressions/arrow-function/dstr/ary-ptrn-elem-id-init-fn-name-class.js": true,
  93. "test/language/expressions/arrow-function/dstr/dflt-obj-ptrn-id-init-fn-name-class.js": true,
  94. "test/language/expressions/arrow-function/dstr/obj-ptrn-id-init-fn-name-class.js": true,
  95. "test/language/expressions/arrow-function/dstr/dflt-ary-ptrn-elem-id-init-fn-name-class.js": true,
  96. "test/language/expressions/arrow-function/lexical-super-property-from-within-constructor.js": true,
  97. "test/language/expressions/arrow-function/lexical-super-property.js": true,
  98. "test/language/expressions/arrow-function/lexical-supercall-from-immediately-invoked-arrow.js": true,
  99. "test/built-ins/Promise/prototype/finally/subclass-species-constructor-resolve-count.js": true,
  100. "test/built-ins/Promise/prototype/finally/subclass-species-constructor-reject-count.js": true,
  101. "test/built-ins/Promise/prototype/finally/subclass-resolve-count.js": true,
  102. "test/built-ins/Promise/prototype/finally/species-symbol.js": true,
  103. "test/built-ins/Promise/prototype/finally/subclass-reject-count.js": true,
  104. "test/built-ins/Promise/prototype/finally/species-constructor.js": true,
  105. "test/language/statements/switch/scope-lex-class.js": true,
  106. "test/language/expressions/arrow-function/lexical-super-call-from-within-constructor.js": true,
  107. "test/language/expressions/object/dstr/meth-dflt-ary-ptrn-elem-id-init-fn-name-class.js": true,
  108. "test/language/expressions/object/dstr/meth-ary-ptrn-elem-id-init-fn-name-class.js": true,
  109. "test/language/expressions/object/dstr/meth-dflt-obj-ptrn-id-init-fn-name-class.js": true,
  110. "test/language/expressions/object/dstr/meth-obj-ptrn-id-init-fn-name-class.js": true,
  111. "test/built-ins/Promise/prototype/finally/resolved-observable-then-calls-PromiseResolve.js": true,
  112. "test/built-ins/Promise/prototype/finally/rejected-observable-then-calls-PromiseResolve.js": true,
  113. "test/built-ins/Function/prototype/toString/class-expression-explicit-ctor.js": true,
  114. "test/built-ins/Function/prototype/toString/class-expression-implicit-ctor.js": true,
  115. "test/language/global-code/decl-lex.js": true,
  116. "test/language/global-code/decl-lex-deletion.js": true,
  117. "test/language/global-code/script-decl-var-collision.js": true,
  118. "test/language/global-code/script-decl-lex.js": true,
  119. "test/language/global-code/script-decl-lex-lex.js": true,
  120. "test/language/global-code/script-decl-lex-deletion.js": true,
  121. // restricted unicode regexp syntax
  122. "test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js": true,
  123. "test/built-ins/RegExp/unicode_restricted_octal_escape.js": true,
  124. "test/built-ins/RegExp/unicode_restricted_incomple_quantifier.js": true,
  125. "test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js": true,
  126. "test/built-ins/RegExp/unicode_restricted_identity_escape_x.js": true,
  127. "test/built-ins/RegExp/unicode_restricted_identity_escape_u.js": true,
  128. "test/built-ins/RegExp/unicode_restricted_identity_escape_c.js": true,
  129. "test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js": true,
  130. "test/built-ins/RegExp/unicode_restricted_identity_escape.js": true,
  131. "test/built-ins/RegExp/unicode_restricted_brackets.js": true,
  132. "test/built-ins/RegExp/unicode_restricted_character_class_escape.js": true,
  133. "test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js": true,
  134. // Because goja parser works in UTF-8 it is not possible to pass strings containing invalid UTF-16 code points.
  135. // This is mitigated by escaping them as \uXXXX, however because of this the RegExp source becomes
  136. // `\uXXXX` instead of `<the actual UTF-16 code point of XXXX>`.
  137. // The resulting RegExp will work exactly the same, but it causes these two tests to fail.
  138. "test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js": true,
  139. "test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js": true,
  140. // x ** y
  141. "test/built-ins/Array/prototype/pop/clamps-to-integer-limit.js": true,
  142. "test/built-ins/Array/prototype/pop/length-near-integer-limit.js": true,
  143. "test/built-ins/Array/prototype/push/clamps-to-integer-limit.js": true,
  144. "test/built-ins/Array/prototype/push/length-near-integer-limit.js": true,
  145. "test/built-ins/Array/prototype/push/throws-if-integer-limit-exceeded.js": true,
  146. "test/built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js": true,
  147. "test/built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js": true,
  148. "test/built-ins/Array/prototype/slice/length-exceeding-integer-limit.js": true,
  149. "test/built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js": true,
  150. "test/built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js": true,
  151. "test/built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js": true,
  152. "test/built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js": true,
  153. "test/built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded.js": true,
  154. "test/built-ins/Array/prototype/unshift/clamps-to-integer-limit.js": true,
  155. "test/built-ins/Array/prototype/unshift/length-near-integer-limit.js": true,
  156. "test/built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js": true,
  157. "test/built-ins/String/prototype/split/separator-undef-limit-custom.js": true,
  158. "test/built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit.js": true,
  159. "test/built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js": true,
  160. "test/built-ins/String/prototype/split/separator-undef-limit-zero.js": true,
  161. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-exponetiation-expression.js": true,
  162. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-math.js": true,
  163. "test/built-ins/RegExp/prototype/exec/failure-lastindex-set.js": true,
  164. // generators
  165. "test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js": true,
  166. "test/language/statements/switch/scope-lex-generator.js": true,
  167. "test/language/expressions/in/rhs-yield-present.js": true,
  168. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-yield-expression.js": true,
  169. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-generator-function-declaration.js": true,
  170. "test/built-ins/TypedArrayConstructors/ctors/object-arg/as-generator-iterable-returns.js": true,
  171. "test/built-ins/Object/seal/seal-generatorfunction.js": true,
  172. // async
  173. "test/language/eval-code/direct/async-func-decl-a-preceding-parameter-is-named-arguments-declare-arguments-and-assign.js": true,
  174. "test/language/statements/switch/scope-lex-async-generator.js": true,
  175. "test/language/statements/switch/scope-lex-async-function.js": true,
  176. "test/language/statements/for-of/head-lhs-async-invalid.js": true,
  177. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-async-arrow-function-expression.js": true,
  178. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-await-expression.js": true,
  179. "test/language/statements/async-function/evaluation-body.js": true,
  180. "test/language/expressions/object/method-definition/object-method-returns-promise.js": true,
  181. "test/language/expressions/object/method-definition/async-super-call-param.js": true,
  182. "test/language/expressions/object/method-definition/async-super-call-body.js": true,
  183. "test/built-ins/Object/seal/seal-asyncgeneratorfunction.js": true,
  184. "test/built-ins/Object/seal/seal-asyncfunction.js": true,
  185. "test/built-ins/Object/seal/seal-asyncarrowfunction.js": true,
  186. "test/language/statements/for/head-init-async-of.js": true,
  187. "test/language/reserved-words/await-module.js": true,
  188. // legacy number literals
  189. "test/language/literals/numeric/non-octal-decimal-integer.js": true,
  190. // coalesce
  191. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-expression-coalesce.js": true,
  192. // integer separators
  193. "test/language/expressions/object/cpn-obj-lit-computed-property-name-from-integer-separators.js": true,
  194. // BigInt
  195. "test/built-ins/Object/seal/seal-biguint64array.js": true,
  196. "test/built-ins/Object/seal/seal-bigint64array.js": true,
  197. // FIXME bugs
  198. // new.target availability
  199. "test/language/global-code/new.target-arrow.js": true,
  200. "test/language/eval-code/direct/new.target-fn.js": true,
  201. // 'in' in a branch
  202. "test/language/expressions/conditional/in-branch-1.js": true,
  203. // Left-hand side as a CoverParenthesizedExpression
  204. "test/language/expressions/assignment/fn-name-lhs-cover.js": true,
  205. // multiplicative order of evaluation
  206. "test/language/expressions/multiplication/order-of-evaluation.js": true,
  207. "test/language/expressions/division/order-of-evaluation.js": true,
  208. "test/language/expressions/modulus/order-of-evaluation.js": true,
  209. }
  210. featuresBlackList = []string{
  211. "async-iteration",
  212. "Symbol.asyncIterator",
  213. "async-functions",
  214. "class",
  215. "class-static-block",
  216. "class-fields-private",
  217. "class-fields-private-in",
  218. "super",
  219. "generators",
  220. "String.prototype.replaceAll",
  221. "String.prototype.at",
  222. "resizable-arraybuffer",
  223. "array-find-from-last",
  224. "Array.prototype.at",
  225. "TypedArray.prototype.at",
  226. "regexp-named-groups",
  227. "regexp-dotall",
  228. "regexp-unicode-property-escapes",
  229. "regexp-match-indices",
  230. "legacy-regexp",
  231. "tail-call-optimization",
  232. "Temporal",
  233. "import-assertions",
  234. "dynamic-import",
  235. "logical-assignment-operators",
  236. "coalesce-expression",
  237. "import.meta",
  238. "optional-chaining",
  239. "Atomics",
  240. "Atomics.waitAsync",
  241. "FinalizationRegistry",
  242. "WeakRef",
  243. "numeric-separator-literal",
  244. "Object.fromEntries",
  245. "Object.hasOwn",
  246. "__getter__",
  247. "__setter__",
  248. "ShadowRealm",
  249. "SharedArrayBuffer",
  250. "error-cause",
  251. }
  252. )
  253. func init() {
  254. skip := func(prefixes ...string) {
  255. for _, prefix := range prefixes {
  256. skipPrefixes.Add(prefix)
  257. }
  258. }
  259. skip(
  260. // class
  261. "test/language/statements/class/",
  262. "test/language/expressions/class/",
  263. "test/language/expressions/super/",
  264. "test/language/expressions/assignment/target-super-",
  265. "test/language/arguments-object/cls-",
  266. "test/built-ins/Function/prototype/toString/class-",
  267. "test/built-ins/Function/prototype/toString/setter-class-",
  268. "test/built-ins/Function/prototype/toString/method-class-",
  269. "test/built-ins/Function/prototype/toString/getter-class-",
  270. // async
  271. "test/language/eval-code/direct/async-",
  272. "test/language/expressions/async-",
  273. "test/language/expressions/await/",
  274. "test/language/statements/async-function/",
  275. "test/built-ins/Async",
  276. // generators
  277. "test/language/eval-code/direct/gen-",
  278. "test/built-ins/GeneratorFunction/",
  279. "test/built-ins/Function/prototype/toString/generator-",
  280. // **
  281. "test/language/expressions/exponentiation",
  282. // BigInt
  283. "test/built-ins/TypedArrayConstructors/BigUint64Array/",
  284. "test/built-ins/TypedArrayConstructors/BigInt64Array/",
  285. )
  286. }
  287. type tc39Test struct {
  288. name string
  289. f func(t *testing.T)
  290. }
  291. type tc39BenchmarkItem struct {
  292. name string
  293. duration time.Duration
  294. }
  295. type tc39BenchmarkData []tc39BenchmarkItem
  296. type tc39TestCtx struct {
  297. base string
  298. t *testing.T
  299. prgCache map[string]*Program
  300. prgCacheLock sync.Mutex
  301. enableBench bool
  302. benchmark tc39BenchmarkData
  303. benchLock sync.Mutex
  304. testQueue []tc39Test
  305. }
  306. type TC39MetaNegative struct {
  307. Phase, Type string
  308. }
  309. type tc39Meta struct {
  310. Negative TC39MetaNegative
  311. Includes []string
  312. Flags []string
  313. Features []string
  314. Es5id string
  315. Es6id string
  316. Esid string
  317. }
  318. type prefixList struct {
  319. prefixes map[int]map[string]struct{}
  320. }
  321. func (pl *prefixList) Add(prefix string) {
  322. l := pl.prefixes[len(prefix)]
  323. if l == nil {
  324. l = make(map[string]struct{})
  325. if pl.prefixes == nil {
  326. pl.prefixes = make(map[int]map[string]struct{})
  327. }
  328. pl.prefixes[len(prefix)] = l
  329. }
  330. l[prefix] = struct{}{}
  331. }
  332. func (pl *prefixList) Match(s string) bool {
  333. for l, prefixes := range pl.prefixes {
  334. if len(s) >= l {
  335. if _, exists := prefixes[s[:l]]; exists {
  336. return true
  337. }
  338. }
  339. }
  340. return false
  341. }
  342. func (m *tc39Meta) hasFlag(flag string) bool {
  343. for _, f := range m.Flags {
  344. if f == flag {
  345. return true
  346. }
  347. }
  348. return false
  349. }
  350. func parseTC39File(name string) (*tc39Meta, string, error) {
  351. f, err := os.Open(name)
  352. if err != nil {
  353. return nil, "", err
  354. }
  355. defer f.Close()
  356. b, err := ioutil.ReadAll(f)
  357. if err != nil {
  358. return nil, "", err
  359. }
  360. str := string(b)
  361. metaStart := strings.Index(str, "/*---")
  362. if metaStart == -1 {
  363. return nil, "", invalidFormatError
  364. } else {
  365. metaStart += 5
  366. }
  367. metaEnd := strings.Index(str, "---*/")
  368. if metaEnd == -1 || metaEnd <= metaStart {
  369. return nil, "", invalidFormatError
  370. }
  371. var meta tc39Meta
  372. err = yaml.Unmarshal([]byte(str[metaStart:metaEnd]), &meta)
  373. if err != nil {
  374. return nil, "", err
  375. }
  376. if meta.Negative.Type != "" && meta.Negative.Phase == "" {
  377. return nil, "", errors.New("negative type is set, but phase isn't")
  378. }
  379. return &meta, str, nil
  380. }
  381. func (*tc39TestCtx) detachArrayBuffer(call FunctionCall) Value {
  382. if obj, ok := call.Argument(0).(*Object); ok {
  383. if buf, ok := obj.self.(*arrayBufferObject); ok {
  384. buf.detach()
  385. return _undefined
  386. }
  387. }
  388. panic(typeError("detachArrayBuffer() is called with incompatible argument"))
  389. }
  390. func (*tc39TestCtx) throwIgnorableTestError(FunctionCall) Value {
  391. panic(ignorableTestError)
  392. }
  393. func (ctx *tc39TestCtx) runTC39Test(name, src string, meta *tc39Meta, t testing.TB) {
  394. defer func() {
  395. if x := recover(); x != nil {
  396. panic(fmt.Sprintf("panic while running %s: %v", name, x))
  397. }
  398. }()
  399. vm := New()
  400. _262 := vm.NewObject()
  401. _262.Set("detachArrayBuffer", ctx.detachArrayBuffer)
  402. _262.Set("createRealm", ctx.throwIgnorableTestError)
  403. _262.Set("evalScript", func(call FunctionCall) Value {
  404. script := call.Argument(0).String()
  405. result, err := vm.RunString(script)
  406. if err != nil {
  407. panic(err)
  408. }
  409. return result
  410. })
  411. vm.Set("$262", _262)
  412. vm.Set("IgnorableTestError", ignorableTestError)
  413. vm.RunProgram(sabStub)
  414. var out []string
  415. async := meta.hasFlag("async")
  416. if async {
  417. err := ctx.runFile(ctx.base, path.Join("harness", "doneprintHandle.js"), vm)
  418. if err != nil {
  419. t.Fatal(err)
  420. }
  421. vm.Set("print", func(msg string) {
  422. out = append(out, msg)
  423. })
  424. } else {
  425. vm.Set("print", t.Log)
  426. }
  427. err, early := ctx.runTC39Script(name, src, meta.Includes, vm)
  428. if err != nil {
  429. if meta.Negative.Type == "" {
  430. if err, ok := err.(*Exception); ok {
  431. if err.Value() == ignorableTestError {
  432. t.Skip("Test threw IgnorableTestError")
  433. }
  434. }
  435. t.Fatalf("%s: %v", name, err)
  436. } else {
  437. if (meta.Negative.Phase == "early" || meta.Negative.Phase == "parse") && !early || meta.Negative.Phase == "runtime" && early {
  438. t.Fatalf("%s: error %v happened at the wrong phase (expected %s)", name, err, meta.Negative.Phase)
  439. }
  440. var errType string
  441. switch err := err.(type) {
  442. case *Exception:
  443. if o, ok := err.Value().(*Object); ok {
  444. if c := o.Get("constructor"); c != nil {
  445. if c, ok := c.(*Object); ok {
  446. errType = c.Get("name").String()
  447. } else {
  448. t.Fatalf("%s: error constructor is not an object (%v)", name, o)
  449. }
  450. } else {
  451. t.Fatalf("%s: error does not have a constructor (%v)", name, o)
  452. }
  453. } else {
  454. t.Fatalf("%s: error is not an object (%v)", name, err.Value())
  455. }
  456. case *CompilerSyntaxError:
  457. errType = "SyntaxError"
  458. case *CompilerReferenceError:
  459. errType = "ReferenceError"
  460. default:
  461. t.Fatalf("%s: error is not a JS error: %v", name, err)
  462. }
  463. if errType != meta.Negative.Type {
  464. vm.vm.prg.dumpCode(t.Logf)
  465. t.Fatalf("%s: unexpected error type (%s), expected (%s)", name, errType, meta.Negative.Type)
  466. }
  467. }
  468. } else {
  469. if meta.Negative.Type != "" {
  470. vm.vm.prg.dumpCode(t.Logf)
  471. t.Fatalf("%s: Expected error: %v", name, err)
  472. }
  473. }
  474. if vm.vm.sp != 0 {
  475. t.Fatalf("sp: %d", vm.vm.sp)
  476. }
  477. if l := len(vm.vm.iterStack); l > 0 {
  478. t.Fatalf("iter stack is not empty: %d", l)
  479. }
  480. if async {
  481. complete := false
  482. for _, line := range out {
  483. if strings.HasPrefix(line, "Test262:AsyncTestFailure:") {
  484. t.Fatal(line)
  485. } else if line == "Test262:AsyncTestComplete" {
  486. complete = true
  487. }
  488. }
  489. if !complete {
  490. for _, line := range out {
  491. t.Log(line)
  492. }
  493. t.Fatal("Test262:AsyncTestComplete was not printed")
  494. }
  495. }
  496. }
  497. func (ctx *tc39TestCtx) runTC39File(name string, t testing.TB) {
  498. if skipList[name] {
  499. t.Skip("Excluded")
  500. }
  501. if skipPrefixes.Match(name) {
  502. t.Skip("Excluded")
  503. }
  504. p := path.Join(ctx.base, name)
  505. meta, src, err := parseTC39File(p)
  506. if err != nil {
  507. //t.Fatalf("Could not parse %s: %v", name, err)
  508. t.Errorf("Could not parse %s: %v", name, err)
  509. return
  510. }
  511. if meta.hasFlag("module") {
  512. t.Skip("module")
  513. }
  514. if meta.Es5id == "" {
  515. if meta.Es6id == "" && meta.Esid == "" {
  516. t.Skip("No ids")
  517. }
  518. for _, feature := range meta.Features {
  519. for _, bl := range featuresBlackList {
  520. if feature == bl {
  521. t.Skip("Blacklisted feature")
  522. }
  523. }
  524. }
  525. }
  526. var startTime time.Time
  527. if ctx.enableBench {
  528. startTime = time.Now()
  529. }
  530. hasRaw := meta.hasFlag("raw")
  531. if hasRaw || !meta.hasFlag("onlyStrict") {
  532. //log.Printf("Running normal test: %s", name)
  533. t.Logf("Running normal test: %s", name)
  534. ctx.runTC39Test(name, src, meta, t)
  535. }
  536. if !hasRaw && !meta.hasFlag("noStrict") {
  537. //log.Printf("Running strict test: %s", name)
  538. t.Logf("Running strict test: %s", name)
  539. ctx.runTC39Test(name, "'use strict';\n"+src, meta, t)
  540. }
  541. if ctx.enableBench {
  542. ctx.benchLock.Lock()
  543. ctx.benchmark = append(ctx.benchmark, tc39BenchmarkItem{
  544. name: name,
  545. duration: time.Since(startTime),
  546. })
  547. ctx.benchLock.Unlock()
  548. }
  549. }
  550. func (ctx *tc39TestCtx) init() {
  551. ctx.prgCache = make(map[string]*Program)
  552. }
  553. func (ctx *tc39TestCtx) compile(base, name string) (*Program, error) {
  554. ctx.prgCacheLock.Lock()
  555. defer ctx.prgCacheLock.Unlock()
  556. prg := ctx.prgCache[name]
  557. if prg == nil {
  558. fname := path.Join(base, name)
  559. f, err := os.Open(fname)
  560. if err != nil {
  561. return nil, err
  562. }
  563. defer f.Close()
  564. b, err := ioutil.ReadAll(f)
  565. if err != nil {
  566. return nil, err
  567. }
  568. str := string(b)
  569. prg, err = Compile(name, str, false)
  570. if err != nil {
  571. return nil, err
  572. }
  573. ctx.prgCache[name] = prg
  574. }
  575. return prg, nil
  576. }
  577. func (ctx *tc39TestCtx) runFile(base, name string, vm *Runtime) error {
  578. prg, err := ctx.compile(base, name)
  579. if err != nil {
  580. return err
  581. }
  582. _, err = vm.RunProgram(prg)
  583. return err
  584. }
  585. func (ctx *tc39TestCtx) runTC39Script(name, src string, includes []string, vm *Runtime) (err error, early bool) {
  586. early = true
  587. err = ctx.runFile(ctx.base, path.Join("harness", "assert.js"), vm)
  588. if err != nil {
  589. return
  590. }
  591. err = ctx.runFile(ctx.base, path.Join("harness", "sta.js"), vm)
  592. if err != nil {
  593. return
  594. }
  595. for _, include := range includes {
  596. err = ctx.runFile(ctx.base, path.Join("harness", include), vm)
  597. if err != nil {
  598. return
  599. }
  600. }
  601. var p *Program
  602. p, err = Compile(name, src, false)
  603. if err != nil {
  604. return
  605. }
  606. early = false
  607. _, err = vm.RunProgram(p)
  608. return
  609. }
  610. func (ctx *tc39TestCtx) runTC39Tests(name string) {
  611. files, err := ioutil.ReadDir(path.Join(ctx.base, name))
  612. if err != nil {
  613. ctx.t.Fatal(err)
  614. }
  615. for _, file := range files {
  616. if file.Name()[0] == '.' {
  617. continue
  618. }
  619. if file.IsDir() {
  620. ctx.runTC39Tests(path.Join(name, file.Name()))
  621. } else {
  622. fileName := file.Name()
  623. if strings.HasSuffix(fileName, ".js") && !strings.HasSuffix(fileName, "_FIXTURE.js") {
  624. name := path.Join(name, fileName)
  625. ctx.runTest(name, func(t *testing.T) {
  626. ctx.runTC39File(name, t)
  627. })
  628. }
  629. }
  630. }
  631. }
  632. func TestTC39(t *testing.T) {
  633. if testing.Short() {
  634. t.Skip()
  635. }
  636. if _, err := os.Stat(tc39BASE); err != nil {
  637. 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)
  638. }
  639. ctx := &tc39TestCtx{
  640. base: tc39BASE,
  641. }
  642. ctx.init()
  643. //ctx.enableBench = true
  644. t.Run("tc39", func(t *testing.T) {
  645. ctx.t = t
  646. //ctx.runTC39File("test/language/types/number/8.5.1.js", t)
  647. //ctx.runTC39Tests("test/language")
  648. ctx.runTC39Tests("test/language/expressions")
  649. ctx.runTC39Tests("test/language/arguments-object")
  650. ctx.runTC39Tests("test/language/asi")
  651. ctx.runTC39Tests("test/language/directive-prologue")
  652. ctx.runTC39Tests("test/language/function-code")
  653. ctx.runTC39Tests("test/language/eval-code")
  654. ctx.runTC39Tests("test/language/global-code")
  655. ctx.runTC39Tests("test/language/identifier-resolution")
  656. ctx.runTC39Tests("test/language/identifiers")
  657. //ctx.runTC39Tests("test/language/literals") // legacy octal escape in strings in strict mode and regexp
  658. ctx.runTC39Tests("test/language/literals/numeric")
  659. ctx.runTC39Tests("test/language/punctuators")
  660. ctx.runTC39Tests("test/language/reserved-words")
  661. ctx.runTC39Tests("test/language/source-text")
  662. ctx.runTC39Tests("test/language/statements")
  663. ctx.runTC39Tests("test/language/types")
  664. ctx.runTC39Tests("test/language/white-space")
  665. ctx.runTC39Tests("test/built-ins")
  666. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/substr")
  667. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimLeft")
  668. ctx.runTC39Tests("test/annexB/built-ins/String/prototype/trimRight")
  669. ctx.runTC39Tests("test/annexB/built-ins/escape")
  670. ctx.runTC39Tests("test/annexB/built-ins/unescape")
  671. ctx.runTC39Tests("test/annexB/built-ins/RegExp")
  672. ctx.flush()
  673. })
  674. if ctx.enableBench {
  675. sort.Slice(ctx.benchmark, func(i, j int) bool {
  676. return ctx.benchmark[i].duration > ctx.benchmark[j].duration
  677. })
  678. bench := ctx.benchmark
  679. if len(bench) > 50 {
  680. bench = bench[:50]
  681. }
  682. for _, item := range bench {
  683. fmt.Printf("%s\t%d\n", item.name, item.duration/time.Millisecond)
  684. }
  685. }
  686. }