object_goarray_reflect_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. package goja
  2. import (
  3. "testing"
  4. )
  5. func TestGoReflectArray(t *testing.T) {
  6. vm := New()
  7. vm.Set("a", [...]int{1, 2, 3})
  8. _, err := vm.RunString(`
  9. if (!Array.isArray(a)) {
  10. throw new Error("isArray() returned false");
  11. }
  12. if (a[0] !== 1 || a[1] !== 2 || a[2] !== 3) {
  13. throw new Error("Array contents is incorrect");
  14. }
  15. if (!a.hasOwnProperty("length")) {
  16. throw new Error("hasOwnProperty() returned false");
  17. }
  18. let desc = Object.getOwnPropertyDescriptor(a, "length");
  19. if (desc.value !== 3 || desc.writable || desc.enumerable || desc.configurable) {
  20. throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
  21. }
  22. `)
  23. if err != nil {
  24. t.Fatal(err)
  25. }
  26. }
  27. func TestGoReflectArraySort(t *testing.T) {
  28. vm := New()
  29. vm.Set("a", [...]int{3, 1, 2})
  30. v, err := vm.RunString(`
  31. a.sort();
  32. if (a[0] !== 1 || a[1] !== 2 || a[2] !== 3) {
  33. throw new Error(a.toString());
  34. }
  35. a;
  36. `)
  37. if err != nil {
  38. t.Fatal(err)
  39. }
  40. res := v.Export()
  41. if a, ok := res.([3]int); ok {
  42. if a[0] != 1 || a[1] != 2 || a[2] != 3 {
  43. t.Fatal(a)
  44. }
  45. } else {
  46. t.Fatalf("Wrong type: %T", res)
  47. }
  48. }
  49. func TestGoReflectArrayCopyOnChange(t *testing.T) {
  50. vm := New()
  51. v, err := vm.RunString(`
  52. a => {
  53. let tmp = a[0];
  54. if (tmp !== a[0]) {
  55. throw new Error("tmp !== a[0]");
  56. }
  57. a[0] = a[1];
  58. if (tmp === a[0]) {
  59. throw new Error("tmp === a[0]");
  60. }
  61. if (tmp.Test !== "1") {
  62. throw new Error("tmp.Test: " + tmp.Test + " (" + typeof tmp.Test + ")");
  63. }
  64. if (a[0].Test !== "2") {
  65. throw new Error("a[0].Test: " + a[0].Test);
  66. }
  67. a[0].Test = "3";
  68. if (a[0].Test !== "3") {
  69. throw new Error("a[0].Test (1): " + a[0].Test);
  70. }
  71. tmp = a[0];
  72. tmp.Test = "4";
  73. if (a[0].Test !== "4") {
  74. throw new Error("a[0].Test (2): " + a[0].Test);
  75. }
  76. delete a[0];
  77. if (a[0] && a[0].Test !== "") {
  78. throw new Error("a[0].Test (3): " + a[0].Test);
  79. }
  80. if (tmp.Test !== "4") {
  81. throw new Error("tmp.Test (1): " + tmp.Test);
  82. }
  83. a[1] = tmp;
  84. if (a[1].Test !== "4") {
  85. throw new Error("a[1].Test: " + a[1].Test);
  86. }
  87. // grow
  88. tmp = a[1];
  89. a.push(null);
  90. if (a.length !== 3) {
  91. throw new Error("a.length after push: " + a.length);
  92. }
  93. tmp.Test = "5";
  94. if (a[1].Test !== "5") {
  95. throw new Error("a[1].Test (1): " + a[1].Test);
  96. }
  97. // shrink
  98. a.length = 1;
  99. if (a.length !== 1) {
  100. throw new Error("a.length after shrink: " + a.length);
  101. }
  102. if (tmp.Test !== "5") {
  103. throw new Error("tmp.Test (shrink): " + tmp.Test);
  104. }
  105. }
  106. `)
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. fn, ok := AssertFunction(v)
  111. if !ok {
  112. t.Fatal("Not a function")
  113. }
  114. t.Run("[]struct", func(t *testing.T) {
  115. a := []struct {
  116. Test string
  117. }{{"1"}, {"2"}}
  118. _, err := fn(nil, vm.ToValue(a))
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. if a[0].Test != "" {
  123. t.Fatalf("a[0]: %#v", a[0])
  124. }
  125. if a[1].Test != "4" {
  126. t.Fatalf("a0[1]: %#v", a[1])
  127. }
  128. })
  129. // The copy-on-change mechanism doesn't apply to the types below because the contained values are references.
  130. // These tests are here for completeness and to prove that the behaviour is consistent.
  131. t.Run("[]I", func(t *testing.T) {
  132. type I interface {
  133. Get() string
  134. }
  135. a := []I{&testGoReflectMethod_O{Test: "1"}, &testGoReflectMethod_O{Test: "2"}}
  136. _, err = fn(nil, vm.ToValue(a))
  137. if err != nil {
  138. t.Fatal(err)
  139. }
  140. })
  141. t.Run("[]interface{}", func(t *testing.T) {
  142. a := []interface{}{&testGoReflectMethod_O{Test: "1"}, &testGoReflectMethod_O{Test: "2"}}
  143. _, err = fn(nil, vm.ToValue(a))
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. })
  148. }
  149. func TestCopyOnChangeReflectSlice(t *testing.T) {
  150. vm := New()
  151. v, err := vm.RunString(`
  152. s => {
  153. s.A.push(1);
  154. if (s.A.length !== 1) {
  155. throw new Error("s.A.length: " + s.A.length);
  156. }
  157. if (s.A[0] !== 1) {
  158. throw new Error("s.A[0]: " + s.A[0]);
  159. }
  160. let tmp = s.A;
  161. if (tmp !== s.A) {
  162. throw new Error("tmp !== s.A");
  163. }
  164. s.A = [2];
  165. if (tmp === s.A) {
  166. throw new Error("tmp === s.A");
  167. }
  168. if (tmp[0] !== 1) {
  169. throw new Error("tmp[0]: " + tmp[0]);
  170. }
  171. if (s.A[0] !== 2) {
  172. throw new Error("s.A[0] (1): " + s.A[0]);
  173. }
  174. }
  175. `)
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. fn, ok := AssertFunction(v)
  180. if !ok {
  181. t.Fatal("Not a function")
  182. }
  183. t.Run("[]int", func(t *testing.T) {
  184. type S struct {
  185. A []int
  186. }
  187. var s S
  188. _, err := fn(nil, vm.ToValue(&s))
  189. if err != nil {
  190. t.Fatal(err)
  191. }
  192. if len(s.A) != 1 {
  193. t.Fatal(s)
  194. }
  195. if s.A[0] != 2 {
  196. t.Fatal(s.A)
  197. }
  198. })
  199. t.Run("[]interface{}", func(t *testing.T) {
  200. type S struct {
  201. A []interface{}
  202. }
  203. var s S
  204. _, err := fn(nil, vm.ToValue(&s))
  205. if err != nil {
  206. t.Fatal(err)
  207. }
  208. if len(s.A) != 1 {
  209. t.Fatal(s)
  210. }
  211. if s.A[0] != int64(2) {
  212. t.Fatal(s.A)
  213. }
  214. })
  215. }
  216. func TestCopyOnChangeSort(t *testing.T) {
  217. a := []struct {
  218. Test string
  219. }{{"2"}, {"1"}}
  220. vm := New()
  221. vm.Set("a", &a)
  222. _, err := vm.RunString(`
  223. let a0 = a[0];
  224. let a1 = a[1];
  225. a.sort((a, b) => a.Test.localeCompare(b.Test));
  226. if (a[0].Test !== "1") {
  227. throw new Error("a[0]: " + a[0]);
  228. }
  229. if (a[1].Test !== "2") {
  230. throw new Error("a[1]: " + a[1]);
  231. }
  232. if (a0 !== a[1]) {
  233. throw new Error("a0 !== a[1]");
  234. }
  235. if (a1 !== a[0]) {
  236. throw new Error("a1 !== a[0]");
  237. }
  238. `)
  239. if err != nil {
  240. t.Fatal(err)
  241. }
  242. if a[0].Test != "1" || a[1].Test != "2" {
  243. t.Fatal(a)
  244. }
  245. }
  246. type testStringerArray [8]byte
  247. func (a testStringerArray) String() string {
  248. return "X"
  249. }
  250. func TestReflectArrayToString(t *testing.T) {
  251. vm := New()
  252. var a testStringerArray
  253. vm.Set("a", &a)
  254. res, err := vm.RunString("`${a}`")
  255. if err != nil {
  256. t.Fatal(err)
  257. }
  258. if exp := res.Export(); exp != "X" {
  259. t.Fatal(exp)
  260. }
  261. var a1 [2]byte
  262. vm.Set("a", &a1)
  263. res, err = vm.RunString("`${a}`")
  264. if err != nil {
  265. t.Fatal(err)
  266. }
  267. if exp := res.Export(); exp != "0,0" {
  268. t.Fatal(exp)
  269. }
  270. }