PageRenderTime 91ms CodeModel.GetById 15ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 0ms

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