builtin_proxy_test.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. package goja
  2. import (
  3. "strconv"
  4. "testing"
  5. )
  6. func TestProxy_Object_target_getPrototypeOf(t *testing.T) {
  7. const SCRIPT = `
  8. var proto = {};
  9. var obj = Object.create(proto);
  10. var proxy = new Proxy(obj, {});
  11. var p = Object.getPrototypeOf(proxy);
  12. assert.sameValue(proto, p);
  13. `
  14. testScript1(TESTLIB+SCRIPT, _undefined, t)
  15. }
  16. func TestProxy_Object_proxy_getPrototypeOf(t *testing.T) {
  17. const SCRIPT = `
  18. var proto = {};
  19. var proto2 = {};
  20. var obj = Object.create(proto);
  21. var proxy = new Proxy(obj, {
  22. getPrototypeOf: function(target) {
  23. return proto2;
  24. }
  25. });
  26. var p = Object.getPrototypeOf(proxy);
  27. assert.sameValue(proto2, p);
  28. `
  29. testScript1(TESTLIB+SCRIPT, _undefined, t)
  30. }
  31. func TestProxy_Object_native_proxy_getPrototypeOf(t *testing.T) {
  32. const SCRIPT = `
  33. var p = Object.getPrototypeOf(proxy);
  34. assert.sameValue(proto, p);
  35. `
  36. runtime := New()
  37. prototype := runtime.NewObject()
  38. runtime.Set("proto", prototype)
  39. target := runtime.NewObject()
  40. proxy := runtime.NewProxy(target, &ProxyTrapConfig{
  41. GetPrototypeOf: func(target *Object) *Object {
  42. return prototype
  43. },
  44. })
  45. runtime.Set("proxy", proxy)
  46. _, err := runtime.RunString(TESTLIB + SCRIPT)
  47. if err != nil {
  48. t.Fatal(err)
  49. }
  50. }
  51. func TestProxy_Object_target_setPrototypeOf(t *testing.T) {
  52. const SCRIPT = `
  53. var proto = {};
  54. var obj = {};
  55. Object.setPrototypeOf(obj, proto);
  56. var proxy = new Proxy(obj, {});
  57. var p = Object.getPrototypeOf(proxy);
  58. assert.sameValue(proto, p);
  59. `
  60. testScript1(TESTLIB+SCRIPT, _undefined, t)
  61. }
  62. func TestProxy_Object_proxy_setPrototypeOf(t *testing.T) {
  63. const SCRIPT = `
  64. var proto = {};
  65. var proto2 = {};
  66. var obj = {};
  67. Object.setPrototypeOf(obj, proto);
  68. var proxy = new Proxy(obj, {
  69. setPrototypeOf: function(target, prototype) {
  70. return Object.setPrototypeOf(target, proto2);
  71. }
  72. });
  73. Object.setPrototypeOf(proxy, null);
  74. var p = Object.getPrototypeOf(proxy);
  75. assert.sameValue(proto2, p);
  76. `
  77. testScript1(TESTLIB+SCRIPT, _undefined, t)
  78. }
  79. func TestProxy_Object_target_isExtensible(t *testing.T) {
  80. const SCRIPT = `
  81. var obj = {};
  82. Object.seal(obj);
  83. var proxy = new Proxy(obj, {});
  84. Object.isExtensible(proxy);
  85. `
  86. testScript1(SCRIPT, valueFalse, t)
  87. }
  88. func TestProxy_proxy_isExtensible(t *testing.T) {
  89. const SCRIPT = `
  90. var obj = {};
  91. Object.seal(obj);
  92. var proxy = new Proxy(obj, {
  93. isExtensible: function(target) {
  94. return false;
  95. }
  96. });
  97. Object.isExtensible(proxy);
  98. `
  99. testScript1(SCRIPT, valueFalse, t)
  100. }
  101. func TestProxy_native_proxy_isExtensible(t *testing.T) {
  102. const SCRIPT = `
  103. (function() {
  104. Object.preventExtensions(target);
  105. return Object.isExtensible(proxy);
  106. })();
  107. `
  108. runtime := New()
  109. target := runtime.NewObject()
  110. runtime.Set("target", target)
  111. proxy := runtime.NewProxy(target, &ProxyTrapConfig{
  112. IsExtensible: func(target *Object) (success bool) {
  113. return false
  114. },
  115. })
  116. runtime.Set("proxy", proxy)
  117. val, err := runtime.RunString(SCRIPT)
  118. if err != nil {
  119. t.Fatal(err)
  120. }
  121. if val.ToBoolean() {
  122. t.Fatal()
  123. }
  124. }
  125. func TestProxy_Object_target_preventExtensions(t *testing.T) {
  126. const SCRIPT = `
  127. var obj = {
  128. canEvolve: true
  129. };
  130. var proxy = new Proxy(obj, {});
  131. Object.preventExtensions(proxy);
  132. proxy.canEvolve
  133. `
  134. testScript1(SCRIPT, valueTrue, t)
  135. }
  136. func TestProxy_proxy_preventExtensions(t *testing.T) {
  137. const SCRIPT = `
  138. var obj = {
  139. canEvolve: true
  140. };
  141. var proxy = new Proxy(obj, {
  142. preventExtensions: function(target) {
  143. target.canEvolve = false;
  144. return false;
  145. }
  146. });
  147. Object.preventExtensions(proxy);
  148. proxy.canEvolve;
  149. `
  150. testScript1(SCRIPT, valueFalse, t)
  151. }
  152. func TestProxy_native_proxy_preventExtensions(t *testing.T) {
  153. const SCRIPT = `
  154. (function() {
  155. Object.preventExtensions(proxy);
  156. return proxy.canEvolve;
  157. })();
  158. `
  159. runtime := New()
  160. target := runtime.NewObject()
  161. target.Set("canEvolve", true)
  162. runtime.Set("target", target)
  163. proxy := runtime.NewProxy(target, &ProxyTrapConfig{
  164. PreventExtensions: func(target *Object) (success bool) {
  165. target.Set("canEvolve", false)
  166. return false
  167. },
  168. })
  169. runtime.Set("proxy", proxy)
  170. val, err := runtime.RunString(SCRIPT)
  171. if err != nil {
  172. t.Fatal(err)
  173. }
  174. if val.ToBoolean() {
  175. t.Fatal()
  176. }
  177. }
  178. func TestProxy_Object_target_getOwnPropertyDescriptor(t *testing.T) {
  179. const SCRIPT = `
  180. var desc = {
  181. configurable: false,
  182. enumerable: false,
  183. value: 42,
  184. writable: false
  185. };
  186. var obj = {};
  187. Object.defineProperty(obj, "foo", desc);
  188. var proxy = new Proxy(obj, {});
  189. var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo");
  190. desc2.value
  191. `
  192. testScript1(SCRIPT, valueInt(42), t)
  193. }
  194. func TestProxy_proxy_getOwnPropertyDescriptor(t *testing.T) {
  195. const SCRIPT = `
  196. var desc = {
  197. configurable: false,
  198. enumerable: false,
  199. value: 42,
  200. writable: false
  201. };
  202. var proxy_desc = {
  203. configurable: false,
  204. enumerable: false,
  205. value: 24,
  206. writable: false
  207. };
  208. var obj = {};
  209. Object.defineProperty(obj, "foo", desc);
  210. var proxy = new Proxy(obj, {
  211. getOwnPropertyDescriptor: function(target, property) {
  212. return proxy_desc;
  213. }
  214. });
  215. assert.throws(TypeError, function() {
  216. Object.getOwnPropertyDescriptor(proxy, "foo");
  217. });
  218. undefined;
  219. `
  220. testScript1(TESTLIB+SCRIPT, _undefined, t)
  221. }
  222. func TestProxy_native_proxy_getOwnPropertyDescriptor(t *testing.T) {
  223. const SCRIPT = `
  224. (function() {
  225. var desc = {
  226. configurable: true,
  227. enumerable: false,
  228. value: 42,
  229. writable: false
  230. };
  231. var proxy_desc = {
  232. configurable: true,
  233. enumerable: false,
  234. value: 24,
  235. writable: false
  236. };
  237. var obj = {};
  238. Object.defineProperty(obj, "foo", desc);
  239. return function(constructor) {
  240. var proxy = constructor(obj, proxy_desc);
  241. var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo");
  242. return desc2.value
  243. }
  244. })();
  245. `
  246. runtime := New()
  247. constructor := func(call FunctionCall) Value {
  248. target := call.Argument(0).(*Object)
  249. proxyDesc := call.Argument(1).(*Object)
  250. return runtime.NewProxy(target, &ProxyTrapConfig{
  251. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  252. return runtime.toPropertyDescriptor(proxyDesc)
  253. },
  254. }).proxy.val
  255. }
  256. val, err := runtime.RunString(SCRIPT)
  257. if err != nil {
  258. t.Fatal(err)
  259. }
  260. if c, ok := val.(*Object).self.assertCallable(); ok {
  261. val := c(FunctionCall{
  262. This: val,
  263. Arguments: []Value{runtime.ToValue(constructor)},
  264. })
  265. if i := val.ToInteger(); i != 24 {
  266. t.Fatalf("val: %d", i)
  267. }
  268. } else {
  269. t.Fatal("not a function")
  270. }
  271. }
  272. func TestProxy_native_proxy_getOwnPropertyDescriptorIdx(t *testing.T) {
  273. vm := New()
  274. a := vm.NewArray()
  275. proxy1 := vm.NewProxy(a, &ProxyTrapConfig{
  276. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  277. panic(vm.NewTypeError("GetOwnPropertyDescriptor was called for %q", prop))
  278. },
  279. GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor {
  280. if prop >= -1 && prop <= 1 {
  281. return PropertyDescriptor{
  282. Value: vm.ToValue(prop),
  283. Configurable: FLAG_TRUE,
  284. }
  285. }
  286. return PropertyDescriptor{}
  287. },
  288. })
  289. proxy2 := vm.NewProxy(a, &ProxyTrapConfig{
  290. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  291. switch prop {
  292. case "-1", "0", "1":
  293. return PropertyDescriptor{
  294. Value: vm.ToValue(prop),
  295. Configurable: FLAG_TRUE,
  296. }
  297. }
  298. return PropertyDescriptor{}
  299. },
  300. })
  301. proxy3 := vm.NewProxy(a, &ProxyTrapConfig{
  302. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  303. return PropertyDescriptor{
  304. Value: vm.ToValue(prop),
  305. Configurable: FLAG_TRUE,
  306. }
  307. },
  308. GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor {
  309. panic(vm.NewTypeError("GetOwnPropertyDescriptorIdx was called for %d", prop))
  310. },
  311. })
  312. vm.Set("proxy1", proxy1)
  313. vm.Set("proxy2", proxy2)
  314. vm.Set("proxy3", proxy3)
  315. _, err := vm.RunString(TESTLIBX + `
  316. var desc;
  317. for (var i = -1; i <= 1; i++) {
  318. desc = Object.getOwnPropertyDescriptor(proxy1, i);
  319. assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. int "+i);
  320. desc = Object.getOwnPropertyDescriptor(proxy1, ""+i);
  321. assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. str "+i);
  322. desc = Object.getOwnPropertyDescriptor(proxy2, i);
  323. assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. int "+i);
  324. desc = Object.getOwnPropertyDescriptor(proxy2, ""+i);
  325. assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. str "+i);
  326. }
  327. for (const prop of ["00", " 0", "-0", "01"]) {
  328. desc = Object.getOwnPropertyDescriptor(proxy3, prop);
  329. assert(deepEqual(desc, {value: prop, writable: false, enumerable: false, configurable: true}), "3. "+prop);
  330. }
  331. `)
  332. if err != nil {
  333. t.Fatal(err)
  334. }
  335. }
  336. func TestProxy_native_proxy_getOwnPropertyDescriptorSym(t *testing.T) {
  337. vm := New()
  338. o := vm.NewObject()
  339. sym := NewSymbol("42")
  340. vm.Set("sym", sym)
  341. proxy := vm.NewProxy(o, &ProxyTrapConfig{
  342. GetOwnPropertyDescriptorSym: func(target *Object, s *Symbol) PropertyDescriptor {
  343. if target != o {
  344. panic(vm.NewTypeError("Invalid target"))
  345. }
  346. if s == sym {
  347. return PropertyDescriptor{
  348. Value: vm.ToValue("passed"),
  349. Writable: FLAG_TRUE,
  350. Configurable: FLAG_TRUE,
  351. }
  352. }
  353. return PropertyDescriptor{}
  354. },
  355. })
  356. vm.Set("proxy", proxy)
  357. _, err := vm.RunString(TESTLIBX + `
  358. var desc = Object.getOwnPropertyDescriptor(proxy, sym);
  359. assert(deepEqual(desc, {value: "passed", writable: true, enumerable: false, configurable: true}));
  360. assert.sameValue(Object.getOwnPropertyDescriptor(proxy, Symbol.iterator), undefined);
  361. `)
  362. if err != nil {
  363. t.Fatal(err)
  364. }
  365. }
  366. func TestProxy_native_proxy_getOwnPropertyDescriptor_non_existing(t *testing.T) {
  367. vm := New()
  368. proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{
  369. GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) {
  370. return // empty PropertyDescriptor
  371. },
  372. })
  373. vm.Set("proxy", proxy)
  374. res, err := vm.RunString(`Object.getOwnPropertyDescriptor(proxy, "foo") === undefined`)
  375. if err != nil {
  376. t.Fatal(err)
  377. }
  378. if res != valueTrue {
  379. t.Fatal(res)
  380. }
  381. }
  382. func TestProxy_Object_target_defineProperty(t *testing.T) {
  383. const SCRIPT = `
  384. var obj = {};
  385. var proxy = new Proxy(obj, {});
  386. Object.defineProperty(proxy, "foo", {
  387. value: "test123"
  388. });
  389. proxy.foo;
  390. `
  391. testScript1(SCRIPT, asciiString("test123"), t)
  392. }
  393. func TestProxy_proxy_defineProperty(t *testing.T) {
  394. const SCRIPT = `
  395. var obj = {};
  396. var proxy = new Proxy(obj, {
  397. defineProperty: function(target, prop, descriptor) {
  398. target.foo = "321tset";
  399. return true;
  400. }
  401. });
  402. Object.defineProperty(proxy, "foo", {
  403. value: "test123"
  404. });
  405. proxy.foo;
  406. `
  407. testScript1(SCRIPT, asciiString("321tset"), t)
  408. }
  409. func TestProxy_native_proxy_defineProperty(t *testing.T) {
  410. const SCRIPT = `
  411. Object.defineProperty(proxy, "foo", {
  412. value: "teststr"
  413. });
  414. Object.defineProperty(proxy, "0", {
  415. value: "testidx"
  416. });
  417. Object.defineProperty(proxy, Symbol.toStringTag, {
  418. value: "testsym"
  419. });
  420. assert.sameValue(proxy.foo, "teststr-passed-str");
  421. assert.sameValue(proxy[0], "testidx-passed-idx");
  422. assert.sameValue(proxy[Symbol.toStringTag], "testsym-passed-sym");
  423. `
  424. runtime := New()
  425. target := runtime.NewObject()
  426. proxy := runtime.NewProxy(target, &ProxyTrapConfig{
  427. DefineProperty: func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) {
  428. target.Set(key, propertyDescriptor.Value.String()+"-passed-str")
  429. return true
  430. },
  431. DefinePropertyIdx: func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) {
  432. target.Set(strconv.Itoa(key), propertyDescriptor.Value.String()+"-passed-idx")
  433. return true
  434. },
  435. DefinePropertySym: func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) {
  436. target.SetSymbol(key, propertyDescriptor.Value.String()+"-passed-sym")
  437. return true
  438. },
  439. })
  440. runtime.Set("proxy", proxy)
  441. _, err := runtime.RunString(TESTLIB + SCRIPT)
  442. if err != nil {
  443. t.Fatal(err)
  444. }
  445. }
  446. func TestProxy_target_has_in(t *testing.T) {
  447. const SCRIPT = `
  448. var obj = {
  449. secret: true
  450. };
  451. var proxy = new Proxy(obj, {});
  452. "secret" in proxy
  453. `
  454. testScript1(SCRIPT, valueTrue, t)
  455. }
  456. func TestProxy_proxy_has_in(t *testing.T) {
  457. const SCRIPT = `
  458. var obj = {
  459. secret: true
  460. };
  461. var proxy = new Proxy(obj, {
  462. has: function(target, key) {
  463. return key !== "secret";
  464. }
  465. });
  466. "secret" in proxy
  467. `
  468. testScript1(SCRIPT, valueFalse, t)
  469. }
  470. func TestProxy_target_has_with(t *testing.T) {
  471. const SCRIPT = `
  472. var obj = {
  473. secret: true
  474. };
  475. var proxy = new Proxy(obj, {});
  476. with(proxy) {
  477. (secret);
  478. }
  479. `
  480. testScript1(SCRIPT, valueTrue, t)
  481. }
  482. func TestProxy_proxy_has_with(t *testing.T) {
  483. const SCRIPT = `
  484. var obj = {
  485. secret: true
  486. };
  487. var proxy = new Proxy(obj, {
  488. has: function(target, key) {
  489. return key !== "secret";
  490. }
  491. });
  492. var thrown = false;
  493. try {
  494. with(proxy) {
  495. (secret);
  496. }
  497. } catch (e) {
  498. if (e instanceof ReferenceError) {
  499. thrown = true;
  500. } else {
  501. throw e;
  502. }
  503. }
  504. thrown;
  505. `
  506. testScript1(SCRIPT, valueTrue, t)
  507. }
  508. func TestProxy_target_get(t *testing.T) {
  509. const SCRIPT = `
  510. var obj = {};
  511. var proxy = new Proxy(obj, {});
  512. Object.defineProperty(proxy, "foo", {
  513. value: "test123"
  514. });
  515. proxy.foo;
  516. `
  517. testScript1(SCRIPT, asciiString("test123"), t)
  518. }
  519. func TestProxy_proxy_get(t *testing.T) {
  520. const SCRIPT = `
  521. var obj = {};
  522. var proxy = new Proxy(obj, {
  523. get: function(target, prop, receiver) {
  524. return "321tset"
  525. }
  526. });
  527. Object.defineProperty(proxy, "foo", {
  528. value: "test123",
  529. configurable: true,
  530. });
  531. proxy.foo;
  532. `
  533. testScript1(SCRIPT, asciiString("321tset"), t)
  534. }
  535. func TestProxy_proxy_get_json_stringify(t *testing.T) {
  536. const SCRIPT = `
  537. var obj = {};
  538. var propValue = "321tset";
  539. var _handler, _target, _prop, _receiver;
  540. var proxy = new Proxy(obj, {
  541. ownKeys: function() {
  542. return ["foo"];
  543. },
  544. getOwnPropertyDescriptor: function(target, prop) {
  545. if (prop === "foo") {
  546. return {
  547. value: propValue,
  548. enumerable: true,
  549. configurable: true
  550. }
  551. }
  552. },
  553. get: function(target, prop, receiver) {
  554. if (prop === "foo") {
  555. _prop = prop;
  556. _receiver = receiver;
  557. return propValue;
  558. }
  559. return obj[prop];
  560. }
  561. });
  562. var res = JSON.stringify(proxy);
  563. assert.sameValue(res, '{"foo":"321tset"}');
  564. assert.sameValue(_prop, "foo");
  565. assert.sameValue(_receiver, proxy);
  566. `
  567. testScript1(TESTLIB+SCRIPT, _undefined, t)
  568. }
  569. func TestProxy_native_proxy_get(t *testing.T) {
  570. vm := New()
  571. propValueStr := vm.ToValue("321tset")
  572. propValueIdx := vm.ToValue("idx")
  573. propValueSym := vm.ToValue("sym")
  574. sym := NewSymbol("test")
  575. obj := vm.NewObject()
  576. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  577. OwnKeys: func(*Object) *Object {
  578. return vm.NewArray("0", "foo")
  579. },
  580. GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) {
  581. if prop == "foo" {
  582. return PropertyDescriptor{
  583. Value: propValueStr,
  584. Enumerable: FLAG_TRUE,
  585. Configurable: FLAG_TRUE,
  586. }
  587. }
  588. if prop == "0" {
  589. panic(vm.NewTypeError("GetOwnPropertyDescriptor(0) was called"))
  590. }
  591. return
  592. },
  593. GetOwnPropertyDescriptorIdx: func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) {
  594. if prop == 0 {
  595. return PropertyDescriptor{
  596. Value: propValueIdx,
  597. Enumerable: FLAG_TRUE,
  598. Configurable: FLAG_TRUE,
  599. }
  600. }
  601. return
  602. },
  603. Get: func(target *Object, property string, receiver Value) (value Value) {
  604. if property == "foo" {
  605. return propValueStr
  606. }
  607. if property == "0" {
  608. panic(vm.NewTypeError("Get(0) was called"))
  609. }
  610. return obj.Get(property)
  611. },
  612. GetIdx: func(target *Object, property int, receiver Value) (value Value) {
  613. if property == 0 {
  614. return propValueIdx
  615. }
  616. return obj.Get(strconv.Itoa(property))
  617. },
  618. GetSym: func(target *Object, property *Symbol, receiver Value) (value Value) {
  619. if property == sym {
  620. return propValueSym
  621. }
  622. return obj.GetSymbol(property)
  623. },
  624. })
  625. vm.Set("proxy", proxy)
  626. res, err := vm.RunString(`JSON.stringify(proxy)`)
  627. if err != nil {
  628. t.Fatal(err)
  629. }
  630. if !res.SameAs(asciiString(`{"0":"idx","foo":"321tset"}`)) {
  631. t.Fatalf("res: %v", res)
  632. }
  633. res, err = vm.RunString(`proxy[Symbol.toPrimitive]`)
  634. if err != nil {
  635. t.Fatal(err)
  636. }
  637. if !IsUndefined(res) {
  638. t.Fatalf("res: %v", res)
  639. }
  640. res, err = vm.RunString(`proxy.hasOwnProperty(Symbol.toPrimitive)`)
  641. if err != nil {
  642. t.Fatal(err)
  643. }
  644. if !res.SameAs(valueFalse) {
  645. t.Fatalf("res: %v", res)
  646. }
  647. if val := vm.ToValue(proxy).(*Object).GetSymbol(sym); val == nil || !val.SameAs(propValueSym) {
  648. t.Fatalf("Get(symbol): %v", val)
  649. }
  650. res, err = vm.RunString(`proxy.toString()`)
  651. if err != nil {
  652. t.Fatal(err)
  653. }
  654. if !res.SameAs(asciiString(`[object Object]`)) {
  655. t.Fatalf("res: %v", res)
  656. }
  657. }
  658. func TestProxy_native_proxy_set(t *testing.T) {
  659. vm := New()
  660. propValueStr := vm.ToValue("321tset")
  661. propValueIdx := vm.ToValue("idx")
  662. propValueSym := vm.ToValue("sym")
  663. sym := NewSymbol("test")
  664. obj := vm.NewObject()
  665. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  666. Set: func(target *Object, property string, value Value, receiver Value) (success bool) {
  667. if property == "str" {
  668. obj.Set(property, propValueStr)
  669. return true
  670. }
  671. panic(vm.NewTypeError("Setter for unexpected property: %q", property))
  672. },
  673. SetIdx: func(target *Object, property int, value Value, receiver Value) (success bool) {
  674. if property == 0 {
  675. obj.Set(strconv.Itoa(property), propValueIdx)
  676. return true
  677. }
  678. panic(vm.NewTypeError("Setter for unexpected idx property: %d", property))
  679. },
  680. SetSym: func(target *Object, property *Symbol, value Value, receiver Value) (success bool) {
  681. if property == sym {
  682. obj.SetSymbol(property, propValueSym)
  683. return true
  684. }
  685. panic(vm.NewTypeError("Setter for unexpected sym property: %q", property.String()))
  686. },
  687. })
  688. proxyObj := vm.ToValue(proxy).ToObject(vm)
  689. err := proxyObj.Set("str", "")
  690. if err != nil {
  691. t.Fatal(err)
  692. }
  693. err = proxyObj.Set("0", "")
  694. if err != nil {
  695. t.Fatal(err)
  696. }
  697. err = proxyObj.SetSymbol(sym, "")
  698. if err != nil {
  699. t.Fatal(err)
  700. }
  701. if v := obj.Get("str"); !propValueStr.SameAs(v) {
  702. t.Fatal(v)
  703. }
  704. if v := obj.Get("0"); !propValueIdx.SameAs(v) {
  705. t.Fatal(v)
  706. }
  707. if v := obj.GetSymbol(sym); !propValueSym.SameAs(v) {
  708. t.Fatal(v)
  709. }
  710. }
  711. func TestProxy_target_set_prop(t *testing.T) {
  712. const SCRIPT = `
  713. var obj = {};
  714. var proxy = new Proxy(obj, {});
  715. proxy.foo = "test123";
  716. proxy.foo;
  717. `
  718. testScript1(SCRIPT, asciiString("test123"), t)
  719. }
  720. func TestProxy_proxy_set_prop(t *testing.T) {
  721. const SCRIPT = `
  722. var obj = {};
  723. var proxy = new Proxy(obj, {
  724. set: function(target, prop, receiver) {
  725. target.foo = "321tset";
  726. return true;
  727. }
  728. });
  729. proxy.foo = "test123";
  730. proxy.foo;
  731. `
  732. testScript1(SCRIPT, asciiString("321tset"), t)
  733. }
  734. func TestProxy_target_set_associative(t *testing.T) {
  735. const SCRIPT = `
  736. var obj = {};
  737. var proxy = new Proxy(obj, {});
  738. proxy["foo"] = "test123";
  739. proxy.foo;
  740. `
  741. testScript1(SCRIPT, asciiString("test123"), t)
  742. }
  743. func TestProxy_proxy_set_associative(t *testing.T) {
  744. const SCRIPT = `
  745. var obj = {};
  746. var proxy = new Proxy(obj, {
  747. set: function(target, property, value, receiver) {
  748. target["foo"] = "321tset";
  749. return true;
  750. }
  751. });
  752. proxy["foo"] = "test123";
  753. proxy.foo;
  754. `
  755. testScript1(SCRIPT, asciiString("321tset"), t)
  756. }
  757. func TestProxy_target_delete(t *testing.T) {
  758. const SCRIPT = `
  759. var obj = {
  760. foo: "test"
  761. };
  762. var proxy = new Proxy(obj, {});
  763. delete proxy.foo;
  764. proxy.foo;
  765. `
  766. testScript1(SCRIPT, _undefined, t)
  767. }
  768. func TestProxy_proxy_delete(t *testing.T) {
  769. const SCRIPT = `
  770. var obj = {
  771. foo: "test"
  772. };
  773. var proxy = new Proxy(obj, {
  774. deleteProperty: function(target, prop) {
  775. return true;
  776. }
  777. });
  778. delete proxy.foo;
  779. proxy.foo;
  780. `
  781. testScript1(SCRIPT, asciiString("test"), t)
  782. }
  783. func TestProxy_native_delete(t *testing.T) {
  784. vm := New()
  785. sym := NewSymbol("test")
  786. obj := vm.NewObject()
  787. var strCalled, idxCalled, symCalled, strNegCalled, idxNegCalled, symNegCalled bool
  788. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  789. DeleteProperty: func(target *Object, property string) (success bool) {
  790. if property == "str" {
  791. strCalled = true
  792. return true
  793. }
  794. if property == "strNeg" {
  795. strNegCalled = true
  796. return false
  797. }
  798. panic(vm.NewTypeError("DeleteProperty for unexpected property: %q", property))
  799. },
  800. DeletePropertyIdx: func(target *Object, property int) (success bool) {
  801. if property == 0 {
  802. idxCalled = true
  803. return true
  804. }
  805. if property == 1 {
  806. idxNegCalled = true
  807. return false
  808. }
  809. panic(vm.NewTypeError("DeletePropertyIdx for unexpected idx property: %d", property))
  810. },
  811. DeletePropertySym: func(target *Object, property *Symbol) (success bool) {
  812. if property == sym {
  813. symCalled = true
  814. return true
  815. }
  816. if property == SymIterator {
  817. symNegCalled = true
  818. return false
  819. }
  820. panic(vm.NewTypeError("DeletePropertySym for unexpected sym property: %q", property.String()))
  821. },
  822. })
  823. proxyObj := vm.ToValue(proxy).ToObject(vm)
  824. err := proxyObj.Delete("str")
  825. if err != nil {
  826. t.Fatal(err)
  827. }
  828. err = proxyObj.Delete("0")
  829. if err != nil {
  830. t.Fatal(err)
  831. }
  832. err = proxyObj.DeleteSymbol(sym)
  833. if err != nil {
  834. t.Fatal(err)
  835. }
  836. if !strCalled {
  837. t.Fatal("str")
  838. }
  839. if !idxCalled {
  840. t.Fatal("idx")
  841. }
  842. if !symCalled {
  843. t.Fatal("sym")
  844. }
  845. vm.Set("proxy", proxy)
  846. _, err = vm.RunString(`
  847. if (delete proxy.strNeg) {
  848. throw new Error("strNeg");
  849. }
  850. if (delete proxy[1]) {
  851. throw new Error("idxNeg");
  852. }
  853. if (delete proxy[Symbol.iterator]) {
  854. throw new Error("symNeg");
  855. }
  856. `)
  857. if err != nil {
  858. t.Fatal(err)
  859. }
  860. if !strNegCalled {
  861. t.Fatal("strNeg")
  862. }
  863. if !idxNegCalled {
  864. t.Fatal("idxNeg")
  865. }
  866. if !symNegCalled {
  867. t.Fatal("symNeg")
  868. }
  869. }
  870. func TestProxy_target_keys(t *testing.T) {
  871. const SCRIPT = `
  872. var obj = {
  873. foo: "test"
  874. };
  875. var proxy = new Proxy(obj, {});
  876. var keys = Object.keys(proxy);
  877. if (keys.length != 1) {
  878. throw new Error("assertion error");
  879. }
  880. `
  881. testScript1(SCRIPT, _undefined, t)
  882. }
  883. func TestProxy_proxy_keys(t *testing.T) {
  884. const SCRIPT = `
  885. var obj = {
  886. foo: "test"
  887. };
  888. var proxy = new Proxy(obj, {
  889. ownKeys: function(target) {
  890. return ["foo", "bar"];
  891. }
  892. });
  893. var keys = Object.keys(proxy);
  894. if (keys.length !== 1) {
  895. throw new Error("length is "+keys.length);
  896. }
  897. if (keys[0] !== "foo") {
  898. throw new Error("keys[0] is "+keys[0]);
  899. }
  900. `
  901. testScript1(SCRIPT, _undefined, t)
  902. }
  903. func TestProxy_target_call(t *testing.T) {
  904. const SCRIPT = `
  905. var obj = function() {
  906. return "test"
  907. }
  908. var proxy = new Proxy(obj, {});
  909. proxy();
  910. `
  911. testScript1(SCRIPT, asciiString("test"), t)
  912. }
  913. func TestProxy_proxy_call(t *testing.T) {
  914. const SCRIPT = `
  915. var obj = function() {
  916. return "test"
  917. }
  918. var proxy = new Proxy(obj, {
  919. apply: function(target, thisArg, args) {
  920. return "tset"
  921. }
  922. });
  923. proxy();
  924. `
  925. testScript1(SCRIPT, asciiString("tset"), t)
  926. }
  927. func TestProxy_target_func_apply(t *testing.T) {
  928. const SCRIPT = `
  929. var obj = function() {
  930. return "test"
  931. }
  932. var proxy = new Proxy(obj, {});
  933. proxy.apply();
  934. `
  935. testScript1(SCRIPT, asciiString("test"), t)
  936. }
  937. func TestProxy_proxy_func_apply(t *testing.T) {
  938. const SCRIPT = `
  939. var obj = function() {
  940. return "test"
  941. }
  942. var proxy = new Proxy(obj, {
  943. apply: function(target, thisArg, args) {
  944. return "tset"
  945. }
  946. });
  947. proxy.apply();
  948. `
  949. testScript1(SCRIPT, asciiString("tset"), t)
  950. }
  951. func TestProxy_target_func_call(t *testing.T) {
  952. const SCRIPT = `
  953. var obj = function() {
  954. return "test"
  955. }
  956. var proxy = new Proxy(obj, {});
  957. proxy.call();
  958. `
  959. testScript1(SCRIPT, asciiString("test"), t)
  960. }
  961. func TestProxy_proxy_func_call(t *testing.T) {
  962. const SCRIPT = `
  963. var obj = function() {
  964. return "test"
  965. }
  966. var proxy = new Proxy(obj, {
  967. apply: function(target, thisArg, args) {
  968. return "tset"
  969. }
  970. });
  971. proxy.call();
  972. `
  973. testScript1(SCRIPT, asciiString("tset"), t)
  974. }
  975. func TestProxy_target_new(t *testing.T) {
  976. const SCRIPT = `
  977. var obj = function(word) {
  978. this.foo = function() {
  979. return word;
  980. }
  981. }
  982. var proxy = new Proxy(obj, {});
  983. var instance = new proxy("test");
  984. instance.foo();
  985. `
  986. testScript1(SCRIPT, asciiString("test"), t)
  987. }
  988. func TestProxy_proxy_new(t *testing.T) {
  989. const SCRIPT = `
  990. var obj = function(word) {
  991. this.foo = function() {
  992. return word;
  993. }
  994. }
  995. var proxy = new Proxy(obj, {
  996. construct: function(target, args, newTarget) {
  997. var word = args[0];
  998. return {
  999. foo: function() {
  1000. return "caught-" + word
  1001. }
  1002. }
  1003. }
  1004. });
  1005. var instance = new proxy("test");
  1006. instance.foo();
  1007. `
  1008. testScript1(SCRIPT, asciiString("caught-test"), t)
  1009. }
  1010. func TestProxy_Object_native_proxy_ownKeys(t *testing.T) {
  1011. headers := map[string][]string{
  1012. "k0": {},
  1013. }
  1014. vm := New()
  1015. proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{
  1016. OwnKeys: func(target *Object) (object *Object) {
  1017. keys := make([]interface{}, 0, len(headers))
  1018. for k := range headers {
  1019. keys = append(keys, k)
  1020. }
  1021. return vm.ToValue(keys).ToObject(vm)
  1022. },
  1023. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  1024. v, exists := headers[prop]
  1025. if exists {
  1026. return PropertyDescriptor{
  1027. Value: vm.ToValue(v),
  1028. Enumerable: FLAG_TRUE,
  1029. Configurable: FLAG_TRUE,
  1030. }
  1031. }
  1032. return PropertyDescriptor{}
  1033. },
  1034. })
  1035. vm.Set("headers", proxy)
  1036. v, err := vm.RunString(`
  1037. var keys = Object.keys(headers);
  1038. keys.length === 1 && keys[0] === "k0";
  1039. `)
  1040. if err != nil {
  1041. t.Fatal(err)
  1042. }
  1043. if v != valueTrue {
  1044. t.Fatal("not true", v)
  1045. }
  1046. }
  1047. func TestProxy_proxy_forIn(t *testing.T) {
  1048. const SCRIPT = `
  1049. var proto = {
  1050. a: 2,
  1051. protoProp: 1
  1052. }
  1053. Object.defineProperty(proto, "protoNonEnum", {
  1054. value: 2,
  1055. writable: true,
  1056. configurable: true
  1057. });
  1058. var target = Object.create(proto);
  1059. var proxy = new Proxy(target, {
  1060. ownKeys: function() {
  1061. return ["a", "b"];
  1062. },
  1063. getOwnPropertyDescriptor: function(target, p) {
  1064. switch (p) {
  1065. case "a":
  1066. case "b":
  1067. return {
  1068. value: 42,
  1069. enumerable: true,
  1070. configurable: true
  1071. }
  1072. }
  1073. },
  1074. });
  1075. var forInResult = [];
  1076. for (var key in proxy) {
  1077. if (forInResult.indexOf(key) !== -1) {
  1078. throw new Error("Duplicate property "+key);
  1079. }
  1080. forInResult.push(key);
  1081. }
  1082. forInResult.length === 3 && forInResult[0] === "a" && forInResult[1] === "b" && forInResult[2] === "protoProp";
  1083. `
  1084. testScript1(SCRIPT, valueTrue, t)
  1085. }
  1086. func TestProxyExport(t *testing.T) {
  1087. vm := New()
  1088. v, err := vm.RunString(`
  1089. new Proxy({}, {});
  1090. `)
  1091. if err != nil {
  1092. t.Fatal(err)
  1093. }
  1094. v1 := v.Export()
  1095. if _, ok := v1.(Proxy); !ok {
  1096. t.Fatalf("Export returned unexpected type: %T", v1)
  1097. }
  1098. }
  1099. func TestProxy_proxy_createTargetNotCallable(t *testing.T) {
  1100. // from https://github.com/tc39/test262/blob/main/test/built-ins/Proxy/create-target-is-not-callable.js
  1101. const SCRIPT = `
  1102. var p = new Proxy({}, {});
  1103. assert.throws(TypeError, function() {
  1104. p();
  1105. });
  1106. `
  1107. testScript1(TESTLIB+SCRIPT, _undefined, t)
  1108. }
  1109. func TestProxyEnumerableSymbols(t *testing.T) {
  1110. const SCRIPT = `
  1111. var getOwnKeys = [];
  1112. var ownKeysResult = [Symbol(), "foo", "0"];
  1113. var proxy = new Proxy({}, {
  1114. getOwnPropertyDescriptor: function(_target, key) {
  1115. getOwnKeys.push(key);
  1116. },
  1117. ownKeys: function() {
  1118. return ownKeysResult;
  1119. },
  1120. });
  1121. let {...$} = proxy;
  1122. compareArray(getOwnKeys, ownKeysResult);
  1123. `
  1124. testScript1(TESTLIB+SCRIPT, valueTrue, t)
  1125. }