4
%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
6
%% The contents of this file are subject to the Erlang Public License,
7
%% Version 1.1, (the "License"); you may not use this file except in
8
%% compliance with the License. You should have received a copy of the
9
%% Erlang Public License along with this software. If not, it can be
10
%% retrieved online at http://www.erlang.org/.
12
%% Software distributed under the License is distributed on an "AS IS"
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
%% the License for the specific language governing rights and limitations
20
%%----------------------------------------------------------------------
21
%% Purpose: Verify the application specifics of the inets application
22
%%----------------------------------------------------------------------
23
-module(inets_app_test).
27
-include("inets_test_lib.hrl").
30
% t() -> megaco_test_lib:t(?MODULE).
31
% t(Case) -> megaco_test_lib:t({?MODULE, Case}).
34
%% Test server callbacks
35
init_per_testcase(undef_funcs, Config) ->
36
NewConfig = lists:keydelete(watchdog, 1, Config),
37
Dog = test_server:timetrap(inets_test_lib:minutes(10)),
38
[{watchdog, Dog}| NewConfig];
39
init_per_testcase(_, Config) ->
42
end_per_testcase(_Case, Config) ->
45
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48
[fields, modules, exportall, app_depend,
54
init_per_group(_GroupName, Config) ->
57
end_per_group(_GroupName, Config) ->
62
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
init_per_suite(suite) -> [];
65
init_per_suite(doc) -> [];
66
init_per_suite(Config) when is_list(Config) ->
69
io:format("AppFile: ~n~p~n", [AppFile]),
70
inets:print_version_info(),
71
[{app_file, AppFile}|Config];
77
LibDir = code:lib_dir(App),
78
File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
79
case file:consult(File) of
80
{ok, [{application, App, AppFile}]} ->
83
{error, {invalid_format, Error}}
87
end_per_suite(suite) -> [];
88
end_per_suite(doc) -> [];
89
end_per_suite(Config) when is_list(Config) ->
93
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99
fields(Config) when is_list(Config) ->
100
AppFile = key1search(app_file, Config),
101
Fields = [vsn, description, modules, registered, applications],
102
case check_fields(Fields, AppFile, []) of
106
fail({missing_fields, Missing})
109
check_fields([], _AppFile, Missing) ->
111
check_fields([Field|Fields], AppFile, Missing) ->
112
check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
114
check_field(Name, AppFile, Missing) ->
115
io:format("checking field: ~p~n", [Name]),
116
case lists:keymember(Name, 1, AppFile) of
124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130
modules(Config) when is_list(Config) ->
131
AppFile = key1search(app_file, Config),
132
Mods = key1search(modules, AppFile),
133
EbinList = get_ebin_mods(inets),
134
case missing_modules(Mods, EbinList, []) of
138
throw({error, {missing_modules, Missing}})
140
case extra_modules(Mods, EbinList, []) of
144
throw({error, {extra_modules, Extra}})
148
get_ebin_mods(App) ->
149
LibDir = code:lib_dir(App),
150
EbinDir = filename:join([LibDir,"ebin"]),
151
{ok, Files0} = file:list_dir(EbinDir),
152
Files1 = [lists:reverse(File) || File <- Files0],
153
[list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
156
missing_modules([], _Ebins, Missing) ->
158
missing_modules([Mod|Mods], Ebins, Missing) ->
159
case lists:member(Mod, Ebins) of
161
missing_modules(Mods, Ebins, Missing);
163
io:format("missing module: ~p~n", [Mod]),
164
missing_modules(Mods, Ebins, [Mod|Missing])
168
extra_modules(_Mods, [], Extra) ->
170
extra_modules(Mods, [Mod|Ebins], Extra) ->
171
case lists:member(Mod, Mods) of
173
extra_modules(Mods, Ebins, Extra);
175
io:format("supefluous module: ~p~n", [Mod]),
176
extra_modules(Mods, Ebins, [Mod|Extra])
180
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
exportall(Config) when is_list(Config) ->
188
AppFile = key1search(app_file, Config),
189
Mods = key1search(modules, AppFile),
190
check_export_all(Mods).
193
check_export_all([]) ->
195
check_export_all([Mod|Mods]) ->
196
case (catch apply(Mod, module_info, [compile])) of
197
{'EXIT', {undef, _}} ->
198
check_export_all(Mods);
200
case lists:keysearch(options, 1, O) of
202
check_export_all(Mods);
203
{value, {options, List}} ->
204
case lists:member(export_all, List) of
206
throw({error, {export_all, Mod}});
208
check_export_all(Mods)
214
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220
app_depend(Config) when is_list(Config) ->
221
AppFile = key1search(app_file, Config),
222
Apps = key1search(applications, AppFile),
228
check_apps([App|Apps]) ->
233
throw({error, {missing_app, {App, Error}}})
237
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239
undef_funcs(suite) ->
243
undef_funcs(Config) when is_list(Config) ->
245
AppFile = key1search(app_file, Config),
246
Mods = key1search(modules, AppFile),
247
Root = code:root_dir(),
248
LibDir = code:lib_dir(App),
249
EbinDir = filename:join([LibDir,"ebin"]),
250
XRefTestName = undef_funcs_make_name(App, xref_test_name),
251
{ok, XRef} = xref:start(XRefTestName),
252
ok = xref:set_default(XRef,
253
[{verbose,false},{warnings,false}]),
254
XRefName = undef_funcs_make_name(App, xref_name),
255
{ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
256
{ok, App} = xref:replace_application(XRef, App, EbinDir),
257
{ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
259
analyze_undefined_function_calls(Undefs, Mods, []).
261
analyze_undefined_function_calls([], _, []) ->
263
analyze_undefined_function_calls([], _, AppUndefs) ->
264
exit({suite_failed, {undefined_function_calls, AppUndefs}});
265
analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
266
AppModules, AppUndefs) ->
267
%% Check that this module is our's
268
case lists:member(Mod,AppModules) of
270
{Calling,Called} = AppUndef,
271
{Mod1,Func1,Ar1} = Calling,
272
{Mod2,Func2,Ar2} = Called,
273
io:format("undefined function call: "
274
"~n ~w:~w/~w calls ~w:~w/~w~n",
275
[Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
276
analyze_undefined_function_calls(Undefs, AppModules,
277
[AppUndef|AppUndefs]);
279
io:format("dropping ~p~n", [Mod]),
280
analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
283
%% This function is used simply to avoid cut-and-paste errors later...
284
undef_funcs_make_name(App, PostFix) ->
285
list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
287
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
exit({suite_failed, Reason}).
293
key1search(Key, L) ->
294
case lists:keysearch(Key, 1, L) of
296
fail({not_found, Key, L});
297
{value, {Key, Value}} ->