object_goreflect_test.go 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  1. package goja
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "reflect"
  7. "strings"
  8. "testing"
  9. "time"
  10. )
  11. func TestGoReflectGet(t *testing.T) {
  12. const SCRIPT = `
  13. o.X + o.Y;
  14. `
  15. type O struct {
  16. X int
  17. Y string
  18. }
  19. r := New()
  20. o := O{X: 4, Y: "2"}
  21. r.Set("o", o)
  22. v, err := r.RunString(SCRIPT)
  23. if err != nil {
  24. t.Fatal(err)
  25. }
  26. if s, ok := v.(valueString); ok {
  27. if s.String() != "42" {
  28. t.Fatalf("Unexpected string: %s", s)
  29. }
  30. } else {
  31. t.Fatalf("Unexpected type: %s", v)
  32. }
  33. }
  34. func TestGoReflectSet(t *testing.T) {
  35. const SCRIPT = `
  36. o.X++;
  37. o.Y += "P";
  38. `
  39. type O struct {
  40. X int
  41. Y string
  42. }
  43. r := New()
  44. o := O{X: 4, Y: "2"}
  45. r.Set("o", &o)
  46. _, err := r.RunString(SCRIPT)
  47. if err != nil {
  48. t.Fatal(err)
  49. }
  50. if o.X != 5 {
  51. t.Fatalf("Unexpected X: %d", o.X)
  52. }
  53. if o.Y != "2P" {
  54. t.Fatalf("Unexpected Y: %s", o.Y)
  55. }
  56. }
  57. func TestGoReflectEnumerate(t *testing.T) {
  58. const SCRIPT = `
  59. var hasX = false;
  60. var hasY = false;
  61. for (var key in o) {
  62. switch (key) {
  63. case "X":
  64. if (hasX) {
  65. throw "Already have X";
  66. }
  67. hasX = true;
  68. break;
  69. case "Y":
  70. if (hasY) {
  71. throw "Already have Y";
  72. }
  73. hasY = true;
  74. break;
  75. default:
  76. throw "Unexpected property: " + key;
  77. }
  78. }
  79. hasX && hasY;
  80. `
  81. type S struct {
  82. X, Y int
  83. }
  84. r := New()
  85. r.Set("o", S{X: 40, Y: 2})
  86. v, err := r.RunString(SCRIPT)
  87. if err != nil {
  88. t.Fatal(err)
  89. }
  90. if !v.StrictEquals(valueTrue) {
  91. t.Fatalf("Expected true, got %v", v)
  92. }
  93. }
  94. func TestGoReflectCustomIntUnbox(t *testing.T) {
  95. const SCRIPT = `
  96. i + 2;
  97. `
  98. type CustomInt int
  99. var i CustomInt = 40
  100. r := New()
  101. r.Set("i", i)
  102. v, err := r.RunString(SCRIPT)
  103. if err != nil {
  104. t.Fatal(err)
  105. }
  106. if !v.StrictEquals(intToValue(42)) {
  107. t.Fatalf("Expected int 42, got %v", v)
  108. }
  109. }
  110. func TestGoReflectPreserveCustomType(t *testing.T) {
  111. const SCRIPT = `
  112. i;
  113. `
  114. type CustomInt int
  115. var i CustomInt = 42
  116. r := New()
  117. r.Set("i", i)
  118. v, err := r.RunString(SCRIPT)
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. ve := v.Export()
  123. if ii, ok := ve.(CustomInt); ok {
  124. if ii != i {
  125. t.Fatalf("Wrong value: %v", ii)
  126. }
  127. } else {
  128. t.Fatalf("Wrong type: %v", ve)
  129. }
  130. }
  131. func TestGoReflectCustomIntValueOf(t *testing.T) {
  132. const SCRIPT = `
  133. if (i instanceof Number) {
  134. i.valueOf();
  135. } else {
  136. throw new Error("Value is not a number");
  137. }
  138. `
  139. type CustomInt int
  140. var i CustomInt = 42
  141. r := New()
  142. r.Set("i", i)
  143. v, err := r.RunString(SCRIPT)
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. if !v.StrictEquals(intToValue(42)) {
  148. t.Fatalf("Expected int 42, got %v", v)
  149. }
  150. }
  151. func TestGoReflectEqual(t *testing.T) {
  152. const SCRIPT = `
  153. x === y;
  154. `
  155. type CustomInt int
  156. var x CustomInt = 42
  157. var y CustomInt = 42
  158. r := New()
  159. r.Set("x", x)
  160. r.Set("y", y)
  161. v, err := r.RunString(SCRIPT)
  162. if err != nil {
  163. t.Fatal(err)
  164. }
  165. if !v.StrictEquals(valueTrue) {
  166. t.Fatalf("Expected true, got %v", v)
  167. }
  168. }
  169. type testGoReflectMethod_O struct {
  170. field string
  171. Test string
  172. }
  173. func (o testGoReflectMethod_O) Method(s string) string {
  174. return o.field + s
  175. }
  176. func TestGoReflectMethod(t *testing.T) {
  177. const SCRIPT = `
  178. o.Method(" 123")
  179. `
  180. o := testGoReflectMethod_O{
  181. field: "test",
  182. }
  183. r := New()
  184. r.Set("o", &o)
  185. v, err := r.RunString(SCRIPT)
  186. if err != nil {
  187. t.Fatal(err)
  188. }
  189. if !v.StrictEquals(asciiString("test 123")) {
  190. t.Fatalf("Expected 'test 123', got %v", v)
  191. }
  192. }
  193. func (o *testGoReflectMethod_O) Set(s string) {
  194. o.field = s
  195. }
  196. func (o *testGoReflectMethod_O) Get() string {
  197. return o.field
  198. }
  199. func TestGoReflectMethodPtr(t *testing.T) {
  200. const SCRIPT = `
  201. o.Set("42")
  202. o.Get()
  203. `
  204. o := testGoReflectMethod_O{
  205. field: "test",
  206. }
  207. r := New()
  208. r.Set("o", &o)
  209. v, err := r.RunString(SCRIPT)
  210. if err != nil {
  211. t.Fatal(err)
  212. }
  213. if !v.StrictEquals(asciiString("42")) {
  214. t.Fatalf("Expected '42', got %v", v)
  215. }
  216. }
  217. func TestGoReflectProp(t *testing.T) {
  218. const SCRIPT = `
  219. var d1 = Object.getOwnPropertyDescriptor(o, "Get");
  220. var d2 = Object.getOwnPropertyDescriptor(o, "Test");
  221. !d1.writable && !d1.configurable && d2.writable && !d2.configurable;
  222. `
  223. o := testGoReflectMethod_O{
  224. field: "test",
  225. }
  226. r := New()
  227. r.Set("o", &o)
  228. v, err := r.RunString(SCRIPT)
  229. if err != nil {
  230. t.Fatal(err)
  231. }
  232. if !v.StrictEquals(valueTrue) {
  233. t.Fatalf("Expected true, got %v", v)
  234. }
  235. }
  236. func TestGoReflectRedefineFieldSuccess(t *testing.T) {
  237. const SCRIPT = `
  238. Object.defineProperty(o, "Test", {value: "AAA"}) === o;
  239. `
  240. o := testGoReflectMethod_O{}
  241. r := New()
  242. r.Set("o", &o)
  243. v, err := r.RunString(SCRIPT)
  244. if err != nil {
  245. t.Fatal(err)
  246. }
  247. if !v.StrictEquals(valueTrue) {
  248. t.Fatalf("Expected true, got %v", v)
  249. }
  250. if o.Test != "AAA" {
  251. t.Fatalf("Expected 'AAA', got '%s'", o.Test)
  252. }
  253. }
  254. func TestGoReflectRedefineFieldNonWritable(t *testing.T) {
  255. const SCRIPT = `
  256. var thrown = false;
  257. try {
  258. Object.defineProperty(o, "Test", {value: "AAA", writable: false});
  259. } catch (e) {
  260. if (e instanceof TypeError) {
  261. thrown = true;
  262. } else {
  263. throw e;
  264. }
  265. }
  266. thrown;
  267. `
  268. o := testGoReflectMethod_O{Test: "Test"}
  269. r := New()
  270. r.Set("o", &o)
  271. v, err := r.RunString(SCRIPT)
  272. if err != nil {
  273. t.Fatal(err)
  274. }
  275. if !v.StrictEquals(valueTrue) {
  276. t.Fatalf("Expected true, got %v", v)
  277. }
  278. if o.Test != "Test" {
  279. t.Fatalf("Expected 'Test', got: '%s'", o.Test)
  280. }
  281. }
  282. func TestGoReflectRedefineFieldConfigurable(t *testing.T) {
  283. const SCRIPT = `
  284. var thrown = false;
  285. try {
  286. Object.defineProperty(o, "Test", {value: "AAA", configurable: true});
  287. } catch (e) {
  288. if (e instanceof TypeError) {
  289. thrown = true;
  290. } else {
  291. throw e;
  292. }
  293. }
  294. thrown;
  295. `
  296. o := testGoReflectMethod_O{Test: "Test"}
  297. r := New()
  298. r.Set("o", &o)
  299. v, err := r.RunString(SCRIPT)
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. if !v.StrictEquals(valueTrue) {
  304. t.Fatalf("Expected true, got %v", v)
  305. }
  306. if o.Test != "Test" {
  307. t.Fatalf("Expected 'Test', got: '%s'", o.Test)
  308. }
  309. }
  310. func TestGoReflectRedefineMethod(t *testing.T) {
  311. const SCRIPT = `
  312. var thrown = false;
  313. try {
  314. Object.defineProperty(o, "Method", {value: "AAA", configurable: true});
  315. } catch (e) {
  316. if (e instanceof TypeError) {
  317. thrown = true;
  318. } else {
  319. throw e;
  320. }
  321. }
  322. thrown;
  323. `
  324. o := testGoReflectMethod_O{Test: "Test"}
  325. r := New()
  326. r.Set("o", &o)
  327. v, err := r.RunString(SCRIPT)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. if !v.StrictEquals(valueTrue) {
  332. t.Fatalf("Expected true, got %v", v)
  333. }
  334. }
  335. func TestGoReflectEmbeddedStruct(t *testing.T) {
  336. const SCRIPT = `
  337. if (o.ParentField2 !== "ParentField2") {
  338. throw new Error("ParentField2 = " + o.ParentField2);
  339. }
  340. if (o.Parent.ParentField2 !== 2) {
  341. throw new Error("o.Parent.ParentField2 = " + o.Parent.ParentField2);
  342. }
  343. if (o.ParentField1 !== 1) {
  344. throw new Error("o.ParentField1 = " + o.ParentField1);
  345. }
  346. if (o.ChildField !== 3) {
  347. throw new Error("o.ChildField = " + o.ChildField);
  348. }
  349. var keys = {};
  350. for (var k in o) {
  351. if (keys[k]) {
  352. throw new Error("Duplicate key: " + k);
  353. }
  354. keys[k] = true;
  355. }
  356. var expectedKeys = ["ParentField2", "ParentField1", "Parent", "ChildField"];
  357. for (var i in expectedKeys) {
  358. if (!keys[expectedKeys[i]]) {
  359. throw new Error("Missing key in enumeration: " + expectedKeys[i]);
  360. }
  361. delete keys[expectedKeys[i]];
  362. }
  363. var remainingKeys = Object.keys(keys);
  364. if (remainingKeys.length > 0) {
  365. throw new Error("Unexpected keys: " + remainingKeys);
  366. }
  367. o.ParentField2 = "ParentField22";
  368. o.Parent.ParentField2 = 22;
  369. o.ParentField1 = 11;
  370. o.ChildField = 33;
  371. `
  372. type Parent struct {
  373. ParentField1 int
  374. ParentField2 int
  375. }
  376. type Child struct {
  377. ParentField2 string
  378. Parent
  379. ChildField int
  380. }
  381. vm := New()
  382. o := Child{
  383. Parent: Parent{
  384. ParentField1: 1,
  385. ParentField2: 2,
  386. },
  387. ParentField2: "ParentField2",
  388. ChildField: 3,
  389. }
  390. vm.Set("o", &o)
  391. _, err := vm.RunString(SCRIPT)
  392. if err != nil {
  393. t.Fatal(err)
  394. }
  395. if o.ParentField2 != "ParentField22" {
  396. t.Fatalf("ParentField2 = %q", o.ParentField2)
  397. }
  398. if o.Parent.ParentField2 != 22 {
  399. t.Fatalf("Parent.ParentField2 = %d", o.Parent.ParentField2)
  400. }
  401. if o.ParentField1 != 11 {
  402. t.Fatalf("ParentField1 = %d", o.ParentField1)
  403. }
  404. if o.ChildField != 33 {
  405. t.Fatalf("ChildField = %d", o.ChildField)
  406. }
  407. }
  408. type jsonTagNamer struct{}
  409. func (jsonTagNamer) FieldName(_ reflect.Type, field reflect.StructField) string {
  410. if jsonTag := field.Tag.Get("json"); jsonTag != "" {
  411. return jsonTag
  412. }
  413. return field.Name
  414. }
  415. func (jsonTagNamer) MethodName(_ reflect.Type, method reflect.Method) string {
  416. return method.Name
  417. }
  418. func TestGoReflectCustomNaming(t *testing.T) {
  419. type testStructWithJsonTags struct {
  420. A string `json:"b"` // <-- script sees field "A" as property "b"
  421. }
  422. o := &testStructWithJsonTags{"Hello world"}
  423. r := New()
  424. r.SetFieldNameMapper(&jsonTagNamer{})
  425. r.Set("fn", func() *testStructWithJsonTags { return o })
  426. t.Run("get property", func(t *testing.T) {
  427. v, err := r.RunString(`fn().b`)
  428. if err != nil {
  429. t.Fatal(err)
  430. }
  431. if !v.StrictEquals(newStringValue(o.A)) {
  432. t.Fatalf("Expected %q, got %v", o.A, v)
  433. }
  434. })
  435. t.Run("set property", func(t *testing.T) {
  436. _, err := r.RunString(`fn().b = "Hello universe"`)
  437. if err != nil {
  438. t.Fatal(err)
  439. }
  440. if o.A != "Hello universe" {
  441. t.Fatalf("Expected \"Hello universe\", got %q", o.A)
  442. }
  443. })
  444. t.Run("enumerate properties", func(t *testing.T) {
  445. v, err := r.RunString(`Object.keys(fn())`)
  446. if err != nil {
  447. t.Fatal(err)
  448. }
  449. if !reflect.DeepEqual(v.Export(), []interface{}{"b"}) {
  450. t.Fatalf("Expected [\"b\"], got %v", v.Export())
  451. }
  452. })
  453. }
  454. func TestGoReflectCustomObjNaming(t *testing.T) {
  455. type testStructWithJsonTags struct {
  456. A string `json:"b"` // <-- script sees field "A" as property "b"
  457. }
  458. r := New()
  459. r.SetFieldNameMapper(&jsonTagNamer{})
  460. t.Run("Set object in slice", func(t *testing.T) {
  461. testSlice := &[]testStructWithJsonTags{{"Hello world"}}
  462. r.Set("testslice", testSlice)
  463. _, err := r.RunString(`testslice[0] = {b:"setted"}`)
  464. if err != nil {
  465. t.Fatal(err)
  466. }
  467. if (*testSlice)[0].A != "setted" {
  468. t.Fatalf("Expected \"setted\", got %q", (*testSlice)[0])
  469. }
  470. })
  471. t.Run("Set object in map", func(t *testing.T) {
  472. testMap := map[string]testStructWithJsonTags{"key": {"Hello world"}}
  473. r.Set("testmap", testMap)
  474. _, err := r.RunString(`testmap["key"] = {b:"setted"}`)
  475. if err != nil {
  476. t.Fatal(err)
  477. }
  478. if testMap["key"].A != "setted" {
  479. t.Fatalf("Expected \"setted\", got %q", testMap["key"])
  480. }
  481. })
  482. t.Run("Add object to map", func(t *testing.T) {
  483. testMap := map[string]testStructWithJsonTags{}
  484. r.Set("testmap", testMap)
  485. _, err := r.RunString(`testmap["newkey"] = {b:"setted"}`)
  486. if err != nil {
  487. t.Fatal(err)
  488. }
  489. if testMap["newkey"].A != "setted" {
  490. t.Fatalf("Expected \"setted\", got %q", testMap["newkey"])
  491. }
  492. })
  493. }
  494. type fieldNameMapper1 struct{}
  495. func (fieldNameMapper1) FieldName(_ reflect.Type, f reflect.StructField) string {
  496. return strings.ToLower(f.Name)
  497. }
  498. func (fieldNameMapper1) MethodName(_ reflect.Type, m reflect.Method) string {
  499. return m.Name
  500. }
  501. func TestNonStructAnonFields(t *testing.T) {
  502. type Test1 struct {
  503. M bool
  504. }
  505. type test3 []int
  506. type Test4 []int
  507. type Test2 struct {
  508. test3
  509. Test4
  510. *Test1
  511. }
  512. const SCRIPT = `
  513. JSON.stringify(a);
  514. a.m && a.test3 === undefined && a.test4.length === 2
  515. `
  516. vm := New()
  517. vm.SetFieldNameMapper(fieldNameMapper1{})
  518. vm.Set("a", &Test2{Test1: &Test1{M: true}, Test4: []int{1, 2}})
  519. v, err := vm.RunString(SCRIPT)
  520. if err != nil {
  521. t.Fatal(err)
  522. }
  523. if !v.StrictEquals(valueTrue) {
  524. t.Fatalf("Unexepected result: %v", v)
  525. }
  526. }
  527. func TestStructNonAddressable(t *testing.T) {
  528. type S struct {
  529. Field int
  530. }
  531. const SCRIPT = `
  532. "use strict";
  533. if (Object.getOwnPropertyDescriptor(s, "Field").writable) {
  534. throw new Error("Field is writable");
  535. }
  536. if (!Object.getOwnPropertyDescriptor(s1, "Field").writable) {
  537. throw new Error("Field is non-writable");
  538. }
  539. s1.Field = 42;
  540. var result;
  541. try {
  542. s.Field = 42;
  543. result = false;
  544. } catch (e) {
  545. result = e instanceof TypeError;
  546. }
  547. result;
  548. `
  549. var s S
  550. vm := New()
  551. vm.Set("s", s)
  552. vm.Set("s1", &s)
  553. v, err := vm.RunString(SCRIPT)
  554. if err != nil {
  555. t.Fatal(err)
  556. }
  557. if !v.StrictEquals(valueTrue) {
  558. t.Fatalf("Unexpected result: %v", v)
  559. }
  560. if s.Field != 42 {
  561. t.Fatalf("Unexpected s.Field value: %d", s.Field)
  562. }
  563. }
  564. type testFieldMapper struct {
  565. }
  566. func (testFieldMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
  567. if tag := f.Tag.Get("js"); tag != "" {
  568. if tag == "-" {
  569. return ""
  570. }
  571. return tag
  572. }
  573. return f.Name
  574. }
  575. func (testFieldMapper) MethodName(_ reflect.Type, m reflect.Method) string {
  576. return m.Name
  577. }
  578. func TestHidingAnonField(t *testing.T) {
  579. type InnerType struct {
  580. AnotherField string
  581. }
  582. type OuterType struct {
  583. InnerType `js:"-"`
  584. SomeField string
  585. }
  586. const SCRIPT = `
  587. var a = Object.getOwnPropertyNames(o);
  588. if (a.length !== 2) {
  589. throw new Error("unexpected length: " + a.length);
  590. }
  591. if (a.indexOf("SomeField") === -1) {
  592. throw new Error("no SomeField");
  593. }
  594. if (a.indexOf("AnotherField") === -1) {
  595. throw new Error("no SomeField");
  596. }
  597. `
  598. var o OuterType
  599. vm := New()
  600. vm.SetFieldNameMapper(testFieldMapper{})
  601. vm.Set("o", &o)
  602. _, err := vm.RunString(SCRIPT)
  603. if err != nil {
  604. t.Fatal(err)
  605. }
  606. }
  607. func TestFieldOverriding(t *testing.T) {
  608. type InnerType struct {
  609. AnotherField string
  610. AnotherField1 string
  611. }
  612. type OuterType struct {
  613. InnerType `js:"-"`
  614. SomeField string
  615. AnotherField string `js:"-"`
  616. AnotherField1 string
  617. }
  618. const SCRIPT = `
  619. if (o.SomeField !== "SomeField") {
  620. throw new Error("SomeField");
  621. }
  622. if (o.AnotherField !== "AnotherField inner") {
  623. throw new Error("AnotherField");
  624. }
  625. if (o.AnotherField1 !== "AnotherField1 outer") {
  626. throw new Error("AnotherField1");
  627. }
  628. if (o.InnerType) {
  629. throw new Error("InnerType is present");
  630. }
  631. `
  632. o := OuterType{
  633. InnerType: InnerType{
  634. AnotherField: "AnotherField inner",
  635. AnotherField1: "AnotherField1 inner",
  636. },
  637. SomeField: "SomeField",
  638. AnotherField: "AnotherField outer",
  639. AnotherField1: "AnotherField1 outer",
  640. }
  641. vm := New()
  642. vm.SetFieldNameMapper(testFieldMapper{})
  643. vm.Set("o", &o)
  644. _, err := vm.RunString(SCRIPT)
  645. if err != nil {
  646. t.Fatal(err)
  647. }
  648. }
  649. func TestDefinePropertyUnexportedJsName(t *testing.T) {
  650. type T struct {
  651. Field int
  652. unexported int
  653. }
  654. vm := New()
  655. vm.SetFieldNameMapper(fieldNameMapper1{})
  656. vm.Set("f", &T{})
  657. _, err := vm.RunString(`
  658. "use strict";
  659. Object.defineProperty(f, "field", {value: 42});
  660. if (f.field !== 42) {
  661. throw new Error("Unexpected value: " + f.field);
  662. }
  663. if (f.hasOwnProperty("unexported")) {
  664. throw new Error("hasOwnProperty('unexported') is true");
  665. }
  666. var thrown;
  667. try {
  668. Object.defineProperty(f, "unexported", {value: 1});
  669. } catch (e) {
  670. thrown = e;
  671. }
  672. if (!(thrown instanceof TypeError)) {
  673. throw new Error("Unexpected error: ", thrown);
  674. }
  675. `)
  676. if err != nil {
  677. t.Fatal(err)
  678. }
  679. }
  680. type fieldNameMapperToLower struct{}
  681. func (fieldNameMapperToLower) FieldName(_ reflect.Type, f reflect.StructField) string {
  682. return strings.ToLower(f.Name)
  683. }
  684. func (fieldNameMapperToLower) MethodName(_ reflect.Type, m reflect.Method) string {
  685. return strings.ToLower(m.Name)
  686. }
  687. func TestHasOwnPropertyUnexportedJsName(t *testing.T) {
  688. vm := New()
  689. vm.SetFieldNameMapper(fieldNameMapperToLower{})
  690. vm.Set("f", &testGoReflectMethod_O{})
  691. _, err := vm.RunString(`
  692. "use strict";
  693. if (!f.hasOwnProperty("test")) {
  694. throw new Error("hasOwnProperty('test') returned false");
  695. }
  696. if (!f.hasOwnProperty("method")) {
  697. throw new Error("hasOwnProperty('method') returned false");
  698. }
  699. `)
  700. if err != nil {
  701. t.Fatal(err)
  702. }
  703. }
  704. func BenchmarkGoReflectGet(b *testing.B) {
  705. type parent struct {
  706. field, Test1, Test2, Test3, Test4, Test5, Test string
  707. }
  708. type child struct {
  709. parent
  710. Test6 string
  711. }
  712. b.StopTimer()
  713. vm := New()
  714. b.StartTimer()
  715. for i := 0; i < b.N; i++ {
  716. v := vm.ToValue(child{parent: parent{Test: "Test"}}).(*Object)
  717. v.Get("Test")
  718. }
  719. }
  720. func TestNestedStructSet(t *testing.T) {
  721. type B struct {
  722. Field int
  723. }
  724. type A struct {
  725. B B
  726. }
  727. const SCRIPT = `
  728. 'use strict';
  729. a.B.Field++;
  730. if (a1.B.Field != 1) {
  731. throw new Error("a1.B.Field = " + a1.B.Field);
  732. }
  733. var d = Object.getOwnPropertyDescriptor(a1.B, "Field");
  734. if (d.writable) {
  735. throw new Error("a1.B is writable");
  736. }
  737. var thrown = false;
  738. try {
  739. a1.B.Field = 42;
  740. } catch (e) {
  741. if (e instanceof TypeError) {
  742. thrown = true;
  743. }
  744. }
  745. if (!thrown) {
  746. throw new Error("TypeError was not thrown");
  747. }
  748. `
  749. a := A{
  750. B: B{
  751. Field: 1,
  752. },
  753. }
  754. vm := New()
  755. vm.Set("a", &a)
  756. vm.Set("a1", a)
  757. _, err := vm.RunString(SCRIPT)
  758. if err != nil {
  759. t.Fatal(err)
  760. }
  761. if v := a.B.Field; v != 2 {
  762. t.Fatalf("Unexpected a.B.Field: %d", v)
  763. }
  764. }
  765. func TestStructNonAddressableAnonStruct(t *testing.T) {
  766. type C struct {
  767. Z int64
  768. X string
  769. }
  770. type B struct {
  771. C
  772. Y string
  773. }
  774. type A struct {
  775. B B
  776. }
  777. a := A{
  778. B: B{
  779. C: C{
  780. Z: 1,
  781. X: "X2",
  782. },
  783. Y: "Y3",
  784. },
  785. }
  786. const SCRIPT = `
  787. "use strict";
  788. var s = JSON.stringify(a);
  789. s;
  790. `
  791. vm := New()
  792. vm.Set("a", &a)
  793. v, err := vm.RunString(SCRIPT)
  794. if err != nil {
  795. t.Fatal(err)
  796. }
  797. expected := `{"B":{"C":{"Z":1,"X":"X2"},"Z":1,"X":"X2","Y":"Y3"}}`
  798. if expected != v.String() {
  799. t.Fatalf("Expected '%s', got '%s'", expected, v.String())
  800. }
  801. }
  802. func TestTagFieldNameMapperInvalidId(t *testing.T) {
  803. vm := New()
  804. vm.SetFieldNameMapper(TagFieldNameMapper("json", true))
  805. type S struct {
  806. Field int `json:"-"`
  807. }
  808. vm.Set("s", S{Field: 42})
  809. res, err := vm.RunString(`s.hasOwnProperty("field") || s.hasOwnProperty("Field")`)
  810. if err != nil {
  811. t.Fatal(err)
  812. }
  813. if res != valueFalse {
  814. t.Fatalf("Unexpected result: %v", res)
  815. }
  816. }
  817. func TestPrimitivePtr(t *testing.T) {
  818. vm := New()
  819. s := "test"
  820. vm.Set("s", &s)
  821. res, err := vm.RunString(`s instanceof String && s == "test"`) // note non-strict equality
  822. if err != nil {
  823. t.Fatal(err)
  824. }
  825. if v := res.ToBoolean(); !v {
  826. t.Fatalf("value: %#v", res)
  827. }
  828. s = "test1"
  829. res, err = vm.RunString(`s == "test1"`)
  830. if err != nil {
  831. t.Fatal(err)
  832. }
  833. if v := res.ToBoolean(); !v {
  834. t.Fatalf("value: %#v", res)
  835. }
  836. }
  837. func TestStringer(t *testing.T) {
  838. vm := New()
  839. vm.Set("e", errors.New("test"))
  840. res, err := vm.RunString("e.toString()")
  841. if err != nil {
  842. t.Fatal(err)
  843. }
  844. if v := res.Export(); v != "test" {
  845. t.Fatalf("v: %v", v)
  846. }
  847. }
  848. func ExampleTagFieldNameMapper() {
  849. vm := New()
  850. vm.SetFieldNameMapper(TagFieldNameMapper("json", true))
  851. type S struct {
  852. Field int `json:"field"`
  853. }
  854. vm.Set("s", S{Field: 42})
  855. res, _ := vm.RunString(`s.field`)
  856. fmt.Println(res.Export())
  857. // Output: 42
  858. }
  859. func ExampleUncapFieldNameMapper() {
  860. vm := New()
  861. s := testGoReflectMethod_O{
  862. Test: "passed",
  863. }
  864. vm.SetFieldNameMapper(UncapFieldNameMapper())
  865. vm.Set("s", s)
  866. res, _ := vm.RunString(`s.test + " and " + s.method("passed too")`)
  867. fmt.Println(res.Export())
  868. // Output: passed and passed too
  869. }
  870. func TestGoReflectWithProto(t *testing.T) {
  871. type S struct {
  872. Field int
  873. }
  874. var s S
  875. vm := New()
  876. vm.Set("s", &s)
  877. _, err := vm.RunString(TESTLIB + `
  878. (function() {
  879. 'use strict';
  880. var proto = {
  881. Field: "protoField",
  882. test: 42
  883. };
  884. var test1Holder;
  885. Object.defineProperty(proto, "test1", {
  886. set: function(v) {
  887. test1Holder = v;
  888. },
  889. get: function() {
  890. return test1Holder;
  891. }
  892. });
  893. Object.setPrototypeOf(s, proto);
  894. assert.sameValue(s.Field, 0, "s.Field");
  895. s.Field = 2;
  896. assert.sameValue(s.Field, 2, "s.Field");
  897. assert.sameValue(s.test, 42, "s.test");
  898. assert.throws(TypeError, function() {
  899. Object.defineProperty(s, "test", {value: 43});
  900. });
  901. test1Holder = 1;
  902. assert.sameValue(s.test1, 1, "s.test1");
  903. s.test1 = 2;
  904. assert.sameValue(test1Holder, 2, "test1Holder");
  905. })();
  906. `)
  907. if err != nil {
  908. t.Fatal(err)
  909. }
  910. }
  911. func TestGoReflectSymbols(t *testing.T) {
  912. type S struct {
  913. Field int
  914. }
  915. var s S
  916. vm := New()
  917. vm.Set("s", &s)
  918. _, err := vm.RunString(`
  919. 'use strict';
  920. var sym = Symbol(66);
  921. s[sym] = "Test";
  922. if (s[sym] !== "Test") {
  923. throw new Error("s[sym]=" + s[sym]);
  924. }
  925. `)
  926. if err != nil {
  927. t.Fatal(err)
  928. }
  929. }
  930. func TestGoReflectSymbolEqualityQuirk(t *testing.T) {
  931. type Field struct {
  932. }
  933. type S struct {
  934. Field *Field
  935. }
  936. var s = S{
  937. Field: &Field{},
  938. }
  939. vm := New()
  940. vm.Set("s", &s)
  941. res, err := vm.RunString(`
  942. var sym = Symbol(66);
  943. var field1 = s.Field;
  944. field1[sym] = true;
  945. var field2 = s.Field;
  946. // Because a wrapper is created every time the property is accessed
  947. // field1 and field2 will be different instances of the wrapper.
  948. // Symbol properties only exist in the wrapper, they cannot be placed into the original Go value,
  949. // hence the following:
  950. field1 === field2 && field1[sym] === true && field2[sym] === undefined;
  951. `)
  952. if err != nil {
  953. t.Fatal(err)
  954. }
  955. if res != valueTrue {
  956. t.Fatal(res)
  957. }
  958. }
  959. func TestGoObj__Proto__(t *testing.T) {
  960. type S struct {
  961. Field int
  962. }
  963. vm := New()
  964. vm.Set("s", S{})
  965. vm.Set("m", map[string]interface{}{})
  966. vm.Set("mr", map[int]string{})
  967. vm.Set("a", []interface{}{})
  968. vm.Set("ar", []string{})
  969. _, err := vm.RunString(`
  970. function f(s, expectedCtor, prefix) {
  971. if (s.__proto__ !== expectedCtor.prototype) {
  972. throw new Error(prefix + ": __proto__: " + s.__proto__);
  973. }
  974. s.__proto__ = null;
  975. if (s.__proto__ !== undefined) { // as there is no longer a prototype, there is no longer the __proto__ property
  976. throw new Error(prefix + ": __proto__ is not undefined: " + s.__proto__);
  977. }
  978. var proto = Object.getPrototypeOf(s);
  979. if (proto !== null) {
  980. throw new Error(prefix + ": proto is not null: " + proto);
  981. }
  982. }
  983. f(s, Object, "struct");
  984. f(m, Object, "simple map");
  985. f(mr, Object, "reflect map");
  986. f(a, Array, "slice");
  987. f(ar, Array, "reflect slice");
  988. `)
  989. if err != nil {
  990. t.Fatal(err)
  991. }
  992. }
  993. func TestGoReflectUnicodeProps(t *testing.T) {
  994. type S struct {
  995. Тест string
  996. }
  997. vm := New()
  998. var s S
  999. vm.Set("s", &s)
  1000. _, err := vm.RunString(`
  1001. if (!s.hasOwnProperty("Тест")) {
  1002. throw new Error("hasOwnProperty");
  1003. }
  1004. `)
  1005. if err != nil {
  1006. t.Fatal(err)
  1007. }
  1008. }
  1009. func TestGoReflectPreserveType(t *testing.T) {
  1010. vm := New()
  1011. var expect = time.Duration(math.MaxInt64)
  1012. vm.Set(`make`, func() time.Duration {
  1013. return expect
  1014. })
  1015. vm.Set(`handle`, func(d time.Duration) {
  1016. if d.String() != expect.String() {
  1017. t.Fatal(`expect`, expect, `, but get`, d)
  1018. }
  1019. })
  1020. _, e := vm.RunString(`
  1021. var d=make()
  1022. handle(d)
  1023. `)
  1024. if e != nil {
  1025. t.Fatal(e)
  1026. }
  1027. }