builtin_proxy_test.go 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  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. }
  1083. func TestProxy_proxy_createTargetNotCallable(t *testing.T) {
  1084. // from https://github.com/tc39/test262/blob/main/test/built-ins/Proxy/create-target-is-not-callable.js
  1085. const SCRIPT = `
  1086. var p = new Proxy({}, {});
  1087. assert.throws(TypeError, function() {
  1088. p();
  1089. });
  1090. `
  1091. testScript1(TESTLIB+SCRIPT, _undefined, t)
  1092. }