You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

367 lines
12 KiB

9 years ago
9 years ago
9 years ago
9 years ago
  1. -module(rebar_dialyzer_SUITE).
  2. -export([suite/0,
  3. init_per_suite/1,
  4. end_per_suite/1,
  5. init_per_group/2,
  6. end_per_group/2,
  7. init_per_testcase/2,
  8. all/0,
  9. groups/0,
  10. empty_base_plt/1,
  11. empty_app_plt/1,
  12. empty_app_succ_typings/1,
  13. update_base_plt/1,
  14. update_app_plt/1,
  15. build_release_plt/1,
  16. plt_apps_option/1,
  17. exclude_and_extra/1]).
  18. -include_lib("common_test/include/ct.hrl").
  19. -include_lib("eunit/include/eunit.hrl").
  20. -include_lib("kernel/include/file.hrl").
  21. suite() ->
  22. [].
  23. init_per_suite(Config) ->
  24. Config.
  25. end_per_suite(_Config) ->
  26. ok.
  27. init_per_group(empty, Config) ->
  28. [{base_plt_apps, []} | Config];
  29. init_per_group(_Group, Config) ->
  30. [{base_plt_apps, [erts]} | Config].
  31. end_per_group(_Group, _Config) ->
  32. ok.
  33. init_per_testcase(Testcase, Config) ->
  34. PrivDir = ?config(priv_dir, Config),
  35. Prefix = ec_cnv:to_list(Testcase),
  36. BasePrefix = Prefix ++ "_base",
  37. Opts = [{plt_prefix, Prefix},
  38. {plt_location, PrivDir},
  39. {base_plt_prefix, BasePrefix},
  40. {base_plt_location, PrivDir},
  41. {base_plt_apps, ?config(base_plt_apps, Config)}],
  42. Suffix = "_" ++ rebar_utils:otp_release() ++ "_plt",
  43. [{plt, filename:join(PrivDir, Prefix ++ Suffix)},
  44. {base_plt, filename:join(PrivDir, BasePrefix ++ Suffix)},
  45. {rebar_config, [{dialyzer, Opts}]} |
  46. rebar_test_utils:init_rebar_state(Config)].
  47. all() ->
  48. [{group, empty}, {group, build_and_check}, {group, update}].
  49. groups() ->
  50. [{empty, [empty_base_plt, empty_app_plt, empty_app_succ_typings]},
  51. {build_and_check, [build_release_plt, plt_apps_option, exclude_and_extra]},
  52. {update, [update_base_plt, update_app_plt]}].
  53. empty_base_plt(Config) ->
  54. AppDir = ?config(apps, Config),
  55. RebarConfig = ?config(rebar_config, Config),
  56. BasePlt = ?config(base_plt, Config),
  57. Plt = ?config(plt, Config),
  58. Name = rebar_test_utils:create_random_name("app1_"),
  59. Vsn = rebar_test_utils:create_random_vsn(),
  60. rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
  61. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  62. {ok, [{app, Name}]}),
  63. {ok, BasePltFiles} = plt_files(BasePlt),
  64. ?assertEqual([], BasePltFiles),
  65. ErtsFiles = erts_files(),
  66. {ok, PltFiles} = plt_files(Plt),
  67. ?assertEqual(ErtsFiles, PltFiles),
  68. ok.
  69. empty_app_plt(Config) ->
  70. AppDir = ?config(apps, Config),
  71. RebarConfig = ?config(rebar_config, Config),
  72. BasePlt = ?config(base_plt, Config),
  73. Plt = ?config(plt, Config),
  74. Name = rebar_test_utils:create_random_name("app1_"),
  75. Vsn = rebar_test_utils:create_random_vsn(),
  76. rebar_test_utils:create_app(AppDir, Name, Vsn, []),
  77. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  78. {ok, [{app, Name}]}),
  79. {ok, BasePltFiles} = plt_files(BasePlt),
  80. ?assertEqual([], BasePltFiles),
  81. {ok, PltFiles} = plt_files(Plt),
  82. ?assertEqual([], PltFiles),
  83. ok.
  84. empty_app_succ_typings(Config) ->
  85. AppDir = ?config(apps, Config),
  86. RebarConfig = ?config(rebar_config, Config),
  87. Name = rebar_test_utils:create_random_name("app1_"),
  88. Vsn = rebar_test_utils:create_random_vsn(),
  89. rebar_test_utils:create_empty_app(AppDir, Name, Vsn, []),
  90. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  91. {ok, [{app, Name}]}),
  92. ok.
  93. update_base_plt(Config) ->
  94. AppDir = ?config(apps, Config),
  95. RebarConfig = ?config(rebar_config, Config),
  96. BasePlt = ?config(base_plt, Config),
  97. Plt = ?config(plt, Config),
  98. Name = rebar_test_utils:create_random_name("app1_"),
  99. Vsn = rebar_test_utils:create_random_vsn(),
  100. rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
  101. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  102. {ok, [{app, Name}]}),
  103. ErtsFiles = erts_files(),
  104. {ok, BasePltFiles} = plt_files(BasePlt),
  105. ?assertEqual(ErtsFiles, BasePltFiles),
  106. alter_plt(BasePlt),
  107. ok = file:delete(Plt),
  108. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  109. {ok, [{app, Name}]}),
  110. {ok, BasePltFiles2} = plt_files(BasePlt),
  111. ?assertEqual(ErtsFiles, BasePltFiles2),
  112. {ok, PltFiles} = plt_files(Plt),
  113. ?assertEqual(ErtsFiles, PltFiles),
  114. add_missing_file(BasePlt),
  115. ok = file:delete(Plt),
  116. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  117. {ok, [{app, Name}]}),
  118. {ok, BasePltFiles3} = plt_files(BasePlt),
  119. ?assertEqual(ErtsFiles, BasePltFiles3).
  120. update_app_plt(Config) ->
  121. AppDir = ?config(apps, Config),
  122. RebarConfig = ?config(rebar_config, Config),
  123. Plt = ?config(plt, Config),
  124. Name = rebar_test_utils:create_random_name("app1_"),
  125. Vsn = rebar_test_utils:create_random_vsn(),
  126. rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
  127. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  128. {ok, [{app, Name}]}),
  129. ErtsFiles = erts_files(),
  130. {ok, PltFiles} = plt_files(Plt),
  131. ?assertEqual(ErtsFiles, PltFiles),
  132. alter_plt(Plt),
  133. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  134. {ok, [{app, Name}]}),
  135. {ok, PltFiles2} = plt_files(Plt),
  136. ?assertEqual(ErtsFiles, PltFiles2),
  137. ok = file:delete(Plt),
  138. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  139. {ok, [{app, Name}]}),
  140. {ok, PltFiles3} = plt_files(Plt),
  141. ?assertEqual(ErtsFiles, PltFiles3),
  142. add_missing_file(Plt),
  143. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  144. {ok, [{app, Name}]}),
  145. {ok, PltFiles4} = plt_files(Plt),
  146. ?assertEqual(ErtsFiles, PltFiles4).
  147. build_release_plt(Config) ->
  148. AppDir = ?config(apps, Config),
  149. RebarConfig = ?config(rebar_config, Config),
  150. BasePlt = ?config(base_plt, Config),
  151. Plt = ?config(plt, Config),
  152. Name1 = rebar_test_utils:create_random_name("relapp1_"),
  153. Vsn1 = rebar_test_utils:create_random_vsn(),
  154. rebar_test_utils:create_app(filename:join([AppDir,"apps",Name1]), Name1, Vsn1,
  155. [erts]),
  156. Name2 = rebar_test_utils:create_random_name("relapp2_"),
  157. Vsn2 = rebar_test_utils:create_random_vsn(),
  158. rebar_test_utils:create_app(filename:join([AppDir,"apps",Name2]), Name2, Vsn2,
  159. [erts, ec_cnv:to_atom(Name1)]),
  160. rebar_test_utils:run_and_check(Config, RebarConfig, ["dialyzer"],
  161. {ok, [{app, Name1}, {app, Name2}]}),
  162. ErtsFiles = erts_files(),
  163. {ok, BasePltFiles} = plt_files(BasePlt),
  164. ?assertEqual(ErtsFiles, BasePltFiles),
  165. {ok, PltFiles} = plt_files(Plt),
  166. ?assertEqual(ErtsFiles, PltFiles).
  167. plt_apps_option(Config) ->
  168. AppDir = ?config(apps, Config),
  169. RebarConfig = ?config(rebar_config, Config),
  170. Plt = ?config(plt, Config),
  171. State = ?config(state, Config),
  172. %% Create applications
  173. Name1 = rebar_test_utils:create_random_name("app1_"),
  174. Vsn1 = rebar_test_utils:create_random_vsn(),
  175. rebar_test_utils:create_app(filename:join([AppDir,"deps",Name1]), Name1, Vsn1,
  176. []),
  177. App1 = ec_cnv:to_atom(Name1),
  178. Name2 = rebar_test_utils:create_random_name("app2_"),
  179. Vsn2 = rebar_test_utils:create_random_vsn(),
  180. rebar_test_utils:create_app(filename:join([AppDir,"deps",Name2]), Name2, Vsn2,
  181. [App1]), % App2 depends on App1
  182. App2 = ec_cnv:to_atom(Name2),
  183. Name3 = rebar_test_utils:create_random_name("app3_"), % the project application
  184. Vsn3 = rebar_test_utils:create_random_vsn(),
  185. rebar_test_utils:create_app(AppDir, Name3, Vsn3,
  186. [App2]), % App3 depends on App2
  187. %% Dependencies settings
  188. State1 = rebar_state:add_resource(State, {localfs, rebar_localfs_resource}),
  189. Config1 = [{state, State1} | Config],
  190. RebarConfig1 = merge_config(
  191. [{deps,
  192. [
  193. {App1, {localfs, filename:join([AppDir,"deps",Name1])}},
  194. {App2, {localfs, filename:join([AppDir,"deps",Name2])}}
  195. ]}],
  196. RebarConfig),
  197. %% Dialyzer: plt_apps = top_level_deps (default)
  198. rebar_test_utils:run_and_check(Config1, RebarConfig1, ["dialyzer"],
  199. {ok, [{app, Name3}]}),
  200. %% NOTE: `erts` is included in `base_plt_apps`
  201. {ok, PltFiles1} = plt_files(Plt),
  202. ?assertEqual([App2, erts], get_apps_from_beam_files(PltFiles1)),
  203. %% Dialyzer: plt_apps = all_deps
  204. RebarConfig2 = merge_config([{dialyzer, [{plt_apps, all_deps}]}],
  205. RebarConfig1),
  206. rebar_test_utils:run_and_check(Config1, RebarConfig2, ["dialyzer"],
  207. {ok, [{app, Name3}]}),
  208. {ok, PltFiles2} = plt_files(Plt),
  209. ?assertEqual([App1, App2, erts], get_apps_from_beam_files(PltFiles2)).
  210. exclude_and_extra(Config) ->
  211. AppDir = ?config(apps, Config),
  212. RebarConfig = ?config(rebar_config, Config),
  213. BasePlt = ?config(base_plt, Config),
  214. Plt = ?config(plt, Config),
  215. {value, {dialyzer, Opts}, Rest} = lists:keytake(dialyzer, 1, RebarConfig),
  216. % Remove erts => []
  217. % Add erlang+zlib => [erlang, zlib],
  218. % Add erl_prim_loader+init => [erl_prim_loader, init, erlang, zlib]
  219. % Remove zlib+init => [erl_prim_loader, erlang]
  220. Opts2 = [{exclude_apps, [erts]},
  221. {base_plt_mods, [erlang, zlib]},
  222. {plt_extra_mods, [erl_prim_loader, init]},
  223. {exclude_mods, [zlib, init]} |
  224. Opts],
  225. RebarConfig2 = [{dialyzer, Opts2} | Rest],
  226. Name = rebar_test_utils:create_random_name("app1_"),
  227. Vsn = rebar_test_utils:create_random_vsn(),
  228. rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
  229. rebar_test_utils:run_and_check(Config, RebarConfig2, ["dialyzer"],
  230. {ok, [{app, Name}]}),
  231. Erlang = code:where_is_file("erlang.beam"),
  232. {ok, BasePltFiles} = plt_files(BasePlt),
  233. ?assertEqual([Erlang], BasePltFiles),
  234. Pair = lists:sort([Erlang, code:where_is_file("erl_prim_loader.beam")]),
  235. {ok, PltFiles} = plt_files(Plt),
  236. ?assertEqual(Pair, PltFiles).
  237. %% Helpers
  238. erts_files() ->
  239. ErtsDir = code:lib_dir(erts, ebin),
  240. ErtsBeams = filelib:wildcard("*.beam", ErtsDir),
  241. ErtsFiles = lists:map(fun(Beam) -> filename:join(ErtsDir, Beam) end,
  242. ErtsBeams),
  243. lists:sort(ErtsFiles).
  244. plt_files(Plt) ->
  245. case dialyzer:plt_info(Plt) of
  246. {ok, Info} ->
  247. Files = proplists:get_value(files, Info),
  248. {ok, lists:sort(Files)};
  249. Other ->
  250. Other
  251. end.
  252. alter_plt(Plt) ->
  253. {ok, Files} = plt_files(Plt),
  254. _ = dialyzer:run([{analysis_type, plt_remove},
  255. {init_plt, Plt},
  256. {files, [hd(Files)]}]),
  257. _ = dialyzer:run([{analysis_type, plt_add},
  258. {init_plt, Plt},
  259. {files, [code:which(dialyzer)]}]),
  260. ok.
  261. add_missing_file(Plt) ->
  262. Source = code:which(dialyzer),
  263. Dest = filename:join(filename:dirname(Plt), "dialyzer.beam"),
  264. {ok, _} = file:copy(Source, Dest),
  265. _ = try
  266. dialyzer:run([{analysis_type, plt_add},
  267. {init_plt, Plt},
  268. {files, [Dest]}])
  269. after
  270. ok = file:delete(Dest)
  271. end,
  272. ok.
  273. -spec merge_config(Config, Config) -> Config when
  274. Config :: [{term(), term()}].
  275. merge_config(NewConfig, OldConfig) ->
  276. dict:to_list(
  277. rebar_opts:merge_opts(dict:from_list(NewConfig),
  278. dict:from_list(OldConfig))).
  279. -spec get_apps_from_beam_files(string()) -> [atom()].
  280. get_apps_from_beam_files(BeamFiles) ->
  281. lists:usort(
  282. [begin
  283. AppNameVsn = filename:basename(filename:dirname(filename:dirname(File))),
  284. [AppName | _] = string:tokens(AppNameVsn ++ "-", "-"),
  285. ec_cnv:to_atom(AppName)
  286. end || File <- BeamFiles]).