object_goslice_reflect_test.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. package goja
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. func TestGoSliceReflectBasic(t *testing.T) {
  7. const SCRIPT = `
  8. var sum = 0;
  9. for (var i = 0; i < a.length; i++) {
  10. sum += a[i];
  11. }
  12. sum;
  13. `
  14. r := New()
  15. r.Set("a", []int{1, 2, 3, 4})
  16. v, err := r.RunString(SCRIPT)
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. if i := v.ToInteger(); i != 10 {
  21. t.Fatalf("Expected 10, got: %d", i)
  22. }
  23. }
  24. func TestGoSliceReflectIn(t *testing.T) {
  25. const SCRIPT = `
  26. var idx = "";
  27. for (var i in a) {
  28. idx += i;
  29. }
  30. idx;
  31. `
  32. r := New()
  33. r.Set("a", []int{1, 2, 3, 4})
  34. v, err := r.RunString(SCRIPT)
  35. if err != nil {
  36. t.Fatal(err)
  37. }
  38. if i := v.String(); i != "0123" {
  39. t.Fatalf("Expected '0123', got: '%s'", i)
  40. }
  41. }
  42. func TestGoSliceReflectSet(t *testing.T) {
  43. const SCRIPT = `
  44. a[0] = 33;
  45. a[1] = 333;
  46. a[2] = "42";
  47. a[3] = {};
  48. a[4] = 0;
  49. `
  50. r := New()
  51. a := []int8{1, 2, 3, 4}
  52. r.Set("a", a)
  53. _, err := r.RunString(SCRIPT)
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. if a[0] != 33 {
  58. t.Fatalf("a[0] = %d, expected 33", a[0])
  59. }
  60. if a[1] != 77 {
  61. t.Fatalf("a[1] = %d, expected 77", a[1])
  62. }
  63. if a[2] != 42 {
  64. t.Fatalf("a[2] = %d, expected 42", a[2])
  65. }
  66. if a[3] != 0 {
  67. t.Fatalf("a[3] = %d, expected 0", a[3])
  68. }
  69. }
  70. func TestGoSliceReflectPush(t *testing.T) {
  71. r := New()
  72. t.Run("Can push to array by array ptr", func(t *testing.T) {
  73. a := []int8{1}
  74. r.Set("a", &a)
  75. _, err := r.RunString(`a.push (10)`)
  76. if err != nil {
  77. t.Fatal(err)
  78. }
  79. if a[1] != 10 {
  80. t.Fatalf("a[1] = %d, expected 10", a[1])
  81. }
  82. })
  83. t.Run("Can push to array by struct ptr", func(t *testing.T) {
  84. type testStr struct {
  85. A []int
  86. }
  87. a := testStr{
  88. A: []int{2},
  89. }
  90. r.Set("a", &a)
  91. _, err := r.RunString(`a.A.push (10)`)
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. if a.A[1] != 10 {
  96. t.Fatalf("a[1] = %v, expected 10", a)
  97. }
  98. })
  99. }
  100. func TestGoSliceReflectStructField(t *testing.T) {
  101. vm := New()
  102. var s struct {
  103. A []int
  104. B *[]int
  105. }
  106. vm.Set("s", &s)
  107. _, err := vm.RunString(`
  108. 'use strict';
  109. s.A.push(1);
  110. if (s.B !== null) {
  111. throw new Error("s.B is not null: " + s.B);
  112. }
  113. s.B = [2];
  114. `)
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. if len(s.A) != 1 || s.A[0] != 1 {
  119. t.Fatalf("s.A: %v", s.A)
  120. }
  121. if len(*s.B) != 1 || (*s.B)[0] != 2 {
  122. t.Fatalf("s.B: %v", *s.B)
  123. }
  124. }
  125. func TestGoSliceReflectExportToStructField(t *testing.T) {
  126. vm := New()
  127. v, err := vm.RunString(`({A: [1], B: [2]})`)
  128. if err != nil {
  129. t.Fatal(err)
  130. }
  131. var s struct {
  132. A []int
  133. B *[]int
  134. }
  135. err = vm.ExportTo(v, &s)
  136. if err != nil {
  137. t.Fatal(err)
  138. }
  139. if len(s.A) != 1 || s.A[0] != 1 {
  140. t.Fatalf("s.A: %v", s.A)
  141. }
  142. if len(*s.B) != 1 || (*s.B)[0] != 2 {
  143. t.Fatalf("s.B: %v", *s.B)
  144. }
  145. }
  146. func TestGoSliceReflectProtoMethod(t *testing.T) {
  147. const SCRIPT = `
  148. a.join(",")
  149. `
  150. r := New()
  151. a := []int8{1, 2, 3, 4}
  152. r.Set("a", a)
  153. ret, err := r.RunString(SCRIPT)
  154. if err != nil {
  155. t.Fatal(err)
  156. }
  157. if s := ret.String(); s != "1,2,3,4" {
  158. t.Fatalf("Unexpected result: '%s'", s)
  159. }
  160. }
  161. type gosliceReflect_withMethods []interface{}
  162. func (s gosliceReflect_withMethods) Method() bool {
  163. return true
  164. }
  165. func TestGoSliceReflectMethod(t *testing.T) {
  166. const SCRIPT = `
  167. typeof a === "object" && a[0] === 42 && a.Method() === true;
  168. `
  169. vm := New()
  170. a := make(gosliceReflect_withMethods, 1)
  171. a[0] = 42
  172. vm.Set("a", a)
  173. v, err := vm.RunString(SCRIPT)
  174. if err != nil {
  175. t.Fatal(err)
  176. }
  177. if !v.StrictEquals(valueTrue) {
  178. t.Fatalf("Expected true, got %v", v)
  179. }
  180. }
  181. func TestGoSliceReflectGetStr(t *testing.T) {
  182. r := New()
  183. v := r.ToValue([]string{"test"})
  184. if o, ok := v.(*Object); ok {
  185. if e := o.Get("0").Export(); e != "test" {
  186. t.Fatalf("Unexpected o.Get(\"0\"): %v", e)
  187. }
  188. }
  189. }
  190. func TestGoSliceReflectNilObjectIfaceVal(t *testing.T) {
  191. r := New()
  192. a := []Value{(*Object)(nil)}
  193. r.Set("a", a)
  194. ret, err := r.RunString(`
  195. ""+a[0];
  196. `)
  197. if err != nil {
  198. t.Fatal(err)
  199. }
  200. if !asciiString("null").SameAs(ret) {
  201. t.Fatalf("ret: %v", ret)
  202. }
  203. }
  204. func TestGoSliceReflectSetLength(t *testing.T) {
  205. r := New()
  206. a := []int{1, 2, 3, 4}
  207. b := []testing.TB{&testing.T{}, &testing.T{}, (*testing.T)(nil)}
  208. r.Set("a", &a)
  209. r.Set("b", &b)
  210. _, err := r.RunString(`
  211. 'use strict';
  212. a.length = 3;
  213. if (a.length !== 3) {
  214. throw new Error("length="+a.length);
  215. }
  216. if (a[3] !== undefined) {
  217. throw new Error("a[3]="+a[3]);
  218. }
  219. a.length = 5;
  220. if (a.length !== 5) {
  221. throw new Error("a.length="+a.length);
  222. }
  223. if (a[3] !== 0) {
  224. throw new Error("a[3]="+a[3]);
  225. }
  226. if (a[4] !== 0) {
  227. throw new Error("a[4]="+a[4]);
  228. }
  229. b.length = 3;
  230. if (b.length !== 3) {
  231. throw new Error("b.length="+b.length);
  232. }
  233. if (b[3] !== undefined) {
  234. throw new Error("b[3]="+b[3]);
  235. }
  236. b.length = 5;
  237. if (b.length !== 5) {
  238. throw new Error("length="+b.length);
  239. }
  240. if (b[3] !== null) {
  241. throw new Error("b[3]="+b[3]);
  242. }
  243. if (b[4] !== null) {
  244. throw new Error("b[4]="+b[4]);
  245. }
  246. if (b[2] !== null) {
  247. throw new Error("b[2]="+b[2]);
  248. }
  249. `)
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. }
  254. func TestGoSliceReflectProto(t *testing.T) {
  255. r := New()
  256. a := []*Object{{}, nil, {}}
  257. r.Set("a", &a)
  258. r.testScriptWithTestLib(`
  259. var proto = [,2,,4];
  260. Object.setPrototypeOf(a, proto);
  261. assert.sameValue(a[1], null, "a[1]");
  262. assert.sameValue(a[3], 4, "a[3]");
  263. var desc = Object.getOwnPropertyDescriptor(a, "1");
  264. assert.sameValue(desc.value, null, "desc.value");
  265. assert(desc.writable, "writable");
  266. assert(desc.enumerable, "enumerable");
  267. assert(!desc.configurable, "configurable");
  268. var v5;
  269. Object.defineProperty(proto, "5", {
  270. set: function(v) {
  271. v5 = v;
  272. }
  273. });
  274. a[5] = "test";
  275. assert.sameValue(v5, "test", "v5");
  276. `, _undefined, t)
  277. }
  278. func TestGoSliceReflectProtoProto(t *testing.T) {
  279. r := New()
  280. a := []*Object{{}, nil, {}}
  281. proto := []*Object{{}, {}, {}, {}}
  282. r.Set("a", &a)
  283. r.Set("proto", proto)
  284. _, err := r.RunString(`
  285. "use strict";
  286. var protoproto = {};
  287. Object.defineProperty(protoproto, "3", {
  288. value: 42
  289. });
  290. Object.setPrototypeOf(proto, protoproto);
  291. Object.setPrototypeOf(a, proto);
  292. if (a.hasOwnProperty("3")) {
  293. throw new Error("a.hasOwnProperty(\"3\")");
  294. }
  295. if (a[3] !== null) {
  296. throw new Error("a[3]="+a[3]);
  297. }
  298. a[3] = null;
  299. if (a[3] !== null) {
  300. throw new Error("a[3]=" + a[3]);
  301. }
  302. `)
  303. if err != nil {
  304. t.Fatal(err)
  305. }
  306. }
  307. func TestGoSliceReflectDelete(t *testing.T) {
  308. r := New()
  309. a := []*Object{{}, nil, {}}
  310. r.Set("a", a)
  311. v, err := r.RunString(`
  312. delete a[0] && delete a[1] && delete a[3];
  313. `)
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. if v != valueTrue {
  318. t.Fatalf("not true: %v", v)
  319. }
  320. }
  321. func TestGoSliceReflectPop(t *testing.T) {
  322. r := New()
  323. a := []string{"1", "", "3"}
  324. r.Set("a", &a)
  325. v, err := r.RunString(`
  326. a.pop()
  327. `)
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. if !v.SameAs(asciiString("3")) {
  332. t.Fatal(v)
  333. }
  334. }
  335. func TestGoSliceReflectPopNoPtr(t *testing.T) {
  336. r := New()
  337. a := []string{"1", "", "3"}
  338. r.Set("a", a)
  339. v, err := r.RunString(`
  340. a.pop()
  341. `)
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. if !v.SameAs(asciiString("3")) {
  346. t.Fatal(v)
  347. }
  348. }
  349. func TestGoSliceReflectLengthProperty(t *testing.T) {
  350. vm := New()
  351. vm.Set("s", []int{2, 3, 4})
  352. _, err := vm.RunString(`
  353. if (!s.hasOwnProperty("length")) {
  354. throw new Error("hasOwnProperty() returned false");
  355. }
  356. let desc = Object.getOwnPropertyDescriptor(s, "length");
  357. if (desc.value !== 3 || !desc.writable || desc.enumerable || desc.configurable) {
  358. throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
  359. }
  360. `)
  361. if err != nil {
  362. t.Fatal(err)
  363. }
  364. }
  365. type testCustomSliceWithMethods []int
  366. func (a testCustomSliceWithMethods) Method() bool {
  367. return true
  368. }
  369. func TestGoSliceReflectMethods(t *testing.T) {
  370. vm := New()
  371. vm.Set("s", testCustomSliceWithMethods{1, 2, 3})
  372. _, err := vm.RunString(`
  373. if (!s.hasOwnProperty("Method")) {
  374. throw new Error("hasOwnProperty() returned false");
  375. }
  376. let desc = Object.getOwnPropertyDescriptor(s, "Method");
  377. if (desc.value() !== true || desc.writable || !desc.enumerable || desc.configurable) {
  378. throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
  379. }
  380. `)
  381. if err != nil {
  382. t.Fatal(err)
  383. }
  384. }
  385. func TestGoSliceReflectExportAfterGrow(t *testing.T) {
  386. vm := New()
  387. vm.Set("a", []int{1})
  388. v, err := vm.RunString(`
  389. a.push(2);
  390. a;
  391. `)
  392. if err != nil {
  393. t.Fatal(err)
  394. }
  395. exp := v.Export()
  396. if a, ok := exp.([]int); ok {
  397. if len(a) != 2 || a[0] != 1 || a[1] != 2 {
  398. t.Fatal(a)
  399. }
  400. } else {
  401. t.Fatalf("Wrong type: %T", exp)
  402. }
  403. }
  404. func TestGoSliceReflectSort(t *testing.T) {
  405. vm := New()
  406. type Thing struct{ Name string }
  407. vm.Set("v", []*Thing{
  408. {Name: "log"},
  409. {Name: "etc"},
  410. {Name: "test"},
  411. {Name: "bin"},
  412. })
  413. ret, err := vm.RunString(`
  414. //v.sort((a, b) => a.Name.localeCompare(b.Name)).map((x) => x.Name);
  415. const tmp = v[0];
  416. v[0] = v[1];
  417. v[1] = tmp;
  418. v[0].Name + v[1].Name;
  419. `)
  420. if err != nil {
  421. panic(err)
  422. }
  423. t.Log(ret.Export())
  424. }
  425. func TestGoSliceReflect111(t *testing.T) {
  426. vm := New()
  427. vm.Set("v", []int32{
  428. 1, 2,
  429. })
  430. ret, err := vm.RunString(`
  431. //v.sort((a, b) => a.Name.localeCompare(b.Name)).map((x) => x.Name);
  432. const tmp = v[0];
  433. v[0] = v[1];
  434. v[1] = tmp;
  435. "" + v[0] + v[1];
  436. `)
  437. if err != nil {
  438. panic(err)
  439. }
  440. t.Log(ret.Export())
  441. a := []int{1, 2}
  442. a0 := reflect.ValueOf(a).Index(0)
  443. a0.Set(reflect.ValueOf(0))
  444. t.Log(a[0])
  445. }
  446. func TestGoSliceReflectExternalLenUpdate(t *testing.T) {
  447. data := &[]int{1}
  448. vm := New()
  449. vm.Set("data", data)
  450. vm.Set("append", func(a *[]int, v int) {
  451. if a != data {
  452. panic(vm.NewTypeError("a != data"))
  453. }
  454. *a = append(*a, v)
  455. })
  456. vm.testScriptWithTestLib(`
  457. assert.sameValue(data.length, 1);
  458. // modify with js
  459. data.push(1);
  460. assert.sameValue(data.length, 2);
  461. // modify with go
  462. append(data, 2);
  463. assert.sameValue(data.length, 3);
  464. `, _undefined, t)
  465. }
  466. func BenchmarkGoSliceReflectSet(b *testing.B) {
  467. vm := New()
  468. a := vm.ToValue([]int{1}).(*Object)
  469. b.ResetTimer()
  470. v := intToValue(0)
  471. for i := 0; i < b.N; i++ {
  472. a.Set("0", v)
  473. }
  474. }