summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/mock_pkg_resource.erl2
-rw-r--r--test/rebar_dialyzer_SUITE.erl158
-rw-r--r--test/rebar_xref_SUITE.erl190
3 files changed, 349 insertions, 1 deletions
diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl
index 502e184..ab2c0d3 100644
--- a/test/mock_pkg_resource.erl
+++ b/test/mock_pkg_resource.erl
@@ -78,7 +78,7 @@ mock_download(Opts) ->
App = binary_to_list(AppBin),
filelib:ensure_dir(Dir),
AppDeps = proplists:get_value({App,Vsn}, Deps, []),
- {ok, AppInfo} = rebar_test_utils:create_app(
+ {ok, AppInfo} = rebar_test_utils:create_empty_app(
Dir, App, Vsn,
[element(1,D) || D <- AppDeps]
),
diff --git a/test/rebar_dialyzer_SUITE.erl b/test/rebar_dialyzer_SUITE.erl
new file mode 100644
index 0000000..724d8f0
--- /dev/null
+++ b/test/rebar_dialyzer_SUITE.erl
@@ -0,0 +1,158 @@
+-module(rebar_dialyzer_SUITE).
+
+-export([suite/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_testcase/2,
+ all/0,
+ update_base_plt/1,
+ update_app_plt/1,
+ build_release_plt/1]).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("kernel/include/file.hrl").
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(Testcase, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Prefix = ec_cnv:to_list(Testcase),
+ Plt = filename:join(PrivDir, Prefix ++ ".project.plt"),
+ BasePlt = Prefix ++ "base.plt",
+ RebarConfig = [{dialyzer_plt, Plt},
+ {dialyzer_base_plt, BasePlt},
+ {dialyzer_base_plt_dir, PrivDir},
+ {dialyzer_base_plt_apps, [erts]}],
+ [{plt, Plt},
+ {base_plt, filename:join(PrivDir, BasePlt)},
+ {rebar_config, RebarConfig} |
+ rebar_test_utils:init_rebar_state(Config)].
+
+all() ->
+ [update_base_plt, update_app_plt, build_release_plt].
+
+update_base_plt(Config) ->
+ AppDir = ?config(apps, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ BasePlt = ?config(base_plt, Config),
+ Plt = ?config(plt, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ ErtsFiles = erts_files(),
+
+ {ok, BasePltFiles} = plt_files(BasePlt),
+ ?assertEqual(ErtsFiles, BasePltFiles),
+
+ alter_plt(BasePlt),
+ ok = file:delete(Plt),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ {ok, BasePltFiles2} = plt_files(BasePlt),
+ ?assertEqual(ErtsFiles, BasePltFiles2),
+
+ {ok, PltFiles} = plt_files(Plt),
+ ?assertEqual(ErtsFiles, PltFiles).
+
+
+update_app_plt(Config) ->
+ AppDir = ?config(apps, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ Plt = ?config(plt, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ ErtsFiles = erts_files(),
+
+ {ok, PltFiles} = plt_files(Plt),
+ ?assertEqual(ErtsFiles, PltFiles),
+
+ alter_plt(Plt),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ {ok, PltFiles2} = plt_files(Plt),
+ ?assertEqual(ErtsFiles, PltFiles2),
+
+ ok = file:delete(Plt),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ {ok, PltFiles3} = plt_files(Plt),
+ ?assertEqual(ErtsFiles, PltFiles3).
+
+build_release_plt(Config) ->
+ AppDir = ?config(apps, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ BasePlt = ?config(base_plt, Config),
+ Plt = ?config(plt, Config),
+
+ Name1 = rebar_test_utils:create_random_name("relapp1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([AppDir,Name1]), Name1, Vsn1,
+ [erts]),
+ Name2 = rebar_test_utils:create_random_name("relapp2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([AppDir,Name2]), Name2, Vsn2,
+ [erts, ec_cnv:to_atom(Name1)]),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
+ {ok, [{app, Name1}, {app, Name2}]}),
+
+ ErtsFiles = erts_files(),
+
+ {ok, BasePltFiles} = plt_files(BasePlt),
+ ?assertEqual(ErtsFiles, BasePltFiles),
+
+ {ok, PltFiles} = plt_files(Plt),
+ ?assertEqual(ErtsFiles, PltFiles).
+
+%% Helpers
+
+erts_files() ->
+ ErtsDir = code:lib_dir(erts, ebin),
+ ErtsBeams = filelib:wildcard("*.beam", ErtsDir),
+ ErtsFiles = lists:map(fun(Beam) -> filename:join(ErtsDir, Beam) end,
+ ErtsBeams),
+ lists:sort(ErtsFiles).
+
+plt_files(Plt) ->
+ case dialyzer:plt_info(Plt) of
+ {ok, Info} ->
+ Files = proplists:get_value(files, Info),
+ {ok, lists:sort(Files)};
+ Other ->
+ Other
+ end.
+
+alter_plt(Plt) ->
+ {ok, Files} = plt_files(Plt),
+ _ = dialyzer:run([{analysis_type, plt_remove},
+ {init_plt, Plt},
+ {files, [hd(Files)]}]),
+ _ = dialyzer:run([{analysis_type, plt_add},
+ {init_plt, Plt},
+ {files, [code:which(dialyzer)]}]),
+ ok.
diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl
new file mode 100644
index 0000000..fde8c8f
--- /dev/null
+++ b/test/rebar_xref_SUITE.erl
@@ -0,0 +1,190 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_xref_SUITE).
+
+-export([suite/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_testcase/2,
+ end_per_testcase/2,
+ all/0,
+ xref_test/1,
+ xref_ignore_test/1]).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("kernel/include/file.hrl").
+
+%% ===================================================================
+%% common_test callbacks
+%% ===================================================================
+
+suite() ->
+ [].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(Case, Config) ->
+ UpdConfig = rebar_test_utils:init_rebar_state(Config),
+ AppDir = ?config(apps, UpdConfig),
+ {ok, OrigDir} = file:get_cwd(),
+ file:set_cwd(AppDir),
+ Name = rebar_test_utils:create_random_name("xrefapp_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_empty_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ AppModules = [behaviour1, behaviour2, mymod, othermod],
+ [write_src_file(AppDir, Name, Module, ignore_xref(Case)) || Module <- AppModules],
+ RebarConfig = [{erl_opts, [debug_info]},
+ {xref_checks, [deprecated_function_calls,deprecated_functions,
+ undefined_function_calls,undefined_functions,
+ exports_not_used,locals_not_used]}],
+ [{app_name, Name},
+ {rebar_config, RebarConfig},
+ {orig_dir, OrigDir} | UpdConfig].
+
+end_per_testcase(_, Config) ->
+ ?debugMsg("End test case cleanup"),
+ AppDir = ?config(apps, Config),
+ OrigDir = ?config(orig_dir, Config),
+ %% Code path cleanup because we set the CWD to the `AppDir' prior
+ %% to launching rebar and these paths make it into the code path
+ %% before the xref module executes so they don't get cleaned up
+ %% automatically after the xref run. Only have to do this because
+ %% we are about to remove the directory and there may be
+ %% subsequent test cases that error out when the code path tries
+ %% to include one of these soon-to-be nonexistent directories.
+ true = code:del_path(AppDir ++ "/."),
+ true = code:del_path(rebar_dir:ebin_dir()),
+ file:set_cwd(OrigDir),
+ ec_file:remove(AppDir, [recursive]),
+ ok.
+
+all() ->
+ [xref_test, xref_ignore_test].
+
+%% ===================================================================
+%% Test cases
+%% ===================================================================
+
+xref_test(Config) ->
+ AppDir = ?config(apps, Config),
+ State = ?config(state, Config),
+ Name = ?config(app_name, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
+ verify_results(xref_test, Name, Result).
+
+xref_ignore_test(Config) ->
+ AppDir = ?config(apps, Config),
+ State = ?config(state, Config),
+ Name = ?config(app_name, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
+ verify_results(xref_ignore_test, Name, Result).
+
+%% ===================================================================
+%% Helper functions
+%% ===================================================================
+
+ignore_xref(xref_ignore_test) ->
+ true;
+ignore_xref(_) ->
+ false.
+
+verify_results(TestCase, AppName, Results) ->
+ {error, {rebar_prv_xref,
+ {xref_issues, XrefResults, QueryResults}}} = Results,
+ verify_test_results(TestCase, AppName, XrefResults, QueryResults).
+
+verify_test_results(xref_test, AppName, XrefResults, _QueryResults) ->
+ AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
+ [Behaviour1Mod, Behaviour2Mod, MyMod, OtherMod, SomeMod] =
+ [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
+ UndefFuns = proplists:get_value(undefined_functions, XrefResults),
+ UndefFunCalls = proplists:get_value(undefined_function_calls, XrefResults),
+ LocalsNotUsed = proplists:get_value(locals_not_used, XrefResults),
+ ExportsNotUsed = proplists:get_value(exports_not_used, XrefResults),
+ DeprecatedFuns = proplists:get_value(deprecated_functions, XrefResults),
+ DeprecatedFunCalls = proplists:get_value(deprecated_function_calls, XrefResults),
+ ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {SomeMod, notavailable, 1}},
+ UndefFunCalls)),
+ ?assert(lists:member({MyMod, fdeprecated, 0}, DeprecatedFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {MyMod, fdeprecated, 0}},
+ DeprecatedFunCalls)),
+ ?assert(lists:member({MyMod, localfunc2, 0}, LocalsNotUsed)),
+ ?assert(lists:member({Behaviour1Mod, behaviour_info, 1}, ExportsNotUsed)),
+ ?assert(lists:member({Behaviour2Mod, behaviour_info, 1}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, other2, 1}, ExportsNotUsed)),
+ ?assert(lists:member({OtherMod, somefunc, 0}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh1_a, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh1_b, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
+ ok;
+verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) ->
+ AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
+ [Behaviour1Mod, Behaviour2Mod, MyMod, OtherMod, SomeMod] =
+ [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
+ UndefFuns = proplists:get_value(undefined_functions, XrefResults),
+ ?assertNot(lists:keymember(undefined_function_calls, 1, XrefResults)),
+ ?assertNot(lists:keymember(locals_not_used, 1, XrefResults)),
+ ?assertNot(lists:keymember(exports_not_used, 1, XrefResults)),
+ ?assertNot(lists:keymember(deprecated_functions, 1, XrefResults)),
+ ?assertNot(lists:keymember(deprecated_function_calls, 1, XrefResults)),
+ ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
+ ok.
+
+write_src_file(Dir, AppName, Module, IgnoreXref) ->
+ Erl = filename:join([Dir, "src", module_name(AppName, Module)]),
+ ok = filelib:ensure_dir(Erl),
+ ok = ec_file:write(Erl, get_module_body(Module, AppName, IgnoreXref)).
+
+module_name(AppName, Module) ->
+ lists:flatten([AppName, "_", atom_to_list(Module), ".erl"]).
+
+get_module_body(behaviour1, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_behaviour1).\n",
+ "-export([behaviour_info/1]).\n",
+ ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
+ "behaviour_info(callbacks) -> [{bh1_a,1},{bh1_b,1}];\n",
+ "behaviour_info(_Other) -> undefined.\n"];
+get_module_body(behaviour2, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_behaviour2).\n",
+ "-export([behaviour_info/1]).\n",
+ ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
+ "behaviour_info(callbacks) -> [{bh2_a,1},{bh2_b,1}];\n",
+ "behaviour_info(_Other) -> undefined.\n"];
+get_module_body(mymod, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_mymod).\n",
+ "-export([bh1_a/1,bh1_b/1,bh2_a/1,bh2_b/1,"
+ "other1/1,other2/1,fdeprecated/0]).\n",
+ ["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"
+ || X <- [IgnoreXref], X =:= true],
+ "-behaviour(", AppName, "_behaviour1).\n", % 2 behaviours
+ "-behaviour(", AppName, "_behaviour2).\n",
+ "-deprecated({fdeprecated,0}).\n", % deprecated function
+ "bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions
+ "bh1_b(A) -> localfunc1(bh1_b, A).\n",
+ "bh2_a(A) -> localfunc1(bh2_a, A).\n",
+ "bh2_b(A) -> localfunc1(bh2_b, A).\n",
+ "other1(A) -> localfunc1(other1, A).\n", % regular exported functions
+ "other2(A) -> localfunc1(other2, A).\n",
+ "localfunc1(A, B) -> {A, B}.\n", % used local
+ "localfunc2() -> ok.\n", % unused local
+ "fdeprecated() -> ok.\n" % deprecated function
+ ];
+get_module_body(othermod, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_othermod).\n",
+ "-export([somefunc/0]).\n",
+ [["-ignore_xref([{", AppName, "_somemod,notavailable,1},{somefunc,0}]).\n",
+ "-ignore_xref({", AppName, "_mymod,fdeprecated,0}).\n"]
+ || X <- [IgnoreXref], X =:= true],
+ "somefunc() ->\n",
+ " ", AppName, "_mymod:other1(arg),\n",
+ " ", AppName, "_somemod:notavailable(arg),\n",
+ " ", AppName, "_mymod:fdeprecated().\n"].