object_dynamic_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package goja
  2. import "testing"
  3. type testDynObject struct {
  4. r *Runtime
  5. m map[string]Value
  6. }
  7. func (t *testDynObject) Get(key string) Value {
  8. return t.m[key]
  9. }
  10. func (t *testDynObject) Set(key string, val Value) bool {
  11. t.m[key] = val
  12. return true
  13. }
  14. func (t *testDynObject) Has(key string) bool {
  15. _, exists := t.m[key]
  16. return exists
  17. }
  18. func (t *testDynObject) Delete(key string) bool {
  19. delete(t.m, key)
  20. return true
  21. }
  22. func (t *testDynObject) Keys() []string {
  23. keys := make([]string, 0, len(t.m))
  24. for k := range t.m {
  25. keys = append(keys, k)
  26. }
  27. return keys
  28. }
  29. type testDynArray struct {
  30. r *Runtime
  31. a []Value
  32. }
  33. func (t *testDynArray) Len() int {
  34. return len(t.a)
  35. }
  36. func (t *testDynArray) Get(idx int) Value {
  37. if idx < 0 {
  38. idx += len(t.a)
  39. }
  40. if idx >= 0 && idx < len(t.a) {
  41. return t.a[idx]
  42. }
  43. return nil
  44. }
  45. func (t *testDynArray) expand(newLen int) {
  46. if newLen > cap(t.a) {
  47. a := make([]Value, newLen)
  48. copy(a, t.a)
  49. t.a = a
  50. } else {
  51. t.a = t.a[:newLen]
  52. }
  53. }
  54. func (t *testDynArray) Set(idx int, val Value) bool {
  55. if idx < 0 {
  56. idx += len(t.a)
  57. }
  58. if idx < 0 {
  59. return false
  60. }
  61. if idx >= len(t.a) {
  62. t.expand(idx + 1)
  63. }
  64. t.a[idx] = val
  65. return true
  66. }
  67. func (t *testDynArray) SetLen(i int) bool {
  68. if i > len(t.a) {
  69. t.expand(i)
  70. return true
  71. }
  72. if i < 0 {
  73. return false
  74. }
  75. if i < len(t.a) {
  76. tail := t.a[i:len(t.a)]
  77. for j := range tail {
  78. tail[j] = nil
  79. }
  80. t.a = t.a[:i]
  81. }
  82. return true
  83. }
  84. func TestDynamicObject(t *testing.T) {
  85. vm := New()
  86. dynObj := &testDynObject{
  87. r: vm,
  88. m: make(map[string]Value),
  89. }
  90. o := vm.NewDynamicObject(dynObj)
  91. vm.Set("o", o)
  92. _, err := vm.RunString(TESTLIBX + `
  93. assert(o instanceof Object, "instanceof Object");
  94. assert(o === o, "self equality");
  95. assert(o !== {}, "non-equality");
  96. o.test = 42;
  97. assert("test" in o, "'test' in o");
  98. assert(deepEqual(Object.getOwnPropertyDescriptor(o, "test"), {value: 42, writable: true, enumerable: true, configurable: true}), "prop desc");
  99. assert.throws(TypeError, function() {
  100. "use strict";
  101. Object.defineProperty(o, "test1", {value: 0, writable: false, enumerable: false, configurable: true});
  102. }, "define prop");
  103. var keys = [];
  104. for (var key in o) {
  105. keys.push(key);
  106. }
  107. assert(compareArray(keys, ["test"]), "for-in");
  108. assert(delete o.test, "delete");
  109. assert(!("test" in o), "'test' in o after delete");
  110. assert("__proto__" in o, "__proto__ in o");
  111. assert.sameValue(o.__proto__, Object.prototype, "__proto__");
  112. o.__proto__ = null;
  113. assert(!("__proto__" in o), "__proto__ in o after setting to null");
  114. `)
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. }
  119. func TestDynamicObjectCustomProto(t *testing.T) {
  120. vm := New()
  121. m := make(map[string]Value)
  122. dynObj := &testDynObject{
  123. r: vm,
  124. m: m,
  125. }
  126. o := vm.NewDynamicObject(dynObj)
  127. vm.Set("o", o)
  128. _, err := vm.RunString(TESTLIB + `
  129. var proto = {
  130. valueOf: function() {
  131. return this.num;
  132. }
  133. };
  134. proto[Symbol.toStringTag] = "GoObject";
  135. Object.setPrototypeOf(o, proto);
  136. o.num = 41;
  137. assert(o instanceof Object, "instanceof");
  138. assert.sameValue(o+1, 42);
  139. assert.sameValue(o.toString(), "[object GoObject]");
  140. `)
  141. if err != nil {
  142. t.Fatal(err)
  143. }
  144. if v := m["num"]; v.Export() != int64(41) {
  145. t.Fatal(v)
  146. }
  147. }
  148. func TestDynamicArray(t *testing.T) {
  149. vm := New()
  150. dynObj := &testDynArray{
  151. r: vm,
  152. }
  153. a := vm.NewDynamicArray(dynObj)
  154. vm.Set("a", a)
  155. _, err := vm.RunString(TESTLIBX + `
  156. assert(a instanceof Array, "instanceof Array");
  157. assert(a instanceof Object, "instanceof Object");
  158. assert(a === a, "self equality");
  159. assert(a !== [], "non-equality");
  160. assert(Array.isArray(a), "isArray()");
  161. assert("length" in a, "length in a");
  162. assert.sameValue(a.length, 0, "len == 0");
  163. assert.sameValue(a[0], undefined, "a[0] (1)");
  164. a[0] = 0;
  165. assert.sameValue(a[0], 0, "a[0] (2)");
  166. assert.sameValue(a.length, 1, "length");
  167. assert(deepEqual(Object.getOwnPropertyDescriptor(a, 0), {value: 0, writable: true, enumerable: true, configurable: true}), "prop desc");
  168. assert(deepEqual(Object.getOwnPropertyDescriptor(a, "length"), {value: 1, writable: true, enumerable: false, configurable: false}), "length prop desc");
  169. assert("__proto__" in a, "__proto__ in a");
  170. assert.sameValue(a.__proto__, Array.prototype, "__proto__");
  171. assert(compareArray(Object.keys(a), ["0"]), "Object.keys()");
  172. assert(compareArray(Reflect.ownKeys(a), ["0", "length"]), "Reflect.ownKeys()");
  173. a.length = 2;
  174. assert.sameValue(a.length, 2, "length after grow");
  175. assert.sameValue(a[1], undefined, "a[1]");
  176. a[1] = 1;
  177. assert.sameValue(a[1], 1, "a[1] after set");
  178. a.length = 1;
  179. assert.sameValue(a.length, 1, "length after shrink");
  180. assert.sameValue(a[1], undefined, "a[1] after shrink");
  181. a.length = 2;
  182. assert.sameValue(a.length, 2, "length after shrink and grow");
  183. assert.sameValue(a[1], undefined, "a[1] after grow");
  184. a[0] = 3; a[1] = 1; a[2] = 2;
  185. assert.sameValue(a.length, 3);
  186. var keys = [];
  187. for (var key in a) {
  188. keys.push(key);
  189. }
  190. assert(compareArray(keys, ["0","1","2"]), "for-in");
  191. var vals = [];
  192. for (var val of a) {
  193. vals.push(val);
  194. }
  195. assert(compareArray(vals, [3,1,2]), "for-of");
  196. a.sort();
  197. assert(compareArray(a, [1,2,3]), "sort: "+a);
  198. assert.sameValue(a[-1], 3);
  199. assert.sameValue(a[-4], undefined);
  200. assert.throws(TypeError, function() {
  201. "use strict";
  202. delete a.length;
  203. }, "delete length");
  204. assert.throws(TypeError, function() {
  205. "use strict";
  206. a.test = true;
  207. }, "set string prop");
  208. assert.throws(TypeError, function() {
  209. "use strict";
  210. Object.defineProperty(a, 0, {value: 0, writable: false, enumerable: false, configurable: true});
  211. }, "define prop");
  212. `)
  213. if err != nil {
  214. t.Fatal(err)
  215. }
  216. }