diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/mock_pkg_resource.erl | 2 | ||||
-rw-r--r-- | test/rebar_dialyzer_SUITE.erl | 158 | ||||
-rw-r--r-- | test/rebar_xref_SUITE.erl | 190 |
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"]. |