builtin_proxy_test.go 27 KB

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