builtin_proxy_test.go 27 KB

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