runtime_test.go 19 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. package goja
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. "testing"
  7. "time"
  8. )
  9. func TestGlobalObjectProto(t *testing.T) {
  10. const SCRIPT = `
  11. this instanceof Object
  12. `
  13. testScript1(SCRIPT, valueTrue, t)
  14. }
  15. func TestArrayProtoProp(t *testing.T) {
  16. const SCRIPT = `
  17. Object.defineProperty(Array.prototype, '0', {value: 42, configurable: true, writable: false})
  18. var a = []
  19. a[0] = 1
  20. a[0]
  21. `
  22. testScript1(SCRIPT, valueInt(42), t)
  23. }
  24. func TestArrayDelete(t *testing.T) {
  25. const SCRIPT = `
  26. var a = [1, 2];
  27. var deleted = delete a[0];
  28. var undef = a[0] === undefined;
  29. var len = a.length;
  30. deleted && undef && len === 2;
  31. `
  32. testScript1(SCRIPT, valueTrue, t)
  33. }
  34. func TestArrayDeleteNonexisting(t *testing.T) {
  35. const SCRIPT = `
  36. Array.prototype[0] = 42;
  37. var a = [];
  38. delete a[0] && a[0] === 42;
  39. `
  40. testScript1(SCRIPT, valueTrue, t)
  41. }
  42. func TestArraySetLength(t *testing.T) {
  43. const SCRIPT = `
  44. var a = [1, 2];
  45. var assert0 = a.length == 2;
  46. a.length = "1";
  47. a.length = 1.0;
  48. a.length = 1;
  49. var assert1 = a.length == 1;
  50. a.length = 2;
  51. var assert2 = a.length == 2;
  52. assert0 && assert1 && assert2 && a[1] === undefined;
  53. `
  54. testScript1(SCRIPT, valueTrue, t)
  55. }
  56. func TestUnicodeString(t *testing.T) {
  57. const SCRIPT = `
  58. var s = "Тест";
  59. s.length === 4 && s[1] === "е";
  60. `
  61. testScript1(SCRIPT, valueTrue, t)
  62. }
  63. func TestArrayReverseNonOptimisable(t *testing.T) {
  64. const SCRIPT = `
  65. var a = [];
  66. Object.defineProperty(a, "0", {get: function() {return 42}, set: function(v) {Object.defineProperty(a, "0", {value: v + 1, writable: true, configurable: true})}, configurable: true})
  67. a[1] = 43;
  68. a.reverse();
  69. a.length === 2 && a[0] === 44 && a[1] === 42;
  70. `
  71. testScript1(SCRIPT, valueTrue, t)
  72. }
  73. func TestArrayPushNonOptimisable(t *testing.T) {
  74. const SCRIPT = `
  75. Object.defineProperty(Object.prototype, "0", {value: 42});
  76. var a = [];
  77. var thrown = false;
  78. try {
  79. a.push(1);
  80. } catch (e) {
  81. thrown = e instanceof TypeError;
  82. }
  83. thrown;
  84. `
  85. testScript1(SCRIPT, valueTrue, t)
  86. }
  87. func TestArraySetLengthWithPropItems(t *testing.T) {
  88. const SCRIPT = `
  89. var a = [1,2,3,4];
  90. var thrown = false;
  91. Object.defineProperty(a, "2", {value: 42, configurable: false, writable: false});
  92. try {
  93. Object.defineProperty(a, "length", {value: 0, writable: false});
  94. } catch (e) {
  95. thrown = e instanceof TypeError;
  96. }
  97. thrown && a.length === 3;
  98. `
  99. testScript1(SCRIPT, valueTrue, t)
  100. }
  101. func Test2TierHierarchyProp(t *testing.T) {
  102. const SCRIPT = `
  103. var a = {};
  104. Object.defineProperty(a, "test", {
  105. value: 42,
  106. writable: false,
  107. enumerable: false,
  108. configurable: true
  109. });
  110. var b = Object.create(a);
  111. var c = Object.create(b);
  112. c.test = 43;
  113. c.test === 42 && !b.hasOwnProperty("test");
  114. `
  115. testScript1(SCRIPT, valueTrue, t)
  116. }
  117. func TestConstStringIter(t *testing.T) {
  118. const SCRIPT = `
  119. var count = 0;
  120. for (var i in "1234") {
  121. for (var j in "1234567") {
  122. count++
  123. }
  124. }
  125. count;
  126. `
  127. testScript1(SCRIPT, intToValue(28), t)
  128. }
  129. func TestUnicodeConcat(t *testing.T) {
  130. const SCRIPT = `
  131. var s = "тест";
  132. var s1 = "test";
  133. var s2 = "абвгд";
  134. s.concat(s1) === "тестtest" && s.concat(s1, s2) === "тестtestабвгд" && s1.concat(s, s2) === "testтестабвгд"
  135. && s.concat(s2) === "тестабвгд";
  136. `
  137. testScript1(SCRIPT, valueTrue, t)
  138. }
  139. func TestIndexOf(t *testing.T) {
  140. const SCRIPT = `
  141. "abc".indexOf("", 4)
  142. `
  143. testScript1(SCRIPT, intToValue(3), t)
  144. }
  145. func TestUnicodeIndexOf(t *testing.T) {
  146. const SCRIPT = `
  147. "абвгд".indexOf("вг", 1) === 2 && '中国'.indexOf('国') === 1
  148. `
  149. testScript1(SCRIPT, valueTrue, t)
  150. }
  151. func TestLastIndexOf(t *testing.T) {
  152. const SCRIPT = `
  153. "abcabab".lastIndexOf("ab", 3)
  154. `
  155. testScript1(SCRIPT, intToValue(3), t)
  156. }
  157. func TestUnicodeLastIndexOf(t *testing.T) {
  158. const SCRIPT = `
  159. "абвабаб".lastIndexOf("аб", 3)
  160. `
  161. testScript1(SCRIPT, intToValue(3), t)
  162. }
  163. func TestUnicodeLastIndexOf1(t *testing.T) {
  164. const SCRIPT = `
  165. "abꞐcde".lastIndexOf("cd");
  166. `
  167. testScript1(SCRIPT, intToValue(3), t)
  168. }
  169. func TestNumber(t *testing.T) {
  170. const SCRIPT = `
  171. (new Number(100111122133144155)).toString()
  172. `
  173. testScript1(SCRIPT, asciiString("100111122133144160"), t)
  174. }
  175. func TestFractionalNumberToStringRadix(t *testing.T) {
  176. const SCRIPT = `
  177. (new Number(123.456)).toString(36)
  178. `
  179. testScript1(SCRIPT, asciiString("3f.gez4w97ry"), t)
  180. }
  181. func TestSetFunc(t *testing.T) {
  182. const SCRIPT = `
  183. sum(40, 2);
  184. `
  185. r := New()
  186. r.Set("sum", func(call FunctionCall) Value {
  187. return r.ToValue(call.Argument(0).ToInteger() + call.Argument(1).ToInteger())
  188. })
  189. v, err := r.RunString(SCRIPT)
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. if i := v.ToInteger(); i != 42 {
  194. t.Fatalf("Expected 42, got: %d", i)
  195. }
  196. }
  197. func TestObjectGetSet(t *testing.T) {
  198. const SCRIPT = `
  199. input.test++;
  200. input;
  201. `
  202. r := New()
  203. o := r.NewObject()
  204. o.Set("test", 42)
  205. r.Set("input", o)
  206. v, err := r.RunString(SCRIPT)
  207. if err != nil {
  208. t.Fatal(err)
  209. }
  210. if o1, ok := v.(*Object); ok {
  211. if v1 := o1.Get("test"); v1.Export() != int64(43) {
  212. t.Fatalf("Unexpected test value: %v (%T)", v1, v1.Export())
  213. }
  214. }
  215. }
  216. func TestThrowFromNativeFunc(t *testing.T) {
  217. const SCRIPT = `
  218. var thrown;
  219. try {
  220. f();
  221. } catch (e) {
  222. thrown = e;
  223. }
  224. thrown;
  225. `
  226. r := New()
  227. r.Set("f", func(call FunctionCall) Value {
  228. panic(r.ToValue("testError"))
  229. })
  230. v, err := r.RunString(SCRIPT)
  231. if err != nil {
  232. t.Fatal(err)
  233. }
  234. if !v.Equals(asciiString("testError")) {
  235. t.Fatalf("Unexpected result: %v", v)
  236. }
  237. }
  238. func TestSetGoFunc(t *testing.T) {
  239. const SCRIPT = `
  240. f(40, 2)
  241. `
  242. r := New()
  243. r.Set("f", func(a, b int) int {
  244. return a + b
  245. })
  246. v, err := r.RunString(SCRIPT)
  247. if err != nil {
  248. t.Fatal(err)
  249. }
  250. if v.ToInteger() != 42 {
  251. t.Fatalf("Unexpected result: %v", v)
  252. }
  253. }
  254. func TestArgsKeys(t *testing.T) {
  255. const SCRIPT = `
  256. function testArgs2(x, y, z) {
  257. // Properties of the arguments object are enumerable.
  258. return Object.keys(arguments);
  259. }
  260. testArgs2(1,2).length
  261. `
  262. testScript1(SCRIPT, intToValue(2), t)
  263. }
  264. func TestIPowOverflow(t *testing.T) {
  265. const SCRIPT = `
  266. Math.pow(65536, 6)
  267. `
  268. testScript1(SCRIPT, floatToValue(7.922816251426434e+28), t)
  269. }
  270. func TestIPowZero(t *testing.T) {
  271. const SCRIPT = `
  272. Math.pow(0, 0)
  273. `
  274. testScript1(SCRIPT, intToValue(1), t)
  275. }
  276. func TestInterrupt(t *testing.T) {
  277. const SCRIPT = `
  278. var i = 0;
  279. for (;;) {
  280. i++;
  281. }
  282. `
  283. vm := New()
  284. time.AfterFunc(200*time.Millisecond, func() {
  285. vm.Interrupt("halt")
  286. })
  287. _, err := vm.RunString(SCRIPT)
  288. if err == nil {
  289. t.Fatal("Err is nil")
  290. }
  291. }
  292. func TestRuntime_ExportToSlice(t *testing.T) {
  293. const SCRIPT = `
  294. var a = [1, 2, 3];
  295. a;
  296. `
  297. vm := New()
  298. v, err := vm.RunString(SCRIPT)
  299. if err != nil {
  300. t.Fatal(err)
  301. }
  302. var a []string
  303. err = vm.ExportTo(v, &a)
  304. if err != nil {
  305. t.Fatal(err)
  306. }
  307. if l := len(a); l != 3 {
  308. t.Fatalf("Unexpected len: %d", l)
  309. }
  310. if a[0] != "1" || a[1] != "2" || a[2] != "3" {
  311. t.Fatalf("Unexpected value: %+v", a)
  312. }
  313. }
  314. func TestRuntime_ExportToMap(t *testing.T) {
  315. const SCRIPT = `
  316. var m = {
  317. "0": 1,
  318. "1": 2,
  319. "2": 3,
  320. }
  321. m;
  322. `
  323. vm := New()
  324. v, err := vm.RunString(SCRIPT)
  325. if err != nil {
  326. t.Fatal(err)
  327. }
  328. var m map[int]string
  329. err = vm.ExportTo(v, &m)
  330. if err != nil {
  331. t.Fatal(err)
  332. }
  333. if l := len(m); l != 3 {
  334. t.Fatalf("Unexpected len: %d", l)
  335. }
  336. if m[0] != "1" || m[1] != "2" || m[2] != "3" {
  337. t.Fatalf("Unexpected value: %+v", m)
  338. }
  339. }
  340. func TestRuntime_ExportToMap1(t *testing.T) {
  341. const SCRIPT = `
  342. var m = {
  343. "0": 1,
  344. "1": 2,
  345. "2": 3,
  346. }
  347. m;
  348. `
  349. vm := New()
  350. v, err := vm.RunString(SCRIPT)
  351. if err != nil {
  352. t.Fatal(err)
  353. }
  354. var m map[string]string
  355. err = vm.ExportTo(v, &m)
  356. if err != nil {
  357. t.Fatal(err)
  358. }
  359. if l := len(m); l != 3 {
  360. t.Fatalf("Unexpected len: %d", l)
  361. }
  362. if m["0"] != "1" || m["1"] != "2" || m["2"] != "3" {
  363. t.Fatalf("Unexpected value: %+v", m)
  364. }
  365. }
  366. func TestRuntime_ExportToStruct(t *testing.T) {
  367. const SCRIPT = `
  368. var m = {
  369. Test: 1,
  370. }
  371. m;
  372. `
  373. vm := New()
  374. v, err := vm.RunString(SCRIPT)
  375. if err != nil {
  376. t.Fatal(err)
  377. }
  378. var o testGoReflectMethod_O
  379. err = vm.ExportTo(v, &o)
  380. if err != nil {
  381. t.Fatal(err)
  382. }
  383. if o.Test != "1" {
  384. t.Fatalf("Unexpected value: '%s'", o.Test)
  385. }
  386. }
  387. func TestRuntime_ExportToFunc(t *testing.T) {
  388. const SCRIPT = `
  389. function f(param) {
  390. return +param + 2;
  391. }
  392. `
  393. vm := New()
  394. _, err := vm.RunString(SCRIPT)
  395. if err != nil {
  396. t.Fatal(err)
  397. }
  398. var fn func(string) string
  399. vm.ExportTo(vm.Get("f"), &fn)
  400. if res := fn("40"); res != "42" {
  401. t.Fatalf("Unexpected value: %q", res)
  402. }
  403. }
  404. func TestRuntime_ExportToFuncThrow(t *testing.T) {
  405. const SCRIPT = `
  406. function f(param) {
  407. throw new Error("testing");
  408. }
  409. `
  410. vm := New()
  411. _, err := vm.RunString(SCRIPT)
  412. if err != nil {
  413. t.Fatal(err)
  414. }
  415. var fn func(string) (string, error)
  416. err = vm.ExportTo(vm.Get("f"), &fn)
  417. if err != nil {
  418. t.Fatal(err)
  419. }
  420. if _, err := fn("40"); err != nil {
  421. if ex, ok := err.(*Exception); ok {
  422. if msg := ex.Error(); msg != "Error: testing at f (<eval>:3:9(4))" {
  423. t.Fatalf("Msg: %q", msg)
  424. }
  425. } else {
  426. t.Fatalf("Error is not *Exception (%T): %v", err, err)
  427. }
  428. } else {
  429. t.Fatal("Expected error")
  430. }
  431. }
  432. func TestRuntime_ExportToFuncFail(t *testing.T) {
  433. const SCRIPT = `
  434. function f(param) {
  435. return +param + 2;
  436. }
  437. `
  438. type T struct {
  439. Field1 int
  440. }
  441. var fn func(string) (T, error)
  442. vm := New()
  443. _, err := vm.RunString(SCRIPT)
  444. if err != nil {
  445. t.Fatal(err)
  446. }
  447. err = vm.ExportTo(vm.Get("f"), &fn)
  448. if err != nil {
  449. t.Fatal(err)
  450. }
  451. if _, err := fn("40"); err == nil {
  452. t.Fatal("Expected error")
  453. }
  454. }
  455. func TestRuntime_ExportToCallable(t *testing.T) {
  456. const SCRIPT = `
  457. function f(param) {
  458. return +param + 2;
  459. }
  460. `
  461. vm := New()
  462. _, err := vm.RunString(SCRIPT)
  463. if err != nil {
  464. t.Fatal(err)
  465. }
  466. var c Callable
  467. err = vm.ExportTo(vm.Get("f"), &c)
  468. if err != nil {
  469. t.Fatal(err)
  470. }
  471. res, err := c(Undefined(), vm.ToValue("40"))
  472. if err != nil {
  473. t.Fatal(err)
  474. } else if !res.StrictEquals(vm.ToValue(42)) {
  475. t.Fatalf("Unexpected value: %v", res)
  476. }
  477. }
  478. func TestRuntime_ExportToObject(t *testing.T) {
  479. const SCRIPT = `
  480. var o = {"test": 42};
  481. o;
  482. `
  483. vm := New()
  484. _, err := vm.RunString(SCRIPT)
  485. if err != nil {
  486. t.Fatal(err)
  487. }
  488. var o *Object
  489. err = vm.ExportTo(vm.Get("o"), &o)
  490. if err != nil {
  491. t.Fatal(err)
  492. }
  493. if v := o.Get("test"); !v.StrictEquals(vm.ToValue(42)) {
  494. t.Fatalf("Unexpected value: %v", v)
  495. }
  496. }
  497. func TestGoFuncError(t *testing.T) {
  498. const SCRIPT = `
  499. try {
  500. f();
  501. } catch (e) {
  502. if (!(e instanceof GoError)) {
  503. throw(e);
  504. }
  505. if (e.value.Error() !== "Test") {
  506. throw("Unexpected value: " + e.value.Error());
  507. }
  508. }
  509. `
  510. f := func() error {
  511. return errors.New("Test")
  512. }
  513. vm := New()
  514. vm.Set("f", f)
  515. _, err := vm.RunString(SCRIPT)
  516. if err != nil {
  517. t.Fatal(err)
  518. }
  519. }
  520. func TestToValueNil(t *testing.T) {
  521. type T struct{}
  522. var a *T
  523. vm := New()
  524. if v := vm.ToValue(a); !IsNull(v) {
  525. t.Fatalf("Expected null, got: %v", v)
  526. }
  527. }
  528. func TestToValueFloat(t *testing.T) {
  529. vm := New()
  530. vm.Set("f64", float64(123))
  531. vm.Set("f32", float32(321))
  532. v, err := vm.RunString("f64 === 123 && f32 === 321")
  533. if err != nil {
  534. t.Fatal(err)
  535. }
  536. if v.Export().(bool) != true {
  537. t.Fatalf("StrictEquals for golang float failed")
  538. }
  539. }
  540. func TestJSONEscape(t *testing.T) {
  541. const SCRIPT = `
  542. var a = "\\+1";
  543. JSON.stringify(a);
  544. `
  545. testScript1(SCRIPT, asciiString(`"\\+1"`), t)
  546. }
  547. func TestJSONObjectInArray(t *testing.T) {
  548. const SCRIPT = `
  549. var a = "[{\"a\":1},{\"a\":2}]";
  550. JSON.stringify(JSON.parse(a)) == a;
  551. `
  552. testScript1(SCRIPT, valueTrue, t)
  553. }
  554. func TestJSONQuirkyNumbers(t *testing.T) {
  555. const SCRIPT = `
  556. var s;
  557. s = JSON.stringify(NaN);
  558. if (s != "null") {
  559. throw new Error("NaN: " + s);
  560. }
  561. s = JSON.stringify(Infinity);
  562. if (s != "null") {
  563. throw new Error("Infinity: " + s);
  564. }
  565. s = JSON.stringify(-Infinity);
  566. if (s != "null") {
  567. throw new Error("-Infinity: " + s);
  568. }
  569. `
  570. testScript1(SCRIPT, _undefined, t)
  571. }
  572. func TestJSONNil(t *testing.T) {
  573. const SCRIPT = `
  574. JSON.stringify(i);
  575. `
  576. vm := New()
  577. var i interface{}
  578. vm.Set("i", i)
  579. ret, err := vm.RunString(SCRIPT)
  580. if err != nil {
  581. t.Fatal(err)
  582. }
  583. if ret.String() != "null" {
  584. t.Fatalf("Expected 'null', got: %v", ret)
  585. }
  586. }
  587. type customJsonEncodable struct{}
  588. func (*customJsonEncodable) JsonEncodable() interface{} {
  589. return "Test"
  590. }
  591. func TestJsonEncodable(t *testing.T) {
  592. var s customJsonEncodable
  593. vm := New()
  594. vm.Set("s", &s)
  595. ret, err := vm.RunString("JSON.stringify(s)")
  596. if err != nil {
  597. t.Fatal(err)
  598. }
  599. if !ret.StrictEquals(vm.ToValue("\"Test\"")) {
  600. t.Fatalf("Expected \"Test\", got: %v", ret)
  601. }
  602. }
  603. func TestSortComparatorReturnValues(t *testing.T) {
  604. const SCRIPT = `
  605. var a = [];
  606. for (var i = 0; i < 12; i++) {
  607. a[i] = i;
  608. }
  609. a.sort(function(x, y) { return y - x });
  610. for (var i = 0; i < 12; i++) {
  611. if (a[i] !== 11-i) {
  612. throw new Error("Value at index " + i + " is incorrect: " + a[i]);
  613. }
  614. }
  615. `
  616. testScript1(SCRIPT, _undefined, t)
  617. }
  618. func TestNilApplyArg(t *testing.T) {
  619. const SCRIPT = `
  620. (function x(a, b) {
  621. return a === undefined && b === 1;
  622. }).apply(this, [,1])
  623. `
  624. testScript1(SCRIPT, valueTrue, t)
  625. }
  626. func TestNilCallArg(t *testing.T) {
  627. const SCRIPT = `
  628. "use strict";
  629. function f(a) {
  630. return this === undefined && a === undefined;
  631. }
  632. `
  633. vm := New()
  634. prg := MustCompile("test.js", SCRIPT, false)
  635. vm.RunProgram(prg)
  636. if f, ok := AssertFunction(vm.Get("f")); ok {
  637. v, err := f(nil, nil)
  638. if err != nil {
  639. t.Fatal(err)
  640. }
  641. if !v.StrictEquals(valueTrue) {
  642. t.Fatalf("Unexpected result: %v", v)
  643. }
  644. }
  645. }
  646. func TestNullCallArg(t *testing.T) {
  647. const SCRIPT = `
  648. f(null);
  649. `
  650. vm := New()
  651. prg := MustCompile("test.js", SCRIPT, false)
  652. vm.Set("f", func(x *int) bool {
  653. return x == nil
  654. })
  655. v, err := vm.RunProgram(prg)
  656. if err != nil {
  657. t.Fatal(err)
  658. }
  659. if !v.StrictEquals(valueTrue) {
  660. t.Fatalf("Unexpected result: %v", v)
  661. }
  662. }
  663. func TestObjectKeys(t *testing.T) {
  664. const SCRIPT = `
  665. var o = { a: 1, b: 2, c: 3, d: 4 };
  666. o;
  667. `
  668. vm := New()
  669. prg := MustCompile("test.js", SCRIPT, false)
  670. res, err := vm.RunProgram(prg)
  671. if err != nil {
  672. t.Fatal(err)
  673. }
  674. if o, ok := res.(*Object); ok {
  675. keys := o.Keys()
  676. if !reflect.DeepEqual(keys, []string{"a", "b", "c", "d"}) {
  677. t.Fatalf("Unexpected keys: %v", keys)
  678. }
  679. }
  680. }
  681. func TestReflectCallExtraArgs(t *testing.T) {
  682. const SCRIPT = `
  683. f(41, "extra")
  684. `
  685. f := func(x int) int {
  686. return x + 1
  687. }
  688. vm := New()
  689. vm.Set("f", f)
  690. prg := MustCompile("test.js", SCRIPT, false)
  691. res, err := vm.RunProgram(prg)
  692. if err != nil {
  693. t.Fatal(err)
  694. }
  695. if !res.StrictEquals(intToValue(42)) {
  696. t.Fatalf("Unexpected result: %v", res)
  697. }
  698. }
  699. func TestReflectCallNotEnoughArgs(t *testing.T) {
  700. const SCRIPT = `
  701. f(42)
  702. `
  703. vm := New()
  704. f := func(x, y int, z *int, s string) (int, error) {
  705. if z != nil {
  706. return 0, fmt.Errorf("z is not nil")
  707. }
  708. if s != "" {
  709. return 0, fmt.Errorf("s is not \"\"")
  710. }
  711. return x + y, nil
  712. }
  713. vm.Set("f", f)
  714. prg := MustCompile("test.js", SCRIPT, false)
  715. res, err := vm.RunProgram(prg)
  716. if err != nil {
  717. t.Fatal(err)
  718. }
  719. if !res.StrictEquals(intToValue(42)) {
  720. t.Fatalf("Unexpected result: %v", res)
  721. }
  722. }
  723. func TestReflectCallVariadic(t *testing.T) {
  724. const SCRIPT = `
  725. var r = f("Hello %s, %d", "test", 42);
  726. if (r !== "Hello test, 42") {
  727. throw new Error("test 1 has failed: " + r);
  728. }
  729. r = f("Hello %s, %d", ["test", 42]);
  730. if (r !== "Hello test, 42") {
  731. throw new Error("test 2 has failed: " + r);
  732. }
  733. r = f("Hello %s, %s", "test");
  734. if (r !== "Hello test, %!s(MISSING)") {
  735. throw new Error("test 3 has failed: " + r);
  736. }
  737. r = f();
  738. if (r !== "") {
  739. throw new Error("test 4 has failed: " + r);
  740. }
  741. `
  742. vm := New()
  743. vm.Set("f", fmt.Sprintf)
  744. prg := MustCompile("test.js", SCRIPT, false)
  745. _, err := vm.RunProgram(prg)
  746. if err != nil {
  747. t.Fatal(err)
  748. }
  749. }
  750. func TestReflectNullValueArgument(t *testing.T) {
  751. rt := New()
  752. rt.Set("fn", func(v Value) {
  753. if v == nil {
  754. t.Error("null becomes nil")
  755. }
  756. if !IsNull(v) {
  757. t.Error("null is not null")
  758. }
  759. })
  760. rt.RunString(`fn(null);`)
  761. }
  762. type testNativeConstructHelper struct {
  763. rt *Runtime
  764. base int64
  765. // any other state
  766. }
  767. func (t *testNativeConstructHelper) calc(call FunctionCall) Value {
  768. return t.rt.ToValue(t.base + call.Argument(0).ToInteger())
  769. }
  770. func TestNativeConstruct(t *testing.T) {
  771. const SCRIPT = `
  772. var f = new F(40);
  773. f instanceof F && f.method() === 42 && f.calc(2) === 42;
  774. `
  775. rt := New()
  776. method := func(call FunctionCall) Value {
  777. return rt.ToValue(42)
  778. }
  779. rt.Set("F", func(call ConstructorCall) *Object { // constructor signature (as opposed to 'func(FunctionCall) Value')
  780. h := &testNativeConstructHelper{
  781. rt: rt,
  782. base: call.Argument(0).ToInteger(),
  783. }
  784. call.This.Set("method", method)
  785. call.This.Set("calc", h.calc)
  786. return nil // or any other *Object which will be used instead of call.This
  787. })
  788. prg := MustCompile("test.js", SCRIPT, false)
  789. res, err := rt.RunProgram(prg)
  790. if err != nil {
  791. t.Fatal(err)
  792. }
  793. if !res.StrictEquals(valueTrue) {
  794. t.Fatalf("Unexpected result: %v", res)
  795. }
  796. if fn, ok := AssertFunction(rt.Get("F")); ok {
  797. v, err := fn(nil, rt.ToValue(42))
  798. if err != nil {
  799. t.Fatal(err)
  800. }
  801. if o, ok := v.(*Object); ok {
  802. if o.Get("method") == nil {
  803. t.Fatal("No method")
  804. }
  805. } else {
  806. t.Fatal("Not an object")
  807. }
  808. } else {
  809. t.Fatal("Not a function")
  810. }
  811. resp := &testNativeConstructHelper{}
  812. value := rt.ToValue(resp)
  813. if value.Export() != resp {
  814. t.Fatal("no")
  815. }
  816. }
  817. func TestCreateObject(t *testing.T) {
  818. const SCRIPT = `
  819. inst instanceof C;
  820. `
  821. r := New()
  822. c := r.ToValue(func(call ConstructorCall) *Object {
  823. return nil
  824. })
  825. proto := c.(*Object).Get("prototype").(*Object)
  826. inst := r.CreateObject(proto)
  827. r.Set("C", c)
  828. r.Set("inst", inst)
  829. prg := MustCompile("test.js", SCRIPT, false)
  830. res, err := r.RunProgram(prg)
  831. if err != nil {
  832. t.Fatal(err)
  833. }
  834. if !res.StrictEquals(valueTrue) {
  835. t.Fatalf("Unexpected result: %v", res)
  836. }
  837. }
  838. func TestInterruptInWrappedFunction(t *testing.T) {
  839. rt := New()
  840. v, err := rt.RunString(`
  841. var fn = function() {
  842. while (true) {}
  843. };
  844. fn;
  845. `)
  846. if err != nil {
  847. t.Fatal(err)
  848. }
  849. fn, ok := AssertFunction(v)
  850. if !ok {
  851. t.Fatal("Not a function")
  852. }
  853. go func() {
  854. <-time.After(10 * time.Millisecond)
  855. rt.Interrupt(errors.New("hi"))
  856. }()
  857. v, err = fn(nil)
  858. if err == nil {
  859. t.Fatal("expected error")
  860. }
  861. if _, ok := err.(*InterruptedError); !ok {
  862. t.Fatalf("Wrong error type: %T", err)
  863. }
  864. }
  865. /*
  866. func TestArrayConcatSparse(t *testing.T) {
  867. function foo(a,b,c)
  868. {
  869. arguments[0] = 1; arguments[1] = 'str'; arguments[2] = 2.1;
  870. if(1 === a && 'str' === b && 2.1 === c)
  871. return true;
  872. }
  873. const SCRIPT = `
  874. var a1 = [];
  875. var a2 = [];
  876. a1[500000] = 1;
  877. a2[1000000] = 2;
  878. var a3 = a1.concat(a2);
  879. a3.length === 1500002 && a3[500000] === 1 && a3[1500001] == 2;
  880. `
  881. testScript1(SCRIPT, valueTrue, t)
  882. }
  883. */
  884. func BenchmarkCallReflect(b *testing.B) {
  885. vm := New()
  886. vm.Set("f", func(v Value) {
  887. })
  888. prg := MustCompile("test.js", "f(null)", true)
  889. b.ResetTimer()
  890. for i := 0; i < b.N; i++ {
  891. vm.RunProgram(prg)
  892. }
  893. }
  894. func BenchmarkCallNative(b *testing.B) {
  895. vm := New()
  896. vm.Set("f", func(call FunctionCall) (ret Value) {
  897. return
  898. })
  899. prg := MustCompile("test.js", "f(null)", true)
  900. b.ResetTimer()
  901. for i := 0; i < b.N; i++ {
  902. vm.RunProgram(prg)
  903. }
  904. }