restructuring done I think
This commit is contained in:
+302
-7
@@ -1,27 +1,322 @@
|
||||
% testing utilities
|
||||
% test suite utilities
|
||||
-module(ts_utils).
|
||||
|
||||
-export([
|
||||
load_test_deps/0,
|
||||
test_deps/0,
|
||||
load_dep/1,
|
||||
clean_after/1, tidily/1,
|
||||
delete_beams/0, tidy/0,
|
||||
run_test_by_name/1,
|
||||
rmm/1, run_mod_main/1,
|
||||
runnable_test_names/0,
|
||||
runnable_test_mods/0,
|
||||
load_test_erls/0,
|
||||
abspath_to_name/1,
|
||||
ls_test_erls/0,
|
||||
ls_test_beams/0,
|
||||
is_erl/1,
|
||||
is_beam/1,
|
||||
ls_test/0,
|
||||
test_dir/0,
|
||||
ct_dir/0,
|
||||
ct_file/1, ct_file_abspath/1
|
||||
ct_file/1, ct_file_abspath/1, ct_abspath/1
|
||||
]).
|
||||
|
||||
|
||||
-spec ct_dir() -> string().
|
||||
load_test_deps() ->
|
||||
lists:foreach(fun load_dep/1, test_deps()).
|
||||
|
||||
test_deps() ->
|
||||
[{"otpr", "sophia", {9, 0, 0}}].
|
||||
|
||||
|
||||
load_dep(D) ->
|
||||
ok =
|
||||
case zx_lib:installed(D) of
|
||||
false ->
|
||||
Id = zx_daemon:fetch(D),
|
||||
ok = zx_daemon:wait_result(Id),
|
||||
ok;
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
zx_daemon:build(D).
|
||||
|
||||
|
||||
-spec clean_after(Fun) -> Result when
|
||||
Fun :: fun(() -> Result),
|
||||
Result :: any().
|
||||
|
||||
% @doc
|
||||
% run Fun(), delete gsc/test/*.beam afterward even if
|
||||
% Fun() errors
|
||||
% @end
|
||||
clean_after(Fun) ->
|
||||
try
|
||||
load_test_deps(),
|
||||
Fun()
|
||||
after
|
||||
delete_beams()
|
||||
end.
|
||||
|
||||
|
||||
% @doc alias for `clean_after/1'
|
||||
tidily(Fun) ->
|
||||
clean_after(Fun).
|
||||
|
||||
|
||||
|
||||
-spec delete_beams() -> ok.
|
||||
|
||||
delete_beams() ->
|
||||
lists:map(fun file:delete/1, ls_test_beams()).
|
||||
|
||||
tidy() ->
|
||||
delete_beams().
|
||||
|
||||
|
||||
-spec run_test_by_name(Name) -> Result when
|
||||
Name :: string(),
|
||||
Result :: ok.
|
||||
|
||||
run_test_by_name(Name) when is_list(Name) ->
|
||||
case find_test_by_name(Name) of
|
||||
{good, Mod} ->
|
||||
rmm(Mod);
|
||||
{bad, Mod} ->
|
||||
io:format("FATAL: Module ~tp didn't compile~n", [Mod]),
|
||||
ok;
|
||||
not_found ->
|
||||
io:format("FATAL: test not found: ~p~n", [Name]),
|
||||
ok
|
||||
end.
|
||||
|
||||
|
||||
run_mod_main(Mod) ->
|
||||
rmm(Mod).
|
||||
|
||||
rmm(Mod) ->
|
||||
try
|
||||
io:format("=================================================~n"),
|
||||
io:format("~p:main()~n", [Mod]),
|
||||
io:format("=================================================~n"),
|
||||
Mod:main()
|
||||
catch
|
||||
Cat:Err:Tr ->
|
||||
io:format("~tp:main(): ERROR~n", [Mod]),
|
||||
io:format("~tp: ~tp~n", [Cat, Err]),
|
||||
io:format("Trace: ~tp~n", [Tr]),
|
||||
ok
|
||||
end.
|
||||
|
||||
|
||||
|
||||
find_test_by_name(Name) ->
|
||||
C1 = list_to_atom(Name),
|
||||
C2 = list_to_atom("gsc_test_" ++ Name),
|
||||
{Gd, Bd} = runnable_test_mods(),
|
||||
C1Gd = lists:member(C1, Gd),
|
||||
C2Gd = lists:member(C2, Gd),
|
||||
C1Bd = lists:member(C1, Gd),
|
||||
C2Bd = lists:member(C2, Bd),
|
||||
if
|
||||
C1Gd -> {good, C1};
|
||||
C2Gd -> {good, C2};
|
||||
C1Bd -> {bad, C1};
|
||||
C2Bd -> {bad, C2};
|
||||
true -> not_found
|
||||
end.
|
||||
|
||||
|
||||
-spec runnable_test_names() -> Result when
|
||||
Result :: [{string(), atom()}].
|
||||
|
||||
runnable_test_names() ->
|
||||
{Gd, Bd} = runnable_test_mods(),
|
||||
rtns([], lists:sort(Gd ++ Bd)).
|
||||
|
||||
rtns(Acc, []) ->
|
||||
lists:reverse(Acc);
|
||||
rtns(Acc, [TestMod | Rest]) ->
|
||||
TestName = test_mod_name(TestMod),
|
||||
rtns([{TestName, TestMod} | Acc], Rest).
|
||||
|
||||
test_mod_name(TestModAtom) ->
|
||||
"gsc_test_" ++ Name = atom_to_list(TestModAtom),
|
||||
Name.
|
||||
|
||||
|
||||
|
||||
-spec runnable_test_mods() -> Result when
|
||||
Result :: {Good, Bad},
|
||||
Good :: Mods,
|
||||
Bad :: Mods,
|
||||
Mods :: [atom()].
|
||||
|
||||
runnable_test_mods() ->
|
||||
{Ld, Bds} = load_test_erls(),
|
||||
Gd = lists:filter(fun is_runnable/1, Ld),
|
||||
Bd = lists:filter(fun is_runnable/1, Bds),
|
||||
{Gd, Bd}.
|
||||
|
||||
|
||||
|
||||
is_runnable(ModAtom) ->
|
||||
case atom_to_list(ModAtom) of
|
||||
"gsc_test_" ++ _ -> true;
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
|
||||
|
||||
-spec load_test_erls() -> {Loaded, Errs} when
|
||||
Loaded :: [atom()],
|
||||
Errs :: [atom()].
|
||||
|
||||
load_test_erls() ->
|
||||
ltes([], [], ls_test_erls()).
|
||||
|
||||
|
||||
ltes(Ld, Errs, []) ->
|
||||
{lists:reverse(Ld), lists:reverse(Errs)};
|
||||
ltes(Ld, Errs, [FP | Rest]) ->
|
||||
FN = abspath_to_name(FP),
|
||||
ModAtom = fp_to_mod_atom(FP),
|
||||
case compile:file(FP) of
|
||||
{ok, Mod} ->
|
||||
ltes([Mod | Ld], Errs, Rest);
|
||||
Err ->
|
||||
io:format("ERROR ~tp: ~tp~n", [FN, Err]),
|
||||
ltes(Ld, [ModAtom | Errs], Rest)
|
||||
end.
|
||||
|
||||
|
||||
fp_to_mod_atom(FP) ->
|
||||
FN = abspath_to_name(FP),
|
||||
[ModStr, "erl"] = string:split(FN, ".", trailing),
|
||||
list_to_atom(ModStr).
|
||||
|
||||
|
||||
|
||||
-spec abspath_to_name(FilePath) -> FileName when
|
||||
FilePath :: string(),
|
||||
FileName :: string().
|
||||
% @doc "/path/to/foo.bar" -> "foo.bar"
|
||||
|
||||
abspath_to_name(FP) ->
|
||||
lists:last(string:tokens(FP, "/")).
|
||||
|
||||
|
||||
|
||||
-spec ls_test_erls() -> AbsPaths when
|
||||
AbsPaths :: [string()].
|
||||
% @doc ["/path/to/gsc/test/foo.erl",
|
||||
% "/path/to/gsc/test/bar.erl",
|
||||
% "/path/to/gsc/test/baz.erl"]
|
||||
|
||||
ls_test_erls() ->
|
||||
lists:filter(fun is_erl/1, ls_test()).
|
||||
|
||||
|
||||
|
||||
-spec ls_test_beams() -> AbsPaths when
|
||||
AbsPaths :: [string()].
|
||||
|
||||
% important: beams get dropped in working dir
|
||||
ls_test_beams() ->
|
||||
lists:filter(fun is_beam/1, ls_pwd()).
|
||||
|
||||
|
||||
|
||||
-spec is_beam(AbsPath) -> IsBeam when
|
||||
AbsPath :: string(),
|
||||
IsBeam :: boolean().
|
||||
|
||||
% @private
|
||||
% "foo.beam" ~> true
|
||||
% _ ~> false
|
||||
is_beam(Filename) ->
|
||||
case filename:extension(Filename) of
|
||||
".beam" -> true;
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
|
||||
|
||||
-spec is_erl(AbsPath) -> IsErl when
|
||||
AbsPath :: string(),
|
||||
IsErl :: boolean().
|
||||
% @private
|
||||
% "foo.erl" ~> true
|
||||
% _ ~> false
|
||||
|
||||
is_erl(Filename) ->
|
||||
case filename:extension(Filename) of
|
||||
".erl" -> true;
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
|
||||
|
||||
-spec ls_test() -> Abspaths when
|
||||
Abspaths :: [string()].
|
||||
% @doc
|
||||
% Includes junk/irrelevant files:
|
||||
%
|
||||
% ["/path/to/gsc/test/foo.erl",
|
||||
% "/path/to/gsc/test/.foo.erl.swp",
|
||||
% "/path/to/gsc/test/bar.erl"]
|
||||
|
||||
ls_test() ->
|
||||
TD = test_dir(),
|
||||
{ok, Names} = file:list_dir(TD),
|
||||
lists:sort([TD ++ "/" ++ Name || Name <- Names]).
|
||||
|
||||
|
||||
ls_pwd() ->
|
||||
{ok, D} = file:get_cwd(),
|
||||
{ok, Ns} = file:list_dir(D),
|
||||
lists:sort([D ++ "/" ++ N || N <- Ns]).
|
||||
|
||||
|
||||
-spec test_dir() -> AbsPath when
|
||||
AbsPath :: string().
|
||||
% @doc "/path/to/gsc/test"
|
||||
|
||||
test_dir() ->
|
||||
zx_daemon:get_home() ++ "/test".
|
||||
|
||||
|
||||
|
||||
-spec ct_dir() -> AbsPath when
|
||||
AbsPath :: string().
|
||||
|
||||
% @doc "/path/to/gsc/test/ct"
|
||||
%
|
||||
% directory containing the tests for the tokenizer
|
||||
ct_dir() ->
|
||||
zx_daemon:get_home() ++ "/ct".
|
||||
test_dir() ++ "/ct".
|
||||
|
||||
|
||||
|
||||
ct_file_abspath(Name) ->
|
||||
ct_file(Name).
|
||||
|
||||
-spec ct_file(Name) -> AbsPath when
|
||||
Name :: string(),
|
||||
AbsPath :: string().
|
||||
% @doc
|
||||
% ct_file("foo.aes") -> "/path/to/ct/foo.aes"
|
||||
% "foo.aes" -> "/path/to/ct/foo.aes"
|
||||
|
||||
ct_file(Name) ->
|
||||
ct_dir() ++ "/" ++ Name.
|
||||
|
||||
|
||||
% @doc alias for `ct_file/1'
|
||||
%
|
||||
% "foo.aes" -> "/path/to/ct/foo.aes"
|
||||
ct_file_abspath(Name) -> ct_file(Name).
|
||||
|
||||
% @doc alias for `ct_file/1'
|
||||
%
|
||||
% "foo.aes" -> "/path/to/ct/foo.aes"
|
||||
ct_abspath(Name) -> ct_file(Name).
|
||||
|
||||
Reference in New Issue
Block a user