%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
-module(escript_SUITE).
-export([
all/1,
init_per_testcase/2,
fin_per_testcase/2,
basic/1,
errors/1,
strange_name/1,
emulator_flags/1,
module_script/1,
beam_script/1,
archive_script/1,
epp/1
]).
-include("test_server.hrl").
all(suite) ->
[
basic,
errors,
strange_name,
emulator_flags,
module_script,
beam_script,
archive_script,
epp
].
init_per_testcase(_Case, Config) ->
?line Dog = ?t:timetrap(?t:minutes(1)),
[{watchdog,Dog}|Config].
fin_per_testcase(_Case, Config) ->
Dog = ?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
basic(Config) when is_list(Config) ->
Data = ?config(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
?line run(Dir, "factorial 5",
<<"factorial 5 = 120\nExitCode:0">>),
?line run(Dir, "factorial_compile 10",
<<"factorial 10 = 3628800\nExitCode:0">>),
?line run(Dir, "factorial_compile_main 7",
<<"factorial 7 = 5040\nExitCode:0">>),
?line run(Dir, "factorial_warning 20",
[data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\n"
"factorial 20 = 2432902008176640000\nExitCode:0">>]),
?line run(Dir, "-s", "factorial_warning",
[data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
?line run(Dir, "-s -i", "factorial_warning",
[data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
?line run(Dir, "-c -s", "factorial_warning",
[data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
?line run(Dir, "filesize "++filename:join(?config(data_dir, Config),"filesize"),
[data_dir,<<"filesize:11: Warning: function id/1 is unused\n324\nExitCode:0">>]),
?line run(Dir, "test_script_name",
[data_dir,<<"test_script_name\nExitCode:0">>]),
?line run(Dir, "tail_rec 1000",
[<<"ok\nExitCode:0">>]),
%% We expect the trap_exit flag for the process to be false,
%% since that is the default state for newly spawned processes.
?line run(Dir, "trap_exit",
<<"false\nExitCode:0">>),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
errors(Config) when is_list(Config) ->
Data = ?config(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
?line run(Dir, "compile_error",
[data_dir,<<"compile_error:5: syntax error before: '*'\n">>,
data_dir,<<"compile_error:8: syntax error before: blarf\n">>,
<<"escript: There were compilation errors.\nExitCode:127">>]),
?line run(Dir, "lint_error",
[data_dir,<<"lint_error:6: function main/1 already defined\n">>,
data_dir,"lint_error:8: variable 'ExitCode' is unbound\n",
<<"escript: There were compilation errors.\nExitCode:127">>]),
?line run(Dir, "-s", "lint_error",
[data_dir,<<"lint_error:6: function main/1 already defined\n">>,
data_dir,"lint_error:8: variable 'ExitCode' is unbound\n",
<<"escript: There were compilation errors.\nExitCode:127">>]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
strange_name(Config) when is_list(Config) ->
Data = ?config(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
?line run(Dir, "strange.name -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"ExitCode:0">>]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
emulator_flags(Config) when is_list(Config) ->
Data = ?config(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
?line run(Dir, "emulator_flags -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[{nostick,[]}]\n"
"mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Pick the source code from the emulator_flags script
%% Generate a new escript with a module header
module_script(Config) when is_list(Config) ->
%% Read orig file
Data = ?config(data_dir, Config),
OrigFile = filename:join([Data,"emulator_flags"]),
{ok, OrigBin} = file:read_file(OrigFile),
?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"),
?line {ok, OrigFI} = file:read_file_info(OrigFile),
%% Write source file
Priv = ?config(priv_dir, Config),
Dir = filename:absname(Priv), % Get rid of trailing slash.
Base = "module_script",
ErlFile = filename:join([Priv, Base ++ ".erl"]),
ErlCode = ["-module(", Base, ").\n",
"-export([main/1]).\n\n",
string:join(Source, "\n"),
"\n"],
?line ok = file:write_file(ErlFile, ErlCode),
%%%%%%%
%% Create and run scripts without emulator flags
%% With shebang
NoArgsBase = Base ++ "_no_args_with_shebang",
NoArgsFile = filename:join([Priv, NoArgsBase]),
?line ok = file:write_file(NoArgsFile,
[Shebang, "\n",
ErlCode]),
?line ok = file:write_file_info(NoArgsFile, OrigFI),
?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%% Without shebang
NoArgsBase2 = Base ++ "_no_args_without_shebang",
NoArgsFile2 = filename:join([Priv, NoArgsBase2]),
?line ok = file:write_file(NoArgsFile2,
["Something else than shebang!!!", "\n",
ErlCode]),
?line ok = file:write_file_info(NoArgsFile2, OrigFI),
?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%% Plain module without header
NoArgsBase3 = Base ++ "_no_args_without_header",
NoArgsFile3 = filename:join([Priv, NoArgsBase3]),
?line ok = file:write_file(NoArgsFile3, [ErlCode]),
?line ok = file:write_file_info(NoArgsFile3, OrigFI),
?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%%%%%%%
%% Create and run scripts with emulator flags
%% With shebang
ArgsBase = Base ++ "_args_with_shebang",
ArgsFile = filename:join([Priv, ArgsBase]),
?line ok = file:write_file(ArgsFile,
[Shebang, "\n",
Mode, "\n",
Flags, "\n",
ErlCode]),
?line ok = file:write_file_info(ArgsFile, OrigFI),
?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[{nostick,[]}]\n"
"mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Pick the source code from the emulator_flags script and compile it.
%% Generate a new escript containing the beam code and the escript header
beam_script(Config) when is_list(Config) ->
%% Read orig file
Data = ?config(data_dir, Config),
OrigFile = filename:join([Data,"emulator_flags"]),
{ok, OrigBin} = file:read_file(OrigFile),
?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"),
?line {ok, OrigFI} = file:read_file_info(OrigFile),
%% Write source file
Priv = ?config(priv_dir, Config),
Dir = filename:absname(Priv), % Get rid of trailing slash.
Base = "beam_script",
ErlFile = filename:join([Priv, Base ++ ".erl"]),
?line ok = file:write_file(ErlFile,
["-module(", Base, ").\n",
"-export([main/1]).\n\n",
string:join(Source, "\n"),
"\n"]),
%% Compile the code
?line {ok, _Mod, BeamCode} = compile:file(ErlFile, [binary]),
%%%%%%%
%% Create and run scripts without emulator flags
%% With shebang
NoArgsBase = Base ++ "_no_args_with_shebang",
NoArgsFile = filename:join([Priv, NoArgsBase]),
?line ok = file:write_file(NoArgsFile,
[Shebang, "\n",
BeamCode]),
?line ok = file:write_file_info(NoArgsFile, OrigFI),
?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%% Without shebang
NoArgsBase2 = Base ++ "_no_args_without_shebang",
NoArgsFile2 = filename:join([Priv, NoArgsBase2]),
?line ok = file:write_file(NoArgsFile2,
["Something else than shebang!!!", "\n",
BeamCode]),
?line ok = file:write_file_info(NoArgsFile2, OrigFI),
?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%% Plain beam file without header
NoArgsBase3 = Base ++ "_no_args_without_header",
NoArgsFile3 = filename:join([Priv, NoArgsBase3]),
?line ok = file:write_file(NoArgsFile3, [BeamCode]),
?line ok = file:write_file_info(NoArgsFile3, OrigFI),
?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[]\n"
"mnesia:[]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
%%%%%%%
%% Create and run scripts with emulator flags
%% With shebang
ArgsBase = Base ++ "_args",
ArgsFile = filename:join([Priv, ArgsBase]),
?line ok = file:write_file(ArgsFile,
[Shebang, "\n",
Mode, "\n",
Flags, "\n",
BeamCode]),
?line ok = file:write_file_info(ArgsFile, OrigFI),
?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"nostick:[{nostick,[]}]\n"
"mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
"ERL_FLAGS=false\n"
"unknown:[]\n"
"ExitCode:0">>]),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create an archive file containing two entire applications plus two
%% alternate main modules. Generate a new escript containing the archive
%% (with .app and .beam files and ) and the escript header.
archive_script(Config) when is_list(Config) ->
%% Copy the orig files to priv_dir
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
Archive = filename:join([PrivDir, "archive_script.zip"]),
?line {ok, _} = zip:create(Archive, ["archive_script"],
[{compress, []}, {cwd, DataDir}]),
?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]),
TopDir = filename:join([PrivDir, "archive_script"]),
%% Compile the code
?line ok = compile_app(TopDir, "archive_script_dict"),
?line ok = compile_app(TopDir, "archive_script_dummy"),
?line {ok, MainFiles} = file:list_dir(TopDir),
?line ok = compile_files(MainFiles, TopDir, TopDir),
%% Create the archive
{ok, TopFiles} = file:list_dir(TopDir),
?line {ok, {_, ArchiveBin}} = zip:create(Archive, TopFiles,
[memory, {compress, []}, {cwd, TopDir}]),
%% Read the source script
OrigFile = filename:join([DataDir, "emulator_flags"]),
{ok, OrigBin} = file:read_file(OrigFile),
?line [Shebang, Mode, _Flags | _Source] =
string:tokens(binary_to_list(OrigBin), "\n"),
Flags = "%%! -archive_script_dict foo bar"
" -archive_script_dict foo"
" -archive_script_dummy bar",
?line {ok, OrigFI} = file:read_file_info(OrigFile),
%%%%%%%
%% Create and run scripts without emulator flags
MainBase = "archive_script_main",
MainScript = filename:join([PrivDir, MainBase]),
%% With shebang
?line ok = file:write_file(MainScript,
[Shebang, "\n",
Flags, "\n",
ArchiveBin]),
?line ok = file:write_file_info(MainScript, OrigFI),
?line run(PrivDir, MainBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
"dummy:[{archive_script_dummy,[\"bar\"]}]\n"
"priv:{ok,<<\"Some private data...\\n\">>}\n"
"ExitCode:0">>]),
?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
"dummy:[{archive_script_dummy,[\"bar\"]}]\n"
"priv:{ok,<<\"Some private data...\\n\">>}\n"
"ExitCode:0">>]),
?line ok = file:rename(MainScript, MainScript ++ "_with_shebang"),
%% Without shebang (no flags)
?line ok = file:write_file(MainScript,
["Something else than shebang!!!", "\n",
ArchiveBin]),
?line ok = file:write_file_info(MainScript, OrigFI),
?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"dict:[]\n"
"dummy:[]\n"
"priv:{ok,<<\"Some private data...\\n\">>}\n"
"ExitCode:0">>]),
?line ok = file:rename(MainScript, MainScript ++ "_without_shebang"),
%% Plain archive without header (no flags)
?line ok = file:write_file(MainScript, [ArchiveBin]),
?line ok = file:write_file_info(MainScript, OrigFI),
?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
[<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"dict:[]\n"
"dummy:[]\n"
"priv:{ok,<<\"Some private data...\\n\">>}\n"
"ExitCode:0">>]),
?line ok = file:rename(MainScript, MainScript ++ "_without_header"),
%%%%%%%
%% Create and run scripts with emulator flags
AltBase = "archive_script_alternate_main",
AltScript = filename:join([PrivDir, AltBase]),
?line ok = file:write_file(AltScript,
[Shebang, "\n",
Mode, "\n",
Flags, " -escript main archive_script_main2\n",
ArchiveBin]),
?line ok = file:write_file_info(AltScript, OrigFI),
?line run(PrivDir, AltBase ++ " -arg1 arg2 arg3",
[<<"main2:[\"-arg1\",\"arg2\",\"arg3\"]\n"
"dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
"dummy:[{archive_script_dummy,[\"bar\"]}]\n"
"priv:{ok,<<\"Some private data...\\n\">>}\n"
"ExitCode:0">>]),
ok.
compile_app(TopDir, AppName) ->
AppDir = filename:join([TopDir, AppName]),
SrcDir = filename:join([AppDir, "src"]),
OutDir = filename:join([AppDir, "ebin"]),
?line {ok, Files} = file:list_dir(SrcDir),
compile_files(Files, SrcDir, OutDir).
compile_files([File | Files], SrcDir, OutDir) ->
case filename:extension(File) of
".erl" ->
AbsFile = filename:join([SrcDir, File]),
case compile:file(AbsFile, [{outdir, OutDir}]) of
{ok, _Mod} ->
compile_files(Files, SrcDir, OutDir);
Error ->
{compilation_error, AbsFile, OutDir, Error}
end;
_ ->
compile_files(Files, SrcDir, OutDir)
end;
compile_files([], _, _) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
epp(Config) when is_list(Config) ->
Data = ?config(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
?line run(Dir, "factorial_epp 5",
<<"factorial 5 = 120\nExitCode:0">>),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run(Dir, Cmd0, Expected0) ->
Expected = iolist_to_binary(expected_output(Expected0, Dir)),
Cmd = case os:type() of
{win32,_} -> "escript " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
_ -> Cmd0
end,
do_run(Dir, Cmd, Expected).
run(Dir, Opts, Cmd0, Expected) ->
Cmd = case os:type() of
{win32,_} -> "escript " ++ Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
_ -> "escript " ++ Opts ++ " " ++ Dir ++ "/" ++ Cmd0
end,
do_run(Dir, Cmd, Expected).
do_run(Dir, Cmd, Expected0) ->
io:format("Run: ~p\n", [Cmd]),
Expected = iolist_to_binary(expected_output(Expected0, Dir)),
Env = [{"PATH",Dir++":"++os:getenv("PATH")}],
Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
Res = get_data(Port, []),
receive
{Port,{exit_status,ExitCode}} ->
case iolist_to_binary([Res,"ExitCode:"++integer_to_list(ExitCode)]) of
Expected ->
ok;
Actual ->
io:format("Expected: ~p\n", [Expected]),
io:format("Actual: ~p\n", [Actual]),
?t:fail()
end
end.
get_data(Port, SoFar) ->
receive
{Port,{data,Bytes}} ->
get_data(Port, [SoFar|Bytes]);
{Port,eof} ->
erlang:port_close(Port),
SoFar
end.
expected_output([data_dir|T], Data) ->
Slash = case os:type() of
{win32,_} -> "\\";
_ -> "/"
end,
[filename:nativename(Data)++Slash|expected_output(T, Data)];
expected_output([H|T], Data) ->
[H|expected_output(T, Data)];
expected_output([], _) ->
[];
expected_output(Bin, _) when is_binary(Bin) ->
Bin.