func_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. }
  70. func TestFuncWrapUnwrap(t *testing.T) {
  71. vm := New()
  72. f := func(a int, b string) bool {
  73. return a > 0 && b != ""
  74. }
  75. var f1 func(int, string) bool
  76. v := vm.ToValue(f)
  77. if et := v.ExportType(); et != reflect.TypeOf(f1) {
  78. t.Fatal(et)
  79. }
  80. err := vm.ExportTo(v, &f1)
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if !f1(1, "a") {
  85. t.Fatal("not true")
  86. }
  87. }
  88. func TestWrappedFunc(t *testing.T) {
  89. vm := New()
  90. f := func(a int, b string) bool {
  91. return a > 0 && b != ""
  92. }
  93. vm.Set("f", f)
  94. const SCRIPT = `
  95. assert.sameValue(typeof f, "function");
  96. const s = f.toString()
  97. assert(s.endsWith("TestWrappedFunc.func1() { [native code] }"), s);
  98. assert(f(1, "a"));
  99. assert(!f(0, ""));
  100. `
  101. vm.testScriptWithTestLib(SCRIPT, _undefined, t)
  102. }
  103. func TestWrappedFuncErrorPassthrough(t *testing.T) {
  104. vm := New()
  105. e := errors.New("test")
  106. f := func(a int) error {
  107. if a > 0 {
  108. return e
  109. }
  110. return nil
  111. }
  112. var f1 func(a int64) error
  113. err := vm.ExportTo(vm.ToValue(f), &f1)
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. if err := f1(1); err != e {
  118. t.Fatal(err)
  119. }
  120. }
  121. func ExampleAssertConstructor() {
  122. vm := New()
  123. res, err := vm.RunString(`
  124. (class C {
  125. constructor(x) {
  126. this.x = x;
  127. }
  128. })
  129. `)
  130. if err != nil {
  131. panic(err)
  132. }
  133. if ctor, ok := AssertConstructor(res); ok {
  134. obj, err := ctor(nil, vm.ToValue("Test"))
  135. if err != nil {
  136. panic(err)
  137. }
  138. fmt.Print(obj.Get("x"))
  139. } else {
  140. panic("Not a constructor")
  141. }
  142. // Output: Test
  143. }
  144. type testAsyncCtx struct {
  145. group string
  146. refCount int
  147. }
  148. type testAsyncContextTracker struct {
  149. ctx *testAsyncCtx
  150. logFunc func(...interface{})
  151. resumed bool
  152. }
  153. func (s *testAsyncContextTracker) Grab() interface{} {
  154. ctx := s.ctx
  155. if ctx != nil {
  156. s.logFunc("Grab", ctx.group)
  157. ctx.refCount++
  158. }
  159. return ctx
  160. }
  161. func (s *testAsyncContextTracker) Resumed(trackingObj interface{}) {
  162. s.logFunc("Resumed", trackingObj)
  163. if s.resumed {
  164. panic("Nested Resumed() calls")
  165. }
  166. s.ctx = trackingObj.(*testAsyncCtx)
  167. s.resumed = true
  168. }
  169. func (s *testAsyncContextTracker) releaseCtx() {
  170. s.ctx.refCount--
  171. if s.ctx.refCount < 0 {
  172. panic("refCount < 0")
  173. }
  174. if s.ctx.refCount == 0 {
  175. s.logFunc(s.ctx.group, "is finished")
  176. }
  177. }
  178. func (s *testAsyncContextTracker) Exited() {
  179. s.logFunc("Exited")
  180. if s.ctx != nil {
  181. s.releaseCtx()
  182. s.ctx = nil
  183. }
  184. s.resumed = false
  185. }
  186. func TestAsyncContextTracker(t *testing.T) {
  187. r := New()
  188. var tracker testAsyncContextTracker
  189. tracker.logFunc = t.Log
  190. group := func(name string, asyncFunc func(FunctionCall) Value) Value {
  191. prevCtx := tracker.ctx
  192. defer func() {
  193. t.Log("Returned", name)
  194. tracker.releaseCtx()
  195. tracker.ctx = prevCtx
  196. }()
  197. tracker.ctx = &testAsyncCtx{
  198. group: name,
  199. refCount: 1,
  200. }
  201. t.Log("Set", name)
  202. return asyncFunc(FunctionCall{})
  203. }
  204. r.SetAsyncContextTracker(&tracker)
  205. r.Set("group", group)
  206. r.Set("check", func(expectedGroup, msg string) {
  207. var groupName string
  208. if tracker.ctx != nil {
  209. groupName = tracker.ctx.group
  210. }
  211. if groupName != expectedGroup {
  212. t.Fatalf("Unexpected group (%q), expected %q in %s", groupName, expectedGroup, msg)
  213. }
  214. t.Log("In", msg)
  215. })
  216. t.Run("", func(t *testing.T) {
  217. _, err := r.RunString(`
  218. group("1", async () => {
  219. check("1", "line A");
  220. await 3;
  221. check("1", "line B");
  222. group("2", async () => {
  223. check("2", "line C");
  224. await 4;
  225. check("2", "line D");
  226. })
  227. }).then(() => {
  228. check("", "line E");
  229. })
  230. `)
  231. if err != nil {
  232. t.Fatal(err)
  233. }
  234. })
  235. t.Run("", func(t *testing.T) {
  236. _, err := r.RunString(`
  237. group("some", async () => {
  238. check("some", "line A");
  239. (async () => {
  240. check("some", "line B");
  241. await 1;
  242. check("some", "line C");
  243. await 2;
  244. check("some", "line D");
  245. })();
  246. check("some", "line E");
  247. });
  248. `)
  249. if err != nil {
  250. t.Fatal(err)
  251. }
  252. })
  253. t.Run("", func(t *testing.T) {
  254. _, err := r.RunString(`
  255. group("Main", async () => {
  256. check("Main", "0.1");
  257. await Promise.all([
  258. group("A", async () => {
  259. check("A", "1.1");
  260. await 1;
  261. check("A", "1.2");
  262. }),
  263. (async () => {
  264. check("Main", "3.1");
  265. })(),
  266. group("B", async () => {
  267. check("B", "2.1");
  268. await 2;
  269. check("B", "2.2");
  270. })
  271. ]);
  272. check("Main", "0.2");
  273. });
  274. `)
  275. if err != nil {
  276. t.Fatal(err)
  277. }
  278. })
  279. }