/src/erlv8.erl

http://github.com/beamjs/erlv8 · Erlang · 831 lines · 715 code · 99 blank · 17 comment · 2 complexity · 28a47dc189b7f8e0870f9fafb2d7cce0 MD5 · raw file

  1. -module(erlv8).
  2. -export([start/0,stop/0]).
  3. -include_lib("erlv8/include/erlv8.hrl").
  4. start() ->
  5. application:start(erlv8).
  6. stop() ->
  7. application:stop(erlv8).
  8. %% TESTS
  9. -include_lib("eunit/include/eunit.hrl").%
  10. -ifdef(TEST).
  11. suppress_kernel_logger_test() ->
  12. % not a test, obviously
  13. error_logger:delete_report_handler(error_logger_tty_h).
  14. valid_vm_creation_test() ->
  15. start(),
  16. {ok, VM} = erlv8_vm:start(),
  17. ?assert(is_pid(VM)),
  18. ?assertEqual({ok, 2}, erlv8_vm:run(VM,"1+1;")),
  19. ok = stop().
  20. few_vms_test() ->
  21. start(),
  22. {ok, VM} = erlv8_vm:start(),
  23. ?assertEqual({ok,2}, erlv8_vm:run(VM,"1+1;")),
  24. ?assertEqual({ok,4}, erlv8_vm:run(VM,"2*2;")),
  25. stop().
  26. compilation_error_test() ->
  27. start(),
  28. {ok, VM} = erlv8_vm:start(),
  29. ?assertMatch({throw, _}, erlv8_vm:run(VM,"1+;")),
  30. stop().
  31. vm_stopping_test() ->
  32. start(),
  33. {ok, VM} = erlv8_vm:start(),
  34. erlv8_vm:stop(VM),
  35. timer:sleep(100), %% allow time for process to stop
  36. ?assertEqual(false,erlang:is_process_alive(VM)),
  37. stop().
  38. vm_global_test() ->
  39. start(),
  40. {ok, VM} = erlv8_vm:start(),
  41. erlv8_vm:run(VM,"var a = 1+1;"),
  42. Global = erlv8_vm:global(VM),
  43. ?assertEqual([{<<"a">>,2}],Global:proplist()),
  44. stop().
  45. vm_set_global_test() ->
  46. start(),
  47. {ok, VM} = erlv8_vm:start(),
  48. Global = erlv8_vm:global(VM),
  49. Global:set_value("a",1),
  50. erlv8_vm:run(VM,"var b = a+1;"),
  51. ?assertEqual([{<<"a">>,1},{<<"b">>,2}],Global:proplist()),
  52. stop().
  53. term_to_js_string_test() ->
  54. start(),
  55. {ok, VM} = erlv8_vm:start(),
  56. Obj = erlv8_vm:taint(VM, "abc"),
  57. ?assertEqual(<<"abc">>,Obj),
  58. stop().
  59. term_to_js_binary_test() ->
  60. start(),
  61. {ok, VM} = erlv8_vm:start(),
  62. Obj = erlv8_vm:taint(VM, <<"abc">>),
  63. ?assertEqual(<<"abc">>,Obj),
  64. stop().
  65. term_to_js_iolist_test() ->
  66. start(),
  67. {ok, VM} = erlv8_vm:start(),
  68. Obj = erlv8_vm:taint(VM, [<<"abc">>,$d,"ef"]),
  69. ?assertEqual(<<"abcdef">>,Obj),
  70. stop().
  71. term_to_js_object_test() ->
  72. start(),
  73. {ok, VM} = erlv8_vm:start(),
  74. Obj = erlv8_vm:taint(VM,?V8Obj([{"a",1},{"b","c"},{<<"c">>,<<"d">>}])),
  75. ?assertMatch([{<<"a">>,1},{<<"b">>,<<"c">>},{<<"c">>,<<"d">>}],Obj:proplist()),
  76. stop().
  77. term_to_js_boolean_test() ->
  78. start(),
  79. {ok, VM} = erlv8_vm:start(),
  80. ?assertEqual(true, erlv8_vm:taint(VM,true)),
  81. ?assertEqual(false, erlv8_vm:taint(VM,false)),
  82. stop().
  83. term_to_js_atom_test() ->
  84. start(),
  85. {ok, VM} = erlv8_vm:start(),
  86. ?assertEqual(<<"a">>, erlv8_vm:taint(VM,a)),
  87. ?assertEqual(<<"b">>, erlv8_vm:taint(VM,b)),
  88. stop().
  89. term_to_js_undefined_test() ->
  90. start(),
  91. {ok, VM} = erlv8_vm:start(),
  92. ?assertEqual(undefined, erlv8_vm:taint(VM,undefined)),
  93. stop().
  94. term_to_js_ok_test() ->
  95. start(),
  96. {ok, VM} = erlv8_vm:start(),
  97. ?assertEqual(true, erlv8_vm:taint(VM,ok)),
  98. stop().
  99. term_to_js_null_test() ->
  100. start(),
  101. {ok, VM} = erlv8_vm:start(),
  102. ?assertEqual(null, erlv8_vm:taint(VM,null)),
  103. stop().
  104. term_to_js_number_test() ->
  105. start(),
  106. {ok, VM} = erlv8_vm:start(),
  107. Nums = [2147483648,-2147483649,1,4294967296,4294967297,3.555],
  108. [ ?assertEqual(N, erlv8_vm:taint(VM,N)) || N <- Nums ],
  109. stop().
  110. term_to_js_array_test() ->
  111. start(),
  112. {ok, VM} = erlv8_vm:start(),
  113. A1 = erlv8_vm:taint(VM,?V8Arr([1,2,3])),
  114. ?assertEqual([1,2,3],A1:list()),
  115. A2 = erlv8_vm:taint(VM,?V8Arr([])),
  116. ?assertEqual([],A2:list()),
  117. stop().
  118. term_to_js_pid_test() ->
  119. start(),
  120. {ok, VM} = erlv8_vm:start(),
  121. ?assertEqual(self(), erlv8_vm:taint(VM,self())),
  122. ?assertEqual(self(), erlv8_vm:taint(VM,self())), % the second call is to ensure memory is managed properly (regression)
  123. stop().
  124. term_to_js_ref_test() ->
  125. start(),
  126. {ok, VM} = erlv8_vm:start(),
  127. Ref = make_ref(),
  128. ?assertEqual(Ref, erlv8_vm:taint(VM,Ref)),
  129. stop().
  130. term_to_js_unsupported_test() ->
  131. start(),
  132. {ok, VM} = erlv8_vm:start(),
  133. ?assertEqual(undefined,erlv8_vm:taint(VM,{this_tuple,is_not_supported})),
  134. stop().
  135. term_to_js_object_invalid_proplist_test() ->
  136. start(),
  137. {ok, VM} = erlv8_vm:start(),
  138. ?assertEqual(undefined, erlv8_vm:taint(VM,?V8Obj([{"a",1},{b,2},{3,4}]))),
  139. stop().
  140. js_to_term_fun_test() ->
  141. start(),
  142. {ok, VM} = erlv8_vm:start(),
  143. erlv8_vm:run(VM,"x = function () {}"),
  144. Global = erlv8_vm:global(VM),
  145. #erlv8_fun{vm=VM} = Global:get_value("x"),
  146. stop().
  147. js_object_to_term_fun_test() ->
  148. start(),
  149. {ok, VM} = erlv8_vm:start(),
  150. erlv8_vm:run(VM,"x = function () {}; x.a = 1"),
  151. Global = erlv8_vm:global(VM),
  152. X = Global:get_value("x"),
  153. O = X:object(),
  154. ?assertEqual([{<<"a">>,1}],O:proplist()),
  155. stop().
  156. term_to_js_object_fun_erlv8_fun_test() ->
  157. start(),
  158. {ok, VM} = erlv8_vm:start(),
  159. Global = erlv8_vm:global(VM),
  160. {ok, #erlv8_fun{vm=VM}=Fun} = erlv8_vm:run(VM,"x = function () {}; x.a = 1; x"),
  161. O = Fun:object(),
  162. ?assertEqual([{<<"a">>,1}],O:proplist()),
  163. Global:set_value("y",Fun),
  164. Y = Global:get_value("y"),
  165. YObj = Y:object(),
  166. ?assertEqual(1, YObj:get_value("a")),
  167. stop().
  168. term_to_js_object_fun_test() ->
  169. start(),
  170. {ok, VM} = erlv8_vm:start(),
  171. Global = erlv8_vm:global(VM),
  172. Global:set_value("x",fun (#erlv8_fun_invocation{},[]) -> 123 end),
  173. X = Global:get_value("x"),
  174. XObj = X:object(),
  175. XObj:set_value("y",1),
  176. ?assertMatch({ok, 1}, erlv8_vm:run(VM,"x.y")),
  177. X0 = Global:get_value("x"), X1 = X0:object(),
  178. ?assertMatch(1, X1:get_value("y")),
  179. ?assertMatch({ok, 123}, erlv8_vm:run(VM,"x()")),
  180. stop().
  181. term_to_js_error_test() ->
  182. start(),
  183. {ok, VM} = erlv8_vm:start(),
  184. Global = erlv8_vm:global(VM),
  185. Global:set_value("x",fun (#erlv8_fun_invocation{},[]) -> {throw, {error, "Hello"}} end),
  186. {throw, Exception} = erlv8_vm:run(VM,"x()"),
  187. ?assertEqual(<<"Hello">>, Exception:get_value("message")),
  188. Global:set_value("x",fun (#erlv8_fun_invocation{},[]) -> {throw, "Goodbye"} end),
  189. {throw, <<"Goodbye">>} = erlv8_vm:run(VM,"x()"),
  190. stop().
  191. object_fun_test() ->
  192. start(),
  193. {ok, VM} = erlv8_vm:start(),
  194. {ok, Fun} = erlv8_vm:run(VM,"f = function() {}; f.y = 1; f"),
  195. FunObj = Fun:object(),
  196. ?assertEqual([{<<"y">>,1}],FunObj:proplist()),
  197. stop().
  198. fun_obj_test() ->
  199. start(),
  200. {ok, VM} = erlv8_vm:start(),
  201. F = erlv8_vm:taint(VM, erlv8_fun:new(fun (#erlv8_fun_invocation{},[]) -> 1 end, erlv8_object:new([{"a",1}]))),
  202. FObj = F:object(),
  203. ?assertEqual(1,FObj:get_value("a")),
  204. stop().
  205. invocation_test() ->
  206. start(),
  207. {ok, VM} = erlv8_vm:start(),
  208. Global = erlv8_vm:global(VM),
  209. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[]) -> 123 end),
  210. ?assertEqual({ok, 123}, erlv8_vm:run(VM,"test()")),
  211. stop().
  212. fun_test() ->
  213. start(),
  214. {ok, VM} = erlv8_vm:start(),
  215. Global = erlv8_vm:global(VM),
  216. Global:set_value("test0", fun (#erlv8_fun_invocation{} = _Invocation, [F]) -> F:call([321]) end),
  217. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[Val]) -> Val end),
  218. ?assertEqual({ok, 321}, erlv8_vm:run(VM,"f = function(x) { return test(x) }; test0(f);")),
  219. stop().
  220. erlang_fun_test() ->
  221. start(),
  222. {ok, VM} = erlv8_vm:start(),
  223. Global = erlv8_vm:global(VM),
  224. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[Val]) -> Val end),
  225. T = Global:get_value("test"),
  226. ?assertEqual(321, T:call([321])),
  227. stop().
  228. erlang_fun_call_on_this_test() ->
  229. start(),
  230. {ok, VM} = erlv8_vm:start(),
  231. Global = erlv8_vm:global(VM),
  232. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation, []) -> 321 end),
  233. ?assertEqual(321, (Global:get_value("test")):call(?V8Obj([]))),
  234. stop().
  235. fun_fail_test() ->
  236. start(),
  237. {ok, VM} = erlv8_vm:start(),
  238. Global = erlv8_vm:global(VM),
  239. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[Val]) -> Val end),
  240. ?assertMatch({throw, _},erlv8_vm:run(VM,"test();")),
  241. stop().
  242. fun_fail_inside_badmatch_test() -> %% TODO: cover all standard exits?
  243. start(),
  244. {ok, VM} = erlv8_vm:start(),
  245. Global = erlv8_vm:global(VM),
  246. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[Val]) -> ok = Val end),
  247. ?assertMatch({throw, _}, erlv8_vm:run(VM,"test('help');")),
  248. stop().
  249. fun_vm_is_pid_test() ->
  250. start(),
  251. {ok, VM} = erlv8_vm:start(),
  252. Global = erlv8_vm:global(VM),
  253. Global:set_value("test", fun (#erlv8_fun_invocation{ vm = VM1 } = _Invocation,[]) -> is_pid(VM1) end),
  254. ?assertEqual({ok, true}, erlv8_vm:run(VM,"test();")),
  255. stop().
  256. fun_returning_fun_test() ->
  257. start(),
  258. {ok, VM} = erlv8_vm:start(),
  259. Global = erlv8_vm:global(VM),
  260. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[Val]) -> Val end),
  261. {ok, #erlv8_fun{vm=VM}=F} = erlv8_vm:run(VM,"f = function() {}; test(f);"),
  262. O = F:object(),
  263. ?assertEqual([],O:proplist()),
  264. stop().
  265. fun_new_vm_inside_test() ->
  266. start(),
  267. {ok, VM} = erlv8_vm:start(),
  268. Global = erlv8_vm:global(VM),
  269. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation,[]) -> {ok, _Pid} = erlv8_vm:start(), 321 end),
  270. ?assertEqual({ok, 321},erlv8_vm:run(VM, "test()")),
  271. stop().
  272. fun_this_test() ->
  273. start(),
  274. {ok, VM} = erlv8_vm:start(),
  275. Global = erlv8_vm:global(VM),
  276. Global:set_value("x",fun (#erlv8_fun_invocation{}=I,[]) -> I:this() end),
  277. {ok, Result} = erlv8_vm:run(VM,"x()"),
  278. ?assertEqual(Global:proplist(), Result:proplist()),
  279. stop().
  280. fun_is_construct_call_test() ->
  281. start(),
  282. {ok, VM} = erlv8_vm:start(),
  283. Global = erlv8_vm:global(VM),
  284. Global:set_value("x",fun (#erlv8_fun_invocation{}=I,[]) -> I:is_construct_call() end),
  285. ?assertEqual({ok, false}, erlv8_vm:run(VM,"x()")),
  286. Global:set_value("x",fun (#erlv8_fun_invocation{ this = This }=I,[]) -> This:set_value("icc",I:is_construct_call()) end),
  287. ?assertEqual({ok, true}, erlv8_vm:run(VM,"new x().icc")),
  288. stop().
  289. fun_global_test() ->
  290. start(),
  291. {ok, VM} = erlv8_vm:start(),
  292. Global = erlv8_vm:global(VM),
  293. Global:set_value("x",fun (#erlv8_fun_invocation{}=I,[]) ->
  294. Global = I:global(),
  295. Global:set_value("a",2)
  296. end),
  297. ?assertMatch([{<<"x">>, _}], Global:proplist()),
  298. erlv8_vm:run(VM,"x()"),
  299. ?assertMatch([{<<"x">>, _},{<<"a">>, 2}], Global:proplist()),
  300. stop().
  301. fun_callback_test() ->
  302. start(),
  303. {ok, VM} = erlv8_vm:start(),
  304. Self = self(),
  305. Global = erlv8_vm:global(VM),
  306. Global:set_value("test", fun (#erlv8_fun_invocation{} = _Invocation, [Cb]) ->
  307. spawn(fun () ->
  308. timer:sleep(1000), %% allow ample time
  309. Self ! {ok, Cb:call([1])}
  310. end),
  311. undefined
  312. end),
  313. erlv8_vm:run(VM,"f = function(x) { return x}; test(f);"),
  314. receive
  315. {ok, 1} ->
  316. ok;
  317. Other1 ->
  318. error({bad_result,Other1})
  319. end,
  320. stop().
  321. js_fun_test() ->
  322. start(),
  323. {ok, VM} = erlv8_vm:start(),
  324. Global = erlv8_vm:global(VM),
  325. erlv8_vm:run(VM,"f = function () { return 100; }"),
  326. F = Global:get_value("f"),
  327. ?assertEqual(100,F:call()),
  328. erlv8_vm:run(VM,"f1 = function (x) { return x*100; }"),
  329. F1 = Global:get_value("f1"),
  330. ?assertEqual(200,F1:call([2])),
  331. stop().
  332. js_fun_this_test() ->
  333. start(),
  334. {ok, VM} = erlv8_vm:start(),
  335. Global = erlv8_vm:global(VM),
  336. erlv8_vm:run(VM,"f = function (a) { this.x = a*100; }; y = {}"),
  337. F = Global:get_value("f"),
  338. Y = Global:get_value("y"),
  339. F:call(Y,[1]),
  340. ?assertEqual(100, Y:get_value("x")),
  341. Y:call(F,[2]), % test another API
  342. ?assertEqual(200, Y:get_value("x")),
  343. stop().
  344. to_string_test() ->
  345. start(),
  346. {ok, VM} = erlv8_vm:start(),
  347. ?assertEqual(<<"1">>,erlv8_vm:to_string(VM,1)),
  348. ?assertEqual(<<"1">>,erlv8_vm:to_string(VM,"1")),
  349. ?assertEqual(<<"true">>,erlv8_vm:to_string(VM,true)),
  350. ?assertEqual(<<"[object Object]">>,erlv8_vm:to_string(VM,?V8Obj([{a,1}]))),
  351. stop().
  352. to_detail_string_test() ->
  353. start(),
  354. {ok, VM} = erlv8_vm:start(),
  355. ?assertEqual(<<"1">>,erlv8_vm:to_detail_string(VM,1)),
  356. ?assertEqual(<<"1">>,erlv8_vm:to_detail_string(VM,"1")),
  357. ?assertEqual(<<"true">>,erlv8_vm:to_detail_string(VM,true)),
  358. ?assertEqual(<<"#<Object>">>,erlv8_vm:to_detail_string(VM,?V8Obj([{a,1}]))),
  359. stop().
  360. proto_test() ->
  361. start(),
  362. {ok, VM} = erlv8_vm:start(),
  363. Global = erlv8_vm:global(VM),
  364. Global:set_value("proto",erlv8_object:new([{"x",1}])),
  365. Global:set_value("obj",erlv8_object:new([{"y",1}])),
  366. Proto = Global:get_value("proto"),
  367. Obj = Global:get_value("obj"),
  368. ?assertEqual(true, Obj:set_prototype(Proto)),
  369. ObjProto = Obj:get_prototype(),
  370. ?assertEqual(Proto:proplist(),ObjProto:proplist()),
  371. ?assertEqual({ok, 1},erlv8_vm:run(VM,"obj.x")),
  372. stop().
  373. hidden_value_test() ->
  374. start(),
  375. {ok, VM} = erlv8_vm:start(),
  376. Global = erlv8_vm:global(VM),
  377. Global:set_hidden_value("a",1),
  378. ?assertEqual(1,Global:get_hidden_value("a")),
  379. ?assertEqual({ok, undefined}, erlv8_vm:run(VM,"this.a")),
  380. ?assertEqual(undefined, Global:get_hidden_value("shouldntbethere")),
  381. stop().
  382. objects_equality_test() ->
  383. start(),
  384. {ok, VM} = erlv8_vm:start(),
  385. Global = erlv8_vm:global(VM),
  386. Global:set_value("v1",?V8Obj([{"a",1}])),
  387. Global:set_value("v2",?V8Obj([{"a",1}])),
  388. V1 = Global:get_value("v1"),
  389. V2 = Global:get_value("v2"),
  390. ?assert(V1:equals(V1)),
  391. ?assert(not V1:strict_equals(V2)),
  392. erlv8_vm:run(VM,"f1 = function() { return 1; }; f2 = function() { return 2; };"),
  393. F1 = Global:get_value("f1"),
  394. F2 = Global:get_value("f2"),
  395. ?assert(F1:equals(F1)),
  396. ?assert(not F1:strict_equals(F2)),
  397. stop().
  398. primitives_equality_test() ->
  399. start(),
  400. {ok, VM} = erlv8_vm:start(),
  401. ?assert(erlv8_vm:equals(VM, 1,"1")),
  402. ?assert(erlv8_vm:equals(VM, 1,1)),
  403. ?assert(not erlv8_vm:equals(VM, 1,2)),
  404. ?assert(not erlv8_vm:strict_equals(VM, 1,"1")),
  405. ?assert(erlv8_vm:strict_equals(VM, 1,1)),
  406. ?assert(not erlv8_vm:equals(VM, 1,2)),
  407. stop().
  408. taint_test() ->
  409. start(),
  410. {ok, VM} = erlv8_vm:start(),
  411. ?assertMatch(#erlv8_object{},erlv8_vm:taint(VM, ?V8Obj([{"a",1}]))),
  412. stop().
  413. implicit_taint_for_erlang_only_calls_test() ->
  414. start(),
  415. {ok, VM} = erlv8_vm:start(),
  416. Global = erlv8_vm:global(VM),
  417. Global:set_value("x",fun (#erlv8_fun_invocation{},[#erlv8_object{vm = VM1}]) -> VM1 =/= undefined end),
  418. X = Global:get_value("x"),
  419. ?assert(X:call([?V8Obj([])])),
  420. stop().
  421. fun_extends_object_test() ->
  422. start(),
  423. {ok, VM} = erlv8_vm:start(),
  424. {ok, F} = erlv8_vm:run(VM,"f = function() { return 1; }; f.x = 1; f"),
  425. ?assertEqual(1, F:get_value("x")),
  426. stop().
  427. array_length_test() ->
  428. start(),
  429. {ok, VM} = erlv8_vm:start(),
  430. A = erlv8_vm:taint(VM,?V8Arr([1,2,3])),
  431. ?assertEqual(3,A:length()),
  432. stop().
  433. array_subscript_test() ->
  434. start(),
  435. {ok, VM} = erlv8_vm:start(),
  436. A = erlv8_vm:taint(VM,?V8Arr([1,2,"a"])),
  437. ?assertEqual(<<"a">>,A:get_value(2)),
  438. A:set_value(1,"b"),
  439. ?assertEqual(<<"b">>,A:get_value(1)),
  440. stop().
  441. array_push_test() ->
  442. start(),
  443. {ok, VM} = erlv8_vm:start(),
  444. A = erlv8_vm:taint(VM,?V8Arr([1,2,3])),
  445. A:push(4),
  446. ?assertEqual([1,2,3,4],A:list()),
  447. stop().
  448. array_unshift_test() ->
  449. start(),
  450. {ok, VM} = erlv8_vm:start(),
  451. A = erlv8_vm:taint(VM,?V8Arr([1,2,3])),
  452. A:unshift(4),
  453. ?assertEqual([4,1,2,3],A:list()),
  454. stop().
  455. object_deletion_test() ->
  456. start(),
  457. {ok, VM} = erlv8_vm:start(),
  458. O = erlv8_vm:taint(VM,?V8Obj([{"a",1},{"b", 2}])),
  459. O:delete("a"),
  460. ?assertEqual(undefined, O:get_value("a")),
  461. stop().
  462. array_deletion_test() ->
  463. start(),
  464. {ok, VM} = erlv8_vm:start(),
  465. A = erlv8_vm:taint(VM,?V8Arr([1,2,3])),
  466. A:delete(0),
  467. ?assertEqual([2,3], A:list()),
  468. stop().
  469. vm_storage_test() ->
  470. start(),
  471. {ok, VM} = erlv8_vm:start(),
  472. erlv8_vm:stor(VM, {my_mod, data}, "Data"),
  473. ?assertEqual("Data",erlv8_vm:retr(VM, {my_mod, data})),
  474. stop().
  475. getter_test() ->
  476. start(),
  477. {ok, VM} = erlv8_vm:start(),
  478. Global = erlv8_vm:global(VM),
  479. true = Global:set_accessor("getter_value", fun (#erlv8_fun_invocation{} = _Invocation, [Prop]) ->
  480. Prop
  481. end),
  482. ?assertEqual(<<"getter_value">>,Global:get_value("getter_value")),
  483. stop().
  484. setter_test() ->
  485. start(),
  486. {ok, VM} = erlv8_vm:start(),
  487. Global = erlv8_vm:global(VM),
  488. true = Global:set_accessor("setter_value", fun (#erlv8_fun_invocation{ this = This } = _Invocation, [_Prop]) ->
  489. This:get_value("val")
  490. end,
  491. fun (#erlv8_fun_invocation{ this = This } = _Invocation, [_Prop, Val]) ->
  492. This:set_value("val",Val)
  493. end, default, dontdelete),
  494. Global:set_value("setter_value", 1),
  495. ?assertEqual(1,Global:get_value("setter_value")),
  496. Global:delete("setter_value"),
  497. ?assertEqual(1,Global:get_value("setter_value")),
  498. stop().
  499. run_new_ctx_test() ->
  500. start(),
  501. {ok, VM} = erlv8_vm:start(),
  502. Global = erlv8_vm:global(VM),
  503. Global:set_value("x",1),
  504. NewCtx = erlv8_context:new(VM),
  505. NewGlobal = erlv8_context:global(NewCtx),
  506. erlv8_vm:run(VM,NewCtx,"x={a:1}"),
  507. T = NewGlobal:get_value("x"),
  508. ?assertEqual(1,T:get_value("a")),
  509. stop().
  510. run_multi_ctx_test() ->
  511. start(),
  512. {ok, VM} = erlv8_vm:start(),
  513. Global = erlv8_vm:global(VM),
  514. Global:set_value("x",1),
  515. NewCtx = erlv8_context:new(VM),
  516. NewCtx1 = erlv8_context:new(VM),
  517. erlv8_vm:run(VM,NewCtx,"x={a:1}"),
  518. NewGlobal1 = erlv8_context:global(NewCtx1),
  519. ?assertEqual(undefined,NewGlobal1:get_value("x")),
  520. stop().
  521. ctx_fun_invocation_test() ->
  522. start(),
  523. {ok, VM} = erlv8_vm:start(),
  524. Global = erlv8_vm:global(VM),
  525. NewCtx = erlv8_context:new(VM),
  526. NewGlobal = erlv8_context:global(NewCtx),
  527. NewGlobal:set_value("f",fun (#erlv8_fun_invocation{}=I,[]) -> G= I:global(), G:set_value("x",1) end),
  528. erlv8_vm:run(VM,NewCtx,"f()"),
  529. ?assertEqual(1,NewGlobal:get_value("x")),
  530. ?assertEqual(undefined,Global:get_value("x")),
  531. stop().
  532. fun_call_exception_test() ->
  533. start(),
  534. {ok, VM} = erlv8_vm:start(),
  535. Global = erlv8_vm:global(VM),
  536. erlv8_vm:run(VM,"f = function () { throw('exc'); }"),
  537. F = Global:get_value("f"),
  538. ?assertEqual({throw, {error, <<"exc">>}}, F:call()),
  539. stop().
  540. js_parallel_fun_call_test_() ->
  541. {timeout, 10,
  542. fun () ->
  543. start(),
  544. {ok, VM} = erlv8_vm:start(),
  545. Global = erlv8_vm:global(VM),
  546. erlv8_vm:run(VM,"f = function (x) { return x }"),
  547. F = Global:get_value("f"),
  548. Self = self(),
  549. lists:map(fun (N) ->
  550. spawn(fun () -> X = F:call([N]), Self ! X end)
  551. end, lists:seq(1,2)),
  552. ?assertEqual(lists:seq(1,2),lists:usort(parallel_call_test_loop(2,[]))),
  553. stop()
  554. end}.
  555. erl_parallel_fun_call_test_() ->
  556. {timeout, 10,
  557. fun () ->
  558. start(),
  559. {ok, VM} = erlv8_vm:start(),
  560. Global = erlv8_vm:global(VM),
  561. Global:set_value("f",fun (#erlv8_fun_invocation{},[N]) -> N end),
  562. F = Global:get_value("f"),
  563. Self = self(),
  564. lists:map(fun (N) ->
  565. spawn(fun () -> X = F:call([N]), Self ! X end)
  566. end, lists:seq(1,2)),
  567. ?assertEqual(lists:seq(1,2),lists:usort(parallel_call_test_loop(2,[]))),
  568. stop()
  569. end}.
  570. parallel_call_test_loop(T,L) when length(L) == T ->
  571. L;
  572. parallel_call_test_loop(T,L) ->
  573. receive
  574. N when is_integer(N) ->
  575. parallel_call_test_loop(T,[N|L]);
  576. Other ->
  577. error({bad_result, Other})
  578. end.
  579. property_attribute_test() ->
  580. start(),
  581. {ok, VM} = erlv8_vm:start(),
  582. Global = erlv8_vm:global(VM),
  583. Global:set_value("a",1,dontdelete),
  584. Global:set_value("b",1,readonly),
  585. Global:set_value("c",1,[dontdelete,readonly]),
  586. Global:delete("a"),
  587. Global:set_value("b",2),
  588. ?assertEqual(1,Global:get_value("a")),
  589. ?assertEqual(1,Global:get_value("b")),
  590. ?assertEqual(1,Global:get_value("c")),
  591. Global:delete("c"),
  592. ?assertEqual(1,Global:get_value("c")),
  593. stop().
  594. instantiate_js_test() ->
  595. start(),
  596. {ok, VM} = erlv8_vm:start(),
  597. {ok, F} = erlv8_vm:run(VM,"f = function(y) { this.x = y}"),
  598. O = F:instantiate([1]),
  599. ?assertEqual(1,O:get_value("x")),
  600. stop().
  601. instantiate_erl_test() ->
  602. start(),
  603. {ok, VM} = erlv8_vm:start(),
  604. Global = erlv8_vm:global(VM),
  605. Global:set_value("f",fun (#erlv8_fun_invocation{ this = This },[Y]) -> This:set_value("x",Y) end),
  606. F = Global:get_value("f"),
  607. O = F:instantiate([1]),
  608. ?assertEqual(1,O:get_value("x")),
  609. stop().
  610. instantiate_erl_from_js_test() ->
  611. start(),
  612. {ok, VM} = erlv8_vm:start(),
  613. Global = erlv8_vm:global(VM),
  614. Global:set_value("f",fun (#erlv8_fun_invocation{ this = This },[Y]) -> This:set_value("x",Y) end),
  615. ?assertEqual({ok, 1}, erlv8_vm:run(VM,"new f(1).x")),
  616. stop().
  617. throwing_object_as_an_error_test() ->
  618. start(),
  619. {ok, VM} = erlv8_vm:start(),
  620. Global = erlv8_vm:global(VM),
  621. Global:set_value("f",fun (#erlv8_fun_invocation{},[]) -> {throw, ?V8Obj([{"a",1}])} end),
  622. {throw, E} = erlv8_vm:run(VM,"f()"),
  623. ?assertEqual(1,E:get_value("a")),
  624. stop().
  625. v8_return_value_test() ->
  626. start(),
  627. {ok, VM} = erlv8_vm:start(),
  628. Global = erlv8_vm:global(VM),
  629. Global:set_value("f",fun (#erlv8_fun_invocation{},[X]) -> X end),
  630. F = Global:get_value("f"),
  631. O = erlv8_vm:taint(VM, ?V8Obj([{"a",1}])),
  632. O1 = F:call([O]),
  633. ?assert(O:equals(O1)),
  634. stop().
  635. clear_env_lockup_regression_test() ->
  636. start(),
  637. {ok, VM} = erlv8_vm:start(),
  638. Global = erlv8_vm:global(VM),
  639. Global:set_value("f",fun (#erlv8_fun_invocation{},[X]) -> X end),
  640. Global:set_value("f1",fun (#erlv8_fun_invocation{},[F]) -> F:call([1]) end),
  641. ?assertEqual({ok, 1}, erlv8_vm:run(VM, "f1(f)")),
  642. stop().
  643. extern_proto_test() ->
  644. start(),
  645. {ok, VM} = erlv8_vm:start(),
  646. Global = erlv8_vm:global(VM),
  647. lists:foreach(fun({Type, Val}) ->
  648. Proto = erlv8_extern:get_proto(VM, Type),
  649. Proto:set_value("toString", fun(#erlv8_fun_invocation{},[]) -> Type end),
  650. Global:set_value("val", Val),
  651. ?assertEqual({ok, atom_to_binary(Type, utf8)}, erlv8_vm:run(VM, "val.toString()"))
  652. end, [{ref, make_ref()},
  653. {pid, self()}]),
  654. stop().
  655. externalize_proto_test() ->
  656. start(),
  657. {ok, VM} = erlv8_vm:start(),
  658. Global = erlv8_vm:global(VM),
  659. Self = self(),
  660. spawn(fun () -> Self ! open_port({spawn, "ls"},[stream]) end),
  661. Port = receive
  662. P -> P
  663. end,
  664. lists:foreach(fun(Val) ->
  665. Global:set_value("val", erlv8_extern:extern(VM, Val)),
  666. ?assertEqual(Val, Global:get_value("val"))
  667. end, [1,
  668. atom,
  669. <<>>,
  670. make_ref(),
  671. fun() -> ok end,
  672. Port,
  673. self(),
  674. {1,2,3, self()},
  675. [1,2,{3,2,1}]]),
  676. stop().
  677. internal_field_test() ->
  678. start(),
  679. {ok, VM} = erlv8_vm:start(),
  680. Global = erlv8_vm:global(VM),
  681. ?assertEqual(0,Global:internal_field_count()),
  682. ?assertEqual(error, Global:get_internal_field(-1)),
  683. ?assertEqual(error, Global:get_internal_field(0)),
  684. ?assertEqual(error, Global:set_internal_field(0, 1)),
  685. %% TODO: Externals don't have internal fields anymore, find another way to test this:
  686. %% Extern = erlv8_extern:extern(VM, atom),
  687. %% ?assertEqual(1,Extern:internal_field_count()),
  688. %% ?assertEqual(error, Global:get_internal_field(1)),
  689. %% ?assertEqual(error, Global:set_internal_field(1, 1)),
  690. %% ?assertEqual(atom, Extern:get_internal_field(0)),
  691. %% Extern:set_internal_field(0,yes),
  692. %% ?assertEqual("yes", Extern:get_internal_field(0)),
  693. %% Extern:set_internal_field(0,erlv8_extern:extern(VM, yes)),
  694. %% ?assertEqual(yes, Extern:get_internal_field(0)),
  695. %% Extern:set_internal_field(0,{extern, yes}),
  696. %% ?assertEqual(yes, Extern:get_internal_field(0)),
  697. stop().
  698. nested_result_tick_regression_test() ->
  699. start(),
  700. {ok, VM} = erlv8_vm:start(),
  701. Global = erlv8_vm:global(VM),
  702. Global:set_value("f1",fun (#erlv8_fun_invocation{},[]) -> register(erlv8_test_f1, self()), receive X -> X end end),
  703. Global:set_value("f2",fun (#erlv8_fun_invocation{},[]) -> register(erlv8_test_f2, self()), receive X -> X end end),
  704. Self = self(),
  705. spawn(fun () ->
  706. Self ! {f1, erlv8_vm:run(VM, "f1()")}
  707. end),
  708. spawn(fun () ->
  709. Self ! {f2, erlv8_vm:run(VM, "f2()")}
  710. end),
  711. timer:sleep(200), %% give them some time to start (I know, I know)
  712. %% so now the ticker should be in f2
  713. %% but we'll return value for f1
  714. erlv8_test_f1 ! 1,
  715. %% and only then for f2
  716. erlv8_test_f2 ! 2,
  717. nested_result_tick_regression_test_loop([]),
  718. stop().
  719. nested_result_tick_regression_test_loop([f1,f2]) ->
  720. ok;
  721. nested_result_tick_regression_test_loop([f2,f1]) ->
  722. ok;
  723. nested_result_tick_regression_test_loop(L) ->
  724. receive
  725. {f1, Result} ->
  726. ?assertEqual({ok, 1}, Result),
  727. nested_result_tick_regression_test_loop([f1|L]);
  728. {f2, Result} ->
  729. ?assertEqual({ok, 2}, Result),
  730. nested_result_tick_regression_test_loop([f2|L])
  731. end.
  732. -endif.