func_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. package goja
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. "testing"
  7. )
  8. func TestFuncProto(t *testing.T) {
  9. const SCRIPT = `
  10. "use strict";
  11. function A() {}
  12. A.__proto__ = Object;
  13. A.prototype = {};
  14. function B() {}
  15. B.__proto__ = Object.create(null);
  16. var thrown = false;
  17. try {
  18. delete B.prototype;
  19. } catch (e) {
  20. thrown = e instanceof TypeError;
  21. }
  22. thrown;
  23. `
  24. testScript(SCRIPT, valueTrue, t)
  25. }
  26. func TestFuncPrototypeRedefine(t *testing.T) {
  27. const SCRIPT = `
  28. let thrown = false;
  29. try {
  30. Object.defineProperty(function() {}, "prototype", {
  31. set: function(_value) {},
  32. });
  33. } catch (e) {
  34. if (e instanceof TypeError) {
  35. thrown = true;
  36. } else {
  37. throw e;
  38. }
  39. }
  40. thrown;
  41. `
  42. testScript(SCRIPT, valueTrue, t)
  43. }
  44. func TestFuncExport(t *testing.T) {
  45. vm := New()
  46. typ := reflect.TypeOf((func(FunctionCall) Value)(nil))
  47. f := func(expr string, t *testing.T) {
  48. v, err := vm.RunString(expr)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. if actualTyp := v.ExportType(); actualTyp != typ {
  53. t.Fatalf("Invalid export type: %v", actualTyp)
  54. }
  55. ev := v.Export()
  56. if actualTyp := reflect.TypeOf(ev); actualTyp != typ {
  57. t.Fatalf("Invalid export value: %v", ev)
  58. }
  59. }
  60. t.Run("regular function", func(t *testing.T) {
  61. f("(function() {})", t)
  62. })
  63. t.Run("arrow function", func(t *testing.T) {
  64. f("(()=>{})", t)
  65. })
  66. t.Run("method", func(t *testing.T) {
  67. f("({m() {}}).m", t)
  68. })
  69. t.Run("class", func(t *testing.T) {
  70. f("(class {})", t)
  71. })
  72. }
  73. func TestFuncWrapUnwrap(t *testing.T) {
  74. vm := New()
  75. f := func(a int, b string) bool {
  76. return a > 0 && b != ""
  77. }
  78. var f1 func(int, string) bool
  79. v := vm.ToValue(f)
  80. if et := v.ExportType(); et != reflect.TypeOf(f1) {
  81. t.Fatal(et)
  82. }
  83. err := vm.ExportTo(v, &f1)
  84. if err != nil {
  85. t.Fatal(err)
  86. }
  87. if !f1(1, "a") {
  88. t.Fatal("not true")
  89. }
  90. }
  91. func TestWrappedFunc(t *testing.T) {
  92. vm := New()
  93. f := func(a int, b string) bool {
  94. return a > 0 && b != ""
  95. }
  96. vm.Set("f", f)
  97. const SCRIPT = `
  98. assert.sameValue(typeof f, "function");
  99. const s = f.toString()
  100. assert(s.endsWith("TestWrappedFunc.func1() { [native code] }"), s);
  101. assert(f(1, "a"));
  102. assert(!f(0, ""));
  103. `
  104. vm.testScriptWithTestLib(SCRIPT, _undefined, t)
  105. }
  106. func TestWrappedFuncErrorPassthrough(t *testing.T) {
  107. vm := New()
  108. e := errors.New("test")
  109. f := func(a int) error {
  110. if a > 0 {
  111. return e
  112. }
  113. return nil
  114. }
  115. var f1 func(a int64) error
  116. err := vm.ExportTo(vm.ToValue(f), &f1)
  117. if err != nil {
  118. t.Fatal(err)
  119. }
  120. if err := f1(1); err != e {
  121. t.Fatal(err)
  122. }
  123. }
  124. func ExampleAssertConstructor() {
  125. vm := New()
  126. res, err := vm.RunString(`
  127. (class C {
  128. constructor(x) {
  129. this.x = x;
  130. }
  131. })
  132. `)
  133. if err != nil {
  134. panic(err)
  135. }
  136. if ctor, ok := AssertConstructor(res); ok {
  137. obj, err := ctor(nil, vm.ToValue("Test"))
  138. if err != nil {
  139. panic(err)
  140. }
  141. fmt.Print(obj.Get("x"))
  142. } else {
  143. panic("Not a constructor")
  144. }
  145. // Output: Test
  146. }
  147. type testAsyncCtx struct {
  148. group string
  149. refCount int
  150. }
  151. type testAsyncContextTracker struct {
  152. ctx *testAsyncCtx
  153. logFunc func(...interface{})
  154. resumed bool
  155. }
  156. func (s *testAsyncContextTracker) Grab() interface{} {
  157. ctx := s.ctx
  158. if ctx != nil {
  159. s.logFunc("Grab", ctx.group)
  160. ctx.refCount++
  161. }
  162. return ctx
  163. }
  164. func (s *testAsyncContextTracker) Resumed(trackingObj interface{}) {
  165. s.logFunc("Resumed", trackingObj)
  166. if s.resumed {
  167. panic("Nested Resumed() calls")
  168. }
  169. s.ctx = trackingObj.(*testAsyncCtx)
  170. s.resumed = true
  171. }
  172. func (s *testAsyncContextTracker) releaseCtx() {
  173. s.ctx.refCount--
  174. if s.ctx.refCount < 0 {
  175. panic("refCount < 0")
  176. }
  177. if s.ctx.refCount == 0 {
  178. s.logFunc(s.ctx.group, "is finished")
  179. }
  180. }
  181. func (s *testAsyncContextTracker) Exited() {
  182. s.logFunc("Exited")
  183. if s.ctx != nil {
  184. s.releaseCtx()
  185. s.ctx = nil
  186. }
  187. s.resumed = false
  188. }
  189. func TestAsyncContextTracker(t *testing.T) {
  190. r := New()
  191. var tracker testAsyncContextTracker
  192. tracker.logFunc = t.Log
  193. group := func(name string, asyncFunc func(FunctionCall) Value) Value {
  194. prevCtx := tracker.ctx
  195. defer func() {
  196. t.Log("Returned", name)
  197. tracker.releaseCtx()
  198. tracker.ctx = prevCtx
  199. }()
  200. tracker.ctx = &testAsyncCtx{
  201. group: name,
  202. refCount: 1,
  203. }
  204. t.Log("Set", name)
  205. return asyncFunc(FunctionCall{})
  206. }
  207. r.SetAsyncContextTracker(&tracker)
  208. r.Set("group", group)
  209. r.Set("check", func(expectedGroup, msg string) {
  210. var groupName string
  211. if tracker.ctx != nil {
  212. groupName = tracker.ctx.group
  213. }
  214. if groupName != expectedGroup {
  215. t.Fatalf("Unexpected group (%q), expected %q in %s", groupName, expectedGroup, msg)
  216. }
  217. t.Log("In", msg)
  218. })
  219. t.Run("", func(t *testing.T) {
  220. _, err := r.RunString(`
  221. group("1", async () => {
  222. check("1", "line A");
  223. await 3;
  224. check("1", "line B");
  225. group("2", async () => {
  226. check("2", "line C");
  227. await 4;
  228. check("2", "line D");
  229. })
  230. }).then(() => {
  231. check("", "line E");
  232. })
  233. `)
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. })
  238. t.Run("", func(t *testing.T) {
  239. _, err := r.RunString(`
  240. group("some", async () => {
  241. check("some", "line A");
  242. (async () => {
  243. check("some", "line B");
  244. await 1;
  245. check("some", "line C");
  246. await 2;
  247. check("some", "line D");
  248. })();
  249. check("some", "line E");
  250. });
  251. `)
  252. if err != nil {
  253. t.Fatal(err)
  254. }
  255. })
  256. t.Run("", func(t *testing.T) {
  257. _, err := r.RunString(`
  258. group("Main", async () => {
  259. check("Main", "0.1");
  260. await Promise.all([
  261. group("A", async () => {
  262. check("A", "1.1");
  263. await 1;
  264. check("A", "1.2");
  265. }),
  266. (async () => {
  267. check("Main", "3.1");
  268. })(),
  269. group("B", async () => {
  270. check("B", "2.1");
  271. await 2;
  272. check("B", "2.2");
  273. })
  274. ]);
  275. check("Main", "0.2");
  276. });
  277. `)
  278. if err != nil {
  279. t.Fatal(err)
  280. }
  281. })
  282. }