您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

148 行
5.9 KiB

  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]).
  5. -export([create_app/4, create_empty_app/4, create_config/2]).
  6. -export([create_random_name/1, create_random_vsn/0]).
  7. %%%%%%%%%%%%%%
  8. %%% Public %%%
  9. %%%%%%%%%%%%%%
  10. %% @doc {@see init_rebar_state/2}
  11. init_rebar_state(Config) -> init_rebar_state(Config, "apps_dir1_").
  12. %% @doc Takes a common test config and a name (string) and sets up
  13. %% a basic OTP app directory with a pre-configured rebar state to
  14. %% run tests with.
  15. init_rebar_state(Config, Name) ->
  16. application:load(rebar),
  17. DataDir = ?config(priv_dir, Config),
  18. AppsDir = filename:join([DataDir, create_random_name(Name)]),
  19. ok = ec_file:mkdir_p(AppsDir),
  20. Verbosity = rebar3:log_level(),
  21. rebar_log:init(command_line, Verbosity),
  22. State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}]),
  23. [{apps, AppsDir}, {state, State} | Config].
  24. %% @doc Takes common test config, a rebar config ([] if empty), a command to
  25. %% run ("install_deps", "compile", etc.), and a list of expected applications
  26. %% and/or dependencies to be present, and verifies whether they are all in
  27. %% place.
  28. %%
  29. %% The expectation list takes elements of the form:
  30. %% - `{app, Name :: string()}': checks that the app is properly built.
  31. %% - `{dep, Name :: string()}': checks that the dependency has been fetched.
  32. %% Ignores the build status of the dependency.
  33. %% - `{dep, Name :: string(), Vsn :: string()}': checks that the dependency
  34. %% has been fetched, and that a given version has been chosen. Useful to
  35. %% test for conflict resolution. Also ignores the build status of the
  36. %% dependency.
  37. %%
  38. %% This function assumes `init_rebar_state/1-2' has run before, in order to
  39. %% fetch the `apps' and `state' values from the CT config.
  40. run_and_check(Config, RebarConfig, Command, Expect) ->
  41. %% Assumes init_rebar_state has run first
  42. AppDir = ?config(apps, Config),
  43. State = ?config(state, Config),
  44. Res = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), Command),
  45. case Expect of
  46. {error, Reason} ->
  47. ?assertEqual({error, Reason}, Res);
  48. {ok, Expected} ->
  49. {ok, _} = Res,
  50. check_results(AppDir, Expected)
  51. end.
  52. %% @doc Creates a dummy application including:
  53. %% - src/<file>.erl
  54. %% - src/<file>.app.src
  55. %% And returns a `rebar_app_info' object.
  56. create_app(AppDir, Name, Vsn, Deps) ->
  57. write_src_file(AppDir, Name),
  58. write_app_src_file(AppDir, Name, Vsn, Deps),
  59. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  60. %% @doc Creates a dummy application including:
  61. %% - ebin/<file>.app
  62. %% And returns a `rebar_app_info' object.
  63. create_empty_app(AppDir, Name, Vsn, Deps) ->
  64. write_app_file(AppDir, Name, Vsn, Deps),
  65. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  66. %% @doc Creates a rebar.config file. The function accepts a list of terms,
  67. %% each of which will be dumped as a consult file. For example, the list
  68. %% `[a, b, c]' will return the consult file `a. b. c.'.
  69. create_config(AppDir, Contents) ->
  70. Conf = filename:join([AppDir, "rebar.config"]),
  71. ok = filelib:ensure_dir(Conf),
  72. Config = lists:flatten([io_lib:fwrite("~p.~n", [Term]) || Term <- Contents]),
  73. ok = ec_file:write(Conf, Config),
  74. Conf.
  75. %% @doc Util to create a random variation of a given name.
  76. create_random_name(Name) ->
  77. random:seed(erlang:now()),
  78. Name ++ erlang:integer_to_list(random:uniform(1000000)).
  79. %% @doc Util to create a random variation of a given version.
  80. create_random_vsn() ->
  81. random:seed(erlang:now()),
  82. lists:flatten([erlang:integer_to_list(random:uniform(100)),
  83. ".", erlang:integer_to_list(random:uniform(100)),
  84. ".", erlang:integer_to_list(random:uniform(100))]).
  85. %%%%%%%%%%%%%%%
  86. %%% Helpers %%%
  87. %%%%%%%%%%%%%%%
  88. check_results(AppDir, Expected) ->
  89. BuildDir = filename:join([AppDir, "_build", "default", "lib"]),
  90. Deps = rebar_app_discover:find_apps([BuildDir], all),
  91. DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
  92. lists:foreach(
  93. fun({app, Name}) ->
  94. [App] = rebar_app_discover:find_apps([AppDir]),
  95. ct:pal("Name: ~p", [Name]),
  96. ?assertEqual(Name, ec_cnv:to_list(rebar_app_info:name(App)))
  97. ; ({dep, Name}) ->
  98. ct:pal("Name: ~p", [Name]),
  99. ?assertNotEqual(false, lists:keyfind(Name, 1, DepsNames))
  100. ; ({dep, Name, Vsn}) ->
  101. ct:pal("Name: ~p, Vsn: ~p", [Name, Vsn]),
  102. case lists:keyfind(Name, 1, DepsNames) of
  103. false ->
  104. error({app_not_found, Name});
  105. {Name, App} ->
  106. ?assertEqual(Vsn, rebar_app_info:original_vsn(App))
  107. end
  108. end, Expected).
  109. write_src_file(Dir, Name) ->
  110. Erl = filename:join([Dir, "src", "not_a_real_src" ++ Name ++ ".erl"]),
  111. ok = filelib:ensure_dir(Erl),
  112. ok = ec_file:write(Erl, erl_src_file("not_a_real_src" ++ Name ++ ".erl")).
  113. write_app_file(Dir, Name, Version, Deps) ->
  114. Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
  115. ok = filelib:ensure_dir(Filename),
  116. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  117. write_app_src_file(Dir, Name, Version, Deps) ->
  118. Filename = filename:join([Dir, "src", Name ++ ".app.src"]),
  119. ok = filelib:ensure_dir(Filename),
  120. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  121. erl_src_file(Name) ->
  122. io_lib:format("-module(~s).\n"
  123. "-export([main/0]).\n"
  124. "main() -> ok.\n", [filename:basename(Name, ".erl")]).
  125. get_app_metadata(Name, Vsn, Deps) ->
  126. {application, erlang:list_to_atom(Name),
  127. [{description, ""},
  128. {vsn, Vsn},
  129. {modules, []},
  130. {included_applications, []},
  131. {registered, []},
  132. {applications, Deps}]}.