Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

191 Zeilen
8.5 KiB

  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. -module(rebar_xref_SUITE).
  4. -export([suite/0,
  5. init_per_suite/1,
  6. end_per_suite/1,
  7. init_per_testcase/2,
  8. end_per_testcase/2,
  9. all/0,
  10. xref_test/1,
  11. xref_ignore_test/1]).
  12. -include_lib("common_test/include/ct.hrl").
  13. -include_lib("eunit/include/eunit.hrl").
  14. -include_lib("kernel/include/file.hrl").
  15. %% ===================================================================
  16. %% common_test callbacks
  17. %% ===================================================================
  18. suite() ->
  19. [].
  20. init_per_suite(Config) ->
  21. Config.
  22. end_per_suite(_Config) ->
  23. ok.
  24. init_per_testcase(Case, Config) ->
  25. UpdConfig = rebar_test_utils:init_rebar_state(Config),
  26. AppDir = ?config(apps, UpdConfig),
  27. {ok, OrigDir} = file:get_cwd(),
  28. file:set_cwd(AppDir),
  29. Name = rebar_test_utils:create_random_name("xrefapp_"),
  30. Vsn = rebar_test_utils:create_random_vsn(),
  31. rebar_test_utils:create_empty_app(AppDir, Name, Vsn, [kernel, stdlib]),
  32. AppModules = [behaviour1, behaviour2, mymod, othermod],
  33. [write_src_file(AppDir, Name, Module, ignore_xref(Case)) || Module <- AppModules],
  34. RebarConfig = [{erl_opts, [debug_info]},
  35. {xref_checks, [deprecated_function_calls,deprecated_functions,
  36. undefined_function_calls,undefined_functions,
  37. exports_not_used,locals_not_used]}],
  38. [{app_name, Name},
  39. {rebar_config, RebarConfig},
  40. {orig_dir, OrigDir} | UpdConfig].
  41. end_per_testcase(_, Config) ->
  42. ?debugMsg("End test case cleanup"),
  43. AppDir = ?config(apps, Config),
  44. OrigDir = ?config(orig_dir, Config),
  45. %% Code path cleanup because we set the CWD to the `AppDir' prior
  46. %% to launching rebar and these paths make it into the code path
  47. %% before the xref module executes so they don't get cleaned up
  48. %% automatically after the xref run. Only have to do this because
  49. %% we are about to remove the directory and there may be
  50. %% subsequent test cases that error out when the code path tries
  51. %% to include one of these soon-to-be nonexistent directories.
  52. Name = ?config(app_name, Config),
  53. EbinDir = filename:join([AppDir, "_build", "default" "lib", Name, "ebin"]),
  54. true = code:del_path(EbinDir),
  55. file:set_cwd(OrigDir),
  56. ec_file:remove(AppDir, [recursive]),
  57. ok.
  58. all() ->
  59. [xref_test, xref_ignore_test].
  60. %% ===================================================================
  61. %% Test cases
  62. %% ===================================================================
  63. xref_test(Config) ->
  64. AppDir = ?config(apps, Config),
  65. State = ?config(state, Config),
  66. Name = ?config(app_name, Config),
  67. RebarConfig = ?config(rebar_config, Config),
  68. Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
  69. verify_results(xref_test, Name, Result).
  70. xref_ignore_test(Config) ->
  71. AppDir = ?config(apps, Config),
  72. State = ?config(state, Config),
  73. Name = ?config(app_name, Config),
  74. RebarConfig = ?config(rebar_config, Config),
  75. Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
  76. verify_results(xref_ignore_test, Name, Result).
  77. %% ===================================================================
  78. %% Helper functions
  79. %% ===================================================================
  80. ignore_xref(xref_ignore_test) ->
  81. true;
  82. ignore_xref(_) ->
  83. false.
  84. verify_results(TestCase, AppName, Results) ->
  85. {error, {rebar_prv_xref,
  86. {xref_issues, XrefResults, QueryResults}}} = Results,
  87. verify_test_results(TestCase, AppName, XrefResults, QueryResults).
  88. verify_test_results(xref_test, AppName, XrefResults, _QueryResults) ->
  89. AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
  90. [Behaviour1Mod, Behaviour2Mod, MyMod, OtherMod, SomeMod] =
  91. [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
  92. UndefFuns = proplists:get_value(undefined_functions, XrefResults),
  93. UndefFunCalls = proplists:get_value(undefined_function_calls, XrefResults),
  94. LocalsNotUsed = proplists:get_value(locals_not_used, XrefResults),
  95. ExportsNotUsed = proplists:get_value(exports_not_used, XrefResults),
  96. DeprecatedFuns = proplists:get_value(deprecated_functions, XrefResults),
  97. DeprecatedFunCalls = proplists:get_value(deprecated_function_calls, XrefResults),
  98. ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
  99. ?assert(lists:member({{OtherMod, somefunc, 0}, {SomeMod, notavailable, 1}},
  100. UndefFunCalls)),
  101. ?assert(lists:member({MyMod, fdeprecated, 0}, DeprecatedFuns)),
  102. ?assert(lists:member({{OtherMod, somefunc, 0}, {MyMod, fdeprecated, 0}},
  103. DeprecatedFunCalls)),
  104. ?assert(lists:member({MyMod, localfunc2, 0}, LocalsNotUsed)),
  105. ?assert(lists:member({Behaviour1Mod, behaviour_info, 1}, ExportsNotUsed)),
  106. ?assert(lists:member({Behaviour2Mod, behaviour_info, 1}, ExportsNotUsed)),
  107. ?assert(lists:member({MyMod, other2, 1}, ExportsNotUsed)),
  108. ?assert(lists:member({OtherMod, somefunc, 0}, ExportsNotUsed)),
  109. ?assertNot(lists:member({MyMod, bh1_a, 1}, ExportsNotUsed)),
  110. ?assertNot(lists:member({MyMod, bh1_b, 1}, ExportsNotUsed)),
  111. ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
  112. ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
  113. ok;
  114. verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) ->
  115. AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
  116. [Behaviour1Mod, Behaviour2Mod, MyMod, OtherMod, SomeMod] =
  117. [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
  118. UndefFuns = proplists:get_value(undefined_functions, XrefResults),
  119. ?assertNot(lists:keymember(undefined_function_calls, 1, XrefResults)),
  120. ?assertNot(lists:keymember(locals_not_used, 1, XrefResults)),
  121. ?assertNot(lists:keymember(exports_not_used, 1, XrefResults)),
  122. ?assertNot(lists:keymember(deprecated_functions, 1, XrefResults)),
  123. ?assertNot(lists:keymember(deprecated_function_calls, 1, XrefResults)),
  124. ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
  125. ok.
  126. write_src_file(Dir, AppName, Module, IgnoreXref) ->
  127. Erl = filename:join([Dir, "src", module_name(AppName, Module)]),
  128. ok = filelib:ensure_dir(Erl),
  129. ok = ec_file:write(Erl, get_module_body(Module, AppName, IgnoreXref)).
  130. module_name(AppName, Module) ->
  131. lists:flatten([AppName, "_", atom_to_list(Module), ".erl"]).
  132. get_module_body(behaviour1, AppName, IgnoreXref) ->
  133. ["-module(", AppName, "_behaviour1).\n",
  134. "-export([behaviour_info/1]).\n",
  135. ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
  136. "behaviour_info(callbacks) -> [{bh1_a,1},{bh1_b,1}];\n",
  137. "behaviour_info(_Other) -> undefined.\n"];
  138. get_module_body(behaviour2, AppName, IgnoreXref) ->
  139. ["-module(", AppName, "_behaviour2).\n",
  140. "-export([behaviour_info/1]).\n",
  141. ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
  142. "behaviour_info(callbacks) -> [{bh2_a,1},{bh2_b,1}];\n",
  143. "behaviour_info(_Other) -> undefined.\n"];
  144. get_module_body(mymod, AppName, IgnoreXref) ->
  145. ["-module(", AppName, "_mymod).\n",
  146. "-export([bh1_a/1,bh1_b/1,bh2_a/1,bh2_b/1,"
  147. "other1/1,other2/1,fdeprecated/0]).\n",
  148. ["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"
  149. || X <- [IgnoreXref], X =:= true],
  150. "-behaviour(", AppName, "_behaviour1).\n", % 2 behaviours
  151. "-behaviour(", AppName, "_behaviour2).\n",
  152. "-deprecated({fdeprecated,0}).\n", % deprecated function
  153. "bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions
  154. "bh1_b(A) -> localfunc1(bh1_b, A).\n",
  155. "bh2_a(A) -> localfunc1(bh2_a, A).\n",
  156. "bh2_b(A) -> localfunc1(bh2_b, A).\n",
  157. "other1(A) -> localfunc1(other1, A).\n", % regular exported functions
  158. "other2(A) -> localfunc1(other2, A).\n",
  159. "localfunc1(A, B) -> {A, B}.\n", % used local
  160. "localfunc2() -> ok.\n", % unused local
  161. "fdeprecated() -> ok.\n" % deprecated function
  162. ];
  163. get_module_body(othermod, AppName, IgnoreXref) ->
  164. ["-module(", AppName, "_othermod).\n",
  165. "-export([somefunc/0]).\n",
  166. [["-ignore_xref([{", AppName, "_somemod,notavailable,1},{somefunc,0}]).\n",
  167. "-ignore_xref({", AppName, "_mymod,fdeprecated,0}).\n"]
  168. || X <- [IgnoreXref], X =:= true],
  169. "somefunc() ->\n",
  170. " ", AppName, "_mymod:other1(arg),\n",
  171. " ", AppName, "_somemod:notavailable(arg),\n",
  172. " ", AppName, "_mymod:fdeprecated().\n"].