builtin_proxy_test.go 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  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"))
  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. vm.Set("proxy1", proxy1)
  302. vm.Set("proxy2", proxy2)
  303. _, err := vm.RunString(TESTLIBX + `
  304. var desc;
  305. for (var i = -1; i <= 1; i++) {
  306. desc = Object.getOwnPropertyDescriptor(proxy1, i);
  307. assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. int "+i);
  308. desc = Object.getOwnPropertyDescriptor(proxy1, ""+i);
  309. assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. str "+i);
  310. desc = Object.getOwnPropertyDescriptor(proxy2, i);
  311. assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. int "+i);
  312. desc = Object.getOwnPropertyDescriptor(proxy2, ""+i);
  313. assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. str "+i);
  314. }
  315. `)
  316. if err != nil {
  317. t.Fatal(err)
  318. }
  319. }
  320. func TestProxy_native_proxy_getOwnPropertyDescriptorSym(t *testing.T) {
  321. vm := New()
  322. o := vm.NewObject()
  323. sym := NewSymbol("42")
  324. vm.Set("sym", sym)
  325. proxy := vm.NewProxy(o, &ProxyTrapConfig{
  326. GetOwnPropertyDescriptorSym: func(target *Object, s *Symbol) PropertyDescriptor {
  327. if target != o {
  328. panic(vm.NewTypeError("Invalid target"))
  329. }
  330. if s == sym {
  331. return PropertyDescriptor{
  332. Value: vm.ToValue("passed"),
  333. Writable: FLAG_TRUE,
  334. Configurable: FLAG_TRUE,
  335. }
  336. }
  337. return PropertyDescriptor{}
  338. },
  339. })
  340. vm.Set("proxy", proxy)
  341. _, err := vm.RunString(TESTLIBX + `
  342. var desc = Object.getOwnPropertyDescriptor(proxy, sym);
  343. assert(deepEqual(desc, {value: "passed", writable: true, enumerable: false, configurable: true}));
  344. assert.sameValue(Object.getOwnPropertyDescriptor(proxy, Symbol.iterator), undefined);
  345. `)
  346. if err != nil {
  347. t.Fatal(err)
  348. }
  349. }
  350. func TestProxy_native_proxy_getOwnPropertyDescriptor_non_existing(t *testing.T) {
  351. vm := New()
  352. proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{
  353. GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) {
  354. return // empty PropertyDescriptor
  355. },
  356. })
  357. vm.Set("proxy", proxy)
  358. res, err := vm.RunString(`Object.getOwnPropertyDescriptor(proxy, "foo") === undefined`)
  359. if err != nil {
  360. t.Fatal(err)
  361. }
  362. if res != valueTrue {
  363. t.Fatal(res)
  364. }
  365. }
  366. func TestProxy_Object_target_defineProperty(t *testing.T) {
  367. const SCRIPT = `
  368. var obj = {};
  369. var proxy = new Proxy(obj, {});
  370. Object.defineProperty(proxy, "foo", {
  371. value: "test123"
  372. });
  373. proxy.foo;
  374. `
  375. testScript1(SCRIPT, asciiString("test123"), t)
  376. }
  377. func TestProxy_proxy_defineProperty(t *testing.T) {
  378. const SCRIPT = `
  379. var obj = {};
  380. var proxy = new Proxy(obj, {
  381. defineProperty: function(target, prop, descriptor) {
  382. target.foo = "321tset";
  383. return true;
  384. }
  385. });
  386. Object.defineProperty(proxy, "foo", {
  387. value: "test123"
  388. });
  389. proxy.foo;
  390. `
  391. testScript1(SCRIPT, asciiString("321tset"), t)
  392. }
  393. func TestProxy_native_proxy_defineProperty(t *testing.T) {
  394. const SCRIPT = `
  395. Object.defineProperty(proxy, "foo", {
  396. value: "teststr"
  397. });
  398. Object.defineProperty(proxy, "0", {
  399. value: "testidx"
  400. });
  401. Object.defineProperty(proxy, Symbol.toStringTag, {
  402. value: "testsym"
  403. });
  404. assert.sameValue(proxy.foo, "teststr-passed-str");
  405. assert.sameValue(proxy[0], "testidx-passed-idx");
  406. assert.sameValue(proxy[Symbol.toStringTag], "testsym-passed-sym");
  407. `
  408. runtime := New()
  409. target := runtime.NewObject()
  410. proxy := runtime.NewProxy(target, &ProxyTrapConfig{
  411. DefineProperty: func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) {
  412. target.Set(key, propertyDescriptor.Value.String()+"-passed-str")
  413. return true
  414. },
  415. DefinePropertyIdx: func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) {
  416. target.Set(strconv.Itoa(key), propertyDescriptor.Value.String()+"-passed-idx")
  417. return true
  418. },
  419. DefinePropertySym: func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) {
  420. target.SetSymbol(key, propertyDescriptor.Value.String()+"-passed-sym")
  421. return true
  422. },
  423. })
  424. runtime.Set("proxy", proxy)
  425. _, err := runtime.RunString(TESTLIB + SCRIPT)
  426. if err != nil {
  427. t.Fatal(err)
  428. }
  429. }
  430. func TestProxy_target_has_in(t *testing.T) {
  431. const SCRIPT = `
  432. var obj = {
  433. secret: true
  434. };
  435. var proxy = new Proxy(obj, {});
  436. "secret" in proxy
  437. `
  438. testScript1(SCRIPT, valueTrue, t)
  439. }
  440. func TestProxy_proxy_has_in(t *testing.T) {
  441. const SCRIPT = `
  442. var obj = {
  443. secret: true
  444. };
  445. var proxy = new Proxy(obj, {
  446. has: function(target, key) {
  447. return key !== "secret";
  448. }
  449. });
  450. "secret" in proxy
  451. `
  452. testScript1(SCRIPT, valueFalse, t)
  453. }
  454. func TestProxy_target_has_with(t *testing.T) {
  455. const SCRIPT = `
  456. var obj = {
  457. secret: true
  458. };
  459. var proxy = new Proxy(obj, {});
  460. with(proxy) {
  461. (secret);
  462. }
  463. `
  464. testScript1(SCRIPT, valueTrue, t)
  465. }
  466. func TestProxy_proxy_has_with(t *testing.T) {
  467. const SCRIPT = `
  468. var obj = {
  469. secret: true
  470. };
  471. var proxy = new Proxy(obj, {
  472. has: function(target, key) {
  473. return key !== "secret";
  474. }
  475. });
  476. var thrown = false;
  477. try {
  478. with(proxy) {
  479. (secret);
  480. }
  481. } catch (e) {
  482. if (e instanceof ReferenceError) {
  483. thrown = true;
  484. } else {
  485. throw e;
  486. }
  487. }
  488. thrown;
  489. `
  490. testScript1(SCRIPT, valueTrue, t)
  491. }
  492. func TestProxy_target_get(t *testing.T) {
  493. const SCRIPT = `
  494. var obj = {};
  495. var proxy = new Proxy(obj, {});
  496. Object.defineProperty(proxy, "foo", {
  497. value: "test123"
  498. });
  499. proxy.foo;
  500. `
  501. testScript1(SCRIPT, asciiString("test123"), t)
  502. }
  503. func TestProxy_proxy_get(t *testing.T) {
  504. const SCRIPT = `
  505. var obj = {};
  506. var proxy = new Proxy(obj, {
  507. get: function(target, prop, receiver) {
  508. return "321tset"
  509. }
  510. });
  511. Object.defineProperty(proxy, "foo", {
  512. value: "test123",
  513. configurable: true,
  514. });
  515. proxy.foo;
  516. `
  517. testScript1(SCRIPT, asciiString("321tset"), t)
  518. }
  519. func TestProxy_proxy_get_json_stringify(t *testing.T) {
  520. const SCRIPT = `
  521. var obj = {};
  522. var propValue = "321tset";
  523. var _handler, _target, _prop, _receiver;
  524. var proxy = new Proxy(obj, {
  525. ownKeys: function() {
  526. return ["foo"];
  527. },
  528. getOwnPropertyDescriptor: function(target, prop) {
  529. if (prop === "foo") {
  530. return {
  531. value: propValue,
  532. enumerable: true,
  533. configurable: true
  534. }
  535. }
  536. },
  537. get: function(target, prop, receiver) {
  538. if (prop === "foo") {
  539. _prop = prop;
  540. _receiver = receiver;
  541. return propValue;
  542. }
  543. return obj[prop];
  544. }
  545. });
  546. var res = JSON.stringify(proxy);
  547. assert.sameValue(res, '{"foo":"321tset"}');
  548. assert.sameValue(_prop, "foo");
  549. assert.sameValue(_receiver, proxy);
  550. `
  551. testScript1(TESTLIB+SCRIPT, _undefined, t)
  552. }
  553. func TestProxy_native_proxy_get(t *testing.T) {
  554. vm := New()
  555. propValueStr := vm.ToValue("321tset")
  556. propValueIdx := vm.ToValue("idx")
  557. propValueSym := vm.ToValue("sym")
  558. sym := NewSymbol("test")
  559. obj := vm.NewObject()
  560. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  561. OwnKeys: func(*Object) *Object {
  562. return vm.NewArray("0", "foo")
  563. },
  564. GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) {
  565. if prop == "foo" {
  566. return PropertyDescriptor{
  567. Value: propValueStr,
  568. Enumerable: FLAG_TRUE,
  569. Configurable: FLAG_TRUE,
  570. }
  571. }
  572. if prop == "0" {
  573. panic(vm.NewTypeError("GetOwnPropertyDescriptor(0) was called"))
  574. }
  575. return
  576. },
  577. GetOwnPropertyDescriptorIdx: func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) {
  578. if prop == 0 {
  579. return PropertyDescriptor{
  580. Value: propValueIdx,
  581. Enumerable: FLAG_TRUE,
  582. Configurable: FLAG_TRUE,
  583. }
  584. }
  585. return
  586. },
  587. Get: func(target *Object, property string, receiver Value) (value Value) {
  588. if property == "foo" {
  589. return propValueStr
  590. }
  591. if property == "0" {
  592. panic(vm.NewTypeError("Get(0) was called"))
  593. }
  594. return obj.Get(property)
  595. },
  596. GetIdx: func(target *Object, property int, receiver Value) (value Value) {
  597. if property == 0 {
  598. return propValueIdx
  599. }
  600. return obj.Get(strconv.Itoa(property))
  601. },
  602. GetSym: func(target *Object, property *Symbol, receiver Value) (value Value) {
  603. if property == sym {
  604. return propValueSym
  605. }
  606. return obj.GetSymbol(property)
  607. },
  608. })
  609. vm.Set("proxy", proxy)
  610. res, err := vm.RunString(`JSON.stringify(proxy)`)
  611. if err != nil {
  612. t.Fatal(err)
  613. }
  614. if !res.SameAs(asciiString(`{"0":"idx","foo":"321tset"}`)) {
  615. t.Fatalf("res: %v", res)
  616. }
  617. res, err = vm.RunString(`proxy[Symbol.toPrimitive]`)
  618. if err != nil {
  619. t.Fatal(err)
  620. }
  621. if !IsUndefined(res) {
  622. t.Fatalf("res: %v", res)
  623. }
  624. res, err = vm.RunString(`proxy.hasOwnProperty(Symbol.toPrimitive)`)
  625. if err != nil {
  626. t.Fatal(err)
  627. }
  628. if !res.SameAs(valueFalse) {
  629. t.Fatalf("res: %v", res)
  630. }
  631. if val := vm.ToValue(proxy).(*Object).GetSymbol(sym); val == nil || !val.SameAs(propValueSym) {
  632. t.Fatalf("Get(symbol): %v", val)
  633. }
  634. res, err = vm.RunString(`proxy.toString()`)
  635. if err != nil {
  636. t.Fatal(err)
  637. }
  638. if !res.SameAs(asciiString(`[object Object]`)) {
  639. t.Fatalf("res: %v", res)
  640. }
  641. }
  642. func TestProxy_native_proxy_set(t *testing.T) {
  643. vm := New()
  644. propValueStr := vm.ToValue("321tset")
  645. propValueIdx := vm.ToValue("idx")
  646. propValueSym := vm.ToValue("sym")
  647. sym := NewSymbol("test")
  648. obj := vm.NewObject()
  649. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  650. Set: func(target *Object, property string, value Value, receiver Value) (success bool) {
  651. if property == "str" {
  652. obj.Set(property, propValueStr)
  653. return true
  654. }
  655. panic(vm.NewTypeError("Setter for unexpected property: %q", property))
  656. },
  657. SetIdx: func(target *Object, property int, value Value, receiver Value) (success bool) {
  658. if property == 0 {
  659. obj.Set(strconv.Itoa(property), propValueIdx)
  660. return true
  661. }
  662. panic(vm.NewTypeError("Setter for unexpected idx property: %d", property))
  663. },
  664. SetSym: func(target *Object, property *Symbol, value Value, receiver Value) (success bool) {
  665. if property == sym {
  666. obj.SetSymbol(property, propValueSym)
  667. return true
  668. }
  669. panic(vm.NewTypeError("Setter for unexpected sym property: %q", property.String()))
  670. },
  671. })
  672. proxyObj := vm.ToValue(proxy).ToObject(vm)
  673. err := proxyObj.Set("str", "")
  674. if err != nil {
  675. t.Fatal(err)
  676. }
  677. err = proxyObj.Set("0", "")
  678. if err != nil {
  679. t.Fatal(err)
  680. }
  681. err = proxyObj.SetSymbol(sym, "")
  682. if err != nil {
  683. t.Fatal(err)
  684. }
  685. if v := obj.Get("str"); !propValueStr.SameAs(v) {
  686. t.Fatal(v)
  687. }
  688. if v := obj.Get("0"); !propValueIdx.SameAs(v) {
  689. t.Fatal(v)
  690. }
  691. if v := obj.GetSymbol(sym); !propValueSym.SameAs(v) {
  692. t.Fatal(v)
  693. }
  694. }
  695. func TestProxy_target_set_prop(t *testing.T) {
  696. const SCRIPT = `
  697. var obj = {};
  698. var proxy = new Proxy(obj, {});
  699. proxy.foo = "test123";
  700. proxy.foo;
  701. `
  702. testScript1(SCRIPT, asciiString("test123"), t)
  703. }
  704. func TestProxy_proxy_set_prop(t *testing.T) {
  705. const SCRIPT = `
  706. var obj = {};
  707. var proxy = new Proxy(obj, {
  708. set: function(target, prop, receiver) {
  709. target.foo = "321tset";
  710. return true;
  711. }
  712. });
  713. proxy.foo = "test123";
  714. proxy.foo;
  715. `
  716. testScript1(SCRIPT, asciiString("321tset"), t)
  717. }
  718. func TestProxy_target_set_associative(t *testing.T) {
  719. const SCRIPT = `
  720. var obj = {};
  721. var proxy = new Proxy(obj, {});
  722. proxy["foo"] = "test123";
  723. proxy.foo;
  724. `
  725. testScript1(SCRIPT, asciiString("test123"), t)
  726. }
  727. func TestProxy_proxy_set_associative(t *testing.T) {
  728. const SCRIPT = `
  729. var obj = {};
  730. var proxy = new Proxy(obj, {
  731. set: function(target, property, value, receiver) {
  732. target["foo"] = "321tset";
  733. return true;
  734. }
  735. });
  736. proxy["foo"] = "test123";
  737. proxy.foo;
  738. `
  739. testScript1(SCRIPT, asciiString("321tset"), t)
  740. }
  741. func TestProxy_target_delete(t *testing.T) {
  742. const SCRIPT = `
  743. var obj = {
  744. foo: "test"
  745. };
  746. var proxy = new Proxy(obj, {});
  747. delete proxy.foo;
  748. proxy.foo;
  749. `
  750. testScript1(SCRIPT, _undefined, t)
  751. }
  752. func TestProxy_proxy_delete(t *testing.T) {
  753. const SCRIPT = `
  754. var obj = {
  755. foo: "test"
  756. };
  757. var proxy = new Proxy(obj, {
  758. deleteProperty: function(target, prop) {
  759. return true;
  760. }
  761. });
  762. delete proxy.foo;
  763. proxy.foo;
  764. `
  765. testScript1(SCRIPT, asciiString("test"), t)
  766. }
  767. func TestProxy_native_delete(t *testing.T) {
  768. vm := New()
  769. sym := NewSymbol("test")
  770. obj := vm.NewObject()
  771. var strCalled, idxCalled, symCalled, strNegCalled, idxNegCalled, symNegCalled bool
  772. proxy := vm.NewProxy(obj, &ProxyTrapConfig{
  773. DeleteProperty: func(target *Object, property string) (success bool) {
  774. if property == "str" {
  775. strCalled = true
  776. return true
  777. }
  778. if property == "strNeg" {
  779. strNegCalled = true
  780. return false
  781. }
  782. panic(vm.NewTypeError("DeleteProperty for unexpected property: %q", property))
  783. },
  784. DeletePropertyIdx: func(target *Object, property int) (success bool) {
  785. if property == 0 {
  786. idxCalled = true
  787. return true
  788. }
  789. if property == 1 {
  790. idxNegCalled = true
  791. return false
  792. }
  793. panic(vm.NewTypeError("DeletePropertyIdx for unexpected idx property: %d", property))
  794. },
  795. DeletePropertySym: func(target *Object, property *Symbol) (success bool) {
  796. if property == sym {
  797. symCalled = true
  798. return true
  799. }
  800. if property == SymIterator {
  801. symNegCalled = true
  802. return false
  803. }
  804. panic(vm.NewTypeError("DeletePropertySym for unexpected sym property: %q", property.String()))
  805. },
  806. })
  807. proxyObj := vm.ToValue(proxy).ToObject(vm)
  808. err := proxyObj.Delete("str")
  809. if err != nil {
  810. t.Fatal(err)
  811. }
  812. err = proxyObj.Delete("0")
  813. if err != nil {
  814. t.Fatal(err)
  815. }
  816. err = proxyObj.DeleteSymbol(sym)
  817. if err != nil {
  818. t.Fatal(err)
  819. }
  820. if !strCalled {
  821. t.Fatal("str")
  822. }
  823. if !idxCalled {
  824. t.Fatal("idx")
  825. }
  826. if !symCalled {
  827. t.Fatal("sym")
  828. }
  829. vm.Set("proxy", proxy)
  830. _, err = vm.RunString(`
  831. if (delete proxy.strNeg) {
  832. throw new Error("strNeg");
  833. }
  834. if (delete proxy[1]) {
  835. throw new Error("idxNeg");
  836. }
  837. if (delete proxy[Symbol.iterator]) {
  838. throw new Error("symNeg");
  839. }
  840. `)
  841. if err != nil {
  842. t.Fatal(err)
  843. }
  844. if !strNegCalled {
  845. t.Fatal("strNeg")
  846. }
  847. if !idxNegCalled {
  848. t.Fatal("idxNeg")
  849. }
  850. if !symNegCalled {
  851. t.Fatal("symNeg")
  852. }
  853. }
  854. func TestProxy_target_keys(t *testing.T) {
  855. const SCRIPT = `
  856. var obj = {
  857. foo: "test"
  858. };
  859. var proxy = new Proxy(obj, {});
  860. var keys = Object.keys(proxy);
  861. if (keys.length != 1) {
  862. throw new Error("assertion error");
  863. }
  864. `
  865. testScript1(SCRIPT, _undefined, t)
  866. }
  867. func TestProxy_proxy_keys(t *testing.T) {
  868. const SCRIPT = `
  869. var obj = {
  870. foo: "test"
  871. };
  872. var proxy = new Proxy(obj, {
  873. ownKeys: function(target) {
  874. return ["foo", "bar"];
  875. }
  876. });
  877. var keys = Object.keys(proxy);
  878. if (keys.length !== 1) {
  879. throw new Error("length is "+keys.length);
  880. }
  881. if (keys[0] !== "foo") {
  882. throw new Error("keys[0] is "+keys[0]);
  883. }
  884. `
  885. testScript1(SCRIPT, _undefined, t)
  886. }
  887. func TestProxy_target_call(t *testing.T) {
  888. const SCRIPT = `
  889. var obj = function() {
  890. return "test"
  891. }
  892. var proxy = new Proxy(obj, {});
  893. proxy();
  894. `
  895. testScript1(SCRIPT, asciiString("test"), t)
  896. }
  897. func TestProxy_proxy_call(t *testing.T) {
  898. const SCRIPT = `
  899. var obj = function() {
  900. return "test"
  901. }
  902. var proxy = new Proxy(obj, {
  903. apply: function(target, thisArg, args) {
  904. return "tset"
  905. }
  906. });
  907. proxy();
  908. `
  909. testScript1(SCRIPT, asciiString("tset"), t)
  910. }
  911. func TestProxy_target_func_apply(t *testing.T) {
  912. const SCRIPT = `
  913. var obj = function() {
  914. return "test"
  915. }
  916. var proxy = new Proxy(obj, {});
  917. proxy.apply();
  918. `
  919. testScript1(SCRIPT, asciiString("test"), t)
  920. }
  921. func TestProxy_proxy_func_apply(t *testing.T) {
  922. const SCRIPT = `
  923. var obj = function() {
  924. return "test"
  925. }
  926. var proxy = new Proxy(obj, {
  927. apply: function(target, thisArg, args) {
  928. return "tset"
  929. }
  930. });
  931. proxy.apply();
  932. `
  933. testScript1(SCRIPT, asciiString("tset"), t)
  934. }
  935. func TestProxy_target_func_call(t *testing.T) {
  936. const SCRIPT = `
  937. var obj = function() {
  938. return "test"
  939. }
  940. var proxy = new Proxy(obj, {});
  941. proxy.call();
  942. `
  943. testScript1(SCRIPT, asciiString("test"), t)
  944. }
  945. func TestProxy_proxy_func_call(t *testing.T) {
  946. const SCRIPT = `
  947. var obj = function() {
  948. return "test"
  949. }
  950. var proxy = new Proxy(obj, {
  951. apply: function(target, thisArg, args) {
  952. return "tset"
  953. }
  954. });
  955. proxy.call();
  956. `
  957. testScript1(SCRIPT, asciiString("tset"), t)
  958. }
  959. func TestProxy_target_new(t *testing.T) {
  960. const SCRIPT = `
  961. var obj = function(word) {
  962. this.foo = function() {
  963. return word;
  964. }
  965. }
  966. var proxy = new Proxy(obj, {});
  967. var instance = new proxy("test");
  968. instance.foo();
  969. `
  970. testScript1(SCRIPT, asciiString("test"), t)
  971. }
  972. func TestProxy_proxy_new(t *testing.T) {
  973. const SCRIPT = `
  974. var obj = function(word) {
  975. this.foo = function() {
  976. return word;
  977. }
  978. }
  979. var proxy = new Proxy(obj, {
  980. construct: function(target, args, newTarget) {
  981. var word = args[0];
  982. return {
  983. foo: function() {
  984. return "caught-" + word
  985. }
  986. }
  987. }
  988. });
  989. var instance = new proxy("test");
  990. instance.foo();
  991. `
  992. testScript1(SCRIPT, asciiString("caught-test"), t)
  993. }
  994. func TestProxy_Object_native_proxy_ownKeys(t *testing.T) {
  995. headers := map[string][]string{
  996. "k0": {},
  997. }
  998. vm := New()
  999. proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{
  1000. OwnKeys: func(target *Object) (object *Object) {
  1001. keys := make([]interface{}, 0, len(headers))
  1002. for k := range headers {
  1003. keys = append(keys, k)
  1004. }
  1005. return vm.ToValue(keys).ToObject(vm)
  1006. },
  1007. GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor {
  1008. v, exists := headers[prop]
  1009. if exists {
  1010. return PropertyDescriptor{
  1011. Value: vm.ToValue(v),
  1012. Enumerable: FLAG_TRUE,
  1013. Configurable: FLAG_TRUE,
  1014. }
  1015. }
  1016. return PropertyDescriptor{}
  1017. },
  1018. })
  1019. vm.Set("headers", proxy)
  1020. v, err := vm.RunString(`
  1021. var keys = Object.keys(headers);
  1022. keys.length === 1 && keys[0] === "k0";
  1023. `)
  1024. if err != nil {
  1025. t.Fatal(err)
  1026. }
  1027. if v != valueTrue {
  1028. t.Fatal("not true", v)
  1029. }
  1030. }
  1031. func TestProxy_proxy_forIn(t *testing.T) {
  1032. const SCRIPT = `
  1033. var proto = {
  1034. a: 2,
  1035. protoProp: 1
  1036. }
  1037. Object.defineProperty(proto, "protoNonEnum", {
  1038. value: 2,
  1039. writable: true,
  1040. configurable: true
  1041. });
  1042. var target = Object.create(proto);
  1043. var proxy = new Proxy(target, {
  1044. ownKeys: function() {
  1045. return ["a", "b"];
  1046. },
  1047. getOwnPropertyDescriptor: function(target, p) {
  1048. switch (p) {
  1049. case "a":
  1050. case "b":
  1051. return {
  1052. value: 42,
  1053. enumerable: true,
  1054. configurable: true
  1055. }
  1056. }
  1057. },
  1058. });
  1059. var forInResult = [];
  1060. for (var key in proxy) {
  1061. if (forInResult.indexOf(key) !== -1) {
  1062. throw new Error("Duplicate property "+key);
  1063. }
  1064. forInResult.push(key);
  1065. }
  1066. forInResult.length === 3 && forInResult[0] === "a" && forInResult[1] === "b" && forInResult[2] === "protoProp";
  1067. `
  1068. testScript1(SCRIPT, valueTrue, t)
  1069. }
  1070. func TestProxyExport(t *testing.T) {
  1071. vm := New()
  1072. v, err := vm.RunString(`
  1073. new Proxy({}, {});
  1074. `)
  1075. if err != nil {
  1076. t.Fatal(err)
  1077. }
  1078. v1 := v.Export()
  1079. if _, ok := v1.(Proxy); !ok {
  1080. t.Fatalf("Export returned unexpected type: %T", v1)
  1081. }
  1082. }