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.

480 lines
19 KiB

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
  1. -module(rebar_deps_SUITE).
  2. -compile(export_all).
  3. -include_lib("common_test/include/ct.hrl").
  4. -include_lib("eunit/include/eunit.hrl").
  5. all() -> [sub_app_deps, newly_added_dep, newly_added_after_empty_lock,
  6. http_proxy_settings, https_proxy_settings,
  7. http_os_proxy_settings, https_os_proxy_settings,
  8. semver_matching_lt, semver_matching_lte, semver_matching_gt,
  9. valid_version, {group, git}, {group, pkg}].
  10. groups() ->
  11. [{all, [], [flat, pick_highest_left, pick_highest_right,
  12. pick_smallest1, pick_smallest2,
  13. circular1, circular2, circular_skip]},
  14. {git, [], [{group, all}]},
  15. {pkg, [], [{group, all}]}].
  16. init_per_suite(Config) ->
  17. application:start(meck),
  18. Config.
  19. end_per_suite(_Config) ->
  20. application:stop(meck).
  21. init_per_group(git, Config) ->
  22. [{deps_type, git} | Config];
  23. init_per_group(pkg, Config) ->
  24. [{deps_type, pkg} | Config];
  25. init_per_group(_, Config) ->
  26. Config.
  27. end_per_group(_, Config) ->
  28. Config.
  29. init_per_testcase(valid_version, Config) ->
  30. rebar_test_utils:init_rebar_state(Config);
  31. init_per_testcase(semver_matching_lt, Config) ->
  32. rebar_test_utils:init_rebar_state(Config);
  33. init_per_testcase(semver_matching_lte, Config) ->
  34. rebar_test_utils:init_rebar_state(Config);
  35. init_per_testcase(semver_matching_gt, Config) ->
  36. rebar_test_utils:init_rebar_state(Config);
  37. init_per_testcase(newly_added_after_empty_lock, Config) ->
  38. rebar_test_utils:init_rebar_state(Config);
  39. init_per_testcase(newly_added_dep, Config) ->
  40. rebar_test_utils:init_rebar_state(Config);
  41. init_per_testcase(sub_app_deps, Config) ->
  42. rebar_test_utils:init_rebar_state(Config);
  43. init_per_testcase(http_proxy_settings, Config) ->
  44. %% Create private rebar.config
  45. Priv = ?config(priv_dir, Config),
  46. GlobalDir = filename:join(Priv, "global"),
  47. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  48. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  49. meck:new(rebar_dir, [passthrough]),
  50. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  51. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  52. %% Insert proxy variables into config
  53. rebar_test_utils:create_config(GlobalConfigDir,
  54. [{http_proxy, "http://localhost:1234"}
  55. ]),
  56. rebar_test_utils:init_rebar_state(Config);
  57. init_per_testcase(https_proxy_settings, Config) ->
  58. SupportsHttpsProxy = case erlang:system_info(otp_release) of
  59. "R16"++_ -> true;
  60. "R"++_ -> false;
  61. _ -> true % 17 and up don't have a "R" in the version
  62. end,
  63. if not SupportsHttpsProxy ->
  64. {skip, https_proxy_unsupported_before_R16};
  65. SupportsHttpsProxy ->
  66. %% Create private rebar.config
  67. Priv = ?config(priv_dir, Config),
  68. GlobalDir = filename:join(Priv, "global"),
  69. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  70. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  71. meck:new(rebar_dir, [passthrough]),
  72. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  73. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  74. %% Insert proxy variables into config
  75. rebar_test_utils:create_config(GlobalConfigDir,
  76. [{https_proxy, "http://localhost:1234"}
  77. ]),
  78. %% Add a bad value by default to show config overtakes default
  79. os:putenv("https_proxy", "unparseable-garbage"),
  80. rebar_test_utils:init_rebar_state(Config)
  81. end;
  82. init_per_testcase(http_os_proxy_settings, Config) ->
  83. %% Create private rebar.config
  84. Priv = ?config(priv_dir, Config),
  85. GlobalDir = filename:join(Priv, "global"),
  86. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  87. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  88. meck:new(rebar_dir, [passthrough]),
  89. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  90. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  91. %% Insert proxy variables into os env, but not config
  92. os:putenv("http_proxy", "http://localhost:1234"),
  93. rebar_test_utils:create_config(GlobalConfigDir, []),
  94. rebar_test_utils:init_rebar_state(Config);
  95. init_per_testcase(https_os_proxy_settings, Config) ->
  96. SupportsHttpsProxy = case erlang:system_info(otp_release) of
  97. "R16"++_ -> true;
  98. "R"++_ -> false;
  99. _ -> true % 17 and up don't have a "R" in the version
  100. end,
  101. if not SupportsHttpsProxy ->
  102. {skip, https_proxy_unsupported_before_R16};
  103. SupportsHttpsProxy ->
  104. %% Create private rebar.config
  105. Priv = ?config(priv_dir, Config),
  106. GlobalDir = filename:join(Priv, "global"),
  107. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  108. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  109. meck:new(rebar_dir, [passthrough]),
  110. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  111. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  112. %% Insert proxy variables into os env, not in config
  113. os:putenv("https_proxy", "http://localhost:1234"),
  114. rebar_test_utils:create_config(GlobalConfigDir, []),
  115. rebar_test_utils:init_rebar_state(Config)
  116. end;
  117. init_per_testcase(Case, Config) ->
  118. {Deps, Warnings, Expect} = deps(Case),
  119. Expected = case Expect of
  120. {ok, List} -> {ok, format_expected_deps(List)};
  121. {error, Reason} -> {error, Reason}
  122. end,
  123. DepsType = ?config(deps_type, Config),
  124. mock_warnings(),
  125. [{expect, Expected},
  126. {warnings, Warnings}
  127. | setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
  128. end_per_testcase(https_proxy_settings, Config) ->
  129. os:putenv("https_proxy", ""),
  130. meck:unload(rebar_dir),
  131. Config;
  132. end_per_testcase(http_proxy_settings, Config) ->
  133. meck:unload(rebar_dir),
  134. Config;
  135. end_per_testcase(http_os_proxy_settings, Config) ->
  136. os:putenv("http_proxy", ""),
  137. meck:unload(rebar_dir),
  138. Config;
  139. end_per_testcase(https_os_proxy_settings, Config) ->
  140. os:putenv("https_proxy", ""),
  141. meck:unload(rebar_dir),
  142. Config;
  143. end_per_testcase(_, Config) ->
  144. meck:unload(),
  145. Config.
  146. format_expected_deps(Deps) ->
  147. [case Dep of
  148. {N,V} -> {dep, N, V};
  149. N -> {dep, N}
  150. end || Dep <- Deps].
  151. %% format:
  152. %% {Spec,
  153. %% [Warning],
  154. %% {ok, Result} | {error, Reason}}
  155. %%
  156. %% Spec is a list of levelled dependencies of two possible forms:
  157. %% - {"Name", Spec}
  158. %% - {"Name", "Vsn", Spec}
  159. %%
  160. %% Warnings are going to match on mocked ?WARN(...)
  161. %% calls to be evaluated. An empty list means we do not care about
  162. %% warnings, not that no warnings will be printed. This means
  163. %% the list of warning isn't interpreted to be exhaustive, and more
  164. %% warnings may be generated than are listed.
  165. deps(flat) ->
  166. {[{"B", []},
  167. {"C", []}],
  168. [],
  169. {ok, ["B", "C"]}};
  170. deps(pick_highest_left) ->
  171. {[{"B", [{"C", "2", []}]},
  172. {"C", "1", []}],
  173. [{"C","2"}],
  174. {ok, ["B", {"C", "1"}]}};
  175. deps(pick_highest_right) ->
  176. {[{"B", "1", []},
  177. {"C", [{"B", "2", []}]}],
  178. [{"B","2"}],
  179. {ok, [{"B","1"}, "C"]}};
  180. deps(pick_smallest1) ->
  181. {[{"B", [{"D", "1", []}]},
  182. {"C", [{"D", "2", []}]}],
  183. [{"D","2"}],
  184. %% we pick D1 because B < C
  185. {ok, ["B","C",{"D","1"}]}};
  186. deps(pick_smallest2) ->
  187. {[{"C", [{"D", "2", []}]},
  188. {"B", [{"D", "1", []}]}],
  189. [{"D","2"}],
  190. %% we pick D1 because B < C
  191. {ok, ["B","C",{"D","1"}]}};
  192. deps(circular1) ->
  193. {[{"B", [{"A", []}]}, % A is the top-level app
  194. {"C", []}],
  195. [],
  196. {error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}};
  197. deps(circular2) ->
  198. {[{"B", [{"C", [{"B", []}]}]},
  199. {"C", []}],
  200. [],
  201. {error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
  202. deps(circular_skip) ->
  203. %% Never spot the circular dep due to being to low in the deps tree
  204. %% in source deps
  205. {[{"B", [{"C", "2", [{"B", []}]}]},
  206. {"C", "1", [{"D",[]}]}],
  207. [{"C","2"}],
  208. {ok, ["B", {"C","1"}, "D"]}}.
  209. setup_project(Case, Config0, Deps) ->
  210. DepsType = ?config(deps_type, Config0),
  211. Config = rebar_test_utils:init_rebar_state(
  212. Config0,
  213. atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
  214. ),
  215. AppDir = ?config(apps, Config),
  216. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  217. TopDeps = rebar_test_utils:top_level_deps(Deps),
  218. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  219. {SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps),
  220. mock_git_resource:mock([{deps, SrcDeps}]),
  221. mock_pkg_resource:mock([{pkgdeps, PkgDeps}]),
  222. [{rebarconfig, RebarConf} | Config].
  223. mock_warnings() ->
  224. %% just let it do its thing, we check warnings through
  225. %% the call log.
  226. meck:new(rebar_log, [no_link, passthrough]).
  227. %%% TESTS %%%
  228. flat(Config) -> run(Config).
  229. pick_highest_left(Config) -> run(Config).
  230. pick_highest_right(Config) -> run(Config).
  231. pick_smallest1(Config) -> run(Config).
  232. pick_smallest2(Config) -> run(Config).
  233. circular1(Config) -> run(Config).
  234. circular2(Config) -> run(Config).
  235. circular_skip(Config) -> run(Config).
  236. %% Test that the deps of project apps that have their own rebar.config
  237. %% are included, but that top level rebar.config deps take precedence
  238. sub_app_deps(Config) ->
  239. AppDir = ?config(apps, Config),
  240. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  241. ,{"b", "1.0.0", []}
  242. ,{"b", "2.0.0", []}]),
  243. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  244. mock_git_resource:mock([{deps, SrcDeps}]),
  245. Name = rebar_test_utils:create_random_name("sub_app1_"),
  246. Vsn = rebar_test_utils:create_random_vsn(),
  247. SubAppsDir = filename:join([AppDir, "apps", Name]),
  248. SubDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  249. ,{"b", "2.0.0", []}])),
  250. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  251. rebar_test_utils:create_config(SubAppsDir, [{deps, SubDeps}]),
  252. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  253. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  254. rebar_test_utils:run_and_check(
  255. Config, RebarConfig, ["compile"],
  256. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}]}).
  257. %% Newly added dependency after locking
  258. newly_added_dep(Config) ->
  259. AppDir = ?config(apps, Config),
  260. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  261. ,{"b", "1.0.0", [{"c", "1.0.0", []}]}
  262. ,{"c", "2.0.0", []}]),
  263. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  264. mock_git_resource:mock([{deps, SrcDeps}]),
  265. Name = rebar_test_utils:create_random_name("app_"),
  266. Vsn = rebar_test_utils:create_random_vsn(),
  267. SubAppsDir = filename:join([AppDir, "apps", Name]),
  268. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  269. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  270. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  271. rebar_test_utils:run_and_check(
  272. Config, RebarConfig, ["compile"],
  273. {ok, [{app, Name}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}),
  274. %% Add a and c to top level
  275. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  276. ,{"c", "2.0.0", []}
  277. ,{"b", "1.0.0", []}])),
  278. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  279. LockFile = filename:join(AppDir, "rebar.lock"),
  280. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  281. rebar_config:consult_lock_file(LockFile)),
  282. %% a should now be installed and c should not change
  283. rebar_test_utils:run_and_check(
  284. Config, RebarConfig3, ["compile"],
  285. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}).
  286. newly_added_after_empty_lock(Config) ->
  287. AppDir = ?config(apps, Config),
  288. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}]),
  289. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  290. mock_git_resource:mock([{deps, SrcDeps}]),
  291. Name = rebar_test_utils:create_random_name("app_"),
  292. Vsn = rebar_test_utils:create_random_vsn(),
  293. SubAppsDir = filename:join([AppDir, "apps", Name]),
  294. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  295. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [])),
  296. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  297. rebar_test_utils:run_and_check(
  298. Config, RebarConfig, ["compile"],
  299. {ok, []}),
  300. %% Add a and c to top level
  301. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}])),
  302. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  303. LockFile = filename:join(AppDir, "rebar.lock"),
  304. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  305. rebar_config:consult_lock_file(LockFile)),
  306. %% a should now be installed and c should not change
  307. rebar_test_utils:run_and_check(
  308. Config, RebarConfig3, ["compile"],
  309. {ok, [{app, Name}, {dep, "a", "1.0.0"}]}).
  310. http_proxy_settings(_Config) ->
  311. %% Load config
  312. rebar_utils:set_httpc_options(),
  313. rebar3:init_config(),
  314. %% Assert variable is right
  315. ?assertEqual({ok,{{"localhost", 1234}, []}},
  316. httpc:get_option(proxy, rebar)).
  317. https_proxy_settings(_Config) ->
  318. %% Load config
  319. rebar_utils:set_httpc_options(),
  320. rebar3:init_config(),
  321. %% Assert variable is right
  322. ?assertEqual({ok,{{"localhost", 1234}, []}},
  323. httpc:get_option(https_proxy, rebar)).
  324. http_os_proxy_settings(_Config) ->
  325. %% Load config
  326. rebar_utils:set_httpc_options(),
  327. rebar3:init_config(),
  328. %% Assert variable is right
  329. ?assertEqual({ok,{{"localhost", 1234}, []}},
  330. httpc:get_option(proxy, rebar)).
  331. https_os_proxy_settings(_Config) ->
  332. %% Load config
  333. rebar_utils:set_httpc_options(),
  334. rebar3:init_config(),
  335. %% Assert variable is right
  336. ?assertEqual({ok,{{"localhost", 1234}, []}},
  337. httpc:get_option(https_proxy, rebar)).
  338. semver_matching_lt(_Config) ->
  339. Dep = <<"test">>,
  340. Dep1 = {Dep, <<"1.0.0">>, Dep},
  341. MaxVsn = <<"0.2.0">>,
  342. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  343. ?assertEqual([{Dep, <<"0.1.9">>}],
  344. rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
  345. fun ec_semver:lt/2)).
  346. semver_matching_lte(_Config) ->
  347. Dep = <<"test">>,
  348. Dep1 = {Dep, <<"1.0.0">>, Dep},
  349. MaxVsn = <<"0.2.0">>,
  350. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  351. ?assertEqual([{Dep, <<"0.2.0">>}],
  352. rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
  353. fun ec_semver:lte/2)).
  354. semver_matching_gt(_Config) ->
  355. Dep = <<"test">>,
  356. Dep1 = {Dep, <<"1.0.0">>, Dep},
  357. MaxVsn = <<"0.2.0">>,
  358. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  359. ?assertEqual([{Dep, <<"0.2.1">>}],
  360. rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
  361. fun ec_semver:gt/2)).
  362. semver_matching_gte(_Config) ->
  363. Dep = <<"test">>,
  364. Dep1 = {Dep, <<"1.0.0">>, Dep},
  365. MaxVsn = <<"0.2.0">>,
  366. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>],
  367. ?assertEqual([{Dep, <<"0.2.0">>}],
  368. rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
  369. fun ec_semver:gt/2)).
  370. valid_version(_Config) ->
  371. ?assert(rebar_prv_update:valid_vsn(<<"0.1">>)),
  372. ?assert(rebar_prv_update:valid_vsn(<<"0.1.0">>)),
  373. ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
  374. ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
  375. ?assert(rebar_prv_update:valid_vsn(<<"<0.1">>)),
  376. ?assert(rebar_prv_update:valid_vsn(<<"<0.1.0">>)),
  377. ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
  378. ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
  379. ?assert(rebar_prv_update:valid_vsn(<<">0.1">>)),
  380. ?assert(rebar_prv_update:valid_vsn(<<">0.1.0">>)),
  381. ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
  382. ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
  383. ?assert(rebar_prv_update:valid_vsn(<<"<=0.1">>)),
  384. ?assert(rebar_prv_update:valid_vsn(<<"<=0.1.0">>)),
  385. ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
  386. ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
  387. ?assert(rebar_prv_update:valid_vsn(<<">=0.1">>)),
  388. ?assert(rebar_prv_update:valid_vsn(<<">=0.1.0">>)),
  389. ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
  390. ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
  391. ?assert(rebar_prv_update:valid_vsn(<<"==0.1">>)),
  392. ?assert(rebar_prv_update:valid_vsn(<<"==0.1.0">>)),
  393. ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
  394. ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
  395. ?assert(rebar_prv_update:valid_vsn(<<"~>0.1">>)),
  396. ?assert(rebar_prv_update:valid_vsn(<<"~>0.1.0">>)),
  397. ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
  398. ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
  399. ?assertNot(rebar_prv_update:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)),
  400. ok.
  401. run(Config) ->
  402. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  403. rebar_test_utils:run_and_check(
  404. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  405. ),
  406. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  407. warning_calls() ->
  408. History = meck:history(rebar_log),
  409. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  410. check_warnings(_, [], _) ->
  411. ok;
  412. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  413. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  414. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  415. check_warnings(Warns, Rest, Type).
  416. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  417. Name = iolist_to_binary(NameRaw),
  418. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  419. AppName =:= Name, Vsn =:= VsnRaw]);
  420. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  421. Name = iolist_to_binary(NameRaw),
  422. Vsn = iolist_to_binary(VsnRaw),
  423. 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns,
  424. AppName =:= Name, AppVsn =:= Vsn]).