object_gomap_reflect_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. package goja
  2. import (
  3. "sort"
  4. "strings"
  5. "testing"
  6. )
  7. func TestGoMapReflectGetSet(t *testing.T) {
  8. const SCRIPT = `
  9. m.c = m.a + m.b;
  10. `
  11. vm := New()
  12. m := map[string]string{
  13. "a": "4",
  14. "b": "2",
  15. }
  16. vm.Set("m", m)
  17. _, err := vm.RunString(SCRIPT)
  18. if err != nil {
  19. t.Fatal(err)
  20. }
  21. if c := m["c"]; c != "42" {
  22. t.Fatalf("Unexpected value: '%s'", c)
  23. }
  24. }
  25. func TestGoMapReflectIntKey(t *testing.T) {
  26. const SCRIPT = `
  27. m[2] = m[0] + m[1];
  28. `
  29. vm := New()
  30. m := map[int]int{
  31. 0: 40,
  32. 1: 2,
  33. }
  34. vm.Set("m", m)
  35. _, err := vm.RunString(SCRIPT)
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. if c := m[2]; c != 42 {
  40. t.Fatalf("Unexpected value: '%d'", c)
  41. }
  42. }
  43. func TestGoMapReflectDelete(t *testing.T) {
  44. const SCRIPT = `
  45. delete m.a;
  46. `
  47. vm := New()
  48. m := map[string]string{
  49. "a": "4",
  50. "b": "2",
  51. }
  52. vm.Set("m", m)
  53. _, err := vm.RunString(SCRIPT)
  54. if err != nil {
  55. t.Fatal(err)
  56. }
  57. if _, exists := m["a"]; exists {
  58. t.Fatal("a still exists")
  59. }
  60. if b := m["b"]; b != "2" {
  61. t.Fatalf("Unexpected b: '%s'", b)
  62. }
  63. }
  64. func TestGoMapReflectJSON(t *testing.T) {
  65. const SCRIPT = `
  66. function f(m) {
  67. return JSON.stringify(m);
  68. }
  69. `
  70. vm := New()
  71. m := map[string]string{
  72. "t": "42",
  73. }
  74. _, err := vm.RunString(SCRIPT)
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. f := vm.Get("f")
  79. if call, ok := AssertFunction(f); ok {
  80. v, err := call(nil, ([]Value{vm.ToValue(m)})...)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if !v.StrictEquals(asciiString(`{"t":"42"}`)) {
  85. t.Fatalf("Unexpected value: %v", v)
  86. }
  87. } else {
  88. t.Fatalf("Not a function: %v", f)
  89. }
  90. }
  91. func TestGoMapReflectProto(t *testing.T) {
  92. const SCRIPT = `
  93. m.hasOwnProperty("t");
  94. `
  95. vm := New()
  96. m := map[string]string{
  97. "t": "42",
  98. }
  99. vm.Set("m", m)
  100. v, err := vm.RunString(SCRIPT)
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. if !v.StrictEquals(valueTrue) {
  105. t.Fatalf("Expected true, got %v", v)
  106. }
  107. }
  108. type gomapReflect_noMethods map[string]interface{}
  109. type gomapReflect_withMethods map[string]interface{}
  110. func (m gomapReflect_withMethods) Method() bool {
  111. return true
  112. }
  113. func TestGoMapReflectNoMethods(t *testing.T) {
  114. const SCRIPT = `
  115. typeof m === "object" && m.hasOwnProperty("t") && m.t === 42;
  116. `
  117. vm := New()
  118. m := make(gomapReflect_noMethods)
  119. m["t"] = 42
  120. vm.Set("m", m)
  121. v, err := vm.RunString(SCRIPT)
  122. if err != nil {
  123. t.Fatal(err)
  124. }
  125. if !v.StrictEquals(valueTrue) {
  126. t.Fatalf("Expected true, got %v", v)
  127. }
  128. }
  129. func TestGoMapReflectWithMethods(t *testing.T) {
  130. const SCRIPT = `
  131. typeof m === "object" && !m.hasOwnProperty("t") && m.hasOwnProperty("Method") && m.Method();
  132. `
  133. vm := New()
  134. m := make(gomapReflect_withMethods)
  135. m["t"] = 42
  136. vm.Set("m", m)
  137. v, err := vm.RunString(SCRIPT)
  138. if err != nil {
  139. t.Fatal(err)
  140. }
  141. if !v.StrictEquals(valueTrue) {
  142. t.Fatalf("Expected true, got %v", v)
  143. }
  144. }
  145. func TestGoMapReflectWithProto(t *testing.T) {
  146. vm := New()
  147. m := map[string]string{
  148. "t": "42",
  149. }
  150. vm.Set("m", m)
  151. vm.testScriptWithTestLib(`
  152. (function() {
  153. 'use strict';
  154. var proto = {};
  155. var getterAllowed = false;
  156. var setterAllowed = false;
  157. var tHolder = "proto t";
  158. Object.defineProperty(proto, "t", {
  159. get: function() {
  160. if (!getterAllowed) throw new Error("getter is called");
  161. return tHolder;
  162. },
  163. set: function(v) {
  164. if (!setterAllowed) throw new Error("setter is called");
  165. tHolder = v;
  166. }
  167. });
  168. var t1Holder;
  169. Object.defineProperty(proto, "t1", {
  170. get: function() {
  171. return t1Holder;
  172. },
  173. set: function(v) {
  174. t1Holder = v;
  175. }
  176. });
  177. Object.setPrototypeOf(m, proto);
  178. assert.sameValue(m.t, "42");
  179. m.t = 43;
  180. assert.sameValue(m.t, "43");
  181. t1Holder = "test";
  182. assert.sameValue(m.t1, "test");
  183. m.t1 = "test1";
  184. assert.sameValue(m.t1, "test1");
  185. delete m.t;
  186. getterAllowed = true;
  187. assert.sameValue(m.t, "proto t", "after delete");
  188. setterAllowed = true;
  189. m.t = true;
  190. assert.sameValue(m.t, true, "m.t === true");
  191. assert.sameValue(tHolder, true, "tHolder === true");
  192. Object.preventExtensions(m);
  193. assert.throws(TypeError, function() {
  194. m.t2 = 1;
  195. });
  196. m.t1 = "test2";
  197. assert.sameValue(m.t1, "test2");
  198. })();
  199. `, _undefined, t)
  200. }
  201. func TestGoMapReflectProtoProp(t *testing.T) {
  202. const SCRIPT = `
  203. (function() {
  204. "use strict";
  205. var proto = {};
  206. Object.defineProperty(proto, "ro", {value: 42});
  207. Object.setPrototypeOf(m, proto);
  208. assert.throws(TypeError, function() {
  209. m.ro = 43;
  210. });
  211. Object.defineProperty(m, "ro", {value: 43});
  212. assert.sameValue(m.ro, "43");
  213. })();
  214. `
  215. r := New()
  216. r.Set("m", map[string]string{})
  217. r.testScriptWithTestLib(SCRIPT, _undefined, t)
  218. }
  219. func TestGoMapReflectUnicode(t *testing.T) {
  220. const SCRIPT = `
  221. Object.setPrototypeOf(m, s);
  222. if (m.Тест !== "passed") {
  223. throw new Error("m.Тест: " + m.Тест);
  224. }
  225. m["é"];
  226. `
  227. type S struct {
  228. Тест string
  229. }
  230. vm := New()
  231. m := map[string]int{
  232. "é": 42,
  233. }
  234. s := S{
  235. Тест: "passed",
  236. }
  237. vm.Set("m", m)
  238. vm.Set("s", &s)
  239. res, err := vm.RunString(SCRIPT)
  240. if err != nil {
  241. t.Fatal(err)
  242. }
  243. if res == nil || !res.StrictEquals(valueInt(42)) {
  244. t.Fatalf("Unexpected value: %v", res)
  245. }
  246. }
  247. func TestGoMapReflectStruct(t *testing.T) {
  248. type S struct {
  249. Test int
  250. }
  251. m := map[string]S{
  252. "1": {Test: 1},
  253. }
  254. vm := New()
  255. vm.Set("m", m)
  256. res, err := vm.RunString("m[1].Test = 2; m[1].Test")
  257. if err != nil {
  258. t.Fatal(err)
  259. }
  260. if res.Export() != int64(1) {
  261. t.Fatal(res)
  262. }
  263. }
  264. func TestGoMapReflectElt(t *testing.T) {
  265. type mapping map[string]interface{}
  266. const SCRIPT = `a.s() && a.t === null && a.t1 === undefined;`
  267. r := New()
  268. r.Set("a", mapping{
  269. "s": func() bool { return true },
  270. "t": nil,
  271. })
  272. r.testScript(SCRIPT, valueTrue, t)
  273. }
  274. func TestGoMapReflectKeyToString(t *testing.T) {
  275. vm := New()
  276. test := func(v any, t *testing.T) {
  277. o1 := vm.ToValue(v).ToObject(vm)
  278. keys := o1.Keys()
  279. sort.Strings(keys)
  280. if len(keys) != 2 || keys[0] != "1" || keys[1] != "2" {
  281. t.Fatal(keys)
  282. }
  283. keys1 := o1.self.stringKeys(true, nil)
  284. sort.Slice(keys1, func(a, b int) bool {
  285. return strings.Compare(keys1[a].String(), keys1[b].String()) < 0
  286. })
  287. if len(keys1) != 2 || keys1[0] != asciiString("1") || keys1[1] != asciiString("2") {
  288. t.Fatal(keys1)
  289. }
  290. }
  291. t.Run("int", func(t *testing.T) {
  292. m1 := map[int]any{
  293. 1: 2,
  294. 2: 3,
  295. }
  296. test(m1, t)
  297. })
  298. t.Run("CustomString", func(t *testing.T) {
  299. type CustomString string
  300. m2 := map[CustomString]any{
  301. "1": 2,
  302. "2": 3,
  303. }
  304. test(m2, t)
  305. })
  306. }