1
0
Fork 0
mirror of https://github.com/rails/execjs synced 2023-03-27 23:21:20 -04:00
execjs/test/test_execjs.rb

449 lines
12 KiB
Ruby

# -*- coding: utf-8 -*-
require "minitest/autorun"
require "execjs/module"
require "json"
begin
require "execjs"
rescue ExecJS::RuntimeUnavailable => e
warn e
exit 2
end
if defined? Minitest::Test
Test = Minitest::Test
elsif defined? MiniTest::Unit::TestCase
Test = MiniTest::Unit::TestCase
end
class TestExecJS < Test
def test_runtime_available
runtime = ExecJS::ExternalRuntime.new(command: "nonexistent")
assert !runtime.available?
runtime = ExecJS::ExternalRuntime.new(command: "ruby")
assert runtime.available?
end
def test_runtime_assignment
original_runtime = ExecJS.runtime
runtime = ExecJS::ExternalRuntime.new(command: "nonexistent")
assert_raises(ExecJS::RuntimeUnavailable) { ExecJS.runtime = runtime }
assert_equal original_runtime, ExecJS.runtime
runtime = ExecJS::ExternalRuntime.new(command: "ruby")
ExecJS.runtime = runtime
assert_equal runtime, ExecJS.runtime
ensure
ExecJS.runtime = original_runtime
end
def test_context_call
context = ExecJS.compile("id = function(v) { return v; }")
assert_equal "bar", context.call("id", "bar")
end
def test_nested_context_call
context = ExecJS.compile("a = {}; a.b = {}; a.b.id = function(v) { return v; }")
assert_equal "bar", context.call("a.b.id", "bar")
end
def test_call_with_complex_properties
context = ExecJS.compile("")
assert_equal 2, context.call("function(a, b) { return a + b }", 1, 1)
context = ExecJS.compile("foo = 1")
assert_equal 2, context.call("(function(bar) { return foo + bar })", 1)
end
def test_call_with_this
# Known bug: https://github.com/cowboyd/therubyrhino/issues/39
skip if ExecJS.runtime.is_a?(ExecJS::RubyRhinoRuntime)
# Make sure that `this` is indeed the global scope
context = ExecJS.compile(<<-EOF)
name = 123;
function Person(name) {
this.name = name;
}
Person.prototype.getThis = function() {
return this.name;
}
EOF
assert_equal 123, context.call("(new Person('Bob')).getThis")
end
def test_context_call_missing_function
context = ExecJS.compile("")
assert_raises ExecJS::ProgramError do
context.call("missing")
end
end
{
"function() {}" => nil,
"0" => 0,
"null" => nil,
"undefined" => nil,
"true" => true,
"false" => false,
"[1, 2]" => [1, 2],
"[1, function() {}]" => [1, nil],
"'hello'" => "hello",
"'red yellow blue'.split(' ')" => ["red", "yellow", "blue"],
"{a:1,b:2}" => {"a"=>1,"b"=>2},
"{a:true,b:function (){}}" => {"a"=>true},
"'café'" => "café",
'"☃"' => "",
'"\u2603"' => "",
"'\u{1f604}'".encode("UTF-8") => "\u{1f604}".encode("UTF-8"), # Smiling emoji
"'\u{1f1fa}\u{1f1f8}'".encode("UTF-8") => "\u{1f1fa}\u{1f1f8}".encode("UTF-8"), # US flag
'"\\\\"' => "\\"
}.each_with_index do |(input, output), index|
define_method("test_exec_string_#{index}") do
assert_output output, ExecJS.exec("return #{input}")
end
define_method("test_eval_string_#{index}") do
assert_output output, ExecJS.eval(input)
end
define_method("test_compile_return_string_#{index}") do
context = ExecJS.compile("var a = #{input};")
assert_output output, context.eval("a")
end
define_method("test_compile_call_string_#{index}") do
context = ExecJS.compile("function a() { return #{input}; }")
assert_output output, context.call("a")
end
end
[
nil,
true,
false,
1,
3.14,
"hello",
"\\",
"café",
"",
"\u{1f604}".encode("UTF-8"), # Smiling emoji
"\u{1f1fa}\u{1f1f8}".encode("UTF-8"), # US flag
[1, 2, 3],
[1, [2, 3]],
[1, [2, [3]]],
["red", "yellow", "blue"],
{ "a" => 1, "b" => 2},
{ "a" => 1, "b" => [2, 3]},
{ "a" => true }
].each_with_index do |value, index|
json_value = JSON.generate(value, quirks_mode: true)
define_method("test_json_value_#{index}") do
assert_output value, JSON.parse(json_value, quirks_mode: true)
end
define_method("test_exec_value_#{index}") do
assert_output value, ExecJS.exec("return #{json_value}")
end
define_method("test_eval_value_#{index}") do
assert_output value, ExecJS.eval("#{json_value}")
end
define_method("test_stringify_value_#{index}") do
context = ExecJS.compile("function json(obj) { return JSON.stringify(obj); }")
assert_output json_value, context.call("json", value)
end
define_method("test_call_value_#{index}") do
context = ExecJS.compile("function id(obj) { return obj; }")
assert_output value, context.call("id", value)
end
end
def test_symbol
context = ExecJS.compile("function echo(test) { return test; }")
assert_equal "symbol", context.call("echo", :symbol)
assert_equal ["symbol"], context.call("echo", [:symbol])
assert_equal({"key" => "value"}, context.call("echo", {key: :value}))
context = ExecJS.compile("function myslice(str) { return str.slice(1); }")
assert_equal "ymbol", context.call("myslice", :symbol)
end
def test_additional_options
assert ExecJS.eval("true", :foo => true)
assert ExecJS.exec("return true", :foo => true)
context = ExecJS.compile("foo = true", :foo => true)
assert context.eval("foo", :foo => true)
assert context.exec("return foo", :foo => true)
end
def test_eval_blank
assert_nil ExecJS.eval("")
assert_nil ExecJS.eval(" ")
assert_nil ExecJS.eval(" ")
end
def test_exec_return
assert_nil ExecJS.exec("return")
end
def test_exec_no_return
assert_nil ExecJS.exec("1")
end
def test_encoding
utf8 = Encoding.find('UTF-8')
assert_equal utf8, ExecJS.exec("return 'hello'").encoding
assert_equal utf8, ExecJS.eval("'☃'").encoding
ascii = "'hello'".encode('US-ASCII')
result = ExecJS.eval(ascii)
assert_equal "hello", result
assert_equal utf8, result.encoding
assert_raises Encoding::UndefinedConversionError do
binary = "\xde\xad\xbe\xef".force_encoding("BINARY")
ExecJS.eval(binary)
end
end
def test_encoding_compile
utf8 = Encoding.find('UTF-8')
context = ExecJS.compile("foo = function(v) { return '¶' + v; }".encode("ISO8859-15"))
assert_equal utf8, context.exec("return foo('hello')").encoding
assert_equal utf8, context.eval("foo('☃')").encoding
ascii = "foo('hello')".encode('US-ASCII')
result = context.eval(ascii)
assert_equal "¶hello", result
assert_equal utf8, result.encoding
assert_raises Encoding::UndefinedConversionError do
binary = "\xde\xad\xbe\xef".force_encoding("BINARY")
context.eval(binary)
end
end
def test_surrogate_pairs
# Smiling emoji
str = "\u{1f604}".encode("UTF-8")
assert_equal 2, ExecJS.eval("'#{str}'.length")
assert_equal str, ExecJS.eval("'#{str}'")
# US flag emoji
str = "\u{1f1fa}\u{1f1f8}".encode("UTF-8")
assert_equal 4, ExecJS.eval("'#{str}'.length")
assert_equal str, ExecJS.eval("'#{str}'")
end
def test_compile_anonymous_function
context = ExecJS.compile("foo = function() { return \"bar\"; }")
assert_equal "bar", context.exec("return foo()")
assert_equal "bar", context.eval("foo()")
assert_equal "bar", context.call("foo")
end
def test_compile_named_function
context = ExecJS.compile("function foo() { return \"bar\"; }")
assert_equal "bar", context.exec("return foo()")
assert_equal "bar", context.eval("foo()")
assert_equal "bar", context.call("foo")
end
def test_this_is_global_scope
assert_equal true, ExecJS.eval("this === (function() {return this})()")
assert_equal true, ExecJS.exec("return this === (function() {return this})()")
end
def test_browser_self_is_undefined
assert ExecJS.eval("typeof self == 'undefined'")
end
def test_node_global_is_undefined
assert ExecJS.eval("typeof global == 'undefined'")
end
def test_node_process_is_undefined
assert ExecJS.eval("typeof process == 'undefined'")
refute ExecJS.eval("'process' in this")
end
def test_commonjs_vars_are_undefined
assert ExecJS.eval("typeof module == 'undefined'")
assert ExecJS.eval("typeof exports == 'undefined'")
assert ExecJS.eval("typeof require == 'undefined'")
refute ExecJS.eval("'module' in this")
refute ExecJS.eval("'exports' in this")
refute ExecJS.eval("'require' in this")
end
def test_console_is_undefined
assert ExecJS.eval("typeof console == 'undefined'")
refute ExecJS.eval("'console' in this")
end
def test_timers_are_undefined
assert ExecJS.eval("typeof setTimeout == 'undefined'")
assert ExecJS.eval("typeof setInterval == 'undefined'")
assert ExecJS.eval("typeof clearTimeout == 'undefined'")
assert ExecJS.eval("typeof clearInterval == 'undefined'")
assert ExecJS.eval("typeof setImmediate == 'undefined'")
assert ExecJS.eval("typeof clearImmediate == 'undefined'")
refute ExecJS.eval("'setTimeout' in this")
refute ExecJS.eval("'setInterval' in this")
refute ExecJS.eval("'clearTimeout' in this")
refute ExecJS.eval("'clearInterval' in this")
refute ExecJS.eval("'setImmediate' in this")
refute ExecJS.eval("'clearImmediate' in this")
end
def test_compile_large_scripts
body = "var foo = 'bar';\n" * 100_000
assert ExecJS.exec("function foo() {\n#{body}\n};\nreturn true")
end
def test_large_return_value
string = ExecJS.eval('(new Array(100001)).join("abcdef")')
assert_equal 600_000, string.size
end
def test_exec_syntax_error
begin
ExecJS.exec(")")
flunk
rescue ExecJS::RuntimeError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_eval_syntax_error
begin
ExecJS.eval(")")
flunk
rescue ExecJS::RuntimeError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_compile_syntax_error
begin
ExecJS.compile(")")
flunk
rescue ExecJS::RuntimeError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_exec_thrown_error
begin
ExecJS.exec("throw new Error('hello')")
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_eval_thrown_error
begin
ExecJS.eval("(function(){ throw new Error('hello') })()")
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_compile_thrown_error
begin
ExecJS.compile("throw new Error('hello')")
flunk
rescue ExecJS::ProgramError => e
assert e
assert e.backtrace[0].include?("(execjs):1"), e.backtrace.join("\n")
end
end
def test_exec_thrown_string
assert_raises ExecJS::ProgramError do
ExecJS.exec("throw 'hello'")
end
end
def test_eval_thrown_string
assert_raises ExecJS::ProgramError do
ExecJS.eval("(function(){ throw 'hello' })()")
end
end
def test_compile_thrown_string
assert_raises ExecJS::ProgramError do
ExecJS.compile("throw 'hello'")
end
end
def test_babel
skip if ExecJS.runtime.is_a?(ExecJS::RubyRhinoRuntime)
assert source = File.read(File.expand_path("../fixtures/babel.js", __FILE__))
source = <<-JS
var self = this;
#{source}
babel.eval = function(code) {
return eval(babel.transform(code)["code"]);
}
JS
context = ExecJS.compile(source)
assert_equal 64, context.call("babel.eval", "((x) => x * x)(8)")
end
def test_coffeescript
assert source = File.read(File.expand_path("../fixtures/coffee-script.js", __FILE__))
context = ExecJS.compile(source)
assert_equal 64, context.call("CoffeeScript.eval", "((x) -> x * x)(8)")
end
def test_uglify
assert source = File.read(File.expand_path("../fixtures/uglify.js", __FILE__))
source = <<-JS
#{source}
function uglify(source) {
var ast = UglifyJS.parse(source);
var stream = UglifyJS.OutputStream();
ast.print(stream);
return stream.toString();
}
JS
context = ExecJS.compile(source)
assert_equal "function foo(bar){return bar}",
context.call("uglify", "function foo(bar) {\n return bar;\n}")
end
private
def assert_output(expected, actual)
if expected.nil?
assert_nil actual
else
assert_equal expected, actual
end
end
end