Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

494 строки
21 KiB

9 лет назад
10 лет назад
9 лет назад
9 лет назад
9 лет назад
9 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
  1. -module(rebar_test_utils).
  2. -include_lib("common_test/include/ct.hrl").
  3. -include_lib("eunit/include/eunit.hrl").
  4. -export([init_rebar_state/1, init_rebar_state/2, run_and_check/4, check_results/3]).
  5. -export([expand_deps/2, flat_deps/1, top_level_deps/1]).
  6. -export([create_app/4, create_plugin/4, create_eunit_app/4, create_empty_app/4,
  7. create_config/2, create_config/3, package_app/4]).
  8. -export([create_random_name/1, create_random_vsn/0, write_src_file/2,
  9. random_element/1]).
  10. %% Pick the right random module
  11. -ifdef(rand_only).
  12. -define(random, rand).
  13. -else.
  14. -define(random, random).
  15. -endif.
  16. %%%%%%%%%%%%%%
  17. %%% Public %%%
  18. %%%%%%%%%%%%%%
  19. %% @doc {@see init_rebar_state/2}
  20. init_rebar_state(Config) -> init_rebar_state(Config, "apps_dir1_").
  21. %% @doc Takes a common test config and a name (string) and sets up
  22. %% a basic OTP app directory with a pre-configured rebar state to
  23. %% run tests with.
  24. init_rebar_state(Config, Name) ->
  25. application:load(rebar),
  26. DataDir = ?config(priv_dir, Config),
  27. AppsDir = filename:join([DataDir, create_random_name(Name)]),
  28. CheckoutsDir = filename:join([AppsDir, "_checkouts"]),
  29. ok = ec_file:mkdir_p(AppsDir),
  30. ok = ec_file:mkdir_p(CheckoutsDir),
  31. Verbosity = rebar3:log_level(),
  32. rebar_log:init(command_line, Verbosity),
  33. GlobalDir = filename:join([DataDir, "cache"]),
  34. Repos = proplists:get_value(repos, Config, []),
  35. State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
  36. ,{global_rebar_dir, GlobalDir}
  37. ,{hex, [{repos, [#{name => R} || R <- Repos]}]}
  38. ,{root_dir, AppsDir}]),
  39. [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, State} | Config].
  40. %% @doc Takes common test config, a rebar config ([] if empty), a command to
  41. %% run ("install_deps", "compile", etc.), and a list of expected applications
  42. %% and/or dependencies to be present, and verifies whether they are all in
  43. %% place.
  44. %%
  45. %% The expectation list takes elements of the form:
  46. %% - `{app, Name :: string()}': checks that the app is properly built.
  47. %% - `{dep, Name :: string()}': checks that the dependency has been fetched.
  48. %% Ignores the build status of the dependency.
  49. %% - `{dep, Name :: string(), Vsn :: string()}': checks that the dependency
  50. %% has been fetched, and that a given version has been chosen. Useful to
  51. %% test for conflict resolution. Also ignores the build status of the
  52. %% dependency.
  53. %%
  54. %% This function assumes `init_rebar_state/1-2' has run before, in order to
  55. %% fetch the `apps' and `state' values from the CT config.
  56. run_and_check(Config, RebarConfig, Command, Expect) ->
  57. %% Assumes init_rebar_state has run first
  58. AppDir = ?config(apps, Config),
  59. State = ?config(state, Config),
  60. try
  61. Res = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), Command),
  62. case Expect of
  63. {error, Reason} ->
  64. ?assertEqual({error, Reason}, Res);
  65. {ok, Expected} ->
  66. {ok, _} = Res,
  67. check_results(AppDir, Expected, "*"),
  68. Res;
  69. {ok, Expected, ProfileRun} ->
  70. {ok, _} = Res,
  71. check_results(AppDir, Expected, ProfileRun),
  72. Res;
  73. return ->
  74. Res
  75. end
  76. catch
  77. rebar_abort when Expect =:= rebar_abort -> rebar_abort
  78. end.
  79. %% @doc Creates a dummy application including:
  80. %% - src/<file>.erl
  81. %% - src/<file>.app.src
  82. %% And returns a `rebar_app_info' object.
  83. create_app(AppDir, Name, Vsn, Deps) ->
  84. write_src_file(AppDir, Name ++ ".erl"),
  85. write_src_file(AppDir, "not_a_real_src_" ++ Name ++ ".erl"),
  86. write_app_src_file(AppDir, Name, Vsn, Deps),
  87. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  88. %% @doc Creates a dummy plugin including:
  89. %% - src/<file>.erl
  90. %% - src/<file>.app.src
  91. %% And returns a `rebar_app_info' object.
  92. create_plugin(AppDir, Name, Vsn, Deps) ->
  93. write_plugin_file(AppDir, Name ++ ".erl"),
  94. write_src_file(AppDir, "not_a_real_src_" ++ Name ++ ".erl"),
  95. write_app_src_file(AppDir, Name, Vsn, Deps),
  96. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  97. %% @doc Creates a dummy application including:
  98. %% - src/<file>.erl
  99. %% - src/<file>.app.src
  100. %% - test/<file>_tests.erl
  101. %% And returns a `rebar_app_info' object.
  102. create_eunit_app(AppDir, Name, Vsn, Deps) ->
  103. write_eunitized_src_file(AppDir, Name),
  104. write_eunit_suite_file(AppDir, Name),
  105. write_app_src_file(AppDir, Name, Vsn, Deps),
  106. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  107. %% @doc Creates a dummy application including:
  108. %% - ebin/<file>.app
  109. %% And returns a `rebar_app_info' object.
  110. create_empty_app(AppDir, Name, Vsn, Deps) ->
  111. write_app_file(AppDir, Name, Vsn, Deps),
  112. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  113. %% @doc Creates a rebar.config file. The function accepts a list of terms,
  114. %% each of which will be dumped as a consult file. For example, the list
  115. %% `[a, b, c]' will return the consult file `a. b. c.'.
  116. create_config(AppDir, Contents) ->
  117. ConfFilename = filename:join([AppDir, "rebar.config"]),
  118. create_config(AppDir, ConfFilename, Contents).
  119. create_config(_AppDir, ConfFilename, Contents) ->
  120. ok = filelib:ensure_dir(ConfFilename),
  121. Config = lists:flatten([io_lib:fwrite("~p.~n", [Term]) || Term <- Contents]),
  122. ok = ec_file:write(ConfFilename, Config),
  123. ConfFilename.
  124. %% @doc Util to create a random variation of a given name.
  125. create_random_name(Name) ->
  126. random_seed(),
  127. Name ++ erlang:integer_to_list(?random:uniform(1000000)).
  128. %% @doc Util to create a random variation of a given version.
  129. create_random_vsn() ->
  130. random_seed(),
  131. lists:flatten([erlang:integer_to_list(?random:uniform(100)),
  132. ".", erlang:integer_to_list(?random:uniform(100)),
  133. ".", erlang:integer_to_list(?random:uniform(100))]).
  134. -ifdef(rand_only).
  135. random_seed() ->
  136. %% the rand module self-seeds
  137. ok.
  138. -else.
  139. random_seed() ->
  140. <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
  141. random:seed({A,B,C}).
  142. -endif.
  143. expand_deps(_, []) -> [];
  144. expand_deps(git, [{Name, Deps} | Rest]) ->
  145. Dep = {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}},
  146. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  147. expand_deps(git, [{Name, Vsn, Deps} | Rest]) ->
  148. Dep = {Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}},
  149. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  150. expand_deps(pkg, [{Name, Deps} | Rest]) ->
  151. Dep = {pkg, Name, "0.0.0", undefined},
  152. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
  153. expand_deps(pkg, [{Name, Vsn, Deps} | Rest]) ->
  154. Dep = {pkg, Name, Vsn, undefined},
  155. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
  156. expand_deps(mixed, [{Name, Deps} | Rest]) ->
  157. Dep = if hd(Name) >= $a, hd(Name) =< $z ->
  158. {pkg, rebar_string:uppercase(Name), "0.0.0", undefined}
  159. ; hd(Name) >= $A, hd(Name) =< $Z ->
  160. {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}}
  161. end,
  162. [{Dep, expand_deps(mixed, Deps)} | expand_deps(mixed, Rest)];
  163. expand_deps(mixed, [{Name, Vsn, Deps} | Rest]) ->
  164. Dep = if hd(Name) >= $a, hd(Name) =< $z ->
  165. {pkg, rebar_string:uppercase(Name), Vsn, undefined}
  166. ; hd(Name) >= $A, hd(Name) =< $Z ->
  167. {Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}}
  168. end,
  169. [{Dep, expand_deps(mixed, Deps)} | expand_deps(mixed, Rest)].
  170. %% Source deps can depend on both source and package dependencies;
  171. %% package deps can only depend on package deps.
  172. %% For things to work we have to go down the dep tree and find all
  173. %% lineages of pkg deps and return them, whereas the source deps
  174. %% can be left as is.
  175. flat_deps(Deps) -> flat_deps(Deps, [], []).
  176. flat_deps([], Src, Pkg) -> {Src, Pkg};
  177. flat_deps([{{pkg, Name, Vsn, undefined}, PkgDeps} | Rest], Src, Pkg) ->
  178. Current = {{iolist_to_binary(Name), iolist_to_binary(Vsn)},
  179. top_level_deps(PkgDeps)},
  180. {[], FlatPkgDeps} = flat_deps(PkgDeps),
  181. flat_deps(Rest,
  182. Src,
  183. Pkg ++ [Current | FlatPkgDeps]);
  184. flat_deps([{{Name,_Vsn,Ref}, Deps} | Rest], Src, Pkg) ->
  185. Current = {{Name,vsn_from_ref(Ref)}, top_level_deps(Deps)},
  186. {FlatDeps, FlatPkgDeps} = flat_deps(Deps),
  187. flat_deps(Rest,
  188. Src ++ [Current | FlatDeps],
  189. Pkg ++ FlatPkgDeps).
  190. vsn_from_ref({git, _, {_, Vsn}}) -> Vsn;
  191. vsn_from_ref({git, _, Vsn}) -> Vsn.
  192. top_level_deps([]) -> [];
  193. top_level_deps([{{pkg, Name, Vsn, undefined}, _} | Deps]) ->
  194. [{list_to_atom(Name), Vsn} | top_level_deps(Deps)];
  195. top_level_deps([{{Name, Vsn, Ref}, _} | Deps]) ->
  196. [{list_to_atom(Name), Vsn, Ref} | top_level_deps(Deps)].
  197. %%%%%%%%%%%%%%%
  198. %%% Helpers %%%
  199. %%%%%%%%%%%%%%%
  200. check_results(AppDir, Expected, ProfileRun) ->
  201. BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "lib", "*"])),
  202. PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "plugins", "*"])),
  203. GlobalPluginDirs = filelib:wildcard(filename:join([AppDir, "global", "plugins", "*"])),
  204. CheckoutsDirs = filelib:wildcard(filename:join([AppDir, "_checkouts", "*"])),
  205. LockFile = filename:join([AppDir, "rebar.lock"]),
  206. Locks = lists:flatten(rebar_config:consult_lock_file(LockFile)),
  207. InvalidApps = rebar_app_discover:find_apps(BuildDirs, invalid),
  208. ValidApps = rebar_app_discover:find_apps(BuildDirs, valid),
  209. InvalidDepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- InvalidApps],
  210. ValidDepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- ValidApps],
  211. Deps = rebar_app_discover:find_apps(BuildDirs, all),
  212. DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
  213. Checkouts = rebar_app_discover:find_apps(CheckoutsDirs, all),
  214. CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
  215. Plugins = rebar_app_discover:find_apps(PluginDirs, all),
  216. PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],
  217. GlobalPlugins = rebar_app_discover:find_apps(GlobalPluginDirs, all),
  218. GlobalPluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- GlobalPlugins],
  219. lists:foreach(
  220. fun({app, Name}) ->
  221. ct:pal("App Name: ~p", [Name]),
  222. case lists:keyfind(Name, 1, DepsNames) of
  223. false ->
  224. error({app_not_found, Name});
  225. {Name, _App} ->
  226. ok
  227. end
  228. ; ({app, Name, invalid}) ->
  229. ct:pal("Invalid Name: ~p", [Name]),
  230. case lists:keyfind(Name, 1, InvalidDepsNames) of
  231. false ->
  232. error({app_not_found, Name});
  233. {Name, _App} ->
  234. ok
  235. end
  236. ; ({app, Name, valid}) ->
  237. ct:pal("Valid Name: ~p", [Name]),
  238. case lists:keyfind(Name, 1, ValidDepsNames) of
  239. false ->
  240. error({app_not_found, Name});
  241. {Name, _App} ->
  242. ok
  243. end
  244. ; ({dep_not_exist, Name}) ->
  245. ct:pal("App Not Exist Name: ~p", [Name]),
  246. case lists:keyfind(Name, 1, DepsNames) of
  247. false ->
  248. ok;
  249. {Name, _App} ->
  250. error({app_found, Name})
  251. end
  252. ; ({checkout, Name}) ->
  253. ct:pal("Checkout Name: ~p", [Name]),
  254. ?assertNotEqual(false, lists:keyfind(Name, 1, CheckoutsNames))
  255. ; ({dep, Name}) ->
  256. ct:pal("Dep Name: ~p", [Name]),
  257. ?assertNotEqual(false, lists:keyfind(Name, 1, DepsNames))
  258. ; ({dep, Name, Vsn}) ->
  259. ct:pal("Dep Name: ~p, Vsn: ~p", [Name, Vsn]),
  260. case lists:keyfind(Name, 1, DepsNames) of
  261. false ->
  262. error({dep_not_found, Name});
  263. {Name, App} ->
  264. ?assertEqual(iolist_to_binary(Vsn),
  265. iolist_to_binary(rebar_app_info:original_vsn(App)))
  266. end
  267. ; ({plugin, Name}) ->
  268. ct:pal("Plugin Name: ~p", [Name]),
  269. ?assertNotEqual(false, lists:keyfind(Name, 1, PluginsNames))
  270. ; ({plugin, Name, Vsn}) ->
  271. ct:pal("Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
  272. case lists:keyfind(Name, 1, PluginsNames) of
  273. false ->
  274. error({plugin_not_found, Name});
  275. {Name, App} ->
  276. ?assertEqual(iolist_to_binary(Vsn),
  277. iolist_to_binary(rebar_app_info:original_vsn(App)))
  278. end
  279. ; ({global_plugin, Name}) ->
  280. ct:pal("Global Plugin Name: ~p", [Name]),
  281. ?assertNotEqual(false, lists:keyfind(Name, 1, GlobalPluginsNames))
  282. ; ({global_plugin, Name, Vsn}) ->
  283. ct:pal("Global Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
  284. case lists:keyfind(Name, 1, GlobalPluginsNames) of
  285. false ->
  286. error({global_plugin_not_found, Name});
  287. {Name, App} ->
  288. ?assertEqual(iolist_to_binary(Vsn),
  289. iolist_to_binary(rebar_app_info:original_vsn(App)))
  290. end
  291. ; ({lock, Name}) ->
  292. ct:pal("Lock Name: ~p", [Name]),
  293. ?assertNotEqual(false, lists:keyfind(iolist_to_binary(Name), 1, Locks))
  294. ; ({lock, Name, Vsn}) ->
  295. ct:pal("Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  296. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  297. false ->
  298. error({lock_not_found, Name});
  299. {_LockName, {pkg, _, LockVsn, Hash}, _} ->
  300. ?assertEqual(iolist_to_binary(Vsn),
  301. iolist_to_binary(LockVsn)),
  302. ?assertNotEqual(undefined, Hash);
  303. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  304. ?assertEqual(iolist_to_binary(Vsn),
  305. iolist_to_binary(LockVsn))
  306. end
  307. ; ({lock, pkg, Name, Vsn}) ->
  308. ct:pal("Pkg Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  309. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  310. false ->
  311. error({lock_not_found, Name});
  312. {_LockName, {pkg, _, LockVsn, Hash}, _} ->
  313. ?assertEqual(iolist_to_binary(Vsn),
  314. iolist_to_binary(LockVsn)),
  315. ?assertNotEqual(undefined, Hash);
  316. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  317. error({source_lock, {Name, LockVsn}})
  318. end
  319. ; ({lock, src, Name, Vsn}) ->
  320. ct:pal("Src Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  321. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  322. false ->
  323. error({lock_not_found, Name});
  324. {_LockName, {pkg, _, LockVsn, _}, _} ->
  325. error({pkg_lock, {Name, LockVsn}});
  326. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  327. ?assertEqual(iolist_to_binary(Vsn),
  328. iolist_to_binary(LockVsn))
  329. end
  330. ; ({release, Name, Vsn, ExpectedDevMode}) ->
  331. ct:pal("Release: ~p-~ts", [Name, Vsn]),
  332. {ok, Cwd} = file:get_cwd(),
  333. try
  334. file:set_cwd(AppDir),
  335. [ReleaseDir] = filelib:wildcard(filename:join([AppDir, "_build", "*", "rel"])),
  336. RelxState = rlx_state:new("", [], []),
  337. RelxState1 = rlx_state:base_output_dir(RelxState, ReleaseDir),
  338. {ok, RelxState2} = rlx_prv_app_discover:do(RelxState1),
  339. {ok, RelxState3} = rlx_prv_rel_discover:do(RelxState2),
  340. LibDir = filename:join([ReleaseDir, Name, "lib"]),
  341. {ok, RelLibs} = rebar_utils:list_dir(LibDir),
  342. IsSymLinkFun =
  343. fun(X) ->
  344. ec_file:is_symlink(filename:join(LibDir, X))
  345. end,
  346. DevMode = lists:all(IsSymLinkFun, RelLibs),
  347. ?assertEqual(ExpectedDevMode, DevMode),
  348. %% throws not_found if it doesn't exist
  349. rlx_state:get_realized_release(RelxState3, Name, Vsn)
  350. catch
  351. _ ->
  352. ct:fail(release_not_found)
  353. after
  354. file:set_cwd(Cwd)
  355. end
  356. ; ({tar, Name, Vsn}) ->
  357. ct:pal("Tarball: ~ts-~ts", [Name, Vsn]),
  358. Tarball = filename:join([AppDir, "_build", "rel", Name, Name++"-"++Vsn++".tar.gz"]),
  359. ?assertNotEqual([], filelib:is_file(Tarball))
  360. ; ({file, Filename}) ->
  361. ct:pal("Filename: ~ts", [Filename]),
  362. ?assert(filelib:is_file(Filename))
  363. ; ({dir, Dirname}) ->
  364. ct:pal("Directory: ~ts", [Dirname]),
  365. ?assert(filelib:is_dir(Dirname))
  366. end, Expected).
  367. write_plugin_file(Dir, Name) ->
  368. Erl = filename:join([Dir, "src", Name]),
  369. ok = filelib:ensure_dir(Erl),
  370. ok = ec_file:write(Erl, plugin_src_file(Name)).
  371. write_src_file(Dir, Name) ->
  372. Erl = filename:join([Dir, "src", Name]),
  373. ok = filelib:ensure_dir(Erl),
  374. ok = ec_file:write(Erl, erl_src_file(Name)).
  375. write_eunitized_src_file(Dir, Name) ->
  376. Erl = filename:join([Dir, "src", "not_a_real_src_" ++ Name ++ ".erl"]),
  377. ok = filelib:ensure_dir(Erl),
  378. ok = ec_file:write(Erl, erl_eunitized_src_file("not_a_real_src_" ++ Name ++ ".erl")).
  379. write_eunit_suite_file(Dir, Name) ->
  380. Erl = filename:join([Dir, "test", "not_a_real_src_" ++ Name ++ "_tests.erl"]),
  381. ok = filelib:ensure_dir(Erl),
  382. ok = ec_file:write(Erl, erl_eunit_suite_file("not_a_real_src_" ++ Name ++ ".erl")).
  383. write_app_file(Dir, Name, Version, Deps) ->
  384. Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
  385. ok = filelib:ensure_dir(Filename),
  386. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  387. write_app_src_file(Dir, Name, Version, Deps) ->
  388. Filename = filename:join([Dir, "src", Name ++ ".app.src"]),
  389. ok = filelib:ensure_dir(Filename),
  390. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  391. erl_src_file(Name) ->
  392. io_lib:format("-module('~s').\n"
  393. "-export([main/0]).\n"
  394. "main() -> ok.\n", [filename:basename(Name, ".erl")]).
  395. plugin_src_file(Name) ->
  396. io_lib:format("-module('~s').\n"
  397. "-export([init/1, do/1]).\n"
  398. "init(State) -> \n"
  399. "Provider = providers:create([\n"
  400. "{name, '~s'},\n"
  401. "{module, '~s'}\n"
  402. "]),\n"
  403. "{ok, rebar_state:add_provider(State, Provider)}.\n"
  404. "do(State) -> {ok, State}.\n", [filename:basename(Name, ".erl"),
  405. filename:basename(Name, ".erl"),
  406. filename:basename(Name, ".erl")]).
  407. erl_eunitized_src_file(Name) ->
  408. io_lib:format("-module('~s').\n"
  409. "-export([main/0]).\n"
  410. "main() -> ok.\n"
  411. "-ifdef(TEST).\n"
  412. "-include_lib(\"eunit/include/eunit.hrl\").\n"
  413. "some_test_() -> ?_assertEqual(ok, main()).\n"
  414. "-endif.\n", [filename:basename(Name, ".erl")]).
  415. erl_eunit_suite_file(Name) ->
  416. BaseName = filename:basename(Name, ".erl"),
  417. io_lib:format("-module('~s_tests').\n"
  418. "-compile(export_all).\n"
  419. "-ifndef(some_define).\n"
  420. "-define(some_define, false).\n"
  421. "-endif.\n"
  422. "-ifdef(TEST).\n"
  423. "-include_lib(\"eunit/include/eunit.hrl\").\n"
  424. "some_test_() -> ?_assertEqual(ok, ~s:main()).\n"
  425. "define_test_() -> ?_assertEqual(true, ?some_define).\n"
  426. "-endif.\n", [BaseName, BaseName]).
  427. get_app_metadata(Name, Vsn, Deps) ->
  428. {application, erlang:list_to_atom(Name),
  429. [{description, ""},
  430. {vsn, Vsn},
  431. {modules, []},
  432. {included_applications, []},
  433. {registered, []},
  434. {applications, Deps}]}.
  435. package_app(AppDir, DestDir, PkgName, PkgVsn) ->
  436. AppSrc = filename:join(AppDir, "src"),
  437. {ok, Fs} = rebar_utils:list_dir(AppSrc),
  438. Files = lists:zip([filename:join("src", F) || F <- Fs], [filename:join(AppSrc,F) || F <- Fs]),
  439. Metadata = #{<<"app">> => list_to_binary(PkgName),
  440. <<"version">> => list_to_binary(PkgVsn)},
  441. {ok, {Tarball, <<Checksum:256/big-unsigned-integer>>}} = hex_tarball:create(Metadata, Files),
  442. Name = PkgName++"-"++PkgVsn++".tar",
  443. Archive = filename:join(DestDir, Name),
  444. file:write_file(Archive, Tarball),
  445. <<E:128/big-unsigned-integer>> = crypto:hash(md5, Tarball),
  446. Checksum1 = list_to_binary(
  447. rebar_string:uppercase(
  448. lists:flatten(io_lib:format("~64.16.0b", [Checksum])))),
  449. {Checksum1, E}.
  450. random_element(Repos) ->
  451. Index = ?random:uniform(length(Repos)),
  452. lists:nth(Index, Repos).