object_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. package goja
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. )
  7. func TestDefineProperty(t *testing.T) {
  8. r := New()
  9. o := r.NewObject()
  10. err := o.DefineDataProperty("data", r.ToValue(42), FLAG_TRUE, FLAG_TRUE, FLAG_TRUE)
  11. if err != nil {
  12. t.Fatal(err)
  13. }
  14. err = o.DefineAccessorProperty("accessor_ro", r.ToValue(func() int {
  15. return 1
  16. }), nil, FLAG_TRUE, FLAG_TRUE)
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. err = o.DefineAccessorProperty("accessor_rw",
  21. r.ToValue(func(call FunctionCall) Value {
  22. return o.Get("__hidden")
  23. }),
  24. r.ToValue(func(call FunctionCall) (ret Value) {
  25. o.Set("__hidden", call.Argument(0))
  26. return
  27. }),
  28. FLAG_TRUE, FLAG_TRUE)
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. if v := o.Get("accessor_ro"); v.ToInteger() != 1 {
  33. t.Fatalf("Unexpected accessor value: %v", v)
  34. }
  35. err = o.Set("accessor_ro", r.ToValue(2))
  36. if err == nil {
  37. t.Fatal("Expected an error")
  38. }
  39. if ex, ok := err.(*Exception); ok {
  40. if msg := ex.Error(); msg != "TypeError: Cannot assign to read only property 'accessor_ro'" {
  41. t.Fatalf("Unexpected error: '%s'", msg)
  42. }
  43. } else {
  44. t.Fatalf("Unexected error type: %T", err)
  45. }
  46. err = o.Set("accessor_rw", 42)
  47. if err != nil {
  48. t.Fatal(err)
  49. }
  50. if v := o.Get("accessor_rw"); v.ToInteger() != 42 {
  51. t.Fatalf("Unexpected value: %v", v)
  52. }
  53. }
  54. func TestPropertyOrder(t *testing.T) {
  55. const SCRIPT = `
  56. var o = {};
  57. var sym1 = Symbol(1);
  58. var sym2 = Symbol(2);
  59. o[sym2] = 1;
  60. o[4294967294] = 1;
  61. o[2] = 1;
  62. o[1] = 1;
  63. o[0] = 1;
  64. o["02"] = 1;
  65. o[4294967295] = 1;
  66. o["01"] = 1;
  67. o["00"] = 1;
  68. o[sym1] = 1;
  69. var expected = ["0", "1", "2", "4294967294", "02", "4294967295", "01", "00", sym2, sym1];
  70. var actual = Reflect.ownKeys(o);
  71. if (actual.length !== expected.length) {
  72. throw new Error("Unexpected length: "+actual.length);
  73. }
  74. for (var i = 0; i < actual.length; i++) {
  75. if (actual[i] !== expected[i]) {
  76. throw new Error("Unexpected list: " + actual);
  77. }
  78. }
  79. `
  80. testScript1(SCRIPT, _undefined, t)
  81. }
  82. func TestDefinePropertiesSymbol(t *testing.T) {
  83. const SCRIPT = `
  84. var desc = {};
  85. desc[Symbol.toStringTag] = {value: "Test"};
  86. var o = {};
  87. Object.defineProperties(o, desc);
  88. o[Symbol.toStringTag] === "Test";
  89. `
  90. testScript1(SCRIPT, valueTrue, t)
  91. }
  92. func TestObjectShorthandProperties(t *testing.T) {
  93. const SCRIPT = `
  94. var b = 1;
  95. var a = {b, get() {return "c"}};
  96. assert.sameValue(a.b, b, "#1");
  97. assert.sameValue(a.get(), "c", "#2");
  98. var obj = {
  99. w\u0069th() { return 42; }
  100. };
  101. assert.sameValue(obj['with'](), 42, 'property exists');
  102. `
  103. testScript1(TESTLIB+SCRIPT, _undefined, t)
  104. }
  105. func TestObjectAssign(t *testing.T) {
  106. const SCRIPT = `
  107. assert.sameValue(Object.assign({ b: 1 }, { get a() {
  108. Object.defineProperty(this, "b", {
  109. value: 3,
  110. enumerable: false
  111. });
  112. }, b: 2 }).b, 1, "#1");
  113. assert.sameValue(Object.assign({ b: 1 }, { get a() {
  114. delete this.b;
  115. }, b: 2 }).b, 1, "#2");
  116. `
  117. testScript1(TESTLIB+SCRIPT, _undefined, t)
  118. }
  119. func TestExportCircular(t *testing.T) {
  120. vm := New()
  121. o := vm.NewObject()
  122. o.Set("o", o)
  123. v := o.Export()
  124. if m, ok := v.(map[string]interface{}); ok {
  125. if reflect.ValueOf(m["o"]).Pointer() != reflect.ValueOf(v).Pointer() {
  126. t.Fatal("Unexpected value")
  127. }
  128. } else {
  129. t.Fatal("Unexpected type")
  130. }
  131. res, err := vm.RunString(`var a = []; a[0] = a;`)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. v = res.Export()
  136. if a, ok := v.([]interface{}); ok {
  137. if reflect.ValueOf(a[0]).Pointer() != reflect.ValueOf(v).Pointer() {
  138. t.Fatal("Unexpected value")
  139. }
  140. } else {
  141. t.Fatal("Unexpected type")
  142. }
  143. }
  144. type test_s struct {
  145. S *test_s1
  146. }
  147. type test_s1 struct {
  148. S *test_s
  149. }
  150. func TestExportToCircular(t *testing.T) {
  151. vm := New()
  152. o := vm.NewObject()
  153. o.Set("o", o)
  154. var m map[string]interface{}
  155. err := vm.ExportTo(o, &m)
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. type K string
  160. type T map[K]T
  161. var m1 T
  162. err = vm.ExportTo(o, &m1)
  163. if err != nil {
  164. t.Fatal(err)
  165. }
  166. type A []A
  167. var a A
  168. res, err := vm.RunString("var a = []; a[0] = a;")
  169. if err != nil {
  170. t.Fatal(err)
  171. }
  172. err = vm.ExportTo(res, &a)
  173. if err != nil {
  174. t.Fatal(err)
  175. }
  176. if &a[0] != &a[0][0] {
  177. t.Fatal("values do not match")
  178. }
  179. o = vm.NewObject()
  180. o.Set("S", o)
  181. var s test_s
  182. err = vm.ExportTo(o, &s)
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. if s.S.S != &s {
  187. t.Fatalf("values do not match: %v, %v", s.S.S, &s)
  188. }
  189. type test_s2 struct {
  190. S interface{}
  191. S1 *test_s2
  192. }
  193. var s2 test_s2
  194. o.Set("S1", o)
  195. err = vm.ExportTo(o, &s2)
  196. if err != nil {
  197. t.Fatal(err)
  198. }
  199. if m, ok := s2.S.(map[string]interface{}); ok {
  200. if reflect.ValueOf(m["S"]).Pointer() != reflect.ValueOf(m).Pointer() {
  201. t.Fatal("Unexpected m.S")
  202. }
  203. } else {
  204. t.Fatalf("Unexpected s2.S type: %T", s2.S)
  205. }
  206. if s2.S1 != &s2 {
  207. t.Fatal("Unexpected s2.S1")
  208. }
  209. o1 := vm.NewObject()
  210. o1.Set("S", o)
  211. o1.Set("S1", o)
  212. err = vm.ExportTo(o1, &s2)
  213. if err != nil {
  214. t.Fatal(err)
  215. }
  216. if s2.S1.S1 != s2.S1 {
  217. t.Fatal("Unexpected s2.S1.S1")
  218. }
  219. }
  220. func TestExportWrappedMap(t *testing.T) {
  221. vm := New()
  222. m := map[string]interface{}{
  223. "test": "failed",
  224. }
  225. exported := vm.ToValue(m).Export()
  226. if exportedMap, ok := exported.(map[string]interface{}); ok {
  227. exportedMap["test"] = "passed"
  228. if v := m["test"]; v != "passed" {
  229. t.Fatalf("Unexpected m[\"test\"]: %v", v)
  230. }
  231. } else {
  232. t.Fatalf("Unexpected export type: %T", exported)
  233. }
  234. }
  235. func TestExportToWrappedMap(t *testing.T) {
  236. vm := New()
  237. m := map[string]interface{}{
  238. "test": "failed",
  239. }
  240. var exported map[string]interface{}
  241. err := vm.ExportTo(vm.ToValue(m), &exported)
  242. if err != nil {
  243. t.Fatal(err)
  244. }
  245. exported["test"] = "passed"
  246. if v := m["test"]; v != "passed" {
  247. t.Fatalf("Unexpected m[\"test\"]: %v", v)
  248. }
  249. }
  250. func TestExportToWrappedMapCustom(t *testing.T) {
  251. type CustomMap map[string]bool
  252. vm := New()
  253. m := CustomMap{}
  254. var exported CustomMap
  255. err := vm.ExportTo(vm.ToValue(m), &exported)
  256. if err != nil {
  257. t.Fatal(err)
  258. }
  259. exported["test"] = true
  260. if v := m["test"]; v != true {
  261. t.Fatalf("Unexpected m[\"test\"]: %v", v)
  262. }
  263. }
  264. func TestSetForeignReturnValue(t *testing.T) {
  265. const SCRIPT = `
  266. var array = [1, 2, 3];
  267. var arrayTarget = new Proxy(array, {});
  268. Object.preventExtensions(array);
  269. !Reflect.set(arrayTarget, "foo", 2);
  270. `
  271. testScript1(SCRIPT, valueTrue, t)
  272. }
  273. func TestDefinePropertiesUndefinedVal(t *testing.T) {
  274. const SCRIPT = `
  275. var target = {};
  276. var sym = Symbol();
  277. target[sym] = 1;
  278. target.foo = 2;
  279. target[0] = 3;
  280. var getOwnKeys = [];
  281. var proxy = new Proxy(target, {
  282. getOwnPropertyDescriptor: function(_target, key) {
  283. getOwnKeys.push(key);
  284. },
  285. });
  286. Object.defineProperties({}, proxy);
  287. true;
  288. `
  289. testScript1(SCRIPT, valueTrue, t)
  290. }
  291. func ExampleObject_Delete() {
  292. vm := New()
  293. obj := vm.NewObject()
  294. _ = obj.Set("test", true)
  295. before := obj.Get("test")
  296. _ = obj.Delete("test")
  297. after := obj.Get("test")
  298. fmt.Printf("before: %v, after: %v", before, after)
  299. // Output: before: true, after: <nil>
  300. }
  301. func BenchmarkPut(b *testing.B) {
  302. v := &Object{}
  303. o := &baseObject{
  304. val: v,
  305. extensible: true,
  306. }
  307. v.self = o
  308. o.init()
  309. var key Value = asciiString("test")
  310. var val Value = valueInt(123)
  311. for i := 0; i < b.N; i++ {
  312. v.setOwn(key, val, false)
  313. }
  314. }
  315. func BenchmarkPutStr(b *testing.B) {
  316. v := &Object{}
  317. o := &baseObject{
  318. val: v,
  319. extensible: true,
  320. }
  321. o.init()
  322. v.self = o
  323. var val Value = valueInt(123)
  324. for i := 0; i < b.N; i++ {
  325. o.setOwnStr("test", val, false)
  326. }
  327. }
  328. func BenchmarkGet(b *testing.B) {
  329. v := &Object{}
  330. o := &baseObject{
  331. val: v,
  332. extensible: true,
  333. }
  334. o.init()
  335. v.self = o
  336. var n Value = asciiString("test")
  337. for i := 0; i < b.N; i++ {
  338. v.get(n, nil)
  339. }
  340. }
  341. func BenchmarkGetStr(b *testing.B) {
  342. v := &Object{}
  343. o := &baseObject{
  344. val: v,
  345. extensible: true,
  346. }
  347. v.self = o
  348. o.init()
  349. for i := 0; i < b.N; i++ {
  350. o.getStr("test", nil)
  351. }
  352. }
  353. func __toString(v Value) string {
  354. switch v := v.(type) {
  355. case asciiString:
  356. return string(v)
  357. default:
  358. return ""
  359. }
  360. }
  361. func BenchmarkToString1(b *testing.B) {
  362. v := asciiString("test")
  363. for i := 0; i < b.N; i++ {
  364. v.toString()
  365. }
  366. }
  367. func BenchmarkToString2(b *testing.B) {
  368. v := asciiString("test")
  369. for i := 0; i < b.N; i++ {
  370. __toString(v)
  371. }
  372. }
  373. func BenchmarkConv(b *testing.B) {
  374. count := int64(0)
  375. for i := 0; i < b.N; i++ {
  376. count += valueInt(123).ToInteger()
  377. }
  378. if count == 0 {
  379. b.Fatal("zero")
  380. }
  381. }
  382. func BenchmarkToUTF8String(b *testing.B) {
  383. var s valueString = asciiString("test")
  384. for i := 0; i < b.N; i++ {
  385. _ = s.String()
  386. }
  387. }
  388. func BenchmarkAdd(b *testing.B) {
  389. var x, y Value
  390. x = valueInt(2)
  391. y = valueInt(2)
  392. for i := 0; i < b.N; i++ {
  393. if xi, ok := x.(valueInt); ok {
  394. if yi, ok := y.(valueInt); ok {
  395. x = xi + yi
  396. }
  397. }
  398. }
  399. }
  400. func BenchmarkAddString(b *testing.B) {
  401. var x, y Value
  402. tst := asciiString("22")
  403. x = asciiString("2")
  404. y = asciiString("2")
  405. for i := 0; i < b.N; i++ {
  406. var z Value
  407. if xi, ok := x.(valueString); ok {
  408. if yi, ok := y.(valueString); ok {
  409. z = xi.concat(yi)
  410. }
  411. }
  412. if !z.StrictEquals(tst) {
  413. b.Fatalf("Unexpected result %v", x)
  414. }
  415. }
  416. }