2019-11-10 20:20:26 -05:00
# frozen_string_literal: true
2017-03-09 18:15:57 -05:00
require 'securerandom'
require 'date'
2016-05-04 02:54:51 -04:00
require 'test_helper'
class MiniRacerTest < Minitest :: Test
2016-06-27 20:51:00 -04:00
# see `test_platform_set_flags_works` below
MiniRacer :: Platform . set_flags! :use_strict
2016-05-10 03:25:42 -04:00
2016-10-09 17:43:18 -04:00
def test_segfault
skip " running this test is very slow "
# 5000.times do
# GC.start
# context = MiniRacer::Context.new(timeout: 5)
# context.attach("echo", proc{|msg| msg.to_sym.to_s})
# assert_raises(MiniRacer::EvalError) do
# context.eval("while(true) echo('foo');")
# end
# end
end
2016-05-04 02:54:51 -04:00
def test_that_it_has_a_version_number
refute_nil :: MiniRacer :: VERSION
end
2016-05-11 05:35:46 -04:00
def test_types
2016-05-04 02:54:51 -04:00
context = MiniRacer :: Context . new
2016-05-11 05:35:46 -04:00
assert_equal 2 , context . eval ( '2' )
assert_equal " two " , context . eval ( '"two"' )
assert_equal 2 . 1 , context . eval ( '2.1' )
assert_equal true , context . eval ( 'true' )
assert_equal false , context . eval ( 'false' )
2017-08-24 17:48:11 -04:00
assert_nil context . eval ( 'null' )
assert_nil context . eval ( 'undefined' )
2016-05-04 02:54:51 -04:00
end
2018-03-12 12:22:14 -04:00
def test_compile_nil_context
context = MiniRacer :: Context . new
assert_raises ( ArgumentError ) do
assert_equal 2 , context . eval ( nil )
end
end
2016-05-11 05:35:46 -04:00
def test_array
2016-05-04 02:54:51 -04:00
context = MiniRacer :: Context . new
2016-05-11 05:35:46 -04:00
assert_equal [ 1 , " two " ] , context . eval ( '[1,"two"]' )
2016-05-04 02:54:51 -04:00
end
2016-05-11 19:38:47 -04:00
def test_object
context = MiniRacer :: Context . new
# remember JavaScript is quirky {"1" : 1} magically turns to {1: 1} cause magic
2017-03-09 16:03:13 -05:00
assert_equal ( { " 1 " = > 2 , " two " = > " two " } , context . eval ( 'var a={"1" : 2, "two" : "two"}; a' ) )
2016-05-11 19:38:47 -04:00
end
2016-05-11 03:02:20 -04:00
def test_it_returns_runtime_error
2016-05-04 02:54:51 -04:00
context = MiniRacer :: Context . new
2016-05-11 03:02:20 -04:00
exp = nil
begin
context . eval ( 'var foo=function(){boom;}; foo()' )
rescue = > e
exp = e
2016-05-04 02:54:51 -04:00
end
2016-05-11 03:02:20 -04:00
2016-05-11 20:14:33 -04:00
assert_equal MiniRacer :: RuntimeError , exp . class
2016-05-11 03:02:20 -04:00
assert_match ( / boom / , exp . message )
assert_match ( / foo / , exp . backtrace [ 0 ] )
assert_match ( / mini_racer / , exp . backtrace [ 2 ] )
2016-05-10 03:25:42 -04:00
# context should not be dead
assert_equal 2 , context . eval ( '1+1' )
2016-05-04 02:54:51 -04:00
end
2016-05-05 23:14:37 -04:00
def test_it_can_stop
context = MiniRacer :: Context . new
2016-05-11 03:02:20 -04:00
exp = nil
begin
2016-05-05 23:14:37 -04:00
Thread . new do
sleep 0 . 001
context . stop
end
context . eval ( 'while(true){}' )
2016-05-11 03:02:20 -04:00
rescue = > e
exp = e
2016-05-05 23:14:37 -04:00
end
2016-05-11 03:02:20 -04:00
2016-05-11 20:14:33 -04:00
assert_equal MiniRacer :: ScriptTerminatedError , exp . class
2016-05-11 03:02:20 -04:00
assert_match ( / terminated / , exp . message )
2016-05-05 23:14:37 -04:00
end
2017-03-09 16:58:46 -05:00
def test_it_can_timeout_during_serialization
context = MiniRacer :: Context . new ( timeout : 500 )
assert_raises ( MiniRacer :: ScriptTerminatedError ) do
context . eval 'var a = {get a(){ while(true); }}; a'
end
end
2016-05-06 03:08:06 -04:00
def test_it_can_automatically_time_out_context
# 2 millisecs is a very short timeout but we don't want test running forever
context = MiniRacer :: Context . new ( timeout : 2 )
assert_raises do
context . eval ( 'while(true){}' )
end
end
2016-05-11 20:59:18 -04:00
def test_returns_javascript_function
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
assert_same MiniRacer :: JavaScriptFunction , context . eval ( " var a = function(){}; a " ) . class
2016-05-11 20:59:18 -04:00
end
2016-05-05 23:14:37 -04:00
def test_it_handles_malformed_js
context = MiniRacer :: Context . new
2016-05-11 20:14:33 -04:00
assert_raises MiniRacer :: ParseError do
2016-05-05 23:14:37 -04:00
context . eval ( 'I am not JavaScript {' )
end
end
2016-05-25 21:30:03 -04:00
def test_it_handles_malformed_js_with_backtrace
context = MiniRacer :: Context . new
assert_raises MiniRacer :: ParseError do
begin
context . eval ( " var i; \n i=2; \n I am not JavaScript { " )
rescue = > e
# I <parse error> am not
assert_match ( / 3:2 / , e . message )
raise
end
end
end
2016-05-04 02:54:51 -04:00
def test_it_remembers_stuff_in_context
context = MiniRacer :: Context . new
context . eval ( 'var x = function(){return 22;}' )
assert_equal 22 , context . eval ( 'x()' )
end
2016-05-08 06:59:10 -04:00
def test_can_attach_functions
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval 'var adder'
2016-05-08 06:59:10 -04:00
context . attach ( " adder " , proc { | a , b | a + b } )
assert_equal 3 , context . eval ( 'adder(1,2)' )
end
2016-05-10 03:35:30 -04:00
def test_es6_arrow_functions
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
assert_equal 42 , context . eval ( 'var adder=(x,y)=>x+y; adder(21,21);' )
2016-05-10 03:35:30 -04:00
end
2016-05-10 22:26:52 -04:00
def test_concurrent_access
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval ( 'var counter=0; var plus=()=>counter++;' )
2016-05-10 04:06:40 -04:00
2016-05-10 22:26:52 -04:00
( 1 .. 10 ) . map do
Thread . new {
context . eval ( " plus() " )
}
end . each ( & :join )
assert_equal 10 , context . eval ( " counter " )
end
2016-05-11 03:58:33 -04:00
class FooError < StandardError
def initialize ( message )
super ( message )
end
end
2016-05-10 22:26:52 -04:00
def test_attached_exceptions
2016-05-10 04:06:40 -04:00
context = MiniRacer :: Context . new
2016-05-11 03:58:33 -04:00
context . attach ( " adder " , proc { raise FooError , " I like foos " } )
2016-05-10 04:06:40 -04:00
assert_raises do
2016-05-11 03:58:33 -04:00
begin
raise FooError , " I like foos "
context . eval ( 'adder()' )
rescue = > e
assert_equal FooError , e . class
assert_match ( / I like foos / , e . message )
# TODO backtrace splicing so js frames are injected
raise
end
2016-05-10 04:06:40 -04:00
end
end
2016-05-16 21:34:24 -04:00
def test_attached_on_object
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval 'var minion'
2016-05-16 21:34:24 -04:00
context . attach ( " minion.speak " , proc { " banana " } )
assert_equal " banana " , context . eval ( " minion.speak() " )
end
def test_attached_on_nested_object
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval 'var minion'
2016-05-16 21:34:24 -04:00
context . attach ( " minion.kevin.speak " , proc { " banana " } )
assert_equal " banana " , context . eval ( " minion.kevin.speak() " )
end
2016-05-19 02:17:20 -04:00
def test_return_arrays
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval 'var nose'
2016-05-19 02:17:20 -04:00
context . attach ( " nose.type " , proc { [ " banana " , [ " nose " ] ] } )
assert_equal [ " banana " , [ " nose " ] ] , context . eval ( " nose.type() " )
end
def test_return_hash
context = MiniRacer :: Context . new
context . attach ( " test " , proc { { banana : :nose , " inner " = > { 42 = > 42 } } } )
2017-03-09 16:03:13 -05:00
assert_equal ( { " banana " = > " nose " , " inner " = > { " 42 " = > 42 } } , context . eval ( " test() " ) )
2016-05-19 02:17:20 -04:00
end
2016-05-25 11:26:35 -04:00
def test_return_date
context = MiniRacer :: Context . new
test_time = Time . new
2016-05-25 22:22:42 -04:00
test_datetime = test_time . to_datetime
2016-05-25 15:10:10 -04:00
context . attach ( " test " , proc { test_time } )
2016-05-25 22:22:42 -04:00
context . attach ( " test_datetime " , proc { test_datetime } )
2016-06-21 21:09:41 -04:00
2016-05-25 14:45:07 -04:00
# check that marshalling to JS creates a date object (getTime())
2016-05-25 15:10:10 -04:00
assert_equal ( ( test_time . to_f * 1000 ) . to_i , context . eval ( " var result = test(); result.getTime(); " ) . to_i )
2016-06-21 21:09:41 -04:00
2016-05-25 14:45:07 -04:00
# check that marshalling to RB creates a Time object
2016-05-25 15:10:10 -04:00
result = context . eval ( " test() " )
assert_equal ( test_time . class , result . class )
2016-05-25 16:30:32 -04:00
assert_equal ( test_time . tv_sec , result . tv_sec )
2016-06-21 21:09:41 -04:00
2016-05-25 16:30:32 -04:00
# check that no precision is lost in the marshalling (js only stores milliseconds)
assert_equal ( ( test_time . tv_usec / 1000 . 0 ) . floor , ( result . tv_usec / 1000 . 0 ) . floor )
2016-06-21 21:09:41 -04:00
2016-05-25 22:22:42 -04:00
# check that DateTime gets marshalled to js date and back out as rb Time
result = context . eval ( " test_datetime() " )
assert_equal ( test_time . class , result . class )
assert_equal ( test_time . tv_sec , result . tv_sec )
assert_equal ( ( test_time . tv_usec / 1000 . 0 ) . floor , ( result . tv_usec / 1000 . 0 ) . floor )
2016-05-25 15:10:10 -04:00
end
2016-05-30 12:11:35 -04:00
def test_datetime_missing
2016-06-29 19:20:41 -04:00
date_time_backup = Object . send ( :remove_const , :DateTime )
2016-06-21 21:09:41 -04:00
2016-06-29 19:20:41 -04:00
begin
# no exceptions should happen here, and non-datetime classes should marshall correctly still.
context = MiniRacer :: Context . new
test_time = Time . new
context . attach ( " test " , proc { test_time } )
assert_equal ( ( test_time . to_f * 1000 ) . to_i , context . eval ( " var result = test(); result.getTime(); " ) . to_i )
result = context . eval ( " test() " )
assert_equal ( test_time . class , result . class )
assert_equal ( test_time . tv_sec , result . tv_sec )
assert_equal ( ( test_time . tv_usec / 1000 . 0 ) . floor , ( result . tv_usec / 1000 . 0 ) . floor )
ensure
Object . const_set ( :DateTime , date_time_backup )
end
2016-05-25 15:10:10 -04:00
end
2016-06-21 21:09:41 -04:00
2016-05-25 20:36:12 -04:00
def test_return_large_number
context = MiniRacer :: Context . new
test_num = 1_000_000_000_000_000
context . attach ( " test " , proc { test_num } )
2016-06-21 21:09:41 -04:00
2016-05-25 20:36:12 -04:00
assert_equal ( true , context . eval ( " test() === 1000000000000000 " ) )
assert_equal ( test_num , context . eval ( " test() " ) )
end
2016-06-21 21:09:41 -04:00
2016-05-27 12:50:50 -04:00
def test_return_int_max
context = MiniRacer :: Context . new
test_num = 2 ** ( 31 ) - 1 #last int32 number
context . attach ( " test " , proc { test_num } )
2016-06-21 21:09:41 -04:00
2016-05-27 12:50:50 -04:00
assert_equal ( true , context . eval ( " test() === 2147483647 " ) )
assert_equal ( test_num , context . eval ( " test() " ) )
end
2016-05-25 15:10:10 -04:00
def test_return_unknown
context = MiniRacer :: Context . new
2016-05-25 22:46:23 -04:00
test_unknown = Date . new # hits T_DATA in convert_ruby_to_v8
2016-06-04 14:07:08 -04:00
context . attach ( " test " , proc { test_unknown } )
assert_equal ( " Undefined Conversion " , context . eval ( " test() " ) )
2016-06-21 21:09:41 -04:00
2016-06-04 14:07:08 -04:00
# clean up and start up a new context
context = nil
GC . start
2016-06-21 21:09:41 -04:00
2016-06-04 14:07:08 -04:00
context = MiniRacer :: Context . new
test_unknown = Date . new # hits T_DATA in convert_ruby_to_v8
2016-05-25 15:10:10 -04:00
context . attach ( " test " , proc { test_unknown } )
assert_equal ( " Undefined Conversion " , context . eval ( " test() " ) )
2016-05-25 11:26:35 -04:00
end
2017-09-26 12:46:45 -04:00
def test_max_memory
context = MiniRacer :: Context . new ( max_memory : 200_000_000 )
2017-08-01 10:33:29 -04:00
2017-09-26 12:46:45 -04:00
assert_raises ( MiniRacer :: V8OutOfMemoryError ) { context . eval ( 'let s = 1000; var a = new Array(s); a.fill(0); while(true) {s *= 1.1; let n = new Array(Math.floor(s)); n.fill(0); a = a.concat(n); };' ) }
end
2020-04-21 03:17:46 -04:00
def test_max_memory_for_call
context = MiniRacer :: Context . new ( max_memory : 200_000_000 )
context . eval ( << ~ JS )
let s ;
function memory_test ( ) {
var a = new Array ( s ) ;
a . fill ( 0 ) ;
while ( true ) {
s *= 1 . 1 ;
let n = new Array ( Math . floor ( s ) ) ;
n . fill ( 0 ) ;
a = a . concat ( n ) ;
if ( s > 1000000 ) {
return ;
}
}
}
function set_s ( val ) {
s = val ;
}
JS
context . call ( 'set_s' , 1000 )
assert_raises ( MiniRacer :: V8OutOfMemoryError ) { context . call ( 'memory_test' ) }
s = context . eval ( 's' )
assert_operator ( s , :> , 100_000 )
end
2017-09-26 12:46:45 -04:00
def test_negative_max_memory
context = MiniRacer :: Context . new ( max_memory : - 200_000_000 )
assert_nil ( context . instance_variable_get ( :@max_memory ) )
2017-08-01 10:33:29 -04:00
end
2016-05-19 02:17:20 -04:00
module Echo
def self . say ( thing )
thing
end
end
def test_can_attach_method
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval 'var Echo'
2016-05-19 02:17:20 -04:00
context . attach ( " Echo.say " , Echo . method ( :say ) )
assert_equal " hello " , context . eval ( " Echo.say('hello') " )
end
2016-05-18 23:11:39 -04:00
def test_attach_error
context = MiniRacer :: Context . new
2016-06-27 20:51:00 -04:00
context . eval ( " var minion = 2 " )
2016-05-18 23:11:39 -04:00
assert_raises do
begin
context . attach ( " minion.kevin.speak " , proc { " banana " } )
rescue = > e
assert_equal MiniRacer :: ParseError , e . class
assert_match ( / expecting minion.kevin / , e . message )
raise
end
end
end
2016-05-16 20:47:21 -04:00
def test_load
context = MiniRacer :: Context . new
context . load ( File . dirname ( __FILE__ ) + " /file.js " )
assert_equal " world " , context . eval ( " hello " )
assert_raises do
context . load ( File . dirname ( __FILE__ ) + " /missing.js " )
end
end
2016-06-21 15:07:36 -04:00
def test_contexts_can_be_safely_GCed
context = MiniRacer :: Context . new
context . eval 'var hello = "world";'
context = nil
GC . start
end
2016-06-16 18:23:28 -04:00
def test_it_can_use_snapshots
snapshot = MiniRacer :: Snapshot . new ( 'function hello() { return "world"; }; var foo = "bar";' )
context = MiniRacer :: Context . new ( snapshot : snapshot )
assert_equal " world " , context . eval ( " hello() " )
assert_equal " bar " , context . eval ( " foo " )
end
def test_snapshot_size
snapshot = MiniRacer :: Snapshot . new ( 'var foo = "bar";' )
# for some reason sizes seem to change across runs, so we just
# check it's a positive integer
assert ( snapshot . size > 0 )
end
2018-08-22 14:39:50 -04:00
def test_snapshot_dump
snapshot = MiniRacer :: Snapshot . new ( 'var foo = "bar";' )
dump = snapshot . dump
assert_equal ( String , dump . class )
assert_equal ( Encoding :: ASCII_8BIT , dump . encoding )
assert_equal ( snapshot . size , dump . length )
end
2016-06-16 18:23:28 -04:00
def test_invalid_snapshots_throw_an_exception
2018-10-15 05:09:01 -04:00
begin
2016-06-16 18:23:28 -04:00
MiniRacer :: Snapshot . new ( 'var foo = bar;' )
2018-10-15 05:09:01 -04:00
rescue MiniRacer :: SnapshotError = > e
assert ( e . backtrace [ 0 ] . include? 'JavaScript' )
got_error = true
2016-06-16 18:23:28 -04:00
end
2018-10-15 05:09:01 -04:00
assert ( got_error , " should raise " )
2016-06-16 18:23:28 -04:00
end
2016-06-17 12:29:08 -04:00
def test_an_empty_snapshot_is_valid
MiniRacer :: Snapshot . new ( '' )
MiniRacer :: Snapshot . new
2016-06-21 15:07:36 -04:00
GC . start
2016-06-17 12:29:08 -04:00
end
def test_snapshots_can_be_warmed_up_with_no_side_effects
# shamelessly insipired by https://github.com/v8/v8/blob/5.3.254/test/cctest/test-serialize.cc#L792-L854
snapshot_source = <<-JS
function f ( ) { return Math . sin ( 1 ) ; }
var a = 5 ;
JS
snapshot = MiniRacer :: Snapshot . new ( snapshot_source )
2018-05-09 13:23:02 -04:00
warmup_source = <<-JS
2016-06-17 12:29:08 -04:00
Math . tan ( 1 ) ;
var a = f ( ) ;
Math . sin = 1 ;
JS
2018-05-09 13:23:02 -04:00
warmed_up_snapshot = snapshot . warmup! ( warmup_source )
2016-06-17 12:29:08 -04:00
context = MiniRacer :: Context . new ( snapshot : snapshot )
assert_equal 5 , context . eval ( " a " )
assert_equal " function " , context . eval ( " typeof(Math.sin) " )
2016-06-21 15:07:36 -04:00
assert_same snapshot , warmed_up_snapshot
2016-06-17 12:29:08 -04:00
end
def test_invalid_warmup_sources_throw_an_exception
assert_raises ( MiniRacer :: SnapshotError ) do
2016-06-21 15:07:36 -04:00
MiniRacer :: Snapshot . new ( 'Math.sin = 1;' ) . warmup! ( 'var a = Math.sin(1);' )
2016-06-17 12:29:08 -04:00
end
end
2018-03-12 12:22:14 -04:00
def test_invalid_warmup_sources_throw_an_exception
assert_raises ( ArgumentError ) do
MiniRacer :: Snapshot . new ( 'function f() { return 1 }' ) . warmup! ( [ ] )
end
end
2016-06-17 12:29:08 -04:00
def test_warming_up_with_invalid_source_does_not_affect_the_snapshot_internal_state
snapshot = MiniRacer :: Snapshot . new ( 'Math.sin = 1;' )
begin
2016-06-21 15:07:36 -04:00
snapshot . warmup! ( 'var a = Math.sin(1);' )
2016-06-17 12:29:08 -04:00
rescue
# do nothing
end
context = MiniRacer :: Context . new ( snapshot : snapshot )
2016-06-21 15:07:36 -04:00
assert_equal 1 , context . eval ( 'Math.sin' )
end
def test_snapshots_can_be_GCed_without_affecting_contexts_created_from_them
snapshot = MiniRacer :: Snapshot . new ( 'Math.sin = 1;' )
context = MiniRacer :: Context . new ( snapshot : snapshot )
# force the snapshot to be GC'ed
snapshot = nil
GC . start
# the context should still work fine
assert_equal 1 , context . eval ( 'Math.sin' )
end
def test_it_can_re_use_isolates_for_multiple_contexts
snapshot = MiniRacer :: Snapshot . new ( 'Math.sin = 1;' )
isolate = MiniRacer :: Isolate . new ( snapshot )
context1 = MiniRacer :: Context . new ( isolate : isolate )
assert_equal 1 , context1 . eval ( 'Math.sin' )
context1 . eval ( 'var a = 5;' )
context2 = MiniRacer :: Context . new ( isolate : isolate )
assert_equal 1 , context2 . eval ( 'Math.sin' )
assert_raises MiniRacer :: RuntimeError do
begin
context2 . eval ( 'a;' )
rescue = > e
assert_equal ( 'ReferenceError: a is not defined' , e . message )
raise
end
end
2016-06-21 21:09:41 -04:00
assert_same isolate , context1 . isolate
assert_same isolate , context2 . isolate
2016-06-21 15:07:36 -04:00
end
def test_empty_isolate_is_valid_and_can_be_GCed
MiniRacer :: Isolate . new
GC . start
end
def test_isolates_from_snapshot_dont_get_corrupted_if_the_snapshot_gets_warmed_up_or_GCed
# basically tests that isolates get their own copy of the snapshot and don't
# get corrupted if the snapshot is subsequently warmed up
snapshot_source = <<-JS
function f ( ) { return Math . sin ( 1 ) ; }
var a = 5 ;
JS
snapshot = MiniRacer :: Snapshot . new ( snapshot_source )
isolate = MiniRacer :: Isolate . new ( snapshot )
warmump_source = <<-JS
Math . tan ( 1 ) ;
var a = f ( ) ;
Math . sin = 1 ;
JS
snapshot . warmup! ( warmump_source )
context1 = MiniRacer :: Context . new ( isolate : isolate )
assert_equal 5 , context1 . eval ( " a " )
assert_equal " function " , context1 . eval ( " typeof(Math.sin) " )
snapshot = nil
GC . start
context2 = MiniRacer :: Context . new ( isolate : isolate )
assert_equal 5 , context2 . eval ( " a " )
assert_equal " function " , context2 . eval ( " typeof(Math.sin) " )
end
def test_isolate_can_be_notified_of_idle_time
isolate = MiniRacer :: Isolate . new
2018-06-24 20:34:59 -04:00
# returns true if embedder should stop calling
assert ( isolate . idle_notification ( 1000 ) )
2016-06-17 12:29:08 -04:00
end
2016-06-21 21:09:41 -04:00
def test_concurrent_access_over_the_same_isolate_1
isolate = MiniRacer :: Isolate . new
context = MiniRacer :: Context . new ( isolate : isolate )
2016-06-29 11:56:46 -04:00
context . eval ( 'var counter=0; var plus=()=>counter++;' )
2016-06-21 21:09:41 -04:00
( 1 .. 10 ) . map do
Thread . new {
context . eval ( " plus() " )
}
end . each ( & :join )
2016-06-29 11:56:46 -04:00
assert_equal 10 , context . eval ( 'counter' )
2016-06-21 21:09:41 -04:00
end
def test_concurrent_access_over_the_same_isolate_2
isolate = MiniRacer :: Isolate . new
equals_after_sleep = { }
( 1 .. 10 ) . map do | i |
Thread . new {
random = SecureRandom . hex
context = MiniRacer :: Context . new ( isolate : isolate )
context . eval ( 'var now = new Date().getTime(); while(new Date().getTime() < now + 20) {}' )
2016-06-29 11:56:46 -04:00
context . eval ( " var a=' #{ random } ' " )
2016-06-21 21:09:41 -04:00
context . eval ( 'var now = new Date().getTime(); while(new Date().getTime() < now + 20) {}' )
# cruby hashes are thread safe as long as you don't mess with the
# same key in different threads
equals_after_sleep [ i ] = context . eval ( 'a' ) == random
}
end . each ( & :join )
assert_equal 10 , equals_after_sleep . size
assert equals_after_sleep . values . all?
end
2016-06-22 14:32:58 -04:00
2016-06-27 20:51:00 -04:00
def test_platform_set_flags_raises_an_exception_if_already_initialized
2016-06-22 14:32:58 -04:00
# makes sure it's initialized
MiniRacer :: Snapshot . new
assert_raises ( MiniRacer :: PlatformAlreadyInitialized ) do
2016-06-27 20:51:00 -04:00
MiniRacer :: Platform . set_flags! :noconcurrent_recompilation
2016-06-22 14:32:58 -04:00
end
end
2016-06-27 20:51:00 -04:00
def test_platform_set_flags_works
context = MiniRacer :: Context . new
assert_raises ( MiniRacer :: RuntimeError ) do
# should fail because of strict mode set for all these tests
context . eval 'x = 28'
end
end
2016-06-30 22:51:58 -04:00
def test_error_on_return_val
v8 = MiniRacer :: Context . new
assert_raises ( MiniRacer :: RuntimeError ) do
v8 . eval ( 'var o = {}; o.__defineGetter__("bar", function() { return null(); }); o' )
end
end
2016-07-29 01:22:11 -04:00
def test_ruby_based_property_in_rval
2016-07-27 01:39:21 -04:00
v8 = MiniRacer :: Context . new
2016-08-31 23:25:47 -04:00
v8 . attach 'echo' , proc { | x | x }
assert_equal ( { " bar " = > 42 } , v8 . eval ( " var o = {get bar() { return echo(42); }}; o " ) )
2016-07-27 01:39:21 -04:00
end
2016-07-29 01:22:11 -04:00
def test_function_rval
context = MiniRacer :: Context . new
2016-08-31 23:25:47 -04:00
context . attach ( " echo " , proc { | msg | msg } )
assert_equal ( " foo " , context . eval ( " echo('foo') " ) )
2016-07-29 01:22:11 -04:00
end
2016-08-31 21:39:32 -04:00
def test_timeout_in_ruby_land
context = MiniRacer :: Context . new ( timeout : 50 )
context . attach ( 'sleep' , proc { sleep 0 . 1 } )
assert_raises ( MiniRacer :: ScriptTerminatedError ) do
context . eval ( 'sleep(); "hi";' )
end
2016-08-31 23:25:47 -04:00
end
def test_undef_mem
context = MiniRacer :: Context . new ( timeout : 5 )
context . attach ( " marsh " , proc do | a , b , c |
return [ a , b , c ] if a . is_a? ( MiniRacer :: FailedV8Conversion ) || b . is_a? ( MiniRacer :: FailedV8Conversion ) || c . is_a? ( MiniRacer :: FailedV8Conversion )
a [ rand ( 10000 ) . to_s ] = " a "
b [ rand ( 10000 ) . to_s ] = " b "
c [ rand ( 10000 ) . to_s ] = " c "
[ a , b , c ]
end )
assert_raises do
# TODO make it raise the correct exception!
context . eval ( " var a = [{},{},{}]; while(true) { a = marsh(a[0],a[1],a[2]); } " )
end
2016-08-31 21:39:32 -04:00
end
2016-06-27 20:51:00 -04:00
class TestPlatform < MiniRacer :: Platform
def self . public_flags_to_strings ( flags )
flags_to_strings ( flags )
end
end
def test_platform_flags_to_strings
flags = [
:flag1 ,
[ [ [ :flag2 ] ] ] ,
{ key1 : :value1 } ,
{ key2 : 42 ,
key3 : 8 . 7 } ,
'--i_already_have_leading_hyphens' ,
[ :'--me_too' ,
'i_dont' ]
]
expected_string_flags = [
'--flag1' ,
'--flag2' ,
'--key1 value1' ,
'--key2 42' ,
'--key3 8.7' ,
'--i_already_have_leading_hyphens' ,
'--me_too' ,
'--i_dont'
]
assert_equal expected_string_flags , TestPlatform . public_flags_to_strings ( flags )
end
2017-07-13 17:43:43 -04:00
def test_can_dispose_context
context = MiniRacer :: Context . new ( timeout : 5 )
context . dispose
assert_raises ( MiniRacer :: ContextDisposedError ) do
context . eval ( " a " )
end
end
def test_estimated_size
context = MiniRacer :: Context . new ( timeout : 5 )
context . eval ( " let a='testing'; " )
stats = context . heap_stats
# eg: {:total_physical_size=>1280640, :total_heap_size_executable=>4194304, :total_heap_size=>3100672, :used_heap_size=>1205376, :heap_size_limit=>1501560832}
assert_equal (
[ :total_physical_size , :total_heap_size_executable , :total_heap_size , :used_heap_size , :heap_size_limit ] . sort ,
stats . keys . sort
)
assert ( stats . values . all? { | v | v > 0 } , " expecting the isolate to have values for all the vals " )
end
2017-07-17 11:05:33 -04:00
def test_eval_with_filename
context = MiniRacer :: Context . new ( )
context . eval ( " var foo = function(){baz();} " , filename : 'b/c/foo1.js' )
got_error = false
begin
context . eval ( " foo() " , filename : 'baz1.js' )
rescue MiniRacer :: RuntimeError = > e
assert_match ( / foo1.js / , e . backtrace [ 0 ] )
assert_match ( / baz1.js / , e . backtrace [ 1 ] )
got_error = true
end
assert ( got_error , " should raise " )
end
def test_estimated_size_when_disposed
context = MiniRacer :: Context . new ( timeout : 5 )
context . eval ( " let a='testing'; " )
context . dispose
stats = context . heap_stats
assert ( stats . values . all? { | v | v == 0 } , " should have 0 values once disposed " )
end
2017-07-13 17:43:43 -04:00
def test_can_dispose
skip " takes too long "
#
# junk_it_up
# 3.times do
# GC.start(full_mark: true, immediate_sweep: true)
# end
end
def junk_it_up
1000 . times do
context = MiniRacer :: Context . new ( timeout : 5 )
context . dispose
end
end
2017-09-05 17:04:34 -04:00
def test_attached_recursion
context = MiniRacer :: Context . new ( timeout : 20 )
context . attach ( " a " , proc { | a | a } )
context . attach ( " b " , proc { | a | a } )
context . eval ( 'const obj = {get r(){ b() }}; a(obj);' )
end
2018-05-09 13:23:02 -04:00
def test_no_disposal_of_isolate_when_it_is_referenced
isolate = MiniRacer :: Isolate . new
context = MiniRacer :: Context . new ( isolate : isolate )
context . dispose
2019-11-10 20:20:26 -05:00
_context2 = MiniRacer :: Context . new ( isolate : isolate ) # Received signal 11 SEGV_MAPERR
2018-05-09 13:23:02 -04:00
end
def test_context_starts_with_no_isolate_value
context = MiniRacer :: Context . new
assert_equal context . instance_variable_get ( '@isolate' ) , false
end
def test_context_isolate_value_is_kept
context = MiniRacer :: Context . new
isolate = context . isolate
assert_same isolate , context . isolate
end
def test_isolate_is_nil_after_disposal
context = MiniRacer :: Context . new
context . dispose
assert_nil context . isolate
context = MiniRacer :: Context . new
context . isolate
context . dispose
assert_nil context . isolate
end
2019-05-14 03:56:04 -04:00
def test_heap_dump
f = Tempfile . new ( " heap " )
path = f . path
f . unlink
context = MiniRacer :: Context . new
context . eval ( 'let x = 1000;' )
context . write_heap_snapshot ( path )
dump = File . read ( path )
assert dump . length > 0
FileUtils . rm ( path )
2019-11-10 20:20:26 -05:00
end
2019-05-14 03:56:04 -04:00
2019-11-10 20:20:26 -05:00
def test_pipe_leak
# in Ruby 2.7 pipes will stay open for longer
# make sure that we clean up early so pipe file
# descriptors are not kept around
context = MiniRacer :: Context . new ( timeout : 1000 )
10000 . times do | i |
context . eval ( " 'hello' " )
end
2019-05-14 03:56:04 -04:00
end
2020-01-08 20:23:07 -05:00
def test_symbol_support
context = MiniRacer :: Context . new ( )
assert_equal :foo , context . eval ( " Symbol('foo') " )
end
def test_proxy_support
js = << ~ JS
function MyProxy ( reference ) {
return new Proxy ( function ( ) { } , {
get : function ( obj , prop ) {
return new MyProxy ( reference . concat ( prop ) ) ;
} ,
apply : function ( target , thisArg , argumentsList ) {
myFunctionLogger ( reference ) ;
}
} ) ;
} ;
( new MyProxy ( [ ] ) ) . function_call ( new MyProxy ( [ ] ) - 1 )
JS
context = MiniRacer :: Context . new ( )
context . attach ( 'myFunctionLogger' , - > ( property ) { } )
context . eval ( js )
end
2016-05-04 02:54:51 -04:00
end