1%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
2%% ex: ts=4 sw=4 et
3-module(rebar_xref_eunit).
4
5-compile(export_all).
6
7-include_lib("eunit/include/eunit.hrl").
8
9-define(REBAR_SCRIPT, "../rebar").
10
11-define(TMP_DIR, "tmp_xref_eunit/").
12
13xref_test_() ->
14    {"Test the various xref warnings",
15     setup, fun() -> setup_project(false), rebar("compile"), rebar("skip_deps=true xref") end,
16     fun teardown/1,
17     fun(RebarOut) ->
18             [
19              {"Undefined function", ?_assert(string:str(RebarOut,
20                "myapp_somemod:notavailable/1 is undefined function") =/= 0)},
21              {"Undefined function call", ?_assert(string:str(RebarOut,
22                "myapp_othermod:somefunc/0 calls undefined function myapp_somemod:notavailable/1") =/= 0)},
23              {"Deprecated function", ?_assert(string:str(RebarOut,
24                "myapp_mymod:fdeprecated/0 is deprecated function") =/= 0)},
25              {"Deprecated function call", ?_assert(string:str(RebarOut,
26                "myapp_othermod:somefunc/0 calls deprecated function myapp_mymod:fdeprecated/0") =/= 0)},
27              {"Unused local", ?_assert(string:str(RebarOut,
28                "myapp_mymod:localfunc2/0 is unused local function") =/= 0)},
29              {"Unused export 1", ?_assert(string:str(RebarOut,
30                "myapp_behaviour1:behaviour_info/1 is unused export") =/= 0)},
31              {"Unused export 2", ?_assert(string:str(RebarOut,
32                "myapp_behaviour2:behaviour_info/1 is unused export") =/= 0)},
33              {"Unused export 3", ?_assert(string:str(RebarOut,
34                "myapp_mymod:other2/1 is unused export") =/= 0)},
35              {"Unused export 4", ?_assert(string:str(RebarOut,
36                "myapp_othermod:somefunc/0 is unused export") =/= 0)},
37              {"Suppressed behaviour export 1", ?_assert(string:str(RebarOut,
38                "myapp_mymod:bh1_a/1 is unused export") =:= 0)},
39              {"Suppressed behaviour export 2", ?_assert(string:str(RebarOut,
40                "myapp_mymod:bh1_b/1 is unused export") =:= 0)},
41              {"Suppressed behaviour export 3", ?_assert(string:str(RebarOut,
42                "myapp_mymod:bh2_a/1 is unused export") =:= 0)},
43              {"Suppressed behaviour export 4", ?_assert(string:str(RebarOut,
44                "myapp_mymod:bh2_b/1 is unused export") =:= 0)}
45            ]
46     end}.
47
48xref_ignore_test_() ->
49    {"Test the suppression of xref warnings",
50     setup, fun() -> setup_project(ignore_xref), rebar("compile"), rebar("skip_deps=true xref") end,
51     fun teardown/1,
52     fun(RebarOut) ->
53             [
54              {"Undefined function can not be suppressed.", ?_assert(string:str(RebarOut,
55                "myapp_somemod:notavailable/1 is undefined function") =/= 0)},
56              {"Supppressed undefined function call", ?_assert(string:str(RebarOut,
57                "myapp_othermod:somefunc/0 calls undefined function myapp_somemod:notavailable/1") =:= 0)},
58              {"Supppressed deprecated function", ?_assert(string:str(RebarOut,
59                "myapp_mymod:fdeprecated/0 is deprecated function") =:= 0)},
60              {"Supppressed deprecated function call", ?_assert(string:str(RebarOut,
61                "myapp_othermod:somefunc/0 calls deprecated function myapp_mymod:fdeprecated/0") =:= 0)},
62              {"Supppressed unused local", ?_assert(string:str(RebarOut,
63                "myapp_mymod:localfunc2/0 is unused local function") =:= 0)},
64              {"Supppressed unused export 1", ?_assert(string:str(RebarOut,
65                "myapp_behaviour1:behaviour_info/1 is unused export") =:= 0)},
66              {"Supppressed unused export 2", ?_assert(string:str(RebarOut,
67                "myapp_behaviour2:behaviour_info/1 is unused export") =:= 0)},
68              {"Supppressed unused export 3", ?_assert(string:str(RebarOut,
69                "myapp_mymod:other2/1 is unused export") =:= 0)},
70              {"Supppressed unused export 4", ?_assert(string:str(RebarOut,
71                "myapp_othermod:somefunc/0 is unused export") =:= 0)},
72              {"Suppressed behaviour export 1", ?_assert(string:str(RebarOut,
73                "myapp_mymod:bh1_a/1 is unused export") =:= 0)},
74              {"Suppressed behaviour export 2", ?_assert(string:str(RebarOut,
75                "myapp_mymod:bh1_b/1 is unused export") =:= 0)},
76              {"Suppressed behaviour export 3", ?_assert(string:str(RebarOut,
77                "myapp_mymod:bh2_a/1 is unused export") =:= 0)},
78              {"Suppressed behaviour export 4", ?_assert(string:str(RebarOut,
79                "myapp_mymod:bh2_b/1 is unused export") =:= 0)}
80            ]
81
82     end}.
83
84
85%% ====================================================================
86%% Setup and Teardown
87%% ====================================================================
88
89-define(myapp_behaviour1,
90        ["-module(myapp_behaviour1).\n",
91         "-export([behaviour_info/1]).\n"]).
92-define(myapp_behaviour1_body,
93        ["behaviour_info(callbacks) -> [{bh1_a,1},{bh1_b,1}];\n",
94         "behaviour_info(_Other) -> undefined.\n"]).
95-define(myapp_behaviour1_ignorexref,
96        ["-ignore_xref({behaviour_info,1}).\n"]).
97
98-define(myapp_behaviour2,
99        ["-module(myapp_behaviour2).\n",
100         "-export([behaviour_info/1]).\n"]).
101-define(myapp_behaviour2_body,
102        ["behaviour_info(callbacks) -> [{bh2_a,1},{bh2_b,1}];\n",
103         "behaviour_info(_Other) -> undefined.\n"]).
104-define(myapp_behaviour2_ignorexref,
105        ["-ignore_xref({behaviour_info,1}).\n"]).
106
107-define(myapp_mymod,
108        ["-module(myapp_mymod).\n",
109         "-export([bh1_a/1,bh1_b/1,bh2_a/1,bh2_b/1,other1/1,other2/1,fdeprecated/0]).\n",
110         "-behaviour(myapp_behaviour1).\n",     % 2 behaviours
111         "-behaviour(myapp_behaviour2).\n",
112         "-deprecated({fdeprecated,0}).\n"]).      % deprecated function
113-define(myapp_mymod_body,
114        ["bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions
115         "bh1_b(A) -> localfunc1(bh1_b, A).\n",
116         "bh2_a(A) -> localfunc1(bh2_a, A).\n",
117         "bh2_b(A) -> localfunc1(bh2_b, A).\n",
118         "other1(A) -> localfunc1(other1, A).\n", % regular exported functions
119         "other2(A) -> localfunc1(other2, A).\n",
120         "localfunc1(A, B) -> {A, B}.\n",       % used local
121         "localfunc2() -> ok.\n",               % unused local
122         "fdeprecated() -> ok.\n"              % deprecated function
123         ]).
124-define(myapp_mymod_ignorexref,
125        ["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"]).
126
127
128
129-define(myapp_othermod,
130        ["-module(myapp_othermod).\n",
131         "-export([somefunc/0]).\n"]).
132-define(myapp_othermod_body,
133        ["somefunc() ->\n",
134         "   myapp_mymod:other1(arg),\n",
135         "   myapp_somemod:notavailable(arg),\n",
136         "   myapp_mymod:fdeprecated().\n"
137         ]).
138-define(myapp_othermod_ignorexref,
139        ["-ignore_xref([{myapp_somemod,notavailable,1},{somefunc,0}]).\n",
140         "-ignore_xref({myapp_mymod,fdeprecated,0}).\n"]).
141
142
143-define(myapp_rebarconfig,
144        ["{erl_opts, [debug_info]}.\n",
145         "{xref_checks, [deprecated_function_calls,deprecated_functions,\n",
146         "               undefined_function_calls,undefined_functions,\n",
147         "               exports_not_used,locals_not_used]}.\n"
148         ]).
149
150setup_environment() ->
151    ok = file:make_dir(?TMP_DIR),
152    prepare_rebar_script(),
153    ok = file:set_cwd(?TMP_DIR).
154
155prepare_project() ->
156    setup_environment(),
157    rebar("create-app appid=myapp"),
158    ok = file:make_dir("ebin").
159
160setup_project(ignore_xref) ->
161    prepare_project(),
162    ok = file:write_file("src/myapp_behaviour1.erl", ?myapp_behaviour1 ++ ?myapp_behaviour1_ignorexref ++ ?myapp_behaviour1_body),
163    ok = file:write_file("src/myapp_behaviour2.erl", ?myapp_behaviour2 ++ ?myapp_behaviour2_ignorexref++ ?myapp_behaviour2_body),
164    ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod ++ ?myapp_mymod_ignorexref ++ ?myapp_mymod_body),
165    ok = file:write_file("src/myapp_othermod.erl", ?myapp_othermod ++ ?myapp_othermod_ignorexref ++ ?myapp_othermod_body),
166    ok = file:write_file("rebar.config", ?myapp_rebarconfig);
167
168setup_project(_) ->
169    prepare_project(),
170    ok = file:write_file("src/myapp_behaviour1.erl", ?myapp_behaviour1 ++ ?myapp_behaviour1_body),
171    ok = file:write_file("src/myapp_behaviour2.erl", ?myapp_behaviour2 ++ ?myapp_behaviour2_body),
172    ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod ++ ?myapp_mymod_body),
173    ok = file:write_file("src/myapp_othermod.erl", ?myapp_othermod ++ ?myapp_othermod_body),
174    ok = file:write_file("rebar.config", ?myapp_rebarconfig).
175
176
177teardown(_) ->
178    ok = file:set_cwd(".."),
179    ok = remove_tmp_dir().
180
181remove_tmp_dir() ->
182    ok = rebar_file_utils:rm_rf(?TMP_DIR).
183
184%% ====================================================================
185%% Helper Functions
186%% ====================================================================
187
188prepare_rebar_script() ->
189    Rebar = ?TMP_DIR ++ "rebar",
190    {ok, _} = file:copy(?REBAR_SCRIPT, Rebar),
191    case os:type() of
192        {unix, _} ->
193            [] = os:cmd("chmod u+x " ++ Rebar);
194        {win32, _} ->
195            {ok, _} = file:copy(?REBAR_SCRIPT ++ ".cmd",
196                                ?TMP_DIR ++ "rebar.cmd")
197    end.
198
199rebar() ->
200    rebar([]).
201
202rebar(Args) when is_list(Args) ->
203    Out = os:cmd(filename:nativename("./rebar") ++ " " ++ Args),
204    %% ?debugMsg("**** Begin"), ?debugMsg(Out), ?debugMsg("**** End"),
205    Out.
206