summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/mock_git_resource.erl17
-rw-r--r--test/mock_pkg_resource.erl103
-rw-r--r--test/rebar_alias_SUITE.erl165
-rw-r--r--test/rebar_as_SUITE.erl19
-rw-r--r--test/rebar_compile_SUITE.erl1226
-rw-r--r--test/rebar_cover_SUITE.erl118
-rw-r--r--test/rebar_ct_SUITE.erl472
-rw-r--r--test/rebar_deps_SUITE.erl160
-rw-r--r--test/rebar_dialyzer_SUITE.erl40
-rw-r--r--test/rebar_dir_SUITE.erl98
-rw-r--r--test/rebar_edoc_SUITE.erl72
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.app.src16
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.erl9
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_sup.erl35
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.app.src16
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.erl12
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_sup.erl35
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.app.src17
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.erl19
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_sup.erl35
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.app.src16
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.erl9
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_sup.erl35
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.app.src16
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.erl9
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_sup.erl35
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.app.src17
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.erl19
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_app.erl26
-rw-r--r--test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_sup.erl35
-rw-r--r--test/rebar_escriptize_SUITE.erl51
-rw-r--r--test/rebar_eunit_SUITE.erl31
-rw-r--r--test/rebar_file_utils_SUITE.erl200
-rw-r--r--test/rebar_hooks_SUITE.erl113
-rw-r--r--test/rebar_install_deps_SUITE.erl131
-rw-r--r--test/rebar_localfs_resource.erl8
-rw-r--r--test/rebar_localfs_resource_v2.erl50
-rw-r--r--test/rebar_paths_SUITE.erl240
-rw-r--r--test/rebar_pkg_SUITE.erl177
-rw-r--r--test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tarbin10240 -> 10240 bytes
-rw-r--r--test/rebar_pkg_SUITE_data/badpkg-1.0.0.tarbin10240 -> 10240 bytes
-rw-r--r--test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tarbin10240 -> 10240 bytes
-rw-r--r--test/rebar_pkg_alias_SUITE.erl209
-rw-r--r--test/rebar_pkg_repos_SUITE.erl376
-rw-r--r--test/rebar_plugins_SUITE.erl30
-rw-r--r--test/rebar_profiles_SUITE.erl218
-rw-r--r--test/rebar_release_SUITE.erl65
-rw-r--r--test/rebar_resource_SUITE.erl9
-rw-r--r--test/rebar_src_dirs_SUITE.erl98
-rw-r--r--test/rebar_test_utils.erl110
-rw-r--r--test/rebar_unlock_SUITE.erl11
-rw-r--r--test/rebar_unlock_SUITE_data/pkg.rebar.lock56
-rw-r--r--test/rebar_upgrade_SUITE.erl489
-rw-r--r--test/rebar_utils_SUITE.erl51
-rw-r--r--test/rebar_xref_SUITE.erl100
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config12
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src16
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl26
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl35
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src17
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl26
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl35
67 files changed, 5313 insertions, 708 deletions
diff --git a/test/mock_git_resource.erl b/test/mock_git_resource.erl
index e922af3..5673349 100644
--- a/test/mock_git_resource.erl
+++ b/test/mock_git_resource.erl
@@ -27,7 +27,7 @@ mock(Opts) ->
mock(Opts, create_app).
mock(Opts, CreateType) ->
- meck:new(?MOD, [no_link]),
+ meck:new(?MOD, [no_link, passthrough]),
mock_lock(Opts),
mock_update(Opts),
mock_vsn(Opts),
@@ -46,8 +46,8 @@ unmock() ->
mock_lock(_) ->
meck:expect(
?MOD, lock,
- fun(_AppDir, Git) ->
- case Git of
+ fun(AppInfo, _) ->
+ case rebar_app_info:source(AppInfo) of
{git, Url, {tag, Ref}} -> {git, Url, {ref, Ref}};
{git, Url, {ref, Ref}} -> {git, Url, {ref, Ref}};
{git, Url} -> {git, Url, {ref, "0.0.0"}};
@@ -62,7 +62,8 @@ mock_update(Opts) ->
% ct:pal("TOUp: ~p", [ToUpdate]),
meck:expect(
?MOD, needs_update,
- fun(_Dir, {git, Url, _Ref}) ->
+ fun(AppInfo, _) ->
+ {git, Url, _Ref} = rebar_app_info:source(AppInfo),
App = app(Url),
% ct:pal("Needed update? ~p (~p) -> ~p", [App, {Url,_Ref}, lists:member(App, ToUpdate)]),
lists:member(App, ToUpdate)
@@ -78,7 +79,8 @@ mock_vsn(Opts) ->
Default = proplists:get_value(default_vsn, Opts, "0.0.0"),
meck:expect(
?MOD, make_vsn,
- fun(Dir) ->
+ fun(AppInfo, _) ->
+ Dir = rebar_app_info:dir(AppInfo),
case filelib:wildcard("*.app.src", filename:join([Dir,"src"])) of
[AppSrc] ->
{ok, App} = file:consult(AppSrc),
@@ -108,7 +110,8 @@ mock_download(Opts, CreateType) ->
Overrides = proplists:get_value(override_vsn, Opts, []),
meck:expect(
?MOD, download,
- fun (Dir, Git, _) ->
+ fun (Dir, AppInfo, _, _) ->
+ Git = rebar_app_info:source(AppInfo),
filelib:ensure_dir(Dir),
{git, Url, {_, Vsn}} = normalize_git(Git, Overrides, Default),
App = app(Url),
@@ -118,7 +121,7 @@ mock_download(Opts, CreateType) ->
[kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config),
- {ok, 'WHATEVER'}
+ ok
end).
%%%%%%%%%%%%%%%
diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl
index f837713..a169efd 100644
--- a/test/mock_pkg_resource.erl
+++ b/test/mock_pkg_resource.erl
@@ -3,6 +3,8 @@
-export([mock/0, mock/1, unmock/0]).
-define(MOD, rebar_pkg_resource).
+-include("rebar.hrl").
+
%%%%%%%%%%%%%%%%%
%%% Interface %%%
%%%%%%%%%%%%%%%%%
@@ -26,7 +28,7 @@ mock() -> mock([]).
Vsn :: string(),
Hash :: string() | undefined.
mock(Opts) ->
- meck:new(?MOD, [no_link]),
+ meck:new(?MOD, [no_link, passthrough]),
mock_lock(Opts),
mock_update(Opts),
mock_vsn(Opts),
@@ -44,7 +46,10 @@ unmock() ->
%% @doc creates values for a lock file.
mock_lock(_) ->
- meck:expect(?MOD, lock, fun(_AppDir, Source) -> Source end).
+ meck:expect(?MOD, lock, fun(AppInfo, _) ->
+ {pkg, Name, Vsn, Hash, _RepoConfig} = rebar_app_info:source(AppInfo),
+ {pkg, Name, Vsn, Hash}
+ end).
%% @doc The config passed to the `mock/2' function can specify which apps
%% should be updated on a per-name basis: `{update, ["App1", "App3"]}'.
@@ -52,7 +57,8 @@ mock_update(Opts) ->
ToUpdate = proplists:get_value(upgrade, Opts, []),
meck:expect(
?MOD, needs_update,
- fun(_Dir, {pkg, App, _Vsn, _Hash}) ->
+ fun(AppInfo, _) ->
+ {pkg, App, _Vsn, _Hash, _} = rebar_app_info:source(AppInfo),
lists:member(binary_to_list(App), ToUpdate)
end).
@@ -60,7 +66,7 @@ mock_update(Opts) ->
mock_vsn(_Opts) ->
meck:expect(
?MOD, make_vsn,
- fun(_Dir) ->
+ fun(_AppInfo, _) ->
{error, "Replacing version of type pkg not supported."}
end).
@@ -77,30 +83,32 @@ mock_download(Opts) ->
Config = proplists:get_value(config, Opts, []),
meck:expect(
?MOD, download,
- fun (Dir, {pkg, AppBin, Vsn, _}, _) ->
- App = binary_to_list(AppBin),
+ fun (Dir, AppInfo, _, _) ->
+ {pkg, AppBin, Vsn, _, _} = rebar_app_info:source(AppInfo),
+ App = rebar_utils:to_list(AppBin),
filelib:ensure_dir(Dir),
AppDeps = proplists:get_value({App,Vsn}, Deps, []),
- {ok, AppInfo} = rebar_test_utils:create_app(
- Dir, App, binary_to_list(Vsn),
+ {ok, AppInfo1} = rebar_test_utils:create_app(
+ Dir, App, rebar_utils:to_list(Vsn),
[kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
),
rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config),
- TarApp = App++"-"++binary_to_list(Vsn)++".tar",
- Tarball = filename:join([Dir, TarApp]),
- Contents = filename:join([Dir, "contents.tar.gz"]),
- Files = all_files(rebar_app_info:dir(AppInfo)),
- ok = erl_tar:create(Contents,
- archive_names(Dir, App, Vsn, Files),
- [compressed]),
- ok = erl_tar:create(Tarball,
- [{"contents.tar.gz", Contents}],
- []),
+
+ TarApp = App++"-"++rebar_utils:to_list(Vsn)++".tar",
+
+ Metadata = #{<<"app">> => AppBin,
+ <<"version">> => Vsn},
+
+ Files = all_files(rebar_app_info:dir(AppInfo1)),
+ {ok, {Tarball, _Checksum}} = hex_tarball:create(Metadata, archive_names(Dir, Files)),
+ Archive = filename:join([Dir, TarApp]),
+ file:write_file(Archive, Tarball),
+
Cache = proplists:get_value(cache_dir, Opts, filename:join(Dir,"cache")),
Cached = filename:join([Cache, TarApp]),
filelib:ensure_dir(Cached),
- rebar_file_utils:mv(Tarball, Cached),
- {ok, true}
+ rebar_file_utils:mv(Archive, Cached),
+ ok
end).
%% @doc On top of the pkg resource mocking, we need to mock the package
@@ -110,16 +118,18 @@ mock_download(Opts) ->
%% specific applications otherwise listed.
mock_pkg_index(Opts) ->
Deps = proplists:get_value(pkgdeps, Opts, []),
+ Repos = proplists:get_value(repos, Opts, [<<"hexpm">>]),
Skip = proplists:get_value(not_in_index, Opts, []),
%% Dict: {App, Vsn}: [{<<"link">>, <<>>}, {<<"deps">>, []}]
%% Index: all apps and deps in the index
Dict = find_parts(Deps, Skip),
+ to_index(Deps, Dict, Repos),
meck:new(rebar_packages, [passthrough, no_link]),
- meck:expect(rebar_packages, packages,
- fun(_State) -> to_index(Deps, Dict) end),
+ meck:expect(rebar_packages, update_package,
+ fun(_, _, _State) -> ok end),
meck:expect(rebar_packages, verify_table,
- fun(_State) -> to_index(Deps, Dict), true end).
+ fun(_State) -> true end).
%%%%%%%%%%%%%%%
%%% Helpers %%%
@@ -128,7 +138,7 @@ mock_pkg_index(Opts) ->
all_files(Dir) ->
filelib:wildcard(filename:join([Dir, "**"])).
-archive_names(Dir, _App, _Vsn, Files) ->
+archive_names(Dir, Files) ->
[{(F -- Dir) -- "/", F} || F <- Files].
find_parts(Apps, Skip) -> find_parts(Apps, Skip, dict:new()).
@@ -143,21 +153,42 @@ find_parts([{AppName, Deps}|Rest], Skip, Acc) ->
Acc),
find_parts(Rest, Skip, AccNew)
end.
+parse_deps(Deps) ->
+ [{maps:get(app, D, Name), {pkg, Name, Constraint, undefined}} || D=#{package := Name,
+ requirement := Constraint} <- Deps].
+
+to_index(AllDeps, Dict, Repos) ->
+ catch ets:delete(?PACKAGE_TABLE),
+ rebar_packages:new_package_table(),
-to_index(AllDeps, Dict) ->
- catch ets:delete(package_index),
- ets:new(package_index, [named_table, public]),
dict:fold(
- fun(K, Deps, _) ->
- DepsList = [{ec_cnv:to_binary(DK), ec_cnv:to_binary(DV)} || {DK, DV} <- Deps],
- ets:insert(package_index, {K, DepsList, <<"checksum">>})
+ fun({N, V}, Deps, _) ->
+ DepsList = [#{package => DKB,
+ app => DKB,
+ requirement => DVB,
+ source => {pkg, DKB, DVB, undefined}}
+ || {DK, DV} <- Deps,
+ DKB <- [ec_cnv:to_binary(DK)],
+ DVB <- [ec_cnv:to_binary(DV)]],
+ Repo = rebar_test_utils:random_element(Repos),
+ ets:insert(?PACKAGE_TABLE, #package{key={N, ec_semver:parse(V), Repo},
+ dependencies=parse_deps(DepsList),
+ retired=false,
+ checksum = <<"checksum">>})
end, ok, Dict),
- ets:insert(package_index, {package_index_version, 3}),
+
lists:foreach(fun({{Name, Vsn}, _}) ->
- case ets:lookup(package_index, ec_cnv:to_binary(Name)) of
- [{_, Vsns}] ->
- ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn) | Vsns]});
- _ ->
- ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn)]})
+ case lists:any(fun(R) ->
+ ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), ec_semver:parse(Vsn), R})
+ end, Repos) of
+ false ->
+ Repo = rebar_test_utils:random_element(Repos),
+ ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(Name), ec_semver:parse(Vsn), Repo},
+ dependencies=[],
+ retired=false,
+ checksum = <<"checksum">>});
+ true ->
+ ok
end
end, AllDeps).
+
diff --git a/test/rebar_alias_SUITE.erl b/test/rebar_alias_SUITE.erl
new file mode 100644
index 0000000..d6e27d9
--- /dev/null
+++ b/test/rebar_alias_SUITE.erl
@@ -0,0 +1,165 @@
+-module(rebar_alias_SUITE).
+-compile([export_all]).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+
+init_per_suite(Config) -> Config.
+end_per_suite(_Config) -> ok.
+
+init_per_testcase(_, Config) ->
+ rebar_test_utils:init_rebar_state(Config, "alias_").
+
+end_per_testcase(_, _Config) ->
+ ok.
+
+all() -> [command, args, many, override_default, no_circular, release,
+ check_namespaces, create_lib].
+
+command() ->
+ [{doc, "Runs multiple regular commands as one alias"}].
+command(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_command_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [compile, unlock]}]}],
+
+ %% compile job ran
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["test"], {ok, [{app, Name}]}),
+ %% unlock job also ran
+ Lockfile = filename:join(?config(apps, Config), "rebar.lock"),
+ ?assertNot(filelib:is_file(Lockfile)),
+ ok.
+
+args() ->
+ [{doc, "Runs multiple regular commands as one alias, some of "
+ "which have default arguments"}].
+args(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_args_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [{eunit,"-c"}, cover]}]}],
+
+ %% test job ran (compiled and succeeded)
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["test"], {ok, [{app, Name}]}),
+ %% cover job also ran, meaning eunit had coverage on, otherwise
+ %% the index file is not generated.
+ CoverFile = filename:join([?config(apps, Config),
+ "_build", "test", "cover", "index.html"]),
+ ?assert(filelib:is_file(CoverFile)),
+ ok.
+
+many() ->
+ [{doc, "Multiple aliases may be registered"}].
+many(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_args_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [{eunit,"-c"}, cover]},
+ {nolock, [compile, unlock]}]}],
+
+ %% test job ran (compiled and succeeded)
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["test"], {ok, [{app, Name}]}),
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["nolock"], {ok, [{app, Name}]}),
+ %% both jobs ran (see args/1 and command/1)
+ CoverFile = filename:join([?config(apps, Config),
+ "_build", "test", "cover", "index.html"]),
+ ?assert(filelib:is_file(CoverFile)),
+ Lockfile = filename:join(?config(apps, Config), "rebar.lock"),
+ ?assertNot(filelib:is_file(Lockfile)),
+ ok.
+
+override_default() ->
+ [{doc, "An alias cannot take over a default provider"}].
+override_default(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_override_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{compile, [help]}]}],
+
+ %% App compiles anyway
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{app, Name}]}),
+ ok.
+
+no_circular() ->
+ [{doc, "An alias cannot define itself as itself"},
+ {timetrap, 2000}].
+no_circular(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_circular_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [help, {test,"-a"}, compile]}]}],
+
+ %% Code does not deadlock forever and errors by not knowing
+ %% the command
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["test"],
+ {error, [$C,$o,$m,$m,$a,$n,$d,$ ,"test",$ ,$n,$o,$t,$ ,
+ $f,$o,$u,$n,$d]}),
+ ok.
+
+release() ->
+ [{doc, "An alias for a release command"}].
+release(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("alias_release_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{relx,
+ [{release, {skipped_release, Vsn}, []},
+ {release, {the_release, Vsn}, [list_to_atom(Name)]},
+ {lib_dirs, [AppDir]}]},
+ {alias,
+ [{the_rel1, [clean, {release, "-n the_release"}]},
+ {the_rel2, [clean, {release, "--relname=the_release"}]}]}],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["the_rel1"],
+ {ok, [{release, the_release, Vsn, false}]}),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["the_rel2"],
+ {ok, [{release, the_release, Vsn, false}]}),
+ ok.
+
+check_namespaces() ->
+ [{doc, "Test calling commands with namespaces from rebar3"}].
+check_namespaces(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("alias_args_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [{eunit,"-c"}, {plugins, list}]}]}],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["test"], {ok, [{app, Name}]}),
+ ok.
+
+create_lib() ->
+ [{doc, "Test calling commands with namespaces from rebar3"}].
+create_lib(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("create_lib_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{alias, [{test, [compile, {do, "new lib shouldexist"}]}]}],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["test"], {ok, [{app, Name}]}),
+ AppFile = filename:join(?config(apps, Config),
+ "../../../../shouldexist/src/shouldexist.app.src"),
+ ?assert(filelib:is_file(AppFile)),
+ ok.
diff --git a/test/rebar_as_SUITE.erl b/test/rebar_as_SUITE.erl
index 0f37dc8..78ea8ae 100644
--- a/test/rebar_as_SUITE.erl
+++ b/test/rebar_as_SUITE.erl
@@ -14,6 +14,7 @@
as_dir_name/1,
as_with_task_args/1,
warn_on_empty_profile/1,
+ error_on_empty_tasks/1,
clean_as_profile/1]).
-include_lib("common_test/include/ct.hrl").
@@ -33,7 +34,7 @@ all() -> [as_basic, as_multiple_profiles, as_multiple_tasks,
as_multiple_profiles_multiple_tasks,
as_comma_placement, as_comma_then_space,
as_dir_name, as_with_task_args,
- warn_on_empty_profile, clean_as_profile].
+ warn_on_empty_profile, error_on_empty_tasks, clean_as_profile].
as_basic(Config) ->
AppDir = ?config(apps, Config),
@@ -159,9 +160,23 @@ warn_on_empty_profile(Config) ->
meck:unload(rebar_log),
ok.
+error_on_empty_tasks(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("as_error_empty_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ meck:new(rebar_log, [passthrough]),
+ rebar_test_utils:run_and_check(Config,
+ [],
+ ["as", "default"],
+ {error, "At least one task must be specified when using `as`"}),
+ ok.
+
warn_match(App, History) ->
lists:any(
- fun({_, {rebar_log,log, [warn, "No entry for profile ~s in config.",
+ fun({_, {rebar_log,log, [warn, "No entry for profile ~ts in config.",
[ArgApp]]}, _}) -> ArgApp =:= App
; (_) ->
false
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index d9b75e4..ddaad0c 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -1,48 +1,6 @@
-module(rebar_compile_SUITE).
--export([suite/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2,
- init_per_group/2,
- end_per_group/2,
- all/0,
- groups/0,
- build_basic_app/1, paths_basic_app/1, clean_basic_app/1,
- build_release_apps/1, paths_release_apps/1, clean_release_apps/1,
- build_checkout_apps/1, paths_checkout_apps/1,
- build_checkout_deps/1, paths_checkout_deps/1,
- build_basic_srcdirs/1, paths_basic_srcdirs/1,
- build_release_srcdirs/1, paths_release_srcdirs/1,
- build_unbalanced_srcdirs/1, paths_unbalanced_srcdirs/1,
- build_basic_extra_dirs/1, paths_basic_extra_dirs/1, clean_basic_extra_dirs/1,
- build_release_extra_dirs/1, paths_release_extra_dirs/1, clean_release_extra_dirs/1,
- build_unbalanced_extra_dirs/1, paths_unbalanced_extra_dirs/1,
- build_extra_dirs_in_project_root/1,
- paths_extra_dirs_in_project_root/1,
- clean_extra_dirs_in_project_root/1,
- recompile_when_hrl_changes/1,
- recompile_when_included_hrl_changes/1,
- recompile_when_opts_change/1,
- dont_recompile_when_opts_dont_change/1,
- dont_recompile_yrl_or_xrl/1,
- deps_in_path/1,
- delete_beam_if_source_deleted/1,
- checkout_priority/1,
- highest_version_of_pkg_dep/1,
- parse_transform_test/1,
- erl_first_files_test/1,
- mib_test/1,
- umbrella_mib_first_test/1,
- only_default_transitive_deps/1,
- clean_all/1,
- override_deps/1,
- profile_override_deps/1,
- deps_build_in_prod/1,
- include_file_relative_to_working_directory/1,
- include_file_in_src/1,
- always_recompile_when_erl_compiler_options_set/1]).
+-compile(export_all).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -58,18 +16,30 @@ all() ->
{group, basic_extras}, {group, release_extras}, {group, unbalanced_extras},
{group, root_extras},
recompile_when_hrl_changes, recompile_when_included_hrl_changes,
+ recompile_when_opts_included_hrl_changes,
recompile_when_opts_change,
dont_recompile_when_opts_dont_change, dont_recompile_yrl_or_xrl,
delete_beam_if_source_deleted,
deps_in_path, checkout_priority, highest_version_of_pkg_dep,
parse_transform_test, erl_first_files_test, mib_test,
- umbrella_mib_first_test, only_default_transitive_deps,
- clean_all, override_deps, profile_override_deps, deps_build_in_prod,
- include_file_relative_to_working_directory, include_file_in_src] ++
- case erlang:function_exported(os, unsetenv, 1) of
- true -> [always_recompile_when_erl_compiler_options_set];
- false -> []
- end.
+ umbrella_mib_first_test, only_default_transitive_deps, clean_all,
+ profile_deps, deps_build_in_prod, only_deps,
+ override_deps, override_add_deps, override_del_deps,
+ override_opts, override_add_opts, override_del_opts,
+ apply_overrides_exactly_once,
+ profile_override_deps, profile_override_add_deps, profile_override_del_deps,
+ profile_override_opts, profile_override_add_opts, profile_override_del_opts,
+ include_file_relative_to_working_directory, include_file_in_src,
+ include_file_relative_to_working_directory_test, include_file_in_src_test,
+ include_file_in_src_test_multiapp,
+ recompile_when_parse_transform_as_opt_changes,
+ recompile_when_parse_transform_inline_changes,
+ regex_filter_skip, regex_filter_regression,
+ recursive, no_recursive,
+ always_recompile_when_erl_compiler_options_set,
+ dont_recompile_when_erl_compiler_options_env_does_not_change,
+ recompile_when_erl_compiler_options_env_changes,
+ rebar_config_os_var].
groups() ->
[{basic_app, [], [build_basic_app, paths_basic_app, clean_basic_app]},
@@ -243,7 +213,31 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
-init_per_testcase(_, Config) ->
+init_per_testcase(Test, Config) when
+ Test == dont_recompile_when_erl_compiler_options_env_does_not_change
+ orelse
+ Test == recompile_when_erl_compiler_options_env_changes ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> maybe_init_config(Config);
+ _ -> {skip, "compile:env_compiler_options/0 unavailable"}
+ end;
+init_per_testcase(always_recompile_when_erl_compiler_options_set, Config) ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> {skip, "compile:env_compiler_options/0 available"};
+ {true, false} -> maybe_init_config(Config);
+ _ -> {skip, "os:unsetenv/1 unavailable"}
+ end;
+init_per_testcase(_, Config) -> maybe_init_config(Config).
+
+maybe_init_config(Config) ->
case ?config(apps, Config) of
undefined -> rebar_test_utils:init_rebar_state(Config);
_ -> Config
@@ -253,7 +247,6 @@ end_per_testcase(_, _Config) ->
catch meck:unload().
-
%% test cases
build_basic_app(Config) ->
@@ -717,6 +710,53 @@ recompile_when_included_hrl_changes(Config) ->
?assert(ModTime =/= NewModTime).
+recompile_when_opts_included_hrl_changes(Config) ->
+ AppsDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ AppDir = filename:join([AppsDir, "apps", Name]),
+
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ ExtraSrc = <<"-module(test_header_include).\n"
+ "-export([main/0]).\n"
+ "-include(\"test_header_include.hrl\").\n"
+ "main() -> ?SOME_DEFINE.\n">>,
+
+ ExtraHeader = <<"-define(SOME_DEFINE, true).\n">>,
+ ok = filelib:ensure_dir(filename:join([AppsDir, "include", "dummy"])),
+ HeaderFile = filename:join([AppsDir, "include", "test_header_include.hrl"]),
+ ok = file:write_file(filename:join([AppDir, "src", "test_header_include.erl"]), ExtraSrc),
+ ok = file:write_file(HeaderFile, ExtraHeader),
+
+ %% Using relative path from the project root
+ RebarConfig = [{erl_opts, [{i, "include/"}]}],
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(AppsDir),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppsDir, "_build", "default", "lib", Name, "ebin"]),
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- Files, filename:extension(F) == ".beam"],
+
+ timer:sleep(1000),
+
+ NewExtraHeader = <<"-define(SOME_DEFINE, false).\n">>,
+ ok = file:write_file(HeaderFile, NewExtraHeader),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ {ok, NewFiles} = rebar_utils:list_dir(EbinDir),
+ NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- NewFiles, filename:extension(F) == ".beam"],
+
+ ok = file:set_cwd(Cwd),
+
+ ?assert(ModTime =/= NewModTime).
+
recompile_when_opts_change(Config) ->
AppDir = ?config(apps, Config),
@@ -735,7 +775,7 @@ recompile_when_opts_change(Config) ->
rebar_test_utils:create_config(AppDir, [{erl_opts, [{d, some_define}]}]),
- rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+ rebar_test_utils:run_and_check(Config, [{erl_opts, [{d, some_define}]}], ["compile"], {ok, [{app, Name}]}),
{ok, NewFiles} = rebar_utils:list_dir(EbinDir),
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
@@ -765,7 +805,7 @@ dont_recompile_when_opts_dont_change(Config) ->
NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- NewFiles, filename:extension(F) == ".beam"],
- ?assert(ModTime == NewModTime).
+ ?assertEqual(ModTime, NewModTime).
dont_recompile_yrl_or_xrl(Config) ->
AppDir = ?config(apps, Config),
@@ -792,19 +832,55 @@ dont_recompile_yrl_or_xrl(Config) ->
"Erlang code.",
ok = ec_file:write(Xrl, XrlBody),
- XrlBeam = filename:join([AppDir, "ebin", filename:basename(Xrl, ".xrl") ++ ".beam"]),
+ Yrl = filename:join([AppDir, "src", "not_a_real_yrl_" ++ Name ++ ".yrl"]),
+ ok = filelib:ensure_dir(Yrl),
+ YrlBody = ["Nonterminals E T F.\n"
+ "Terminals '+' '*' '(' ')' number.\n"
+ "Rootsymbol E.\n"
+ "E -> E '+' T: {'$2', '$1', '$3'}.\n"
+ "E -> T : '$1'.\n"
+ "T -> T '*' F: {'$2', '$1', '$3'}.\n"
+ "T -> F : '$1'.\n"
+ "F -> '(' E ')' : '$2'.\n"
+ "F -> number : '$1'.\n"],
+ ok = ec_file:write(Yrl, YrlBody),
+
+ XrlErl = filename:join([AppDir, "src", filename:basename(Xrl, ".xrl") ++ ".erl"]),
+ YrlErl = filename:join([AppDir, "src", filename:basename(Yrl, ".yrl") ++ ".erl"]),
- rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ XrlBeam = filename:join([EbinDir, filename:basename(Xrl, ".xrl") ++ ".beam"]),
+ YrlBeam = filename:join([EbinDir, filename:basename(Yrl, ".yrl") ++ ".beam"]),
+
+ Hrl = filename:join([AppDir, "include", "some_header.hrl"]),
+ ok = filelib:ensure_dir(Hrl),
+ HrlBody = yeccpre_hrl(),
+ ok = ec_file:write(Hrl, HrlBody),
+ RebarConfig = [{yrl_opts, [{includefile, "include/some_header.hrl"}]}],
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
- ModTime = filelib:last_modified(XrlBeam),
+ XrlModTime = filelib:last_modified(XrlErl),
+ YrlModTime = filelib:last_modified(YrlErl),
+
+ XrlBeamModTime = filelib:last_modified(XrlBeam),
+ YrlBeamModTime = filelib:last_modified(YrlBeam),
timer:sleep(1000),
- rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ NewXrlModTime = filelib:last_modified(XrlErl),
+ NewYrlModTime = filelib:last_modified(YrlErl),
- NewModTime = filelib:last_modified(XrlBeam),
+ NewXrlBeamModTime = filelib:last_modified(XrlBeam),
+ NewYrlBeamModTime = filelib:last_modified(YrlBeam),
- ?assert(ModTime == NewModTime).
+ ?assert(XrlBeamModTime == NewXrlBeamModTime),
+ ?assert(YrlBeamModTime == NewYrlBeamModTime),
+
+ ?assert(XrlModTime == NewXrlModTime),
+ ?assert(YrlModTime == NewYrlModTime).
delete_beam_if_source_deleted(Config) ->
AppDir = ?config(apps, Config),
@@ -1085,17 +1161,19 @@ umbrella_mib_first_test(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
- MibsSrc = <<"-- SIMPLE-MIB.\n"
+ BExporterSrc = <<"-- BEXPORTER-MIB.\n"
"-- This is just a simple MIB used for testing!\n"
"--\n"
-"SIMPLE-MIB DEFINITIONS ::= BEGIN\n"
+"BEXPORTER-MIB DEFINITIONS ::= BEGIN\n"
"IMPORTS\n"
+" TEXTUAL-CONVENTION\n"
+" FROM SNMPv2-TC\n"
" MODULE-IDENTITY, enterprises\n"
" FROM SNMPv2-SMI;\n"
"\n"
"ericsson MODULE-IDENTITY\n"
" LAST-UPDATED\n"
-" \"201403060000Z\"\n"
+" \"201812050000Z\"\n"
" ORGANIZATION\n"
" \"rebar\"\n"
" CONTACT-INFO\n"
@@ -1107,25 +1185,71 @@ umbrella_mib_first_test(Config) ->
" \"This very small module is made available\n"
" for mib-compilation testing.\"\n"
" ::= { enterprises 999 }\n"
+"\n"
+"Something ::= TEXTUAL-CONVENTION\n"
+" STATUS current\n"
+" DESCRIPTION \"\"\n"
+" SYNTAX OCTET STRING (SIZE (4))\n"
+"END\n">>,
+
+ AImporterSrc = <<"-- AIMPORTER-MIB.\n"
+"-- This is just a simple MIB used for testing!\n"
+"--\n"
+"AIMPORTER-MIB DEFINITIONS ::= BEGIN\n"
+"IMPORTS\n"
+" Something\n"
+" FROM BEXPORTER-MIB\n"
+" MODULE-IDENTITY, enterprises\n"
+" FROM SNMPv2-SMI;\n"
+"\n"
+"ericsson MODULE-IDENTITY\n"
+" LAST-UPDATED\n"
+" \"201812050000Z\"\n"
+" ORGANIZATION\n"
+" \"rebar\"\n"
+" CONTACT-INFO\n"
+" \"rebar <rebar@example.com>\n"
+" or\n"
+" whoever is currently responsible for the SIMPLE\n"
+" enterprise MIB tree branch (enterprises.999).\"\n"
+" DESCRIPTION\n"
+" \"This very small module is made available\n"
+" for mib-compilation testing.\"\n"
+" ::= { enterprises 1000 }\n"
"END\n">>,
+
+
ok = filelib:ensure_dir(filename:join([AppDir, "mibs", "dummy"])),
- ok = file:write_file(filename:join([AppDir, "mibs", "SIMPLE-MIB.mib"]), MibsSrc),
+ ok = file:write_file(filename:join([AppDir, "mibs", "AIMPORTER-MIB.mib"]), AImporterSrc),
+ ok = file:write_file(filename:join([AppDir, "mibs", "BEXPORTER-MIB.mib"]), BExporterSrc),
- RebarConfig = [{mib_first_files, ["mibs/SIMPLE-MIB.mib"]}],
+ FailureRebarConfig = [{mib_first_files, ["mibs/AIMPORTER-MIB.mib"]}],
+ SuccessRebarConfig = [{mib_first_files, ["mibs/BEXPORTER-MIB.mib"]}],
- rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+ PrivMibsDir = filename:join([AppsDir, "_build", "default", "lib", Name, "priv", "mibs"]),
+
+ FailureRebarConfig = [{mib_first_files, ["mibs/AIMPORTER-MIB.mib"]}],
+ catch (
+ rebar_test_utils:run_and_check(Config, FailureRebarConfig, ["compile"], {ok, [{app, Name}]}) ),
+
+ %% check that the bin file was NOT cretated
+ false = filelib:is_file(filename:join([PrivMibsDir, "AIMPORTER-MIB.bin"])),
+
+
+ SuccessRebarConfig = [{mib_first_files, ["mibs/BEXPORTER-MIB.mib"]}],
+ rebar_test_utils:run_and_check(Config, SuccessRebarConfig, ["compile"], {ok, [{app, Name}]}),
%% check a bin corresponding to the mib in the mibs dir exists in priv/mibs
- PrivMibsDir = filename:join([AppsDir, "_build", "default", "lib", Name, "priv", "mibs"]),
- true = filelib:is_file(filename:join([PrivMibsDir, "SIMPLE-MIB.bin"])),
+ true = filelib:is_file(filename:join([PrivMibsDir, "AIMPORTER-MIB.bin"])),
%% check a hrl corresponding to the mib in the mibs dir exists in include
- true = filelib:is_file(filename:join([AppDir, "include", "SIMPLE-MIB.hrl"])),
+ true = filelib:is_file(filename:join([AppDir, "include", "AIMPORTER-MIB.hrl"])),
%% check the mibs dir was linked into the _build dir
true = filelib:is_dir(filename:join([AppsDir, "_build", "default", "lib", Name, "mibs"])).
+
only_default_transitive_deps(Config) ->
AppDir = ?config(apps, Config),
@@ -1184,41 +1308,455 @@ clean_all(Config) ->
{app, PkgName, invalid}]}).
override_deps(Config) ->
- mock_git_resource:mock([{deps, [{some_dep, "0.0.1"},{other_dep, "0.0.1"}]}]),
Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
TopDeps = rebar_test_utils:top_level_deps(Deps),
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
RebarConfig = [
{deps, TopDeps},
{overrides, [
{override, some_dep, [
- {deps, []}
- ]}
- ]}
- ],
+ {deps, []}
+ ]}
+ ]}
+ ],
rebar_test_utils:run_and_check(
Config, RebarConfig, ["compile"],
- {ok, [{dep, "some_dep"},{dep_not_exist, "other_dep"}]}
+ {ok, [{dep, "some_dep"},
+ {dep_not_exist, "other_dep"}]}
).
+override_add_deps(Config) ->
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ DepA = {dep_a, "0.0.1", {git, "http://site.com/dep_a.git", {tag, "0.0.1"}}},
+ DepB = {dep_b, "0.0.1", {git, "http://site.com/dep_b.git", {tag, "0.0.1"}}},
+ DepC = {dep_c, "0.0.1", {git, "http://site.com/dep_c.git", {tag, "0.0.1"}}},
+
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, [DepA, DepB, DepC | SrcDeps]}]),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {overrides, [
+ {add, some_dep, [
+ {deps, [DepA, DepB]}
+ ]},
+ {add, [
+ {deps, [DepC]}
+ ]}
+ ]}
+ ],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{dep, "some_dep"},
+ {dep, "other_dep"},
+ {dep, "dep_a"},
+ {dep, "dep_b"},
+ {dep, "dep_c"}]}
+ ).
+
+override_del_deps(Config) ->
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"dep_a", "0.0.1", []},
+ {"dep_b", "0.0.1", []},
+ {"dep_c", "0.0.1", []}]},
+ {"other_dep", "0.0.1", [{"dep_c", "0.0.1", []},
+ {"dep_d", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ DepA = {dep_a, "0.0.1", {git, "https://example.org/user/dep_a.git", {tag, "0.0.1"}}},
+ DepB = {dep_b, "0.0.1", {git, "https://example.org/user/dep_b.git", {tag, "0.0.1"}}},
+ DepC = {dep_c, "0.0.1", {git, "https://example.org/user/dep_c.git", {tag, "0.0.1"}}},
+
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {overrides, [
+ {del, some_dep, [
+ {deps, [DepA, DepB]}
+ ]},
+ {del, [
+ {deps, [DepC]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{dep, "some_dep"},
+ {dep, "other_dep"},
+ {dep_not_exist, "dep_a"},
+ {dep_not_exist, "dep_b"},
+ {dep_not_exist, "dep_c"},
+ {dep, "dep_d"}]}
+ ).
+
+override_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ compressed,
+ warn_missing_spec
+ ]},
+ {overrides, [
+ {override, [
+ {erl_opts, [compressed]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
+%% test for fix of https://github.com/erlang/rebar3/issues/1801
+%% only apply overrides once
+%% verify by having an override add the macro TEST to the dep some_dep
+%% building under `ct` will fail if the `add` is applied more than once
+apply_overrides_exactly_once(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{deps, TopDeps},
+ {overrides, [
+ {add, some_dep, [
+ {erl_opts, [{d, 'TEST'}]}
+ ]}
+ ]}],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["ct", "--compile_only"], {ok, [{app, Name}, {dep, "some_dep"}], "test"}).
+
+override_add_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ warn_missing_spec
+ ]},
+ {overrides, [
+ {add, [
+ {erl_opts, [compressed]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ true = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
+override_del_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ compressed,
+ warn_missing_spec
+ ]},
+ {overrides, [
+ {del, [
+ {erl_opts, [warn_missing_spec]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
profile_override_deps(Config) ->
- mock_git_resource:mock([{deps, [{some_dep, "0.0.1"},{other_dep, "0.0.1"}]}]),
Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
TopDeps = rebar_test_utils:top_level_deps(Deps),
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
RebarConfig = [
{deps, TopDeps},
- {profiles, [{a,
- [{overrides, [
- {override, some_dep, [
- {deps, []}
- ]}
- ]}
+ {profiles, [
+ {a, [
+ {overrides, [
+ {override, some_dep, [
+ {deps, []}
]}
+ ]}
+ ]}
]}],
rebar_test_utils:run_and_check(
Config, RebarConfig, ["as", "a", "compile"],
- {ok, [{dep, "some_dep"},{dep_not_exist, "other_dep"}]}
+ {ok, [{dep, "some_dep"},
+ {dep_not_exist, "other_dep"}]}
+ ).
+
+profile_override_add_deps(Config) ->
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ DepA = {dep_a, "0.0.1", {git, "http://site.com/dep_a.git", {tag, "0.0.1"}}},
+ DepB = {dep_b, "0.0.1", {git, "http://site.com/dep_b.git", {tag, "0.0.1"}}},
+ DepC = {dep_c, "0.0.1", {git, "http://site.com/dep_c.git", {tag, "0.0.1"}}},
+
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, [DepA, DepB, DepC | SrcDeps]}]),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {profiles, [
+ {a, [
+ {overrides, [
+ {add, some_dep, [
+ {deps, [DepA, DepB]}
+ ]},
+ {add, [
+ {deps, [DepC]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"],
+ {ok, [{dep, "some_dep"},
+ {dep, "other_dep"},
+ {dep, "dep_a"},
+ {dep, "dep_b"},
+ {dep, "dep_c"}]}
+ ).
+
+profile_override_del_deps(Config) ->
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"dep_a", "0.0.1", []},
+ {"dep_b", "0.0.1", []},
+ {"dep_c", "0.0.1", []}]},
+ {"other_dep", "0.0.1", [{"dep_c", "0.0.1", []},
+ {"dep_d", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ DepA = {dep_a, "0.0.1", {git, "https://example.org/user/dep_a.git", {tag, "0.0.1"}}},
+ DepB = {dep_b, "0.0.1", {git, "https://example.org/user/dep_b.git", {tag, "0.0.1"}}},
+ DepC = {dep_c, "0.0.1", {git, "https://example.org/user/dep_c.git", {tag, "0.0.1"}}},
+
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {profiles, [
+ {a, [
+ {overrides, [
+ {del, some_dep, [
+ {deps, [DepA, DepB]}
+ ]},
+ {del, [
+ {deps, [DepC]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"],
+ {ok, [{dep, "some_dep"},
+ {dep, "other_dep"},
+ {dep_not_exist, "dep_a"},
+ {dep_not_exist, "dep_b"},
+ {dep_not_exist, "dep_c"},
+ {dep, "dep_d"}]}
+ ).
+
+profile_override_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ compressed,
+ warn_missing_spec
+ ]},
+ {profiles, [
+ {a, [
+ {overrides, [
+ {override, [
+ {erl_opts, [compressed]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
+profile_override_add_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ warn_missing_spec
+ ]},
+ {profiles, [
+ {a, [
+ {overrides, [
+ {add, [
+ {erl_opts, [compressed]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ true = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
+profile_override_del_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [
+ compressed,
+ warn_missing_spec
+ ]},
+ {profiles, [
+ {a, [
+ {overrides, [
+ {del, [
+ {erl_opts, [warn_missing_spec]}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])).
+
+profile_deps(Config) ->
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {profiles, [{a, []}]}],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "a", "compile"],
+ {ok, [{dep, "some_dep"},{dep, "other_dep"}]}
+ ).
+
+only_deps(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+ {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
+ mock_git_resource:mock([{deps, SrcDeps}]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
+ {ok, RConf} = file:consult(RConfFile),
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile", "--deps_only"],
+ {ok, [{app_not_exist, Name}, {dep, "some_dep"},{dep, "other_dep"}]}
).
%% verify a deps prod profile is used
@@ -1310,7 +1848,151 @@ include_file_in_src(Config) ->
["compile"],
{ok, [{app, Name}]}).
-always_recompile_when_erl_compiler_options_set(Config) ->
+%% verify that the proper include path is defined
+%% according the erlang doc which states:
+%% If the filename File is absolute (possibly after variable substitution),
+%% the include file with that name is included. Otherwise, the specified file
+%% is searched for in the following directories, and in this order:
+%% * The current working directory
+%% * The directory where the module is being compiled
+%% * The directories given by the include option
+%%
+%% This test ensures that things keep working when additional directories
+%% are used for apps, such as the test/ directory within the test profile.
+include_file_relative_to_working_directory_test(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Src = <<"-module(test).\n"
+"\n"
+"-include(\"include/test.hrl\").\n"
+"\n"
+"test() -> ?TEST_MACRO.\n"
+"\n">>,
+ Include = <<"-define(TEST_MACRO, test).\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src),
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "include", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "include", "test.hrl"]), Include),
+
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "test", "compile"],
+ {ok, [{app, Name}]}).
+
+%% Same as `include_file_in_src/1' but using the `test/' directory
+%% within the test profile.
+include_file_in_src_test(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Src = <<"-module(test).\n"
+"\n"
+"-include(\"test.hrl\").\n"
+"\n"
+"test() -> ?TEST_MACRO.\n"
+"\n">>,
+ Include = <<"-define(TEST_MACRO, test).\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src),
+
+ ok = file:write_file(filename:join([AppDir, "src", "test.hrl"]), Include),
+
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "test", "compile"],
+ {ok, [{app, Name}]}).
+
+%% Same as `include_file_in_src_test/1' but using multiple top-level
+%% apps as dependencies.
+include_file_in_src_test_multiapp(Config) ->
+
+ Name1 = rebar_test_utils:create_random_name("app2_"),
+ Name2 = rebar_test_utils:create_random_name("app1_"),
+ AppDir1 = filename:join([?config(apps, Config), "lib", Name1]),
+ AppDir2 = filename:join([?config(apps, Config), "lib", Name2]),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir1, Name1, Vsn, [kernel, stdlib, list_to_atom(Name2)]),
+ rebar_test_utils:create_app(AppDir2, Name2, Vsn, [kernel, stdlib]),
+
+ Src = "-module(test).\n"
+"\n"
+"-include_lib(\"" ++ Name2 ++ "/include/test.hrl\").\n"
+"\n"
+"test() -> ?TEST_MACRO.\n"
+"\n",
+ Include = <<"-define(TEST_MACRO, test).\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir1, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir1, "test", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir2, "src", "dummy"])),
+ ok = filelib:ensure_dir(filename:join([AppDir2, "include", "dummy"])),
+ ok = file:write_file(filename:join([AppDir1, "test", "test.erl"]), Src),
+
+ ok = file:write_file(filename:join([AppDir2, "include", "test.hrl"]), Include),
+
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "test", "compile"],
+ {ok, [{app, Name1}]}),
+ ok.
+
+%% this test sets the env var, compiles, records the file last modified timestamp,
+%% recompiles and compares the file last modified timestamp to ensure it hasn't
+%% changed. this test should run on 19.x+
+dont_recompile_when_erl_compiler_options_env_does_not_change(Config) ->
+ %% save existing env to restore after test
+ ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"),
+
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("erl_compiler_options_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ true = os:unsetenv("ERL_COMPILER_OPTIONS"),
+
+ true = os:putenv("ERL_COMPILER_OPTIONS", "[{d, some_macro}]"),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- Files, filename:extension(F) == ".beam"],
+
+ timer:sleep(1000),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ {ok, NewFiles} = rebar_utils:list_dir(EbinDir),
+ NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- NewFiles, filename:extension(F) == ".beam"],
+
+ ?assert(ModTime == NewModTime),
+
+ %% restore existing env
+ case ExistingEnv of
+ false -> ok;
+ _ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv)
+ end.
+
+%% this test compiles, records the file last modified timestamp, sets the env
+%% var, recompiles and compares the file last modified timestamp to ensure it
+%% has changed. this test should run on 19.x+
+recompile_when_erl_compiler_options_env_changes(Config) ->
%% save existing env to restore after test
ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"),
@@ -1348,5 +2030,381 @@ always_recompile_when_erl_compiler_options_set(Config) ->
_ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv)
end.
+rebar_config_os_var(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("rebar_config_os_var_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ rebar_test_utils:create_config(AppDir, [{erl_opts, []}]),
+
+ AltConfig = filename:join(AppDir, "test.rebar.config"),
+ file:write_file(AltConfig, "{erl_opts, [compressed]}."),
+ true = os:putenv("REBAR_CONFIG", AltConfig),
+
+ rebar_test_utils:run_and_check(Config, ["compile"], {ok, [{app, Name}]}),
+
+ Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ code:add_patha(Path),
+
+ Mod = list_to_atom("not_a_real_src_" ++ Name),
+
+ true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])),
+ ok.
+
+%% this test sets the env var, compiles, records the file last modified
+%% timestamp, recompiles and compares the file last modified timestamp to
+%% ensure it has changed. this test should run on 18.x
+always_recompile_when_erl_compiler_options_set(Config) ->
+ %% save existing env to restore after test
+ ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"),
+
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("erl_compiler_options_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ true = os:unsetenv("ERL_COMPILER_OPTIONS"),
+
+ true = os:putenv("ERL_COMPILER_OPTIONS", "[{d, some_macro}]"),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- Files, filename:extension(F) == ".beam"],
+
+ timer:sleep(1000),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ {ok, NewFiles} = rebar_utils:list_dir(EbinDir),
+ NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- NewFiles, filename:extension(F) == ".beam"],
+
+ ?assert(ModTime =/= NewModTime),
+
+ %% restore existing env
+ case ExistingEnv of
+ false -> ok;
+ _ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv)
+ end.
+
+recompile_when_parse_transform_inline_changes(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("parse_transform_inline_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+
+ ModSrc = <<"-module(example).\n"
+ "-export([foo/2]).\n"
+ "-compile([{parse_transform, example_parse_transform}]).\n"
+ "foo(_, _) -> ok.">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "example.erl"]),
+ ModSrc),
+
+ ParseTransform = <<"-module(example_parse_transform).\n"
+ "-export([parse_transform/2]).\n"
+ "parse_transform(AST, _) -> AST.\n">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
+ ParseTransform),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- Files, filename:basename(F, ".beam") == "example"],
+
+ timer:sleep(1000),
+
+ NewParseTransform = <<"-module(example_parse_transform).\n"
+ "-export([parse_transform/2]).\n"
+ "parse_transform(AST, _) -> identity(AST).\n"
+ "identity(AST) -> AST.\n">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
+ NewParseTransform),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ {ok, NewFiles} = rebar_utils:list_dir(EbinDir),
+ NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- NewFiles, filename:basename(F, ".beam") == "example"],
+
+ ?assert(ModTime =/= NewModTime).
+
+recompile_when_parse_transform_as_opt_changes(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("parse_transform_opt_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])),
+
+ ModSrc = <<"-module(example).\n"
+ "-export([foo/2]).\n"
+ "foo(_, _) -> ok.">>,
+ ok = file:write_file(filename:join([AppDir, "src", "example.erl"]),
+ ModSrc),
+
+ ParseTransform = <<"-module(example_parse_transform).\n"
+ "-export([parse_transform/2]).\n"
+ "parse_transform(AST, _) -> AST.">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
+ ParseTransform),
+
+ RebarConfig = [{erl_opts, [{parse_transform, example_parse_transform}]}],
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- Files, filename:basename(F, ".beam") == "example"],
+
+ timer:sleep(1000),
+
+ NewParseTransform = <<"-module(example_parse_transform).\n"
+ "-export([parse_transform/2]).\n"
+ "parse_transform(AST, _) -> identity(AST).\n"
+ "identity(AST) -> AST.">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]),
+ NewParseTransform),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ {ok, NewFiles} = rebar_utils:list_dir(EbinDir),
+ NewModTime = [filelib:last_modified(filename:join([EbinDir, F]))
+ || F <- NewFiles, filename:basename(F, ".beam") == "example"],
+
+ ?assert(ModTime =/= NewModTime).
+
+recursive(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:write_src_file(filename:join(AppDir,src),"rec.erl"),
+
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ {ok, Files} = rebar_utils:list_dir(EbinDir),
+ ?assert(lists:member("rec.beam",Files)),
+
+ %% check that rec is in modules list of .app file
+ AppFile = filename:join(EbinDir, Name++".app"),
+ {ok, [{application, _, List}]} = file:consult(AppFile),
+ {modules, Modules} = lists:keyfind(modules, 1, List),
+ ?assert(lists:member(rec, Modules)).
+
+no_recursive(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:write_src_file(filename:join(AppDir,src),"rec.erl"),
+
+ RebarConfig1 = [{erlc_compiler,[{recursive,false}]}],
+ rebar_test_utils:run_and_check(Config, RebarConfig1, ["compile"],
+ {ok, [{app, Name}]}),
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ {ok, Files1} = rebar_utils:list_dir(EbinDir),
+ ?assert(false==lists:member("rec.beam",Files1)),
+
+ RebarConfig2 = [{src_dirs,[{"src",[{recursive,false}]}]}],
+ rebar_test_utils:run_and_check(Config, RebarConfig2, ["compile"],
+ {ok, [{app, Name}]}),
+ {ok, Files2} = rebar_utils:list_dir(EbinDir),
+ ?assert(false==lists:member("rec.beam",Files2)),
+ ok.
+
+regex_filter_skip(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("regex_skip"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:write_src_file(filename:join(AppDir,src),"._rec.erl"),
+ Expected = filename:join([AppDir, "_build", "default", "lib", Name, "ebin","._rec.beam"]),
+
+ RebarConfig = [],
+ try
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{file, Expected}]}),
+ throw(should_not_be_found)
+ catch
+ %% the file was not found, as desired!
+ error:{assertion_failed,_} -> %% OTP =< 17
+ ok;
+ error:{assert,_} -> %% OTP >= 18
+ ok
+ end.
+
+regex_filter_regression(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("regex_regression"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:write_src_file(filename:join(AppDir,src),"r_f.erl"),
+ Expected = filename:join([AppDir, "_build", "default", "lib", Name, "ebin","r_f.beam"]),
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{file, Expected}]}),
+ ok.
+
+%%
+
+%% a copy of lib/parsetools/include/yeccpre.hrl so we can test yrl includefile
+yeccpre_hrl() ->
+ <<"-type yecc_ret() :: {'error', _} | {'ok', _}.
+
+-spec parse(Tokens :: list()) -> yecc_ret().
+parse(Tokens) ->
+ yeccpars0(Tokens, {no_func, no_line}, 0, [], []).
+
+-spec parse_and_scan({function() | {atom(), atom()}, [_]}
+ | {atom(), atom(), [_]}) -> yecc_ret().
+parse_and_scan({F, A}) ->
+ yeccpars0([], {{F, A}, no_line}, 0, [], []);
+parse_and_scan({M, F, A}) ->
+ Arity = length(A),
+ yeccpars0([], {{fun M:F/Arity, A}, no_line}, 0, [], []).
+
+-spec format_error(any()) -> [char() | list()].
+format_error(Message) ->
+ case io_lib:deep_char_list(Message) of
+ true ->
+ Message;
+ _ ->
+ io_lib:write(Message)
+ end.
+
+%% To be used in grammar files to throw an error message to the parser
+%% toplevel. Doesn't have to be exported!
+-compile({nowarn_unused_function, return_error/2}).
+-spec return_error(integer(), any()) -> no_return().
+return_error(Line, Message) ->
+ throw({error, {Line, ?MODULE, Message}}).
+
+-define(CODE_VERSION, \"1.4\").
+
+yeccpars0(Tokens, Tzr, State, States, Vstack) ->
+ try yeccpars1(Tokens, Tzr, State, States, Vstack)
+ catch
+ error:Error ->
+ try yecc_error_type(Error, []) of
+ Desc ->
+ erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
+ [])
+ catch _:_ -> erlang:raise(error, Error, [])
+ end;
+ %% Probably thrown from return_error/2:
+ throw: {error, {_Line, ?MODULE, _M}} = Error ->
+ Error
+ end.
+
+yecc_error_type(function_clause, _) ->
+ not_implemented.
+
+yeccpars1([Token | Tokens], Tzr, State, States, Vstack) ->
+ yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr);
+yeccpars1([], {{F, A},_Line}, State, States, Vstack) ->
+ case apply(F, A) of
+ {ok, Tokens, Endline} ->
+ yeccpars1(Tokens, {{F, A}, Endline}, State, States, Vstack);
+ {eof, Endline} ->
+ yeccpars1([], {no_func, Endline}, State, States, Vstack);
+ {error, Descriptor, _Endline} ->
+ {error, Descriptor}
+ end;
+yeccpars1([], {no_func, no_line}, State, States, Vstack) ->
+ Line = 999999,
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [],
+ {no_func, Line});
+yeccpars1([], {no_func, Endline}, State, States, Vstack) ->
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Endline), [],
+ {no_func, Endline}).
+
+%% yeccpars1/7 is called from generated code.
+%%
+%% When using the {includefile, Includefile} option, make sure that
+%% yeccpars1/7 can be found by parsing the file without following
+%% include directives. yecc will otherwise assume that an old
+%% yeccpre.hrl is included (one which defines yeccpars1/5).
+yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) ->
+ yeccpars2(State, element(1, Token), [State1 | States],
+ [Token0 | Vstack], Token, Tokens, Tzr);
+yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Line}=Tzr) ->
+ yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]);
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_line}) ->
+ Line = yecctoken_end_location(Token0),
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line});
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Line}) ->
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line}).
+
+%% For internal use only.
+yecc_end({Line,_Column}) ->
+ {'$end', Line};
+yecc_end(Line) ->
+ {'$end', Line}.
+
+yecctoken_end_location(Token) ->
+ try erl_anno:end_location(element(2, Token)) of
+ undefined -> yecctoken_location(Token);
+ Loc -> Loc
+ catch _:_ -> yecctoken_location(Token)
+ end.
+
+-compile({nowarn_unused_function, yeccerror/1}).
+yeccerror(Token) ->
+ Text = yecctoken_to_string(Token),
+ Location = yecctoken_location(Token),
+ {error, {Location, ?MODULE, [\"syntax error before: \", Text]}}.
+
+-compile({nowarn_unused_function, yecctoken_to_string/1}).
+yecctoken_to_string(Token) ->
+ try erl_scan:text(Token) of
+ undefined -> yecctoken2string(Token);
+ Txt -> Txt
+ catch _:_ -> yecctoken2string(Token)
+ end.
+
+yecctoken_location(Token) ->
+ try erl_scan:location(Token)
+ catch _:_ -> element(2, Token)
+ end.
+-compile({nowarn_unused_function, yecctoken2string/1}).
+yecctoken2string({atom, _, A}) -> io_lib:write_atom(A);
+yecctoken2string({integer,_,N}) -> io_lib:write(N);
+yecctoken2string({float,_,F}) -> io_lib:write(F);
+yecctoken2string({char,_,C}) -> io_lib:write_char(C);
+yecctoken2string({var,_,V}) -> io_lib:format(\"~s\", [V]);
+yecctoken2string({string,_,S}) -> io_lib:write_string(S);
+yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
+yecctoken2string({_Cat, _, Val}) -> io_lib:format(\"~p\", [Val]);
+yecctoken2string({dot, _}) -> \"'.'\";
+yecctoken2string({'$end', _}) -> [];
+yecctoken2string({Other, _}) when is_atom(Other) ->
+ io_lib:write_atom(Other);
+yecctoken2string(Other) ->
+ io_lib:format(\"~p\", [Other]).
+">>.
diff --git a/test/rebar_cover_SUITE.erl b/test/rebar_cover_SUITE.erl
index 841e29f..8d6429d 100644
--- a/test/rebar_cover_SUITE.erl
+++ b/test/rebar_cover_SUITE.erl
@@ -7,12 +7,17 @@
all/0,
flag_coverdata_written/1,
config_coverdata_written/1,
+ config_coverdata_overridden_name_written/1,
basic_extra_src_dirs/1,
release_extra_src_dirs/1,
root_extra_src_dirs/1,
index_written/1,
flag_verbose/1,
- config_verbose/1]).
+ config_verbose/1,
+ excl_mods_and_apps/1,
+ coverdata_is_reset_on_write/1,
+ flag_min_coverage/1,
+ config_min_coverage/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -32,10 +37,13 @@ init_per_testcase(_, Config) ->
all() ->
[flag_coverdata_written, config_coverdata_written,
+ config_coverdata_overridden_name_written,
basic_extra_src_dirs, release_extra_src_dirs,
root_extra_src_dirs,
index_written,
- flag_verbose, config_verbose].
+ flag_verbose, config_verbose,
+ excl_mods_and_apps, coverdata_is_reset_on_write,
+ flag_min_coverage, config_min_coverage].
flag_coverdata_written(Config) ->
AppDir = ?config(apps, Config),
@@ -67,6 +75,21 @@ config_coverdata_written(Config) ->
true = filelib:is_file(filename:join([AppDir, "_build", "test", "cover", "eunit.coverdata"])).
+config_coverdata_overridden_name_written(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("cover_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_enabled, true}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--cover_export_name=test_name"],
+ {ok, [{app, Name}]}),
+
+ true = filelib:is_file(filename:join([AppDir, "_build", "test", "cover", "test_name.coverdata"])).
+
basic_extra_src_dirs(Config) ->
AppDir = ?config(apps, Config),
@@ -206,3 +229,94 @@ config_verbose(Config) ->
{ok, [{app, Name}]}),
true = filelib:is_file(filename:join([AppDir, "_build", "test", "cover", "index.html"])).
+
+excl_mods_and_apps(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name1 = rebar_test_utils:create_random_name("relapp1_"),
+ Vsn1 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([AppDir, "apps", Name1]), Name1, Vsn1, [kernel, stdlib]),
+
+ Name2 = rebar_test_utils:create_random_name("relapp2_"),
+ Vsn2 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([AppDir, "apps", Name2]), Name2, Vsn2, [kernel, stdlib]),
+
+ Name3 = rebar_test_utils:create_random_name("excludeme_"),
+ Vsn3 = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(filename:join([AppDir, "apps", Name3]), Name3, Vsn3, [kernel, stdlib]),
+
+ Mod1 = list_to_atom(Name1),
+ Mod2 = list_to_atom(Name2),
+ Mod3 = list_to_atom(Name3),
+ RebarConfig = [{erl_opts, [{d, some_define}]},
+ {cover_excl_mods, [Mod2]},
+ {cover_excl_apps, [Name3]}],
+
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit", "--cover"],
+ {ok, [{app, Name1}, {app, Name2}, {app, Name3}]}),
+
+ {file, _} = cover:is_compiled(Mod1),
+ false = cover:is_compiled(Mod2),
+ false = cover:is_compiled(Mod3).
+
+coverdata_is_reset_on_write(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("coverdata_is_reset_on_write_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_enabled, true}],
+ rebar_test_utils:run_and_check(Config,
+ RebarConfig,
+ ["eunit"],
+ {ok, [{app, Name}]}),
+
+ Res = lists:map(fun(M) -> cover:analyse(M) end, cover:modules()),
+ Ok = lists:foldl(fun({ok, R}, Acc) -> R ++ Acc end, [], Res),
+ [] = lists:filter(fun({_, {0,_}}) -> false; (_) -> true end, Ok).
+
+flag_min_coverage(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("min_cover_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{d, some_define}]}],
+ ?assertMatch({ok, _},
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["do", "eunit", "--cover", ",", "cover", "--min_coverage=5"],
+ return)),
+
+ ?assertMatch({error,{rebar_prv_cover,{min_coverage_failed,{65,_}}}},
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["do", "eunit", "--cover", ",", "cover", "--min_coverage=65"],
+ return)),
+ ok.
+
+config_min_coverage(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("cover_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig1 = [{erl_opts, [{d, some_define}]}, {cover_opts, [{min_coverage,5}]}],
+ ?assertMatch({ok, _},
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig1,
+ ["do", "eunit", "--cover", ",", "cover"],
+ return)),
+
+ RebarConfig2 = [{erl_opts, [{d, some_define}]}, {cover_opts, [{min_coverage,65}]}],
+ ?assertMatch({error,{rebar_prv_cover,{min_coverage_failed,{65,_}}}},
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig2,
+ ["do", "eunit", "--cover", ",", "cover"],
+ return)),
+ ok.
diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl
index c10875b..15dc63e 100644
--- a/test/rebar_ct_SUITE.erl
+++ b/test/rebar_ct_SUITE.erl
@@ -24,6 +24,8 @@
data_dir_correct/1,
cmd_label/1,
cmd_config/1,
+ cmd_spec/1,
+ cmd_join_specs/1,
cmd_allow_user_terms/1,
cmd_logdir/1,
cmd_logopts/1,
@@ -44,13 +46,19 @@
cmd_sys_config/1,
cfg_opts/1,
cfg_arbitrary_opts/1,
- cfg_test_spec/1,
cfg_cover_spec/1,
cfg_atom_suites/1,
cover_compiled/1,
+ cover_export_name/1,
misspecified_ct_opts/1,
misspecified_ct_compile_opts/1,
- misspecified_ct_first_files/1]).
+ misspecified_ct_first_files/1,
+ testspec/1,
+ testspec_at_root/1,
+ testspec_parse_error/1,
+ cmd_vs_cfg_opts/1,
+ single_testspec_in_ct_opts/1,
+ compile_only/1]).
-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -62,11 +70,17 @@ all() -> [{group, basic_app},
{group, ct_opts},
{group, cover},
cfg_opts, cfg_arbitrary_opts,
- cfg_test_spec, cfg_cover_spec,
+ cfg_cover_spec,
cfg_atom_suites,
misspecified_ct_opts,
misspecified_ct_compile_opts,
- misspecified_ct_first_files].
+ misspecified_ct_first_files,
+ testspec,
+ testspec_at_root,
+ testspec_parse_error,
+ cmd_vs_cfg_opts,
+ single_testspec_in_ct_opts,
+ compile_only].
groups() -> [{basic_app, [], [basic_app_default_dirs,
basic_app_default_beams,
@@ -88,6 +102,8 @@ groups() -> [{basic_app, [], [basic_app_default_dirs,
{data_dirs, [], [data_dir_correct]},
{ct_opts, [], [cmd_label,
cmd_config,
+ cmd_spec,
+ cmd_join_specs,
cmd_allow_user_terms,
cmd_logdir,
cmd_logopts,
@@ -106,7 +122,8 @@ groups() -> [{basic_app, [], [basic_app_default_dirs,
cmd_create_priv_dir,
cmd_include_dir,
cmd_sys_config]},
- {cover, [], [cover_compiled]}].
+ {cover, [], [cover_compiled,
+ cover_export_name]}].
init_per_group(basic_app, Config) ->
C = rebar_test_utils:init_rebar_state(Config, "ct_"),
@@ -686,7 +703,33 @@ suite_at_root(Config) ->
true = filelib:is_dir(DataDir),
DataFile = filename:join([AppDir, "_build", "test", "extras", "root_SUITE_data", "some_data.txt"]),
- true = filelib:is_file(DataFile).
+ true = filelib:is_file(DataFile),
+
+ %% Same test again, but using relative path to the suite from the
+ %% project root
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+ rebar_file_utils:rm_rf("_build"),
+
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec, ["--suite=" ++ "root_SUITE"]),
+
+ State3 = rebar_state:command_parsed_args(State1, GetOptResult2),
+
+ Tests2 = rebar_prv_common_test:prepare_tests(State3),
+ {ok, NewState2} = rebar_prv_common_test:compile(State3, Tests2),
+ {ok, T2} = Tests2,
+ Opts2 = rebar_prv_common_test:translate_paths(NewState2, T2),
+
+ ok = file:set_cwd(Cwd),
+
+ Suite2 = proplists:get_value(suite, Opts2),
+ [Expected] = Suite2,
+ true = filelib:is_file(TestHrl),
+ true = filelib:is_file(TestBeam),
+ true = filelib:is_dir(DataDir),
+ true = filelib:is_file(DataFile),
+
+ ok.
suite_at_app_root(Config) ->
AppDir = ?config(apps, Config),
@@ -723,7 +766,32 @@ suite_at_app_root(Config) ->
true = filelib:is_dir(DataDir),
DataFile = filename:join([AppDir, "_build", "test", "lib", Name2, "app_root_SUITE_data", "some_data.txt"]),
- true = filelib:is_file(DataFile).
+ true = filelib:is_file(DataFile),
+
+ %% Same test again using relative path to the suite from the project root
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+ rebar_file_utils:rm_rf("_build"),
+
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec, ["--suite=" ++ filename:join(["apps", Name2, "app_root_SUITE"])]),
+
+ State3 = rebar_state:command_parsed_args(State1, GetOptResult2),
+
+ Tests2 = rebar_prv_common_test:prepare_tests(State3),
+ {ok, NewState2} = rebar_prv_common_test:compile(State3, Tests2),
+ {ok, T2} = Tests2,
+ Opts2 = rebar_prv_common_test:translate_paths(NewState2, T2),
+
+ ok = file:set_cwd(Cwd),
+
+ Suite2 = proplists:get_value(suite, Opts2),
+ [Expected] = Suite2,
+ true = filelib:is_file(TestHrl),
+ true = filelib:is_file(TestBeam),
+ true = filelib:is_dir(DataDir),
+ true = filelib:is_file(DataFile),
+
+ ok.
%% this test probably only fails when this suite is run via rebar3 with the --cover flag
data_dir_correct(Config) ->
@@ -761,6 +829,36 @@ cmd_config(Config) ->
true = lists:member({config, ["config/foo", "config/bar", "config/baz"]}, TestOpts).
+cmd_spec(Config) ->
+ State = ?config(result, Config),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+ {ok, GetOptResult} = getopt:parse(GetOptSpec, ["--spec=foo.spec,bar.spec,baz.spec"]),
+
+ NewState = rebar_state:command_parsed_args(State, GetOptResult),
+
+ {ok, TestOpts} = rebar_prv_common_test:prepare_tests(NewState),
+
+ true = lists:member({spec, ["foo.spec", "bar.spec", "baz.spec"]}, TestOpts).
+
+cmd_join_specs(Config) ->
+ State = ?config(result, Config),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+ {ok, GetOptResult} = getopt:parse(GetOptSpec, ["--join_specs=true"]),
+
+ NewState = rebar_state:command_parsed_args(State, GetOptResult),
+
+ {ok, TestOpts} = rebar_prv_common_test:prepare_tests(NewState),
+
+ true = lists:member({join_specs, true}, TestOpts).
+
cmd_allow_user_terms(Config) ->
State = ?config(result, Config),
@@ -1036,12 +1134,19 @@ cmd_sys_config(Config) ->
CfgFile = filename:join([AppDir, "config", "cfg_sys.config"]),
ok = filelib:ensure_dir(CfgFile),
ok = file:write_file(CfgFile, cfg_sys_config_file(AppName)),
+
+ OtherCfgFile = filename:join([AppDir, "config", "other.config"]),
+ ok = filelib:ensure_dir(OtherCfgFile),
+ ok = file:write_file(OtherCfgFile, other_sys_config_file(AppName)),
+
RebarConfig = [{ct_opts, [{sys_config, CfgFile}]}],
{ok, State1} = rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "test", "lock"], return),
{ok, _} = rebar_prv_common_test:prepare_tests(State1),
?assertEqual({ok, cfg_value}, application:get_env(AppName, key)),
+ ?assertEqual({ok, other_cfg_value}, application:get_env(AppName, other_key)),
+
Providers = rebar_state:providers(State1),
Namespace = rebar_state:namespace(State1),
CommandProvider = providers:get_provider(ct, Providers, Namespace),
@@ -1096,23 +1201,6 @@ cfg_arbitrary_opts(Config) ->
true = lists:member({bar, 2}, TestOpts),
true = lists:member({baz, 3}, TestOpts).
-cfg_test_spec(Config) ->
- C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_test_spec_opts_"),
-
- AppDir = ?config(apps, C),
-
- Name = rebar_test_utils:create_random_name("ct_cfg_test_spec_opts_"),
- Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
-
- RebarConfig = [{ct_opts, [Opt = {test_spec, "spec/foo.spec"}]}],
-
- {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return),
-
- {ok, TestOpts} = rebar_prv_common_test:prepare_tests(State),
-
- false = lists:member(Opt, TestOpts).
-
cfg_cover_spec(Config) ->
C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_cover_spec_opts_"),
@@ -1165,6 +1253,29 @@ cover_compiled(Config) ->
Mod = list_to_atom(Name),
{file, _} = cover:is_compiled(Mod).
+cover_export_name(Config) ->
+ State = ?config(result, Config),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+ {ok, GetOptResult} = getopt:parse(GetOptSpec, ["--cover", "--cover_export_name=export_name"]),
+
+ NewState = rebar_state:command_parsed_args(State, GetOptResult),
+
+ Tests = rebar_prv_common_test:prepare_tests(NewState),
+ {ok, _} = rebar_prv_common_test:compile(NewState, Tests),
+ rebar_prv_common_test:maybe_write_coverdata(NewState),
+
+ Name = ?config(name, Config),
+ Mod = list_to_atom(Name),
+ {file, _} = cover:is_compiled(Mod),
+
+ Dir = rebar_dir:profile_dir(rebar_state:opts(NewState), [default, test]),
+ ct:pal("DIR ~s", [Dir]),
+ true = filelib:is_file(filename:join([Dir, "cover", "export_name.coverdata"])).
+
misspecified_ct_opts(Config) ->
C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_atom_suites_"),
@@ -1218,6 +1329,312 @@ misspecified_ct_first_files(Config) ->
{badconfig, {"Value `~p' of option `~p' must be a list", {some_file, ct_first_files}}} = Error.
+testspec(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ Spec1 = filename:join([AppDir, "test", "some.spec"]),
+ ok = filelib:ensure_dir(Spec1),
+ ok = file:write_file(Spec1, "{suites,\".\",all}.\n"),
+ Spec2 = filename:join([AppDir, "specs", "another.spec"]),
+ ok = filelib:ensure_dir(Spec2),
+ Suites2 = filename:join([AppDir,"suites","*"]),
+ ok = filelib:ensure_dir(Suites2),
+ ok = file:write_file(Spec2, "{suites,\"../suites/\",all}.\n"),
+
+ {ok,Wd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+
+ {ok, State} = rebar_test_utils:run_and_check(C,
+ [],
+ ["as", "test", "lock"],
+ return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ %% Testspec in "test" directory
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, ["--spec","test/some.spec"]),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {ok, NewState1} = rebar_prv_common_test:compile(State1, Tests1),
+ {ok, T1} = Tests1,
+ Opts1= rebar_prv_common_test:translate_paths(NewState1, T1),
+
+ %% check that extra src dir is added
+ [App1] = rebar_state:project_apps(NewState1),
+ ["test"] = rebar_dir:extra_src_dirs(rebar_app_info:opts(App1)),
+
+ %% check that path is translated
+ ExpectedSpec1 = filename:join([AppDir, "_build", "test", "lib", Name,
+ "test", "some.spec"]),
+ [ExpectedSpec1] = proplists:get_value(spec, Opts1),
+
+
+ %% Testspec in directory other than "test"
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec,
+ ["--spec","specs/another.spec"]),
+ State2 = rebar_state:command_parsed_args(State, GetOptResult2),
+ Tests2 = {ok, T2} =rebar_prv_common_test:prepare_tests(State2),
+ {ok, NewState2} = rebar_prv_common_test:compile(State2, Tests2),
+ Opts2= rebar_prv_common_test:translate_paths(NewState2, T2),
+
+ %% check that extra src dirs are added
+ [App2] = rebar_state:project_apps(NewState2),
+ ["specs","suites","test"] =
+ lists:sort(rebar_dir:extra_src_dirs(rebar_app_info:opts(App2))),
+
+ %% check that paths are translated
+ ExpectedSpec2 = filename:join([AppDir, "_build", "test", "lib", Name,
+ "specs", "another.spec"]),
+ [ExpectedSpec2] = proplists:get_value(spec, Opts2),
+
+ ok = file:set_cwd(Wd),
+
+ ok.
+
+testspec_at_root(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_at_root_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_at_root_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ AppDir1 = filename:join([AppDir, "apps", Name]),
+ rebar_test_utils:create_app(AppDir1, Name, Vsn, [kernel, stdlib]),
+
+ Spec1 = filename:join([AppDir, "root.spec"]),
+ ok = filelib:ensure_dir(Spec1),
+ ok = file:write_file(Spec1, "{suites,\"test\",all}."),
+ Spec2 = filename:join([AppDir, "root1.spec"]),
+ ok = file:write_file(Spec2, "{suites,\".\",all}."),
+ Spec3 = filename:join([AppDir, "root2.spec"]),
+ ok = file:write_file(Spec3, "{suites,\"suites\",all}."),
+ Suite1 = filename:join(AppDir,"root_SUITE.erl"),
+ ok = file:write_file(Suite1, test_suite("root")),
+ Suite2 = filename:join([AppDir,"suites","test_SUITE.erl"]),
+ ok = filelib:ensure_dir(Suite2),
+ ok = file:write_file(Suite2, test_suite("test")),
+
+ {ok, State} = rebar_test_utils:run_and_check(C,
+ [],
+ ["as", "test", "lock"],
+ return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ SpecArg1 = rebar_string:join([Spec1,Spec2,Spec3],","),
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, ["--spec",SpecArg1]),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {ok, NewState1} = rebar_prv_common_test:compile(State1, Tests1),
+ {ok, T1} = Tests1,
+ Opts1= rebar_prv_common_test:translate_paths(NewState1, T1),
+
+ %% check that extra src dir is added
+ ExtraDir = filename:join([AppDir, "_build", "test", "extras"]),
+ [ExtraDir,"suites","test"] =
+ rebar_dir:extra_src_dirs(rebar_state:opts(NewState1)),
+
+ %% check that path is translated
+ ExpectedSpec1 = filename:join([AppDir, "_build", "test",
+ "extras", "root.spec"]),
+ ExpectedSpec2 = filename:join([AppDir, "_build", "test",
+ "extras", "root1.spec"]),
+ ExpectedSpec3 = filename:join([AppDir, "_build", "test",
+ "extras", "root2.spec"]),
+ [ExpectedSpec1,ExpectedSpec2,ExpectedSpec3] =
+ lists:sort(proplists:get_value(spec, Opts1)),
+
+ %% check that test specs are copied
+ [ExpectedSpec1,ExpectedSpec2,ExpectedSpec3] =
+ lists:sort(filelib:wildcard(filename:join([AppDir, "_build", "test",
+ "extras", "*.spec"]))),
+
+ %% Same test again, using relative path
+ {ok,Cwd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+ ok = rebar_file_utils:rm_rf("_build"),
+
+ SpecArg2 = "root.spec,root1.spec,root2.spec",
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec, ["--spec",SpecArg2]),
+ State2 = rebar_state:command_parsed_args(State, GetOptResult2),
+ Tests2 = rebar_prv_common_test:prepare_tests(State2),
+ {ok, NewState2} = rebar_prv_common_test:compile(State2, Tests2),
+ {ok, T2} = Tests2,
+ Opts2= rebar_prv_common_test:translate_paths(NewState2, T2),
+
+ %% check that extra src dir is added
+ [ExtraDir,"suites","test"] =
+ rebar_dir:extra_src_dirs(rebar_state:opts(NewState2)),
+
+ %% check that path is translated
+ [ExpectedSpec1,ExpectedSpec2,ExpectedSpec3] =
+ lists:sort(proplists:get_value(spec, Opts2)),
+
+ %% check that test specs are copied
+ [ExpectedSpec1,ExpectedSpec2,ExpectedSpec3] =
+ lists:sort(filelib:wildcard(filename:join([AppDir, "_build", "test",
+ "extras", "root*.spec"]))),
+
+ ok = file:set_cwd(Cwd),
+
+ ok.
+
+testspec_parse_error(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_error"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_error"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ Spec1 = filename:join([AppDir, "test", "nonexisting.spec"]),
+ Spec2 = filename:join([AppDir, "test", "some.spec"]),
+ ok = filelib:ensure_dir(Spec2),
+ ok = file:write_file(Spec2, ".\n"),
+
+ {ok, State} = rebar_test_utils:run_and_check(C,
+ [],
+ ["as", "test", "lock"],
+ return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ %% Non existing testspec
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, ["--spec",Spec1]),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {error,
+ {rebar_prv_common_test,
+ {error_reading_testspec,
+ {Spec1,"no such file or directory"}}}} =
+ rebar_prv_common_test:compile(State1, Tests1),
+
+ %% Syntax error
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec, ["--spec",Spec2]),
+ State2 = rebar_state:command_parsed_args(State, GetOptResult2),
+ Tests2 = rebar_prv_common_test:prepare_tests(State2),
+ {error,
+ {rebar_prv_common_test,
+ {error_reading_testspec,
+ {Spec2,"1: syntax error before: '.'"}}}} =
+ rebar_prv_common_test:compile(State2, Tests2),
+
+ ok.
+
+cmd_vs_cfg_opts(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_cmd_vs_cfg_opts_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_cmd_vs_cfg_opts_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{ct_opts, [{spec,"mytest.spec"},
+ {dir,"test"},
+ {suite,"some_SUITE"},
+ {group,"some_group"},
+ {testcase,"some_test"}]}],
+
+ {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return),
+
+ {ok, TestOpts} = rebar_prv_common_test:prepare_tests(State),
+ true = lists:member({spec, "mytest.spec"}, TestOpts),
+ true = lists:member({dir, "test"}, TestOpts),
+ true = lists:member({suite, "some_SUITE"}, TestOpts),
+ true = lists:member({group, "some_group"}, TestOpts),
+ true = lists:member({testcase, "some_test"}, TestOpts),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, ["--spec","test/some.spec"]),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ {ok, TestOpts1} = rebar_prv_common_test:prepare_tests(State1),
+ true = lists:member({spec, ["test/some.spec"]}, TestOpts1),
+ false = lists:keymember(dir, 1, TestOpts1),
+ false = lists:keymember(suite, 1, TestOpts1),
+ false = lists:keymember(group, 1, TestOpts1),
+ false = lists:keymember(testcase, 1, TestOpts1),
+
+ {ok, GetOptResult2} = getopt:parse(GetOptSpec, ["--suite","test/some_SUITE"]),
+ State2 = rebar_state:command_parsed_args(State, GetOptResult2),
+ {ok, TestOpts2} = rebar_prv_common_test:prepare_tests(State2),
+ true = lists:member({suite, ["test/some_SUITE"]}, TestOpts2),
+ false = lists:keymember(spec, 1, TestOpts2),
+ false = lists:keymember(dir, 1, TestOpts2),
+ false = lists:keymember(group, 1, TestOpts2),
+ false = lists:keymember(testcase, 1, TestOpts2),
+
+ ok.
+
+single_testspec_in_ct_opts(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ Spec = filename:join([AppDir, "test", "some.spec"]),
+ ok = filelib:ensure_dir(Spec),
+ ok = file:write_file(Spec, "{suites,\".\",all}.\n"),
+
+ {ok,Wd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+
+ RebarConfig = [{ct_opts, [{spec,"test/some.spec"}]}],
+
+ {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ %% Testspec in "test" directory
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, []),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {ok, T1} = Tests1,
+ "test/some.spec" = proplists:get_value(spec,T1),
+ {ok, _NewState} = rebar_prv_common_test:compile(State1, Tests1),
+
+ ok = file:set_cwd(Wd),
+ ok.
+
+compile_only(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "compile_only_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name(atom_to_list(basic_app) ++ "_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Suite = filename:join([AppDir, "test", Name ++ "_SUITE.erl"]),
+ ok = filelib:ensure_dir(Suite),
+ ok = file:write_file(Suite, test_suite(Name)),
+
+ {ok, _State} = rebar_test_utils:run_and_check(C, [], ["ct", "--compile_only"], {ok, [{app,Name}], "test"}).
+
+
%% helper for generating test data
test_suite(Name) ->
io_lib:format("-module(~ts_SUITE).\n"
@@ -1226,7 +1643,10 @@ test_suite(Name) ->
"some_test(_) -> ok.\n", [Name]).
cmd_sys_config_file(AppName) ->
- io_lib:format("[{~s, [{key, cmd_value}]}].", [AppName]).
+ io_lib:format("[{~ts, [{key, cmd_value}]}].", [AppName]).
cfg_sys_config_file(AppName) ->
- io_lib:format("[{~s, [{key, cfg_value}]}].", [AppName]).
+ io_lib:format("[{~ts, [{key, cfg_value}]}, \"config/other\"].", [AppName]).
+
+other_sys_config_file(AppName) ->
+ io_lib:format("[{~ts, [{other_key, other_cfg_value}]}].", [AppName]).
diff --git a/test/rebar_deps_SUITE.erl b/test/rebar_deps_SUITE.erl
index 24bf2a0..8a3362d 100644
--- a/test/rebar_deps_SUITE.erl
+++ b/test/rebar_deps_SUITE.erl
@@ -7,7 +7,7 @@ all() -> [sub_app_deps, newly_added_dep, newly_added_after_empty_lock,
http_proxy_settings, https_proxy_settings,
http_os_proxy_settings, https_os_proxy_settings,
semver_matching_lt, semver_matching_lte, semver_matching_gt,
- valid_version, {group, git}, {group, pkg}].
+ valid_version, top_override, {group, git}, {group, pkg}].
groups() ->
[{all, [], [flat, pick_highest_left, pick_highest_right,
@@ -47,6 +47,8 @@ init_per_testcase(newly_added_dep, Config) ->
rebar_test_utils:init_rebar_state(Config);
init_per_testcase(sub_app_deps, Config) ->
rebar_test_utils:init_rebar_state(Config);
+init_per_testcase(top_override, Config) ->
+ rebar_test_utils:init_rebar_state(Config);
init_per_testcase(http_proxy_settings, Config) ->
%% Create private rebar.config
Priv = ?config(priv_dir, Config),
@@ -186,27 +188,27 @@ deps(flat) ->
[],
{ok, ["B", "C"]}};
deps(pick_highest_left) ->
- {[{"B", [{"C", "2", []}]},
- {"C", "1", []}],
- [{"C","2"}],
- {ok, ["B", {"C", "1"}]}};
+ {[{"B", [{"C", "2.0.0", []}]},
+ {"C", "1.0.0", []}],
+ [{"C","2.0.0"}],
+ {ok, ["B", {"C", "1.0.0"}]}};
deps(pick_highest_right) ->
- {[{"B", "1", []},
- {"C", [{"B", "2", []}]}],
- [{"B","2"}],
- {ok, [{"B","1"}, "C"]}};
+ {[{"B", "1.0.0", []},
+ {"C", [{"B", "2.0.0", []}]}],
+ [{"B","2.0.0"}],
+ {ok, [{"B","1.0.0"}, "C"]}};
deps(pick_smallest1) ->
- {[{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}],
- [{"D","2"}],
+ {[{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}],
+ [{"D","2.0.0"}],
%% we pick D1 because B < C
- {ok, ["B","C",{"D","1"}]}};
+ {ok, ["B","C",{"D","1.0.0"}]}};
deps(pick_smallest2) ->
- {[{"C", [{"D", "2", []}]},
- {"B", [{"D", "1", []}]}],
- [{"D","2"}],
+ {[{"C", [{"D", "2.0.0", []}]},
+ {"B", [{"D", "1.0.0", []}]}],
+ [{"D","2.0.0"}],
%% we pick D1 because B < C
- {ok, ["B","C",{"D","1"}]}};
+ {ok, ["B","C",{"D","1.0.0"}]}};
deps(circular1) ->
{[{"B", [{"A", []}]}, % A is the top-level app
{"C", []}],
@@ -220,15 +222,17 @@ deps(circular2) ->
deps(circular_skip) ->
%% Never spot the circular dep due to being to low in the deps tree
%% in source deps
- {[{"B", [{"C", "2", [{"B", []}]}]},
- {"C", "1", [{"D",[]}]}],
- [{"C","2"}],
- {ok, ["B", {"C","1"}, "D"]}}.
+ {[{"B", [{"C", "2.0.0", [{"B", []}]}]},
+ {"C", "1.0.0", [{"D",[]}]}],
+ [{"C","2.0.0"}],
+ {ok, ["B", {"C","1.0.0"}, "D"]}}.
setup_project(Case, Config0, Deps) ->
DepsType = ?config(deps_type, Config0),
+ %% spread packages across 3 repos randomly
+ Repos = [<<"test-repo-1">>, <<"test-repo-2">>, <<"hexpm">>],
Config = rebar_test_utils:init_rebar_state(
- Config0,
+ [{repos, Repos} | Config0],
atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
),
AppDir = ?config(apps, Config),
@@ -237,7 +241,7 @@ setup_project(Case, Config0, Deps) ->
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
{SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps),
mock_git_resource:mock([{deps, SrcDeps}]),
- mock_pkg_resource:mock([{pkgdeps, PkgDeps}]),
+ mock_pkg_resource:mock([{pkgdeps, PkgDeps}, {repos, Repos}]),
[{rebarconfig, RebarConf} | Config].
mock_warnings() ->
@@ -255,6 +259,32 @@ circular1(Config) -> run(Config).
circular2(Config) -> run(Config).
circular_skip(Config) -> run(Config).
+%% Test that a top-level application overtakes dependencies, and
+%% works even if said deps do not exist.
+top_override(Config) ->
+ AppDir = ?config(apps, Config),
+ ct:pal("dir: ~p", [AppDir]),
+ Name1 = rebar_test_utils:create_random_name("sub_app1_"),
+ Name2 = rebar_test_utils:create_random_name("sub_app2_"),
+ SubAppsDir1 = filename:join([AppDir, "apps", Name1]),
+ SubAppsDir2 = filename:join([AppDir, "apps", Name2]),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(SubAppsDir1, Name1, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_app(SubAppsDir2, Name2, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_config(
+ SubAppsDir1,
+ [{deps, [list_to_atom(Name2)]}]
+ ),
+ rebar_test_utils:create_config(
+ SubAppsDir2,
+ [{deps, [{list_to_atom(Name1),
+ {git, "https://example.org", {branch, "master"}}}]}]
+ ),
+ rebar_test_utils:run_and_check(
+ Config, [], ["compile"],
+ {ok, [{app, Name1}, {app,Name2}]}
+ ).
+
%% Test that the deps of project apps that have their own rebar.config
%% are included, but that top level rebar.config deps take precedence
sub_app_deps(Config) ->
@@ -384,70 +414,62 @@ https_os_proxy_settings(_Config) ->
httpc:get_option(https_proxy, rebar)).
semver_matching_lt(_Config) ->
- Dep = <<"test">>,
- Dep1 = {Dep, <<"1.0.0">>, Dep},
MaxVsn = <<"0.2.0">>,
Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
- ?assertEqual([{Dep, <<"0.1.9">>}],
- rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
+ ?assertEqual({ok, <<"0.1.9">>},
+ rebar_packages:cmpl_(undefined, MaxVsn, Vsns,
fun ec_semver:lt/2)).
semver_matching_lte(_Config) ->
- Dep = <<"test">>,
- Dep1 = {Dep, <<"1.0.0">>, Dep},
MaxVsn = <<"0.2.0">>,
Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
- ?assertEqual([{Dep, <<"0.2.0">>}],
- rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
+ ?assertEqual({ok, <<"0.2.0">>},
+ rebar_packages:cmpl_(undefined, MaxVsn, Vsns,
fun ec_semver:lte/2)).
semver_matching_gt(_Config) ->
- Dep = <<"test">>,
- Dep1 = {Dep, <<"1.0.0">>, Dep},
MaxVsn = <<"0.2.0">>,
Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
- ?assertEqual([{Dep, <<"0.2.1">>}],
- rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
+ ?assertEqual({ok, <<"0.2.1">>},
+ rebar_packages:cmp_(undefined, MaxVsn, Vsns,
fun ec_semver:gt/2)).
semver_matching_gte(_Config) ->
- Dep = <<"test">>,
- Dep1 = {Dep, <<"1.0.0">>, Dep},
MaxVsn = <<"0.2.0">>,
Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>],
- ?assertEqual([{Dep, <<"0.2.0">>}],
- rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
+ ?assertEqual({ok, <<"0.2.0">>},
+ rebar_packages:cmp_(undefined, MaxVsn, Vsns,
fun ec_semver:gt/2)).
valid_version(_Config) ->
- ?assert(rebar_prv_update:valid_vsn(<<"0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<=0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<=0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">=0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">=0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"==0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"==0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"~>0.1">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"~>0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
- ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
- ?assertNot(rebar_prv_update:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<"0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<" 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<" 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"< 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"< 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<">0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<">0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"> 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"> 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<=0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<=0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<= 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"<= 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<">=0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<">=0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<">= 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<">= 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"==0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<"==0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"== 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"== 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"~>0.1">>)),
+ ?assert(rebar_packages:valid_vsn(<<"~>0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"~> 0.1.0">>)),
+ ?assert(rebar_packages:valid_vsn(<<"~> 0.1.0">>)),
+ ?assertNot(rebar_packages:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)),
ok.
@@ -476,5 +498,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) ->
in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw),
Vsn = iolist_to_binary(VsnRaw),
- 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns,
+ 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]).
diff --git a/test/rebar_dialyzer_SUITE.erl b/test/rebar_dialyzer_SUITE.erl
index e5d8c52..6579afb 100644
--- a/test/rebar_dialyzer_SUITE.erl
+++ b/test/rebar_dialyzer_SUITE.erl
@@ -14,7 +14,8 @@
update_base_plt/1,
update_app_plt/1,
build_release_plt/1,
- plt_apps_option/1]).
+ plt_apps_option/1,
+ exclude_and_extra/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -57,7 +58,7 @@ all() ->
groups() ->
[{empty, [empty_base_plt, empty_app_plt, empty_app_succ_typings]},
- {build_and_check, [build_release_plt, plt_apps_option]},
+ {build_and_check, [build_release_plt, plt_apps_option, exclude_and_extra]},
{update, [update_base_plt, update_app_plt]}].
empty_base_plt(Config) ->
@@ -275,6 +276,39 @@ plt_apps_option(Config) ->
{ok, PltFiles2} = plt_files(Plt),
?assertEqual([App1, App2, erts], get_apps_from_beam_files(PltFiles2)).
+exclude_and_extra(Config) ->
+ AppDir = ?config(apps, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ BasePlt = ?config(base_plt, Config),
+ Plt = ?config(plt, Config),
+
+ {value, {dialyzer, Opts}, Rest} = lists:keytake(dialyzer, 1, RebarConfig),
+ % Remove erts => []
+ % Add erlang+zlib => [erlang, zlib],
+ % Add erl_prim_loader+init => [erl_prim_loader, init, erlang, zlib]
+ % Remove zlib+init => [erl_prim_loader, erlang]
+ Opts2 = [{exclude_apps, [erts]},
+ {base_plt_mods, [erlang, zlib]},
+ {plt_extra_mods, [erl_prim_loader, init]},
+ {exclude_mods, [zlib, init]} |
+ Opts],
+ RebarConfig2 = [{dialyzer, Opts2} | Rest],
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [erts]),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig2, ["dialyzer"],
+ {ok, [{app, Name}]}),
+
+ Erlang = code:where_is_file("erlang.beam"),
+ {ok, BasePltFiles} = plt_files(BasePlt),
+ ?assertEqual([Erlang], BasePltFiles),
+
+ Pair = lists:sort([Erlang, code:where_is_file("erl_prim_loader.beam")]),
+ {ok, PltFiles} = plt_files(Plt),
+ ?assertEqual(Pair, PltFiles).
+
%% Helpers
erts_files() ->
@@ -328,6 +362,6 @@ get_apps_from_beam_files(BeamFiles) ->
lists:usort(
[begin
AppNameVsn = filename:basename(filename:dirname(filename:dirname(File))),
- [AppName | _] = string:tokens(AppNameVsn ++ "-", "-"),
+ [AppName | _] = rebar_string:lexemes(AppNameVsn ++ "-", "-"),
ec_cnv:to_atom(AppName)
end || File <- BeamFiles]).
diff --git a/test/rebar_dir_SUITE.erl b/test/rebar_dir_SUITE.erl
index 9734830..81051e6 100644
--- a/test/rebar_dir_SUITE.erl
+++ b/test/rebar_dir_SUITE.erl
@@ -3,8 +3,11 @@
-export([all/0, init_per_testcase/2, end_per_testcase/2]).
-export([default_src_dirs/1, default_extra_src_dirs/1, default_all_src_dirs/1]).
--export([src_dirs/1, extra_src_dirs/1, all_src_dirs/1]).
+-export([src_dirs/1, alt_src_dir_nested/1, src_dirs_with_opts/1, extra_src_dirs/1, all_src_dirs/1]).
+-export([src_dir_opts/1, recursive/1]).
+-export([top_src_dirs/1]).
-export([profile_src_dirs/1, profile_extra_src_dirs/1, profile_all_src_dirs/1]).
+-export([profile_src_dir_opts/1]).
-export([retarget_path/1, alt_base_dir_abs/1, alt_base_dir_rel/1]).
-export([global_cache_dir/1, default_global_cache_dir/1, overwrite_default_global_cache_dir/1]).
@@ -14,8 +17,9 @@
all() -> [default_src_dirs, default_extra_src_dirs, default_all_src_dirs,
- src_dirs, extra_src_dirs, all_src_dirs,
+ src_dirs, alt_src_dir_nested, extra_src_dirs, all_src_dirs, src_dir_opts, recursive,
profile_src_dirs, profile_extra_src_dirs, profile_all_src_dirs,
+ profile_src_dir_opts, top_src_dirs,
retarget_path, alt_base_dir_abs, alt_base_dir_rel, global_cache_dir,
default_global_cache_dir, overwrite_default_global_cache_dir].
@@ -65,10 +69,35 @@ default_all_src_dirs(Config) ->
["src", "test"] = rebar_dir:all_src_dirs(rebar_state:opts(State), ["src"], ["test"]).
src_dirs(Config) ->
- RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar", "baz"]}]}],
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "./bar", "bar", "bar/", "./bar/", "baz",
+ "./", ".", "../", "..", "./../", "../.", ".././../"]}]}],
{ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
- ["bar", "baz", "foo"] = rebar_dir:src_dirs(rebar_state:opts(State)).
+ [".", "..", "../..", "bar", "baz", "foo"] = rebar_dir:src_dirs(rebar_state:opts(State)).
+
+alt_src_dir_nested(Config) ->
+ RebarConfig = [{src_dirs, ["src", "alt/nested"]}],
+ AppsDir = ?config(apps, Config),
+ Name1 = ?config(app_one, Config),
+ ModDir = filename:join([AppsDir, "apps", Name1, "alt", "nested"]),
+ Mod = "-module(altmod). -export([main/0]). main() -> ok.",
+
+ ec_file:mkdir_path(ModDir),
+ ok = file:write_file(filename:join([ModDir, "altmod.erl"]), Mod),
+
+ Ebin = filename:join([AppsDir, "_build", "default", "lib", Name1, "ebin", "altmod.beam"]),
+ {ok, State} = rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{file, Ebin}]}
+ ),
+ ["alt/nested", "src"] = rebar_dir:src_dirs(rebar_state:opts(State)).
+
+src_dirs_with_opts(Config) ->
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar", "baz"]},
+ {src_dirs, [{"foo",[{recursive,false}]}, "qux"]}]}],
+ {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
+
+ ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State)).
extra_src_dirs(Config) ->
RebarConfig = [{erl_opts, [{extra_src_dirs, ["foo", "bar", "baz"]}]}],
@@ -77,11 +106,50 @@ extra_src_dirs(Config) ->
["bar", "baz", "foo"] = rebar_dir:extra_src_dirs(rebar_state:opts(State)).
all_src_dirs(Config) ->
- RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}, {extra_src_dirs, ["baz", "qux"]}]}],
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}, {extra_src_dirs, ["baz", "qux"]}, {src_dirs, [{"foo", [{recursive,false}]}]}]}],
{ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
["bar", "baz", "foo", "qux"] = rebar_dir:all_src_dirs(rebar_state:opts(State)).
+src_dir_opts(Config) ->
+ RebarConfig =
+ [{erl_opts, [{src_dirs, [{"foo",[{recursive,true}]}, "bar"]},
+ {extra_src_dirs, ["baz", {"foo", [{recursive,false}]}]},
+ {src_dirs, [{"foo", [{recursive,false}]}]}]}],
+ {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["compile"], return),
+ [{recursive,true}] = rebar_dir:src_dir_opts(rebar_state:opts(State), "foo"),
+ [] = rebar_dir:src_dir_opts(rebar_state:opts(State), "bar"),
+ [] = rebar_dir:src_dir_opts(rebar_state:opts(State), "nonexisting").
+
+recursive(Config) ->
+ RebarConfig1 =
+ [{erl_opts, [{src_dirs, ["foo", "bar"]},
+ {extra_src_dirs, ["baz", {"foo", [{recursive,true}]}]},
+ {src_dirs, [{"foo", [{recursive,false}]}]}]}],
+ {ok, State1} = rebar_test_utils:run_and_check(Config, RebarConfig1,
+ ["compile"], return),
+ false = rebar_dir:recursive(rebar_state:opts(State1), "foo"),
+ true = rebar_dir:recursive(rebar_state:opts(State1), "bar"),
+
+ RebarConfig2 = [{erlc_compiler,[{recursive,false}]},
+ {erl_opts,[{src_dirs,["foo",{"bar",[{recursive,true}]}]}]}],
+ {ok, State2} = rebar_test_utils:run_and_check(Config, RebarConfig2,
+ ["compile"], return),
+ false = rebar_dir:recursive(rebar_state:opts(State2), "foo"),
+ true = rebar_dir:recursive(rebar_state:opts(State2), "bar"),
+
+ ok.
+
+top_src_dirs(Config) ->
+ %% We can get the same result out of specifying src_dirs from the config root,
+ %% not just the erl_opts
+ RebarConfig = [{src_dirs, ["foo", "./bar", "bar", "bar/", "./bar/", "baz",
+ "./", ".", "../", "..", "./../", "../.", ".././../"]}],
+ {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
+
+ [".", "..", "../..", "bar", "baz", "foo"] = rebar_dir:src_dirs(rebar_state:opts(State)).
+
profile_src_dirs(Config) ->
RebarConfig = [
{erl_opts, [{src_dirs, ["foo", "bar"]}]},
@@ -118,6 +186,26 @@ profile_all_src_dirs(Config) ->
R = lists:sort(["foo", "bar", "baz", "qux"]),
R = rebar_dir:all_src_dirs(rebar_state:opts(State)).
+profile_src_dir_opts(Config) ->
+ RebarConfig = [
+ {erl_opts, [{src_dirs, ["foo"]},
+ {extra_src_dirs, [{"bar",[recursive]}]}]},
+ {profiles, [
+ {more, [{erl_opts, [{src_dirs, [{"bar",[{recursive,false}]}]},
+ {extra_src_dirs, ["qux"]}]}]}
+ ]}
+ ],
+ {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["as", "more", "compile"],
+ return),
+
+ [{recursive,false}] = rebar_dir:src_dir_opts(rebar_state:opts(State),"bar"),
+
+ {ok, State1} = rebar_test_utils:run_and_check(Config, RebarConfig,
+ ["compile"], return),
+
+ [{recursive,true}] = rebar_dir:src_dir_opts(rebar_state:opts(State1),"bar").
+
retarget_path(Config) ->
{ok, State} = rebar_test_utils:run_and_check(Config, [], ["compile"], return),
diff --git a/test/rebar_edoc_SUITE.erl b/test/rebar_edoc_SUITE.erl
new file mode 100644
index 0000000..2c4aba5
--- /dev/null
+++ b/test/rebar_edoc_SUITE.erl
@@ -0,0 +1,72 @@
+-module(rebar_edoc_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-compile(export_all).
+
+all() -> [multiapp, error_survival].
+
+init_per_testcase(multiapp, Config) ->
+ application:load(rebar),
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Name = rebar_test_utils:create_random_name("multiapp"),
+ AppsDir = filename:join([PrivDir, rebar_test_utils:create_random_name(Name)]),
+ ec_file:copy(filename:join([DataDir, "foo"]), AppsDir, [recursive]),
+ Verbosity = rebar3:log_level(),
+ rebar_log:init(command_line, Verbosity),
+ State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
+ ,{root_dir, AppsDir}]),
+ [{apps, AppsDir}, {state, State}, {name, Name} | Config];
+init_per_testcase(error_survival, Config) ->
+ application:load(rebar),
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Name = rebar_test_utils:create_random_name("error_survival"),
+ AppsDir = filename:join([PrivDir, rebar_test_utils:create_random_name(Name)]),
+ ec_file:copy(filename:join([DataDir, "bad"]), AppsDir, [recursive]),
+ Verbosity = rebar3:log_level(),
+ rebar_log:init(command_line, Verbosity),
+ State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
+ ,{root_dir, AppsDir}]),
+ [{apps, AppsDir}, {state, State}, {name, Name} | Config].
+
+end_per_testcase(_, Config) ->
+ Config.
+
+multiapp(Config) ->
+ %% With an empty config (no `dir'), links are being processed
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["edoc"], {ok, []}),
+ %% validate that all doc entries are generated and links work
+ AppsDir = ?config(apps, Config),
+ ct:pal("AppsDir: ~s", [AppsDir]),
+ ?assert(file_content_matches(
+ filename:join([AppsDir, "apps", "bar1", "doc", "bar1.html"]),
+ "barer1")),
+ ?assert(file_content_matches(
+ filename:join([AppsDir, "apps", "bar2", "doc", "bar2.html"]),
+ "barer2")),
+ %% Links are in place for types
+ ?assert(file_content_matches(
+ filename:join([AppsDir, "apps", "foo", "doc", "foo.html"]),
+ "barer1")),
+ ?assert(file_content_matches(
+ filename:join([AppsDir, "apps", "foo", "doc", "foo.html"]),
+ "apps/bar1/doc/bar1.html")).
+
+error_survival(Config) ->
+ RebarConfig = [],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["edoc"],
+ {error,{rebar_prv_edoc,{app_failed,"bar2"}}}
+ ),
+ ok.
+
+
+file_content_matches(Path, Regex) ->
+ case file:read_file(Path) of
+ {ok, Bin} ->
+ nomatch =/= re:run(Bin, Regex);
+ {error, Reason} ->
+ Reason
+ end.
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.app.src b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.app.src
new file mode 100644
index 0000000..6e7ec24
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.app.src
@@ -0,0 +1,16 @@
+{application, bar1,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { bar1_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.erl
new file mode 100644
index 0000000..2700aef
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1.erl
@@ -0,0 +1,9 @@
+-module(bar1).
+-export([bar1/0]).
+-export_type([barer1/0]).
+
+-type barer1() :: string().
+
+% @doc Bar1 bars the bar.
+-spec bar1() -> barer1().
+bar1() -> "Barer1". \ No newline at end of file
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_app.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_app.erl
new file mode 100644
index 0000000..414ac30
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc bar1 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar1_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ bar1_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_sup.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_sup.erl
new file mode 100644
index 0000000..f9d6670
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar1/src/bar1_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc bar1 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.app.src b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.app.src
new file mode 100644
index 0000000..58de8bc
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.app.src
@@ -0,0 +1,16 @@
+{application, bar2,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { bar2_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.erl
new file mode 100644
index 0000000..2afb745
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2.erl
@@ -0,0 +1,12 @@
+%% @doc one docline is fine
+%% @doc a second docline causes a failure
+%% @doc if not, then a & causes a bad ref error.
+-module(bar2).
+-export([bar2/0]).
+-export_type([barer2/0]).
+
+-type barer2() :: string().
+
+% @doc Bar2 bars the bar2.
+-spec bar2() -> barer2().
+bar2() -> "Barer2".
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_app.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_app.erl
new file mode 100644
index 0000000..d0058a0
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc bar2 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar2_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ bar2_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_sup.erl b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_sup.erl
new file mode 100644
index 0000000..0bdaf4a
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/bar2/src/bar2_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc bar2 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.app.src b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.app.src
new file mode 100644
index 0000000..9987fd5
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.app.src
@@ -0,0 +1,17 @@
+{application, foo,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { foo_app, []}},
+ {applications,
+ [kernel,
+ stdlib,
+ bar1, bar2
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.erl b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.erl
new file mode 100644
index 0000000..52e3d0a
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo.erl
@@ -0,0 +1,19 @@
+-module(foo).
+
+-export([foo/0, bar1/0, bar2/0]).
+
+-export_type([fooer/0]).
+
+-type fooer() :: string().
+
+% @doc Foo function returns fooer.
+-spec foo() -> fooer().
+foo() -> "fooer".
+
+% @doc Bar1 function returns barer1.
+-spec bar1() -> bar1:barer1().
+bar1() -> bar1:bar1().
+
+% @doc Bar2 functions returns barer2.
+-spec bar2() -> bar2:barer2().
+bar2() -> bar2:bar2(). \ No newline at end of file
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_app.erl b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_app.erl
new file mode 100644
index 0000000..d0158d7
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc foo public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(foo_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ foo_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_sup.erl b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_sup.erl
new file mode 100644
index 0000000..67e88b4
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/bad/apps/foo/src/foo_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc foo top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(foo_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.app.src b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.app.src
new file mode 100644
index 0000000..6e7ec24
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.app.src
@@ -0,0 +1,16 @@
+{application, bar1,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { bar1_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.erl
new file mode 100644
index 0000000..2700aef
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1.erl
@@ -0,0 +1,9 @@
+-module(bar1).
+-export([bar1/0]).
+-export_type([barer1/0]).
+
+-type barer1() :: string().
+
+% @doc Bar1 bars the bar.
+-spec bar1() -> barer1().
+bar1() -> "Barer1". \ No newline at end of file
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_app.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_app.erl
new file mode 100644
index 0000000..414ac30
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc bar1 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar1_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ bar1_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_sup.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_sup.erl
new file mode 100644
index 0000000..f9d6670
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar1/src/bar1_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc bar1 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.app.src b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.app.src
new file mode 100644
index 0000000..58de8bc
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.app.src
@@ -0,0 +1,16 @@
+{application, bar2,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { bar2_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.erl
new file mode 100644
index 0000000..c639db0
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2.erl
@@ -0,0 +1,9 @@
+-module(bar2).
+-export([bar2/0]).
+-export_type([barer2/0]).
+
+-type barer2() :: string().
+
+% @doc Bar2 bars the bar2.
+-spec bar2() -> barer2().
+bar2() -> "Barer2". \ No newline at end of file
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_app.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_app.erl
new file mode 100644
index 0000000..d0058a0
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc bar2 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar2_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ bar2_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_sup.erl b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_sup.erl
new file mode 100644
index 0000000..0bdaf4a
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/bar2/src/bar2_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc bar2 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(bar2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.app.src b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.app.src
new file mode 100644
index 0000000..9987fd5
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.app.src
@@ -0,0 +1,17 @@
+{application, foo,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { foo_app, []}},
+ {applications,
+ [kernel,
+ stdlib,
+ bar1, bar2
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.erl b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.erl
new file mode 100644
index 0000000..52e3d0a
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo.erl
@@ -0,0 +1,19 @@
+-module(foo).
+
+-export([foo/0, bar1/0, bar2/0]).
+
+-export_type([fooer/0]).
+
+-type fooer() :: string().
+
+% @doc Foo function returns fooer.
+-spec foo() -> fooer().
+foo() -> "fooer".
+
+% @doc Bar1 function returns barer1.
+-spec bar1() -> bar1:barer1().
+bar1() -> bar1:bar1().
+
+% @doc Bar2 functions returns barer2.
+-spec bar2() -> bar2:barer2().
+bar2() -> bar2:bar2(). \ No newline at end of file
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_app.erl b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_app.erl
new file mode 100644
index 0000000..d0158d7
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc foo public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(foo_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ foo_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_sup.erl b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_sup.erl
new file mode 100644
index 0000000..67e88b4
--- /dev/null
+++ b/test/rebar_edoc_SUITE_data/foo/apps/foo/src/foo_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc foo top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(foo_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_escriptize_SUITE.erl b/test/rebar_escriptize_SUITE.erl
index 1817d6b..a6901f9 100644
--- a/test/rebar_escriptize_SUITE.erl
+++ b/test/rebar_escriptize_SUITE.erl
@@ -5,7 +5,10 @@
end_per_suite/1,
init_per_testcase/2,
all/0,
- build_and_clean_app/1]).
+ escriptize_with_name/1,
+ escriptize_with_bad_name/1,
+ build_and_clean_app/1,
+ escriptize_with_ebin_subdir/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -24,7 +27,12 @@ init_per_testcase(_, Config) ->
rebar_test_utils:init_rebar_state(Config).
all() ->
- [build_and_clean_app].
+ [
+ build_and_clean_app,
+ escriptize_with_name,
+ escriptize_with_bad_name,
+ escriptize_with_ebin_subdir
+ ].
%% Test escriptize builds and runs the app's escript
build_and_clean_app(Config) ->
@@ -35,3 +43,42 @@ build_and_clean_app(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
rebar_test_utils:run_and_check(Config, [], ["escriptize"],
{ok, [{app, Name, valid}]}).
+
+escriptize_with_name(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:run_and_check(Config, [{escript_main_app, Name}], ["escriptize"],
+ {ok, [{app, Name, valid}]}).
+
+escriptize_with_bad_name(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:run_and_check(Config, [{escript_main_app, boogers}], ["escriptize"],
+ {error,{rebar_prv_escriptize, {bad_name, boogers}}}).
+
+escriptize_with_ebin_subdir(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ filelib:ensure_dir(filename:join([AppDir, "ebin", "subdir", "subdirfile"])),
+
+ %% To work, this test must run from the AppDir itself. To avoid breaking
+ %% other tests, be careful with cwd
+ Cwd = file:get_cwd(),
+ try
+ file:set_cwd(AppDir),
+ {ok, _} = rebar3:run(rebar_state:new(?config(state,Config), [], AppDir),
+ ["escriptize"])
+ after
+ file:set_cwd(Cwd) % reset always
+ end,
+ ok.
diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl
index 41ab6ff..1a8bade 100644
--- a/test/rebar_eunit_SUITE.erl
+++ b/test/rebar_eunit_SUITE.erl
@@ -1,7 +1,8 @@
-module(rebar_eunit_SUITE).
-export([all/0, groups/0]).
--export([init_per_suite/1, init_per_group/2, end_per_group/2]).
+-export([init_per_suite/1, end_per_suite/1]).
+-export([init_per_group/2, end_per_group/2]).
-export([basic_app_compiles/1, basic_app_files/1]).
-export([basic_app_exports/1, basic_app_testset/1]).
-export([basic_app_eunit_macro/1]).
@@ -18,6 +19,7 @@
-export([misspecified_eunit_tests/1]).
-export([misspecified_eunit_compile_opts/1]).
-export([misspecified_eunit_first_files/1]).
+-export([alternate_test_regex/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -27,7 +29,8 @@ all() ->
[{group, basic_app}, {group, multi_app}, {group, cmd_line_args},
misspecified_eunit_tests,
misspecified_eunit_compile_opts,
- misspecified_eunit_first_files].
+ misspecified_eunit_first_files,
+ alternate_test_regex].
groups() ->
[{basic_app, [sequence], [basic_app_compiles, {group, basic_app_results}]},
@@ -58,6 +61,8 @@ init_per_suite(Config) ->
{ok, _} = zip:extract(filename:join([PrivDir, "multi_app.zip"]), [{cwd, PrivDir}]),
Config.
+end_per_suite(Config) -> Config.
+
init_per_group(basic_app, Config) ->
GroupState = rebar_test_utils:init_rebar_state(Config, "basic_app_"),
@@ -579,3 +584,25 @@ misspecified_eunit_first_files(Config) ->
{error, {rebar_prv_eunit, Error}} = rebar_test_utils:run_and_check(State, RebarConfig, ["eunit"], return),
{badconfig, {"Value `~p' of option `~p' must be a list", {some_file, eunit_first_files}}} = Error.
+
+alternate_test_regex(Config) ->
+ State = rebar_test_utils:init_rebar_state(Config, "alternate_test_regex_"),
+
+ AppDir = ?config(apps, State),
+ PrivDir = ?config(priv_dir, State),
+
+ AppDirs = ["src", "include", "test"],
+
+ lists:foreach(fun(F) -> ec_file:copy(filename:join([PrivDir, "basic_app", F]),
+ filename:join([AppDir, F]),
+ [recursive]) end, AppDirs),
+
+ BaseConfig = [{erl_opts, [{d, config_define}]}, {eunit_compile_opts, [{d, eunit_compile_define}]}],
+
+ RebarConfig = [{eunit_test_regex, "basic_app_tests.erl"}|BaseConfig],
+
+ {ok, S} = rebar_test_utils:run_and_check(State, RebarConfig, ["as", "test", "lock"], return),
+
+ Set = {ok, [{application, basic_app},
+ {module, basic_app_tests}]},
+ Set = rebar_prv_eunit:prepare_tests(S).
diff --git a/test/rebar_file_utils_SUITE.erl b/test/rebar_file_utils_SUITE.erl
index a44a06d..4cc6a93 100644
--- a/test/rebar_file_utils_SUITE.erl
+++ b/test/rebar_file_utils_SUITE.erl
@@ -4,6 +4,8 @@
groups/0,
init_per_group/2,
end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2,
raw_tmpdir/1,
empty_tmpdir/1,
simple_tmpdir/1,
@@ -14,7 +16,14 @@
path_from_ancestor/1,
canonical_path/1,
resolve_link/1,
- split_dirname/1]).
+ split_dirname/1,
+ mv_warning_is_ignored/1,
+ mv_dir/1,
+ mv_file_same/1,
+ mv_file_diff/1,
+ mv_file_dir_same/1,
+ mv_file_dir_diff/1,
+ mv_no_clobber/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -24,14 +33,18 @@
all() ->
[{group, tmpdir},
{group, reset_dir},
+ {group, mv},
path_from_ancestor,
canonical_path,
resolve_link,
- split_dirname].
+ split_dirname,
+ mv_warning_is_ignored].
groups() ->
[{tmpdir, [], [raw_tmpdir, empty_tmpdir, simple_tmpdir, multi_tmpdir]},
- {reset_dir, [], [reset_nonexistent_dir, reset_empty_dir, reset_dir]}].
+ {reset_dir, [], [reset_nonexistent_dir, reset_empty_dir, reset_dir]},
+ {mv, [], [mv_dir, mv_file_same, mv_file_diff,
+ mv_file_dir_same, mv_file_dir_diff, mv_no_clobber]}].
init_per_group(reset_dir, Config) ->
TmpDir = rebar_file_utils:system_tmpdir(["rebar_file_utils_SUITE", "resetable"]),
@@ -39,6 +52,20 @@ init_per_group(reset_dir, Config) ->
init_per_group(_, Config) -> Config.
end_per_group(_, Config) -> Config.
+init_per_testcase(Test, Config) ->
+ case os:type() of
+ {win32, _} ->
+ case lists:member(Test, [resolve_link, mv_warning_is_ignored]) of
+ true -> {skip, "broken in windows"};
+ false -> Config
+ end;
+ _ ->
+ Config
+ end.
+
+end_per_testcase(_Test, Config) ->
+ Config.
+
raw_tmpdir(_Config) ->
case rebar_file_utils:system_tmpdir() of
"/tmp" -> ok;
@@ -135,3 +162,170 @@ split_dirname(_Config) ->
?assertEqual({".", "foo"}, rebar_file_utils:split_dirname("foo")),
?assertEqual({"/foo", "bar"}, rebar_file_utils:split_dirname("/foo/bar")),
?assertEqual({"foo", "bar"}, rebar_file_utils:split_dirname("foo/bar")).
+
+mv_warning_is_ignored(_Config) ->
+ meck:new(rebar_utils, [passthrough]),
+ meck:expect(rebar_utils, sh, fun("mv ding dong", _) -> {ok, "Warning"} end),
+ ok = rebar_file_utils:mv("ding", "dong"),
+ meck:unload(rebar_utils).
+
+%%% Ensure Windows & Unix operations to move files
+
+mv_dir(Config) ->
+ %% Move a directory to another one location
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_dir),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ %% empty dir movement
+ DstDir1 = filename:join(BaseDir, "dst1/"),
+ ?assertNot(filelib:is_dir(DstDir1)),
+ ?assertEqual(ok, rebar_file_utils:mv(SrcDir, DstDir1)),
+ ?assert(filelib:is_dir(DstDir1)),
+
+ %% move files from dir to empty dir
+ F1 = filename:join(SrcDir, "file1"),
+ F2 = filename:join(SrcDir, "subdir/file2"),
+ filelib:ensure_dir(F2),
+ file:write_file(F1, "hello"),
+ file:write_file(F2, "world"),
+ DstDir2 = filename:join(BaseDir, "dst2/"),
+ D2F1 = filename:join(DstDir2, "file1"),
+ D2F2 = filename:join(DstDir2, "subdir/file2"),
+ ?assertNot(filelib:is_dir(DstDir2)),
+ ?assertEqual(ok, rebar_file_utils:mv(SrcDir, DstDir2)),
+ ?assert(filelib:is_file(D2F1)),
+ ?assert(filelib:is_file(D2F2)),
+
+ %% move files from dir to existing dir moves it to
+ %% a subdir
+ filelib:ensure_dir(F2),
+ file:write_file(F1, "hello"),
+ file:write_file(F2, "world"),
+ DstDir3 = filename:join(BaseDir, "dst3/"),
+ D3F1 = filename:join(DstDir3, "src/file1"),
+ D3F2 = filename:join(DstDir3, "src/subdir/file2"),
+ ec_file:mkdir_p(DstDir3),
+ ?assert(filelib:is_dir(DstDir3)),
+ ?assertEqual(ok, rebar_file_utils:mv(SrcDir, DstDir3)),
+ ?assertNot(filelib:is_file(F1)),
+ ?assertNot(filelib:is_file(F2)),
+ ?assert(filelib:is_file(D3F1)),
+ ?assert(filelib:is_file(D3F2)),
+ ?assertNot(filelib:is_dir(SrcDir)),
+ ok.
+
+mv_file_same(Config) ->
+ %% Move a file from a directory to the other without renaming
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_file_same),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ F = filename:join(SrcDir, "file"),
+ file:write_file(F, "hello"),
+ DstDir = filename:join(BaseDir, "dst/"),
+ ec_file:mkdir_p(DstDir),
+ Dst = filename:join(DstDir, "file"),
+ ?assertEqual(ok, rebar_file_utils:mv(F, Dst)),
+ ?assert(filelib:is_file(Dst)),
+ ?assertNot(filelib:is_file(F)),
+ ok.
+
+mv_file_diff(Config) ->
+ %% Move a file from a directory to another one while renaming
+ %% into a pre-existing file
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_file_diff),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ F = filename:join(SrcDir, "file"),
+ file:write_file(F, "hello"),
+ DstDir = filename:join(BaseDir, "dst/"),
+ ec_file:mkdir_p(DstDir),
+ Dst = filename:join(DstDir, "file-rename"),
+ file:write_file(Dst, "not-the-right-content"),
+ ?assert(filelib:is_file(Dst)),
+ ?assertEqual(ok, rebar_file_utils:mv(F, Dst)),
+ ?assert(filelib:is_file(Dst)),
+ ?assertEqual({ok, <<"hello">>}, file:read_file(Dst)),
+ ?assertNot(filelib:is_file(F)),
+ ok.
+
+mv_file_dir_same(Config) ->
+ %% Move a file to a directory without renaming
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_file_dir_same),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ F = filename:join(SrcDir, "file"),
+ file:write_file(F, "hello"),
+ DstDir = filename:join(BaseDir, "dst/"),
+ ec_file:mkdir_p(DstDir),
+ Dst = filename:join(DstDir, "file"),
+ ?assert(filelib:is_dir(DstDir)),
+ ?assertEqual(ok, rebar_file_utils:mv(F, DstDir)),
+ ?assert(filelib:is_file(Dst)),
+ ?assertNot(filelib:is_file(F)),
+ ok.
+
+mv_file_dir_diff(Config) ->
+ %% Move a file to a directory while renaming
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_file_dir_diff),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ F = filename:join(SrcDir, "file"),
+ file:write_file(F, "hello"),
+ DstDir = filename:join(BaseDir, "dst/"),
+ ec_file:mkdir_p(DstDir),
+ Dst = filename:join(DstDir, "file-rename"),
+ ?assert(filelib:is_dir(DstDir)),
+ ?assertNot(filelib:is_file(Dst)),
+ ?assertEqual(ok, rebar_file_utils:mv(F, Dst)),
+ ?assert(filelib:is_file(Dst)),
+ ?assertNot(filelib:is_file(F)),
+ ok.
+
+mv_no_clobber(Config) ->
+ %% Moving a file while renaming does not clobber other files
+ PrivDir = ?config(priv_dir, Config),
+ BaseDir = mk_base_dir(PrivDir, mv_no_clobber),
+ SrcDir = filename:join(BaseDir, "src/"),
+ ec_file:mkdir_p(SrcDir),
+ ?assert(filelib:is_dir(SrcDir)),
+ F = filename:join(SrcDir, "file"),
+ file:write_file(F, "hello"),
+ FBad = filename:join(SrcDir, "file-alt"),
+ file:write_file(FBad, "wrong-data"),
+ DstDir = filename:join(BaseDir, "dst/"),
+ ec_file:mkdir_p(DstDir),
+ Dst = filename:join(DstDir, "file-alt"),
+ DstBad = filename:join(DstDir, "file"),
+ file:write_file(DstBad, "wrong-data"),
+ ?assert(filelib:is_file(F)),
+ ?assert(filelib:is_file(FBad)),
+ ?assert(filelib:is_dir(DstDir)),
+ ?assertNot(filelib:is_file(Dst)),
+ ?assert(filelib:is_file(DstBad)),
+ ?assertEqual(ok, rebar_file_utils:mv(F, Dst)),
+ ?assert(filelib:is_file(Dst)),
+ ?assertNot(filelib:is_file(F)),
+ ?assert(filelib:is_file(DstBad)),
+ ?assert(filelib:is_file(FBad)),
+ ?assertEqual({ok, <<"hello">>}, file:read_file(Dst)),
+ ?assertEqual({ok, <<"wrong-data">>}, file:read_file(FBad)),
+ ?assertEqual({ok, <<"wrong-data">>}, file:read_file(DstBad)),
+ ok.
+
+
+mk_base_dir(BasePath, Name) ->
+ {_,_,Micro} = os:timestamp(),
+ Index = integer_to_list(Micro),
+ Path = filename:join(BasePath, atom_to_list(Name) ++ Index),
+ ec_file:mkdir_p(Path),
+ Path.
diff --git a/test/rebar_hooks_SUITE.erl b/test/rebar_hooks_SUITE.erl
index b121dd5..29e343f 100644
--- a/test/rebar_hooks_SUITE.erl
+++ b/test/rebar_hooks_SUITE.erl
@@ -1,17 +1,6 @@
-module(rebar_hooks_SUITE).
--export([suite/0,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2,
- all/0,
- build_and_clean_app/1,
- escriptize_artifacts/1,
- run_hooks_once/1,
- run_hooks_for_plugins/1,
- eunit_app_hooks/1,
- deps_hook_namespace/1]).
+-compile(export_all).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -33,8 +22,10 @@ end_per_testcase(_, _Config) ->
catch meck:unload().
all() ->
- [build_and_clean_app, run_hooks_once, escriptize_artifacts,
- run_hooks_for_plugins, deps_hook_namespace, eunit_app_hooks].
+ [build_and_clean_app, run_hooks_once, run_hooks_once_profiles,
+ escriptize_artifacts, run_hooks_for_plugins, deps_hook_namespace,
+ bare_compile_hooks_default_ns, deps_clean_hook_namespace, eunit_app_hooks,
+ sub_app_hooks, root_hooks].
%% Test post provider hook cleans compiled project app, leaving it invalid
build_and_clean_app(Config) ->
@@ -93,11 +84,23 @@ run_hooks_once(Config) ->
Name = rebar_test_utils:create_random_name("app1_"),
Vsn = rebar_test_utils:create_random_vsn(),
- RebarConfig = [{pre_hooks, [{compile, "mkdir blah"}]}],
+ RebarConfig = [{pre_hooks, [{compile, "mkdir \"$REBAR_ROOT_DIR/blah\""}]}],
rebar_test_utils:create_config(AppDir, RebarConfig),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name, valid}]}).
+%% test that even if a hook is defined at the project level in a used profile
+%% the hook is not run for each application in the project umbrella
+run_hooks_once_profiles(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ RebarConfig = [{profiles, [{hooks, [{pre_hooks, [{compile, "mkdir \"$REBAR_ROOT_DIR/blah\""}]}]}]}],
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "hooks", "compile"], {ok, [{app, Name, valid}]}).
+
deps_hook_namespace(Config) ->
mock_git_resource:mock([{deps, [{some_dep, "0.0.1"}]}]),
Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", []}]),
@@ -120,6 +123,44 @@ deps_hook_namespace(Config) ->
{ok, [{dep, "some_dep"}]}
).
+%% tests that hooks to compile when running bare compile run in the default namespace
+bare_compile_hooks_default_ns(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir,
+ [{provider_hooks, [{post, [{compile, clean}]}]}]),
+ {ok, RConf} = file:consult(RConfFile),
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["bare", "compile", "--paths", "."],
+ {ok, []}
+ ).
+
+deps_clean_hook_namespace(Config) ->
+ mock_git_resource:mock([{deps, [{some_dep, "0.0.1"}]}]),
+ Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", []}]),
+ TopDeps = rebar_test_utils:top_level_deps(Deps),
+
+ RebarConfig = [
+ {deps, TopDeps},
+ {overrides, [
+ {override, some_dep, [
+ {provider_hooks, [
+ {pre, [
+ {compile, clean}
+ ]}
+ ]}
+ ]}
+ ]}
+ ],
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["clean"],
+ {ok, [{dep, "some_dep"}]}
+ ).
+
%% Checks that a hook that is defined on an app (not a top level hook of a project with subapps) is run
eunit_app_hooks(Config) ->
AppDir = ?config(apps, Config),
@@ -161,3 +202,45 @@ run_hooks_for_plugins(Config) ->
rebar_test_utils:run_and_check(Config, RConf, ["compile"], {ok, [{app, Name, valid},
{plugin, PluginName},
{file, filename:join([AppDir, "_build", "default", "plugins", PluginName, "randomfile"])}]}).
+
+%% test that a subapp of a project keeps its hooks
+sub_app_hooks(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("sub_app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+
+ SubAppsDir = filename:join([AppDir, "apps", Name]),
+
+ rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_config(SubAppsDir, [{provider_hooks, [{post, [{compile, clean}]}]}]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, []),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name, invalid}]}
+ ).
+
+%% test that hooks at the top level don't run in the subapps
+root_hooks(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("sub_app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+
+ SubAppsDir = filename:join([AppDir, "apps", Name]),
+
+ rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_config(SubAppsDir, [{provider_hooks, [{post, [{compile, clean}]}]}]),
+
+ RConfFile = rebar_test_utils:create_config(AppDir, [{pre_hooks, [{compile, "mkdir \"$REBAR_ROOT_DIR/blah\""}]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Build with deps.
+ rebar_test_utils:run_and_check(
+ Config, RConf, ["compile"],
+ {ok, [{app, Name, invalid}]}
+ ).
diff --git a/test/rebar_install_deps_SUITE.erl b/test/rebar_install_deps_SUITE.erl
index 9ff28c7..96b9d38 100644
--- a/test/rebar_install_deps_SUITE.erl
+++ b/test/rebar_install_deps_SUITE.erl
@@ -17,7 +17,7 @@ groups() ->
{mixed, [], [
m_flat1, m_flat2, m_circular1, m_circular2,
m_pick_source1, m_pick_source2, m_pick_source3,
- m_pick_source4, m_pick_source5, m_source_to_pkg,
+ m_pick_source4, m_pick_source5, m_pick_source6, m_source_to_pkg,
m_pkg_level1, m_pkg_level2, m_pkg_level3, m_pkg_level3_alpha_order
]}
].
@@ -82,22 +82,24 @@ format_expected_mdeps(Deps) ->
lists:append([
case Dep of
{N,V} when hd(N) >= $a, hd(N) =< $z ->
- UN = string:to_upper(N),
+ UN = rebar_string:uppercase(N),
[{dep, UN, V}, {lock, pkg, UN, V}];
{N,V} when hd(N) >= $A, hd(N) =< $Z ->
[{dep, N, V}, {lock, src, N, V}];
N when hd(N) >= $a, hd(N) =< $z ->
- UN = string:to_upper(N),
+ UN = rebar_string:uppercase(N),
[{dep, UN}, {lock, pkg, UN, "0.0.0"}];
N when hd(N) >= $A, hd(N) =< $Z ->
[{dep, N}, {lock, src, N, "0.0.0"}]
end || Dep <- Deps]).
+format_expected_mixed_warnings(none) ->
+ none;
format_expected_mixed_warnings(Warnings) ->
[case W of
- {N, Vsn} when hd(N) >= $a, hd(N) =< $z -> {pkg, string:to_upper(N), Vsn};
+ {N, Vsn} when hd(N) >= $a, hd(N) =< $z -> {pkg, rebar_string:uppercase(N), Vsn};
{N, Vsn} when hd(N) >= $A, hd(N) =< $Z -> {git, N, Vsn};
- N when hd(N) >= $a, hd(N) =< $z -> {pkg, string:to_upper(N), "0.0.0"};
+ N when hd(N) >= $a, hd(N) =< $z -> {pkg, rebar_string:uppercase(N), "0.0.0"};
N when hd(N) >= $A, hd(N) =< $Z -> {git, N, "0.0.0"}
end || W <- Warnings].
@@ -121,27 +123,27 @@ deps(flat) ->
[],
{ok, ["B", "C"]}};
deps(pick_highest_left) ->
- {[{"B", [{"C", "2", []}]},
- {"C", "1", []}],
- [{"C","2"}],
- {ok, ["B", {"C", "1"}]}};
+ {[{"B", [{"C", "2.0.0", []}]},
+ {"C", "1.0.0", []}],
+ [{"C","2.0.0"}],
+ {ok, ["B", {"C", "1.0.0"}]}};
deps(pick_highest_right) ->
- {[{"B", "1", []},
- {"C", [{"B", "2", []}]}],
- [{"B","2"}],
- {ok, [{"B","1"}, "C"]}};
+ {[{"B", "1.0.0", []},
+ {"C", [{"B", "2.0.0", []}]}],
+ [{"B","2.0.0"}],
+ {ok, [{"B","1.0.0"}, "C"]}};
deps(pick_smallest1) ->
- {[{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}],
- [{"D","2"}],
+ {[{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}],
+ [{"D","2.0.0"}],
%% we pick D1 because B < C
- {ok, ["B","C",{"D","1"}]}};
+ {ok, ["B","C",{"D","1.0.0"}]}};
deps(pick_smallest2) ->
- {[{"C", [{"D", "2", []}]},
- {"B", [{"D", "1", []}]}],
- [{"D","2"}],
+ {[{"C", [{"D", "2.0.0", []}]},
+ {"B", [{"D", "1.0.0", []}]}],
+ [{"D","2.0.0"}],
%% we pick D1 because B < C
- {ok, ["B","C",{"D","1"}]}};
+ {ok, ["B","C",{"D","1.0.0"}]}};
deps(circular1) ->
{[{"B", [{"A", []}]}, % A is the top-level app
{"C", []}],
@@ -155,14 +157,14 @@ deps(circular2) ->
deps(circular_skip) ->
%% Never spot the circular dep due to being to low in the deps tree
%% in source deps
- {[{"B", [{"C", "2", [{"B", []}]}]},
- {"C", "1", [{"D",[]}]}],
- [{"C","2"}],
- {ok, ["B", {"C","1"}, "D"]}};
+ {[{"B", [{"C", "2.0.0", [{"B", []}]}]},
+ {"C", "1.0.0", [{"D",[]}]}],
+ [{"C","2.0.0"}],
+ {ok, ["B", {"C","1.0.0"}, "D"]}};
deps(fail_conflict) ->
- {[{"B", [{"C", "2", []}]},
- {"C", "1", []}],
- [{"C","2"}],
+ {[{"B", [{"C", "2.0.0", []}]},
+ {"C", "1.0.0", []}],
+ [{"C","2.0.0"}],
rebar_abort};
deps(default_profile) ->
{[{"B", []},
@@ -216,39 +218,44 @@ mdeps(m_pick_source3) ->
[],
{ok, ["B"]}};
mdeps(m_pick_source4) ->
- {[{"b", [{"d", "1", []}]},
- {"C", [{"D", "1", []}]}],
- [{"D", "1"}],
- {ok, ["b", "C", {"d", "1"}]}};
+ {[{"b", [{"d", "1.0.0", []}]},
+ {"C", [{"D", "1.0.0", []}]}],
+ [{"D", "1.0.0"}],
+ {ok, ["b", "C", {"d", "1.0.0"}]}};
mdeps(m_pick_source5) ->
- {[{"B", [{"d", "1", []}]},
- {"C", [{"D", "1", []}]}],
- [{"D", "1"}],
- {ok, ["B", "C", {"d", "1"}]}};
+ {[{"B", [{"d", "1.0.0", []}]},
+ {"C", [{"D", "1.0.0", []}]}],
+ [{"D", "1.0.0"}],
+ {ok, ["B", "C", {"d", "1.0.0"}]}};
+mdeps(m_pick_source6) ->
+ {[{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "1.0.0", []}]}],
+ none,
+ {ok, ["B", "C", {"D", "1.0.0"}]}};
mdeps(m_source_to_pkg) ->
{[{"B", [{"c",[{"d", []}]}]}],
[],
{ok, ["B", "c", "d"]}};
mdeps(m_pkg_level1) ->
- {[{"B", [{"D", [{"e", "2", []}]}]},
- {"C", [{"e", "1", []}]}],
- [{"e","2"}],
- {ok, ["B","C","D",{"e","1"}]}};
+ {[{"B", [{"D", [{"e", "2.0.0", []}]}]},
+ {"C", [{"e", "1.0.0", []}]}],
+ [{"e","2.0.0"}],
+ {ok, ["B","C","D",{"e","1.0.0"}]}};
mdeps(m_pkg_level2) ->
- {[{"B", [{"e", "1", []}]},
- {"C", [{"D", [{"e", "2", []}]}]}],
- [{"e","2"}],
- {ok, ["B","C","D",{"e","1"}]}};
+ {[{"B", [{"e", "1.0.0", []}]},
+ {"C", [{"D", [{"e", "2.0.0", []}]}]}],
+ [{"e","2.0.0"}],
+ {ok, ["B","C","D",{"e","1.0.0"}]}};
mdeps(m_pkg_level3_alpha_order) ->
- {[{"B", [{"d", [{"f", "1", []}]}]},
- {"C", [{"E", [{"f", "2", []}]}]}],
- [{"f","2"}],
- {ok, ["B","C","d","E",{"f","1"}]}};
+ {[{"B", [{"d", [{"f", "1.0.0", []}]}]},
+ {"C", [{"E", [{"f", "2.0.0", []}]}]}],
+ [{"f","2.0.0"}],
+ {ok, ["B","C","d","E",{"f","1.0.0"}]}};
mdeps(m_pkg_level3) ->
- {[{"B", [{"d", [{"f", "1", []}]}]},
- {"C", [{"E", [{"G", [{"f", "2", []}]}]}]}],
- [{"f","2"}],
- {ok, ["B","C","d","E","G",{"f","1"}]}}.
+ {[{"B", [{"d", [{"f", "1.0.0", []}]}]},
+ {"C", [{"E", [{"G", [{"f", "2.0.0", []}]}]}]}],
+ [{"f","2.0.0"}],
+ {ok, ["B","C","d","E","G",{"f","1.0.0"}]}}.
setup_project(fail_conflict, Config0, Deps) ->
DepsType = ?config(deps_type, Config0),
@@ -289,8 +296,8 @@ setup_project(nondefault_pick_highest, Config0, _) ->
),
AppDir = ?config(apps, Config),
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
- DefaultDeps = rebar_test_utils:expand_deps(DepsType, [{"B", [{"C", "1", []}]}]),
- ProfileDeps = rebar_test_utils:expand_deps(DepsType, [{"C", "2", []}]),
+ DefaultDeps = rebar_test_utils:expand_deps(DepsType, [{"B", [{"C", "1.0.0", []}]}]),
+ ProfileDeps = rebar_test_utils:expand_deps(DepsType, [{"C", "2.0.0", []}]),
DefaultTop = rebar_test_utils:top_level_deps(DefaultDeps),
ProfileTop = rebar_test_utils:top_level_deps(ProfileDeps),
RebarConf = rebar_test_utils:create_config(
@@ -412,19 +419,19 @@ nondefault_pick_highest(Config) ->
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
rebar_test_utils:run_and_check(
Config, RebarConfig, ["lock"],
- {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "1"}], "default"}
+ {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "1.0.0"}], "default"}
),
rebar_test_utils:run_and_check(
Config, RebarConfig, ["as", "nondef", "lock"],
- {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "2"}], "nondef"}
+ {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "2.0.0"}], "nondef"}
),
rebar_test_utils:run_and_check(
Config, RebarConfig, ["lock"],
- {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "1"}, {lock, "C", "1"}], "default"}
+ {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "1.0.0"}, {lock, "C", "1.0.0"}], "default"}
),
rebar_test_utils:run_and_check(
Config, RebarConfig, ["as", "nondef", "lock"],
- {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "2"}], "nondef"}
+ {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "2.0.0"}], "nondef"}
).
m_flat1(Config) -> run(Config).
@@ -436,6 +443,7 @@ m_pick_source2(Config) -> run(Config).
m_pick_source3(Config) -> run(Config).
m_pick_source4(Config) -> run(Config).
m_pick_source5(Config) -> run(Config).
+m_pick_source6(Config) -> run(Config).
m_source_to_pkg(Config) -> run(Config).
m_pkg_level1(Config) -> run(Config).
m_pkg_level2(Config) -> run(Config).
@@ -466,7 +474,10 @@ check_warnings(Warns, [{Type, Name, Vsn} | Rest], mixed) ->
check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
?assert(in_warnings(Type, Warns, Name, Vsn)),
- check_warnings(Warns, Rest, Type).
+ check_warnings(Warns, Rest, Type);
+check_warnings(Warns, none, _Type) ->
+ ct:pal("Checking that there were no warnings", []),
+ ?assert(Warns == []).
in_warnings(git, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw),
@@ -475,5 +486,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) ->
in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Name = iolist_to_binary(NameRaw),
Vsn = iolist_to_binary(VsnRaw),
- 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns,
+ 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]).
diff --git a/test/rebar_localfs_resource.erl b/test/rebar_localfs_resource.erl
index d60421e..3d1296a 100644
--- a/test/rebar_localfs_resource.erl
+++ b/test/rebar_localfs_resource.erl
@@ -2,6 +2,7 @@
%% ex: ts=4 sw=4 et
%%
%% @doc A localfs custom resource (for testing purposes only)
+%% implementing the deprecated rebar_resource instead of v2
%%
%% ```
%% {deps, [
@@ -13,13 +14,18 @@
-behaviour(rebar_resource).
--export([lock/2
+-export([init/1
+ ,lock/2
,download/3
,needs_update/2
,make_vsn/1]).
-include_lib("eunit/include/eunit.hrl").
+-spec init(rebar_state:t()) -> {ok, term()}.
+init(_State) ->
+ {ok, #{}}.
+
lock(AppDir, {localfs, Path, _Ref}) ->
lock(AppDir, {localfs, Path});
lock(_AppDir, {localfs, Path}) ->
diff --git a/test/rebar_localfs_resource_v2.erl b/test/rebar_localfs_resource_v2.erl
new file mode 100644
index 0000000..52af4d4
--- /dev/null
+++ b/test/rebar_localfs_resource_v2.erl
@@ -0,0 +1,50 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%%
+%% @doc A localfs custom resource (for testing purposes only)
+%%
+%% ```
+%% {deps, [
+%% %% Application files are copied from "/path/to/app_name"
+%% {app_name, {localfs, "/path/to/app_name", undefined}}
+%% ]}.
+%% '''
+-module(rebar_localfs_resource_v2).
+
+-behaviour(rebar_resource_v2).
+
+-export([init/2
+ ,lock/2
+ ,download/4
+ ,needs_update/2
+ ,make_vsn/2]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-spec init(atom(), rebar_state:t()) -> {ok, term()}.
+init(Type, _State) ->
+ Resource = rebar_resource_v2:new(Type, ?MODULE, #{}),
+ {ok, Resource}.
+
+lock(AppInfo, _) ->
+ case rebar_app_info:source(AppInfo) of
+ {localfs, Path, _Ref} ->
+ {localfs, Path, undefined};
+ {localfs, Path} ->
+ {localfs, Path, undefined}
+ end.
+
+needs_update(_AppInfo, _) ->
+ false.
+
+download(TmpDir, AppInfo, State, _) ->
+ download_(TmpDir, rebar_app_info:source(AppInfo), State).
+
+download_(TmpDir, {localfs, Path, _Ref}, State) ->
+ download_(TmpDir, {localfs, Path}, State);
+download_(TmpDir, {localfs, Path}, _State) ->
+ ok = rebar_file_utils:cp_r(filelib:wildcard(Path ++ "/*"), TmpDir),
+ {ok, undefined}.
+
+make_vsn(_AppInfo, _) ->
+ {plain, "undefined"}.
diff --git a/test/rebar_paths_SUITE.erl b/test/rebar_paths_SUITE.erl
new file mode 100644
index 0000000..96cda45
--- /dev/null
+++ b/test/rebar_paths_SUITE.erl
@@ -0,0 +1,240 @@
+-module(rebar_paths_SUITE).
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("common_test/include/ct.hrl").
+-compile(export_all).
+
+all() ->
+ [clashing_apps,
+ check_modules,
+ set_paths,
+ misloaded_mods
+ ].
+
+%%%%%%%%%%%%%%%%%%
+%%% TEST SETUP %%%
+%%%%%%%%%%%%%%%%%%
+
+init_per_testcase(Case, Config) ->
+ BasePaths = code:get_path(),
+ %% This test checks that the right module sets get loaded; however, we must
+ %% ensure that we do not have clashes with other test suites' loaded modules,
+ %% which we cannot track. As such, we have to ensure all module names here are
+ %% unique.
+ %%
+ %% This is done by hand; if you see this test suite failing on its own, you
+ %% probably wrote a test suite that clashes!
+ Dir = filename:join([?config(priv_dir, Config), atom_to_list(?MODULE),
+ atom_to_list(Case)]),
+ InDir = fun(Path) -> filename:join([Dir, Path]) end,
+ ADep = fake_app(<<"rp_a">>, <<"1.0.0">>, InDir("_build/default/lib/rp_a/")),
+ BDep = fake_app(<<"rp_b">>, <<"1.0.0">>, InDir("_build/default/lib/rp_b/")),
+ CDep = fake_app(<<"rp_c">>, <<"1.0.0">>, InDir("_build/default/lib/rp_c/")),
+ DDep = fake_app(<<"rp_d">>, <<"1.0.0">>, InDir("_build/default/lib/rp_d/")),
+ RelxDep = fake_app(<<"relx">>, <<"1.0.0">>, InDir("_build/default/lib/relx/")),
+
+ APlug = fake_app(<<"rp_a">>, <<"1.0.0">>,
+ InDir("_build/default/plugins/lib/rp_a/")),
+ RelxPlug = fake_app(<<"relx">>, <<"1.1.1">>,
+ InDir("_build/default/plugins/lib/relx")),
+ EPlug = fake_app(<<"rp_e">>, <<"1.0.0">>,
+ InDir("_build/default/plugins/lib/rp_e/")),
+
+ S0 = rebar_state:new(),
+ S1 = rebar_state:all_deps(S0, [ADep, BDep, CDep, DDep, RelxDep]),
+ S2 = rebar_state:all_plugin_deps(S1, [APlug, RelxPlug]),
+ S3 = rebar_state:code_paths(S2, default, code:get_path()),
+ S4 = rebar_state:code_paths(
+ S3,
+ all_deps,
+ [rebar_app_info:ebin_dir(A) || A <- [ADep, BDep, CDep, DDep, RelxDep]]
+ ),
+ S5 = rebar_state:code_paths(
+ S4,
+ all_plugin_deps,
+ [rebar_app_info:ebin_dir(A) || A <- [APlug, RelxPlug, EPlug]]
+ ),
+ [{base_paths, BasePaths}, {root_dir, Dir}, {state, S5} | Config].
+
+end_per_testcase(_, Config) ->
+ %% this is deeply annoying because we interfere with rebar3's own
+ %% path handling!
+ rebar_paths:unset_paths([plugins, deps], ?config(state, Config)),
+ Config.
+
+fake_app(Name, Vsn, OutDir) ->
+ {ok, App} = rebar_app_info:new(Name, Vsn, OutDir),
+ compile_fake_appmod(App),
+ App.
+
+compile_fake_appmod(App) ->
+ OutDir = rebar_app_info:ebin_dir(App),
+ Vsn = rebar_app_info:original_vsn(App),
+ Name = rebar_app_info:name(App),
+
+ ok = filelib:ensure_dir(filename:join([OutDir, ".touch"])),
+
+ AppFile = [
+ "{application,", Name, ", "
+ " [{description, \"some app\"}, "
+ " {vsn, \"", Vsn, "\"}, "
+ " {modules, [",Name,"]}, "
+ " {registered, []}, "
+ " {applications, [stdlib, kernel]} "
+ " ]}. "],
+
+ ok = file:write_file(filename:join([OutDir, <<Name/binary, ".app">>]), AppFile),
+
+ Mod = [{attribute, 1, module, binary_to_atom(Name, utf8)},
+ {attribute, 2, export, [{f,0}]},
+ {function,3,f,0,
+ [{clause,3, [], [],
+ [{string,3,OutDir}]
+ }]}
+ ],
+
+ {ok, _, Bin} = compile:forms(Mod),
+ ok = file:write_file(filename:join([OutDir, <<Name/binary, ".beam">>]), Bin).
+
+%%%%%%%%%%%%%
+%%% TESTS %%%
+%%%%%%%%%%%%%
+
+clashing_apps(Config) ->
+ Clashes = rebar_paths:clashing_apps([deps, plugins],
+ ?config(state, Config)),
+ ct:pal("Clashes: ~p", [Clashes]),
+
+ ?assertEqual([<<"relx">>, <<"rp_a">>], lists:sort(proplists:get_value(deps, Clashes))),
+ ?assertEqual([], proplists:get_value(plugins, Clashes)),
+ ok.
+
+set_paths(Config) ->
+ State = ?config(state, Config),
+ RootDir = filename:split(?config(root_dir, Config)),
+ rebar_paths:set_paths([plugins, deps], State),
+ PluginPaths = code:get_path(),
+ rebar_paths:set_paths([deps, plugins], State),
+ DepPaths = code:get_path(),
+
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "plugins", "lib", "rp_a", "ebin"],
+ find_first_instance("rp_a", PluginPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_b", "ebin"],
+ find_first_instance("rp_b", PluginPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_c", "ebin"],
+ find_first_instance("rp_c", PluginPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_d", "ebin"],
+ find_first_instance("rp_d", PluginPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "plugins", "lib", "rp_e", "ebin"],
+ find_first_instance("rp_e", PluginPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "plugins", "lib", "relx", "ebin"],
+ find_first_instance("relx", PluginPaths)
+ ),
+
+
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_a", "ebin"],
+ find_first_instance("rp_a", DepPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_b", "ebin"],
+ find_first_instance("rp_b", DepPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_c", "ebin"],
+ find_first_instance("rp_c", DepPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "rp_d", "ebin"],
+ find_first_instance("rp_d", DepPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "plugins", "lib", "rp_e", "ebin"],
+ find_first_instance("rp_e", DepPaths)
+ ),
+ ?assertEqual(
+ RootDir ++ ["_build", "default", "lib", "relx", "ebin"],
+ find_first_instance("relx", DepPaths)
+ ),
+ ok.
+
+check_modules(Config) ->
+ State = ?config(state, Config),
+ RootDir = ?config(root_dir, Config)++"/",
+ rebar_paths:set_paths([plugins, deps], State),
+ ct:pal("code:get_path() -> ~p", [code:get_path()]),
+
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_a/ebin", rp_a:f()),
+ ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/")]),
+ ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/rp_b/")]),
+ ct:pal("~p", [catch file:list_dir(RootDir ++ "_build/default/lib/rp_b/ebin")]),
+ ct:pal("~p", [catch b:module_info()]),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/relx/ebin", relx:f()),
+ ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
+
+ rebar_paths:set_paths([deps, plugins], State),
+ ct:pal("code:get_path() -> ~p", [code:get_path()]),
+
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_a/ebin", rp_a:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/relx/ebin", relx:f()),
+ ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
+
+ %% once again
+ rebar_paths:set_paths([plugins, deps], State),
+ ct:pal("code:get_path() -> ~p", [code:get_path()]),
+
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_a/ebin", rp_a:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_b/ebin", rp_b:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_c/ebin", rp_c:f()),
+ ?assertEqual(RootDir ++ "_build/default/lib/rp_d/ebin", rp_d:f()),
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/rp_e/ebin", rp_e:f()),
+ ?assertEqual(RootDir ++ "_build/default/plugins/lib/relx/ebin", relx:f()),
+ ?assertEqual(3, length(relx:module_info(exports))), % can't replace bundled
+ ok.
+
+misloaded_mods(_Config) ->
+ Res = rebar_paths:misloaded_modules(
+ ["/1/2/3/4",
+ "/1/2/4",
+ "/2/1/1",
+ "/3/4/5"],
+ [{a, "/0/1/2/file.beam"},
+ {b, "/1/2/3/4/file.beam"},
+ {c, "/2/1/file.beam"},
+ {f, preloaded},
+ {d, "/3/5/7/file.beam"},
+ {e, "/3/4/5/file.beam"}]
+ ),
+ ?assertEqual([a,c,d], Res),
+ ok.
+
+%%%%%%%%%%%%%%%
+%%% HELPERS %%%
+%%%%%%%%%%%%%%%
+
+find_first_instance(Frag, []) ->
+ {not_found, Frag};
+find_first_instance(Frag, [Path|Rest]) ->
+ Frags = filename:split(Path),
+ case lists:member(Frag, Frags) of
+ true -> Frags;
+ false -> find_first_instance(Frag, Rest)
+ end.
diff --git a/test/rebar_pkg_SUITE.erl b/test/rebar_pkg_SUITE.erl
index 30cc0a8..ee74af5 100644
--- a/test/rebar_pkg_SUITE.erl
+++ b/test/rebar_pkg_SUITE.erl
@@ -4,16 +4,19 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
+-include("rebar.hrl").
--define(bad_etag, "abcdef").
--define(good_etag, "22e1d7387c9085a462340088a2a8ba67").
+-define(bad_etag, <<"abcdef">>).
+-define(good_etag, <<"22e1d7387c9085a462340088a2a8ba67">>).
+-define(badpkg_checksum, <<"A14E3718B33F8124E98004433193509EC6660F6CA03302657CAB8785751D77A0">>).
+-define(badindex_checksum, <<"7B2CBED315C89F3126B5BF553DD7FF0FB5FE94B064888DD1B095CE8BF4B6A16A">>).
-define(bad_checksum, <<"D576B442A68C7B92BACDE1EFE9C6E54D8D6C74BDB71D8175B9D3C6EC8C7B62A7">>).
--define(good_checksum, <<"1C6CE379D191FBAB41B7905075E0BF87CBBE23C77CECE775C5A0B786B2244C35">>).
+-define(good_checksum, <<"12726BDE1F65583A0817A7E8AADCA73F03FD8CB06F01E6CD29117C4A0DA0AFCF">>).
+-define(BADPKG_ETAG, <<"BADETAG">>).
-all() -> [good_uncached, good_cached, badindexchk, badpkg,
- badhash_nocache, badhash_cache,
- bad_to_good, good_disconnect, bad_disconnect, pkgs_provider,
- find_highest_matching].
+all() -> [good_uncached, good_cached, badpkg, badhash_nocache,
+ badindexchk, badhash_cache, bad_to_good, good_disconnect,
+ bad_disconnect, pkgs_provider, find_highest_matching].
init_per_suite(Config) ->
application:start(meck),
@@ -31,10 +34,6 @@ init_per_testcase(pkgs_provider=Name, Config) ->
CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
filelib:ensure_dir(filename:join([CacheDir, "registry"])),
ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
- meck:new(rebar_packages, [passthrough]),
- meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
- meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
- rebar_prv_update:hex_to_index(rebar_state:new()),
Config;
init_per_testcase(good_uncached=Name, Config0) ->
Config = [{good_cache, false},
@@ -83,14 +82,14 @@ init_per_testcase(bad_to_good=Name, Config0) ->
Config;
init_per_testcase(good_disconnect=Name, Config0) ->
Pkg = {<<"goodpkg">>, <<"1.0.0">>},
- Config1 = [{good_cache, true},
+ Config1 = [{good_cache, false},
{pkg, Pkg}
| Config0],
Config = mock_config(Name, Config1),
copy_to_cache(Pkg, Config),
- meck:unload(httpc),
+ %% meck:unload(httpc),
meck:new(httpc, [passthrough, unsticky]),
- meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
+ meck:expect(httpc, request, fun(_, _, _, _) -> {error, econnrefused} end),
Config;
init_per_testcase(bad_disconnect=Name, Config0) ->
Pkg = {<<"goodpkg">>, <<"1.0.0">>},
@@ -98,9 +97,9 @@ init_per_testcase(bad_disconnect=Name, Config0) ->
{pkg, Pkg}
| Config0],
Config = mock_config(Name, Config1),
- meck:unload(httpc),
- meck:new(httpc, [passthrough, unsticky]),
- meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
+ meck:expect(hex_repo, get_tarball, fun(_, _, _) ->
+ {error, econnrefused}
+ end),
Config;
init_per_testcase(Name, Config0) ->
Config = [{good_cache, false},
@@ -116,8 +115,8 @@ good_uncached(Config) ->
Tmp = ?config(tmp_dir, Config),
{Pkg,Vsn} = ?config(pkg, Config),
State = ?config(state, Config),
- ?assertEqual({ok, true},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)),
Cache = ?config(cache_dir, Config),
?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
@@ -129,16 +128,17 @@ good_cached(Config) ->
CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
?assert(filelib:is_regular(CachedFile)),
{ok, Content} = file:read_file(CachedFile),
- ?assertEqual({ok, true},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)),
{ok, Content} = file:read_file(CachedFile).
+
badindexchk(Config) ->
Tmp = ?config(tmp_dir, Config),
{Pkg,Vsn} = ?config(pkg, Config),
State = ?config(state, Config),
- ?assertMatch({bad_registry_checksum, _Path},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
+ ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}},
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)),
%% The cached file is there for forensic purposes
Cache = ?config(cache_dir, Config),
?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
@@ -147,18 +147,22 @@ badpkg(Config) ->
Tmp = ?config(tmp_dir, Config),
{Pkg,Vsn} = ?config(pkg, Config),
State = ?config(state, Config),
- ?assertMatch({bad_download, _Path},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
- %% The cached file is there for forensic purposes
Cache = ?config(cache_dir, Config),
- ?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
+ CachePath = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
+ ETagPath = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".etag">>),
+ rebar_pkg_resource:store_etag_in_cache(ETagPath, ?BADPKG_ETAG),
+ ?assertMatch({error, {hex_tarball, {tarball, {checksum_mismatch, _, _}}}},
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?badpkg_checksum, #{}}, State, #{}, false)),
+ %% The cached/etag files are there for forensic purposes
+ ?assert(filelib:is_regular(ETagPath)),
+ ?assert(filelib:is_regular(CachePath)).
badhash_nocache(Config) ->
Tmp = ?config(tmp_dir, Config),
{Pkg,Vsn} = ?config(pkg, Config),
State = ?config(state, Config),
- ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)),
+ ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}},
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)),
%% The cached file is there for forensic purposes
Cache = ?config(cache_dir, Config),
?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
@@ -171,8 +175,8 @@ badhash_cache(Config) ->
CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
?assert(filelib:is_regular(CachedFile)),
{ok, Content} = file:read_file(CachedFile),
- ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)),
+ ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}},
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)),
%% The cached file is there still, unchanged.
?assert(filelib:is_regular(CachedFile)),
?assertEqual({ok, Content}, file:read_file(CachedFile)).
@@ -185,8 +189,8 @@ bad_to_good(Config) ->
CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
?assert(filelib:is_regular(CachedFile)),
{ok, Contents} = file:read_file(CachedFile),
- ?assertEqual({ok, true},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)),
%% Cache has refreshed
?assert({ok, Contents} =/= file:read_file(CachedFile)).
@@ -196,10 +200,12 @@ good_disconnect(Config) ->
State = ?config(state, Config),
Cache = ?config(cache_dir, Config),
CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
+ ETagFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".etag">>),
?assert(filelib:is_regular(CachedFile)),
{ok, Content} = file:read_file(CachedFile),
- ?assertEqual({ok, true},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
+ rebar_pkg_resource:store_etag_in_cache(ETagFile, ?BADPKG_ETAG),
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)),
{ok, Content} = file:read_file(CachedFile).
bad_disconnect(Config) ->
@@ -207,27 +213,36 @@ bad_disconnect(Config) ->
{Pkg,Vsn} = ?config(pkg, Config),
State = ?config(state, Config),
?assertEqual({fetch_fail, Pkg, Vsn},
- rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)).
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)).
pkgs_provider(Config) ->
Config1 = rebar_test_utils:init_rebar_state(Config),
rebar_test_utils:run_and_check(
- Config1, [], ["pkgs"],
+ Config1, [], ["pkgs", "relx"],
{ok, []}
).
find_highest_matching(_Config) ->
State = rebar_state:new(),
- {ok, Vsn} = rebar_packages:find_highest_matching(
- <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0.0">>, package_index, State),
- ?assertEqual(<<"1.0.1">>, Vsn),
+ {ok, Vsn} = rebar_packages:find_highest_matching_(
+ <<"goodpkg">>, ec_semver:parse(<<"1.0.0">>), #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State),
+ ?assertEqual({{1,0,1},{[],[]}}, Vsn),
{ok, Vsn1} = rebar_packages:find_highest_matching(
- <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0">>, package_index, State),
- ?assertEqual(<<"1.1.1">>, Vsn1),
+ <<"goodpkg">>, ec_semver:parse(<<"1.0">>), #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State),
+ ?assertEqual({{1,1,1},{[],[]}}, Vsn1),
{ok, Vsn2} = rebar_packages:find_highest_matching(
- <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"2.0">>, package_index, State),
- ?assertEqual(<<"2.0.0">>, Vsn2).
+ <<"goodpkg">>, ec_semver:parse(<<"2.0">>), #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State),
+ ?assertEqual({{2,0,0},{[],[]}}, Vsn2),
+
+ %% regression test. ~> constraints higher than the available packages would result
+ %% in returning the first package version instead of 'none'.
+ ?assertEqual(none, rebar_packages:find_highest_matching_(<<"goodpkg">>, ec_semver:parse(<<"5.0">>),
+ #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State)),
+
+ {ok, Vsn3} = rebar_packages:find_highest_matching_(<<"goodpkg">>, ec_semver:parse(<<"3.0.0-rc.0">>),
+ #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State),
+ ?assertEqual({{3,0,0},{[<<"rc">>,0],[]}}, Vsn3).
%%%%%%%%%%%%%%%
%%% Helpers %%%
@@ -237,49 +252,85 @@ mock_config(Name, Config) ->
CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
Tid = ets:new(registry_table, [public]),
- ets:insert_new(Tid, [
- {<<"badindexchk">>,[[<<"1.0.0">>]]},
- {<<"goodpkg">>,[[<<"1.0.0">>, <<"1.0.1">>, <<"1.1.1">>, <<"2.0.0">>]]},
- {<<"badpkg">>,[[<<"1.0.0">>]]},
+ AllDeps = [
{{<<"badindexchk">>,<<"1.0.0">>}, [[], ?bad_checksum, [<<"rebar3">>]]},
{{<<"goodpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]},
{{<<"goodpkg">>,<<"1.0.1">>}, [[], ?good_checksum, [<<"rebar3">>]]},
{{<<"goodpkg">>,<<"1.1.1">>}, [[], ?good_checksum, [<<"rebar3">>]]},
{{<<"goodpkg">>,<<"2.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]},
- {{<<"badpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]}
- ]),
+ {{<<"goodpkg">>,<<"3.0.0-rc.0">>}, [[], ?good_checksum, [<<"rebar3">>]]},
+ {{<<"badpkg">>,<<"1.0.0">>}, [[], ?badpkg_checksum, [<<"rebar3">>]]}
+ ],
+ ets:insert_new(Tid, AllDeps),
CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
filelib:ensure_dir(filename:join([CacheDir, "registry"])),
ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
+ catch ets:delete(?PACKAGE_TABLE),
+ rebar_packages:new_package_table(),
+ lists:foreach(fun({{N, Vsn}, [Deps, Checksum, _]}) ->
+ case ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(N), Vsn, <<"hexpm">>}) of
+ false ->
+ ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), ec_semver:parse(Vsn), <<"hexpm">>},
+ dependencies=Deps,
+ retired=false,
+ checksum=Checksum});
+ true ->
+ ok
+ end
+ end, AllDeps),
+
+
+ meck:new(hex_repo, [passthrough]),
+ meck:expect(hex_repo, get_package,
+ fun(_Config, PkgName) ->
+ Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
+ Releases =
+ [#{checksum => Checksum,
+ version => Vsn,
+ dependencies => Deps} ||
+ {{_, Vsn}, [Deps, Checksum, _]} <- Matches],
+ {ok, {200, #{}, #{releases => Releases}}}
+ end),
+
%% The state returns us a fake registry
meck:new(rebar_state, [passthrough]),
meck:expect(rebar_state, get,
fun(_State, rebar_packages_cdn, _Default) ->
- "http://test.com/"
+ "http://test.com/";
+ (_, _, Default) ->
+ Default
+ end),
+ meck:expect(rebar_state, resources,
+ fun(_State) ->
+ DefaultConfig = hex_core:default_config(),
+ [rebar_resource_v2:new(pkg, rebar_pkg_resource,
+ #{repos => [DefaultConfig#{name => <<"hexpm">>}],
+ base_config => #{}})]
end),
meck:new(rebar_dir, [passthrough]),
meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
- meck:new(rebar_packages, [passthrough]),
meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
- meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
- rebar_prv_update:hex_to_index(rebar_state:new()),
+ meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end),
+
+ meck:new(rebar_prv_update, [passthrough]),
+ meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end),
%% Cache fetches are mocked -- we assume the server and clients are
%% correctly used.
GoodCache = ?config(good_cache, Config),
- {Pkg,Vsn} = ?config(pkg, Config),
+ {Pkg,Vsn} = ?config(pkg, Config),
PkgFile = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
{ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
- meck:new(httpc, [passthrough, unsticky]),
- meck:expect(httpc, request,
- fun(get, {_Url, _Opts}, _, _, _) when GoodCache ->
- {ok, {{Vsn, 304, <<"Not Modified">>}, [{"etag", ?good_etag}], <<>>}};
- (get, {_Url, _Opts}, _, _, _) ->
- {ok, {{Vsn, 200, <<"OK">>}, [{"etag", ?good_etag}], PkgContents}}
- end),
+
+ meck:expect(hex_repo, get_tarball, fun(_, _, _) when GoodCache ->
+ {ok, {304, #{<<"etag">> => ?good_etag}, <<>>}};
+ (_, _, _) ->
+ {ok, {200, #{<<"etag">> => ?good_etag}, PkgContents}}
+ end),
+
[{cache_root, CacheRoot},
{cache_dir, CacheDir},
{tmp_dir, TmpDir},
@@ -287,7 +338,7 @@ mock_config(Name, Config) ->
unmock_config(Config) ->
meck:unload(),
- ets:delete(?config(mock_table, Config)).
+ catch ets:delete(?config(mock_table, Config)).
copy_to_cache({Pkg,Vsn}, Config) ->
Name = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
diff --git a/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar b/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar
index e5b963f..1765bb3 100644
--- a/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar
+++ b/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar
Binary files differ
diff --git a/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar b/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar
index 4930cd2..37bb57d 100644
--- a/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar
+++ b/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar
Binary files differ
diff --git a/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar b/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar
index e5b963f..d0fa4cb 100644
--- a/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar
+++ b/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar
Binary files differ
diff --git a/test/rebar_pkg_alias_SUITE.erl b/test/rebar_pkg_alias_SUITE.erl
index 8915357..079a3fd 100644
--- a/test/rebar_pkg_alias_SUITE.erl
+++ b/test/rebar_pkg_alias_SUITE.erl
@@ -3,38 +3,61 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("kernel/include/file.hrl").
+-include("rebar.hrl").
-all() -> [same_alias, diff_alias, diff_alias_vsn].
+all() -> [same_alias, diff_alias, diff_alias_vsn, transitive_alias%% ,
+ %% transitive_hash_mismatch
+ ].
%% {uuid, {pkg, uuid}} = uuid
%% {uuid, {pkg, alias}} = uuid on disk
%% another run should yield the same lock file without error
init_per_suite(Config) ->
- mock_config(?MODULE, Config).
+ Config.
+ %% mock_config(?MODULE, Config).
end_per_suite(Config) ->
- unmock_config(Config).
+ Config.
+ %% unmock_config(Config).
init_per_testcase(same_alias, Config0) ->
+ mock_config(?MODULE, Config0),
Config = rebar_test_utils:init_rebar_state(Config0,"same_alias_"),
AppDir = ?config(apps, Config),
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, fakelib}}]}]),
[{rebarconfig, RebarConf} | Config];
init_per_testcase(diff_alias, Config0) ->
+ mock_config(?MODULE, Config0),
Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_"),
AppDir = ?config(apps, Config),
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, goodpkg}}]}]),
[{rebarconfig, RebarConf} | Config];
init_per_testcase(diff_alias_vsn, Config0) ->
+ mock_config(?MODULE, Config0),
Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_vsn_"),
AppDir = ?config(apps, Config),
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, "1.0.0", {pkg, goodpkg}}]}]),
+ [{rebarconfig, RebarConf} | Config];
+init_per_testcase(transitive_alias, Config0) ->
+ mock_config(?MODULE, Config0),
+ Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"),
+ AppDir = ?config(apps, Config),
+ rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
+ RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{topdep, "1.0.0", {pkg, topdep}}]}]),
+ [{rebarconfig, RebarConf} | Config];
+init_per_testcase(transitive_hash_mismatch, Config0) ->
+ mock_config(?MODULE, Config0),
+ Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"),
+ AppDir = ?config(apps, Config),
+ rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
+ RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{topdep, "1.0.0", {pkg, topdep}}]}]),
[{rebarconfig, RebarConf} | Config].
end_per_testcase(_, Config) ->
+ unmock_config(Config),
Config.
same_alias(Config) ->
@@ -73,42 +96,168 @@ diff_alias(Config) ->
diff_alias_vsn(Config) -> diff_alias(Config).
+transitive_alias(Config) ->
+ %% ensure that the apps fetched under transitive aliases are
+ %% locked properly, but also that they are stored in the right
+ %% directory in the build dir to avoid breaking includes and
+ %% static analysis tools that rely on the location to work
+ AppDir = ?config(apps, Config),
+ Lockfile = filename:join([AppDir, "rebar.lock"]),
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["lock"],
+ {ok, [{lock, "topdep"},{dep, "topdep"},
+ {lock,"transitive_app"},{dep,"transitive_app"}]}
+ ),
+ {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
+ ?assert(lists:any(fun({<<"transitive_app">>,{pkg,<<"transitive">>,_},_}) -> true
+ ; (_) -> false end, LockData)),
+ AppDir = ?config(apps, Config),
+ AliasedName = filename:join([AppDir, "_build", "default", "lib", "transitive_app"]),
+ PkgName = filename:join([AppDir, "_build", "default", "lib", "transitive"]),
+ ?assert(filelib:is_dir(AliasedName)),
+ ?assertNot(filelib:is_dir(PkgName)),
+ %% An second run yields the same
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["lock"],
+ {ok, [{lock, "topdep"},{dep, "topdep"},
+ {lock,"transitive_app"},{dep,"transitive_app"}]}
+ ),
+ {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
+ ?assert(filelib:is_dir(AliasedName)),
+ ?assertNot(filelib:is_dir(PkgName)),
+ %% So does an upgrade
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["upgrade"],
+ {ok, [{lock, "topdep"},{dep, "topdep"},
+ {lock,"transitive_app"},{dep,"transitive_app"}]}
+ ),
+ {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
+ ?assert(filelib:is_dir(AliasedName)),
+ ?assertNot(filelib:is_dir(PkgName)),
+ ok.
+
+transitive_hash_mismatch(Config) ->
+ %% ensure that the apps fetched under transitive aliases are
+ %% locked properly, but also that they are stored in the right
+ %% directory in the build dir to avoid breaking includes and
+ %% static analysis tools that rely on the location to work
+ AppDir = ?config(apps, Config),
+ Lockfile = filename:join([AppDir, "rebar.lock"]),
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["lock"],
+ {ok, [{lock, "topdep"},{dep, "topdep"},
+ {lock,"transitive_app"},{dep,"transitive_app"}]}
+ ),
+ {ok, [LockData|Attrs]} = file:consult(Lockfile),
+ %% Change Lock hash data to cause a failure next time, but on transitive
+ %% deps only
+ NewLock = [LockData|lists:map(
+ fun([{pkg_hash, Hashes}|Rest]) ->
+ [{pkg_hash, [{<<"transitive_app">>, <<"fakehash">>}
+ | lists:keydelete(<<"transitive_app">>, 1, Hashes)]}
+ | Rest]
+ ; (Attr) ->
+ Attr
+ end, Attrs)],
+ {ok, Io} = file:open(Lockfile, [write]),
+ [io:format(Io, "~p.~n", [Attr]) || Attr <- NewLock],
+ file:close(Io),
+ ct:pal("lock: ~p", [file:consult(Lockfile)]),
+ ec_file:remove(filename:join([AppDir, "_build"]), [recursive]),
+ ?assertMatch(
+ {error, {rebar_fetch, {unexpected_hash, _, _, _}}},
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], return)
+ ),
+ ok.
+
+parse_deps(Deps) ->
+ [{maps:get(app, D, Name), {pkg, Name, Constraint, undefined}} || D=#{package := Name,
+ requirement := Constraint} <- Deps].
+
mock_config(Name, Config) ->
+ {ChkFake, Etag} = create_lib(Name, Config, "fakelib"),
+ {ChkTop, _} = create_lib(Name, Config, "topdep"),
+ {ChkTrans, _} = create_lib(Name, Config, "transitive_app", "transitive"),
+ ct:pal("{~p, _}",[ChkTop]),
+ ct:pal("{~p, _}",[ChkTrans]),
Priv = ?config(priv_dir, Config),
+ TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
+ %% Add an alias for goodpkg -> fakelib by hand
AppDir = filename:join([Priv, "fakelib"]),
CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
- TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
- filelib:ensure_dir(filename:join([CacheDir, "registry"])),
rebar_test_utils:create_app(AppDir, "fakelib", "1.0.0", [kernel, stdlib]),
- {Chk,Etag} = rebar_test_utils:package_app(AppDir, CacheDir, "fakelib-1.0.0"),
- {Chk,Etag} = rebar_test_utils:package_app(AppDir, CacheDir, "goodpkg-1.0.0"),
+ ct:pal("{~p, ~p}",[ChkFake, Etag]),
+ {ChkGood, EtagGood} = rebar_test_utils:package_app(AppDir, CacheDir, "goodpkg", "1.0.0"),
+ AllDeps = [
+ {<<"fakelib">>,[[<<"1.0.0">>]]},
+ {<<"goodpkg">>,[[<<"1.0.0">>]]},
+ {<<"topdep">>,[[<<"1.0.0">>]]},
+ {<<"transitive">>, [[<<"1.0.0">>]]},
+ {{<<"fakelib">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]},
+ {{<<"goodpkg">>,<<"1.0.0">>}, [[], ChkGood, [<<"rebar3">>]]},
+ {{<<"topdep">>,<<"1.0.0">>},
+ [[
+ {<<"transitive">>, <<"1.0.0">>, false, <<"transitive_app">>}
+ ], ChkTop, [<<"rebar3">>]]},
+ {{<<"transitive">>,<<"1.0.0">>}, [[], ChkTrans, [<<"rebar3">>]]}
+ ],
Tid = ets:new(registry_table, [public]),
- ets:insert_new(Tid, [
- {<<"fakelib">>,[[<<"1.0.0">>]]},
- {<<"goodpkg">>,[[<<"1.0.0">>]]},
- {{<<"fakelib">>,<<"1.0.0">>}, [[], Chk, [<<"rebar3">>]]},
- {{<<"goodpkg">>,<<"1.0.0">>}, [[], Chk, [<<"rebar3">>]]}
- ]),
+ ets:insert_new(Tid, AllDeps),
ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
- ets:delete(Tid),
+ %% ets:delete(Tid),
%% The state returns us a fake registry
meck:new(rebar_dir, [passthrough, no_link]),
meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
meck:new(rebar_packages, [passthrough, no_link]),
meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
- meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
- rebar_prv_update:hex_to_index(rebar_state:new()),
-
- %% Cache fetches are mocked -- we assume the server and clients are
- %% correctly used.
- meck:new(httpc, [passthrough, unsticky, no_link]),
- meck:expect(httpc, request,
- fun(get, {_Url, _Opts}, _, _, _) ->
- {ok, {{<<"1.0.0">>, 304, <<"Not Modified">>}, [{"etag", Etag}], <<>>}}
- end),
+ meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end),
+
+ %% TODO: is something else wrong that we need this for transitive_alias to pass
+ meck:expect(rebar_packages, update_package, fun(_, _, _) -> ok end),
+
+ meck:new(rebar_prv_update, [passthrough]),
+ meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end),
+
+ catch ets:delete(?PACKAGE_TABLE),
+ rebar_packages:new_package_table(),
+
+ lists:foreach(fun({{N, Vsn}, [Deps, Checksum, _]}) ->
+ case ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(N), Vsn, <<"hexpm">>}) of
+ false ->
+ ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), ec_semver:parse(Vsn), <<"hexpm">>},
+ dependencies=[{DAppName, {pkg, DN, DV, undefined}} || {DN, DV, _, DAppName} <- Deps],
+ retired=false,
+ checksum=Checksum});
+ true ->
+ ok
+ end;
+ ({_N, _Vsns}) ->
+ ok
+
+ end, AllDeps),
+
+ meck:new(hex_repo, [passthrough]),
+ meck:expect(hex_repo, get_package,
+ fun(_Config, PkgName) ->
+ Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
+ Releases =
+ [#{checksum => Checksum,
+ version => Vsn,
+ dependencies => [{DAppName, {pkg, DN, DV, undefined}} ||
+ {DN, DV, _, DAppName} <- Deps]} ||
+ {{_, Vsn}, [Deps, Checksum, _]} <- Matches],
+ {ok, {200, #{}, #{releases => Releases}}}
+ end),
+
+ meck:expect(hex_repo, get_tarball, fun(_, _, _) ->
+ {ok, {304, #{<<"etag">> => EtagGood}, <<>>}}
+ end),
+
%% Move all packages to cache
NewConf = [{cache_root, CacheRoot},
{cache_dir, CacheDir},
@@ -119,3 +268,15 @@ mock_config(Name, Config) ->
unmock_config(Config) ->
meck:unload(),
Config.
+
+create_lib(Name, Config, PkgName) ->
+ create_lib(Name, Config, PkgName, PkgName).
+
+create_lib(Name, Config, AppName, PkgName) ->
+ Priv = ?config(priv_dir, Config),
+ AppDir = filename:join([Priv, PkgName]),
+ CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
+ CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
+ filelib:ensure_dir(filename:join([CacheDir, "registry"])),
+ rebar_test_utils:create_app(AppDir, AppName, "1.0.0", [kernel, stdlib]),
+ rebar_test_utils:package_app(AppDir, CacheDir, PkgName, "1.0.0").
diff --git a/test/rebar_pkg_repos_SUITE.erl b/test/rebar_pkg_repos_SUITE.erl
new file mode 100644
index 0000000..c808475
--- /dev/null
+++ b/test/rebar_pkg_repos_SUITE.erl
@@ -0,0 +1,376 @@
+%% Test suite for the handling hexpm repo configurations
+-module(rebar_pkg_repos_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-include("rebar.hrl").
+
+all() ->
+ [default_repo, repo_merging, repo_replacing,
+ auth_merging, organization_merging, {group, resolve_version}].
+
+groups() ->
+ [{resolve_version, [use_first_repo_match, use_exact_with_hash, fail_repo_update,
+ ignore_match_in_excluded_repo, optional_prereleases]}].
+
+init_per_group(resolve_version, Config) ->
+ Repo1 = <<"test-repo-1">>,
+ Repo2 = <<"test-repo-2">>,
+ Repo3 = <<"test-repo-3">>,
+ Hexpm = <<"hexpm">>,
+ Repos = [Repo1, Repo2, Repo3, Hexpm],
+
+ Deps = [{"A", "0.1.1", <<"good checksum">>, Repo1, false},
+ {"A", "0.1.1", <<"good checksum">>, Repo2, false},
+ {"B", "1.0.0", Repo1, false},
+ {"B", "2.0.0", Repo2, false},
+ {"B", "1.4.0", Repo3, false},
+ {"B", "1.4.3", Hexpm, false},
+ {"B", "1.4.6", Hexpm, #{reason => 'RETIRED_INVALID'}},
+ {"B", "1.5.0", Hexpm, false},
+ {"B", "1.5.6-rc.0", Hexpm, true},
+ {"C", "1.3.1", <<"bad checksum">>, Repo1, false},
+ {"C", "1.3.1", <<"good checksum">>, Repo2, false}],
+ [{deps, Deps}, {repos, Repos} | Config];
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, _) ->
+ ok.
+
+init_per_testcase(use_first_repo_match, Config) ->
+ Deps = ?config(deps, Config),
+ Repos = ?config(repos, Config),
+ State = setup_deps_and_repos(Deps, Repos),
+
+ meck:new(rebar_packages, [passthrough, no_link]),
+
+ %% fail when the first repo is updated since it doesn't have a matching package
+ %% should continue anyway
+ meck:expect(rebar_packages, update_package,
+ fun(_, _, _State) -> ok end),
+ meck:expect(rebar_packages, verify_table,
+ fun(_State) -> true end),
+
+ [{state, State} | Config];
+init_per_testcase(use_exact_with_hash, Config) ->
+ Deps = ?config(deps, Config),
+ Repos = ?config(repos, Config),
+ State = setup_deps_and_repos(Deps, Repos),
+
+ meck:new(rebar_packages, [passthrough, no_link]),
+
+ %% fail when the first repo is updated since it doesn't have a matching package
+ %% should continue anyway
+ meck:expect(rebar_packages, update_package,
+ fun(_, _, _State) -> ok end),
+ meck:expect(rebar_packages, verify_table,
+ fun(_State) -> true end),
+
+ [{state, State} | Config];
+init_per_testcase(fail_repo_update, Config) ->
+ Deps = ?config(deps, Config),
+ Repos = ?config(repos, Config),
+ State = setup_deps_and_repos(Deps, Repos),
+
+ meck:new(rebar_packages, [passthrough, no_link]),
+
+ %% fail when the first repo is updated since it doesn't have a matching package
+ %% should continue anyway
+ [Repo1 | _] = Repos,
+ meck:expect(rebar_packages, update_package,
+ fun(_, #{name := Repo}, _State) when Repo =:= Repo1 -> fail;
+ (_, _, _State) -> ok end),
+ meck:expect(rebar_packages, verify_table,
+ fun(_State) -> true end),
+
+ [{state, State} | Config];
+init_per_testcase(ignore_match_in_excluded_repo, Config) ->
+ Deps = ?config(deps, Config),
+ Repos = [Repo1, _, Repo3 | _] = ?config(repos, Config),
+
+ %% drop repo1 and repo2 from the repos to be used by the pkg resource
+ State = setup_deps_and_repos(Deps, [R || R <- Repos, R =/= Repo3, R =/= Repo1]),
+
+ meck:new(rebar_packages, [passthrough, no_link]),
+
+ %% fail when the first repo is updated since it doesn't have a matching package
+ %% should continue anyway
+ [_, _, Repo3 | _] = Repos,
+ meck:expect(rebar_packages, update_package,
+ fun(_, _, _State) -> ok end),
+ meck:expect(rebar_packages, verify_table,
+ fun(_State) -> true end),
+
+ [{state, State} | Config];
+init_per_testcase(optional_prereleases, Config) ->
+ Deps = ?config(deps, Config),
+ Repos = ?config(repos, Config),
+
+ State = setup_deps_and_repos(Deps, Repos),
+
+ meck:new(rebar_packages, [passthrough, no_link]),
+
+ meck:expect(rebar_packages, update_package,
+ fun(_, _, _State) -> ok end),
+ meck:expect(rebar_packages, verify_table,
+ fun(_State) -> true end),
+
+ [{state, State} | Config];
+init_per_testcase(auth_merging, Config) ->
+ meck:new(file, [passthrough, no_link, unstick]),
+ meck:new(rebar_packages, [passthrough, no_link]),
+ Config;
+init_per_testcase(organization_merging, Config) ->
+ meck:new(file, [passthrough, no_link, unstick]),
+ meck:new(rebar_packages, [passthrough, no_link]),
+ Config;
+init_per_testcase(_, Config) ->
+ Config.
+
+end_per_testcase(Case, _Config) when Case =:= auth_merging ;
+ Case =:= organization_merging ->
+ meck:unload(file),
+ meck:unload(rebar_packages);
+end_per_testcase(Case, _Config) when Case =:= use_first_repo_match ;
+ Case =:= use_exact_with_hash ;
+ Case =:= fail_repo_update ;
+ Case =:= ignore_match_in_excluded_repo ;
+ Case =:= optional_prereleases ->
+ meck:unload(rebar_packages);
+end_per_testcase(_, _) ->
+ ok.
+
+
+default_repo(_Config) ->
+ Repo1 = #{name => <<"hexpm">>,
+ api_key => <<"asdf">>},
+
+ MergedRepos = rebar_hex_repos:repos([{repos, [Repo1]}]),
+
+ ?assertMatch([#{name := <<"hexpm">>,
+ api_key := <<"asdf">>,
+ api_url := <<"https://hex.pm/api">>}], MergedRepos).
+
+
+repo_merging(_Config) ->
+ Repo1 = #{name => <<"repo-1">>,
+ api_url => <<"repo-1/api">>},
+ Repo2 = #{name => <<"repo-2">>,
+ repo_url => <<"repo-2/repo">>,
+ repo_verify => false},
+ Result = rebar_hex_repos:merge_repos([Repo1, Repo2,
+ #{name => <<"repo-2">>,
+ api_url => <<"repo-2/api">>,
+ repo_url => <<"bad url">>,
+ repo_verify => true},
+ #{name => <<"repo-1">>,
+ api_url => <<"bad url">>,
+ repo_verify => true},
+ #{name => <<"repo-2">>,
+ api_url => <<"repo-2/api-2">>,
+ repo_url => <<"other/repo">>}]),
+ ?assertMatch([#{name := <<"repo-1">>,
+ api_url := <<"repo-1/api">>,
+ repo_verify := true},
+ #{name := <<"repo-2">>,
+ api_url := <<"repo-2/api">>,
+ repo_url := <<"repo-2/repo">>,
+ repo_verify := false}], Result).
+
+repo_replacing(_Config) ->
+ Repo1 = #{name => <<"repo-1">>,
+ api_url => <<"repo-1/api">>},
+ Repo2 = #{name => <<"repo-2">>,
+ repo_url => <<"repo-2/repo">>,
+ repo_verify => false},
+
+ ?assertMatch([Repo1, Repo2, #{name := <<"hexpm">>}],
+ rebar_hex_repos:repos([{repos, [Repo1]},
+ {repos, [Repo2]}])),
+
+ %% use of replace is ignored if found in later entries than the first
+ ?assertMatch([Repo1, Repo2, #{name := <<"hexpm">>}],
+ rebar_hex_repos:repos([{repos, [Repo1]},
+ {repos, replace, [Repo2]}])),
+
+ ?assertMatch([Repo1],
+ rebar_hex_repos:repos([{repos, replace, [Repo1]},
+ {repos, [Repo2]}])).
+
+auth_merging(_Config) ->
+ Repo1 = #{name => <<"repo-1">>,
+ api_url => <<"repo-1/api">>},
+ Repo2 = #{name => <<"repo-2">>,
+ repo_url => <<"repo-2/repo">>,
+ repo_verify => false},
+
+ State = rebar_state:new([{hex, [{repos, [Repo1, Repo2]}]}]),
+ meck:expect(file, consult,
+ fun(_) ->
+ {ok, [#{<<"repo-1">> => #{read_key => <<"read key">>,
+ write_key => <<"write key">>},
+ <<"repo-2">> => #{read_key => <<"read key 2">>,
+ repos_key => <<"repos key 2">>,
+ write_key => <<"write key 2">>},
+ <<"hexpm">> => #{write_key => <<"write key hexpm">>}}]}
+ end),
+
+ ?assertMatch({ok,
+ #resource{state=#{repos := [#{name := <<"repo-1">>,
+ read_key := <<"read key">>,
+ write_key := <<"write key">>},
+ #{name := <<"repo-2">>,
+ read_key := <<"read key 2">>,
+ repos_key := <<"repos key 2">>,
+ write_key := <<"write key 2">>},
+ #{name := <<"hexpm">>,
+ write_key := <<"write key hexpm">>}]}}},
+ rebar_pkg_resource:init(pkg, State)),
+
+ ok.
+
+organization_merging(_Config) ->
+ Repo1 = #{name => <<"hexpm:repo-1">>,
+ api_url => <<"repo-1/api">>},
+ Repo2 = #{name => <<"hexpm:repo-2">>,
+ repo_url => <<"repo-2/repo">>,
+ repo_verify => false},
+
+ State = rebar_state:new([{hex, [{repos, [Repo1, Repo2]}]}]),
+ meck:expect(file, consult,
+ fun(_) ->
+ {ok, [#{<<"hexpm:repo-1">> => #{read_key => <<"read key">>},
+ <<"hexpm:repo-2">> => #{read_key => <<"read key 2">>,
+ repos_key => <<"repos key 2">>,
+ write_key => <<"write key 2">>},
+ <<"hexpm">> => #{write_key => <<"write key hexpm">>}}]}
+ end),
+
+ ?assertMatch({ok,
+ #resource{state=#{repos := [#{name := <<"hexpm:repo-1">>,
+ parent := <<"hexpm">>,
+ read_key := <<"read key">>,
+ write_key := <<"write key hexpm">>},
+ #{name := <<"hexpm:repo-2">>,
+ parent := <<"hexpm">>,
+ read_key := <<"read key 2">>,
+ repos_key := <<"repos key 2">>,
+ write_key := <<"write key 2">>},
+ #{name := <<"hexpm">>,
+ write_key := <<"write key hexpm">>}]}}},
+ rebar_pkg_resource:init(pkg, State)),
+
+ ok.
+
+use_first_repo_match(Config) ->
+ State = ?config(state, Config),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{2,0,0}, {[],[]}}, Repo2},
+ <<"some checksum">>, false, []},
+ #{name := Repo2,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"> 1.4.0">>, undefined,
+ ?PACKAGE_TABLE, State)),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{1,4,0}, {[],[]}}, Repo3},
+ <<"some checksum">>, false, []},
+ #{name := Repo3,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined,
+ ?PACKAGE_TABLE, State)).
+
+%% tests that even though an easier repo has C-1.3.1 it doesn't use it since its hash is different
+use_exact_with_hash(Config) ->
+ State = ?config(state, Config),
+
+ ?assertMatch({ok,{package,{<<"C">>, {{1,3,1}, {[],[]}}, Repo2},
+ <<"good checksum">>, false, []},
+ #{name := Repo2,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"C">>, <<"1.3.1">>, <<"good checksum">>,
+ ?PACKAGE_TABLE, State)).
+
+fail_repo_update(Config) ->
+ State = ?config(state, Config),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{1,4,0}, {[],[]}}, Repo3},
+ <<"some checksum">>, false, []},
+ #{name := Repo3,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined,
+ ?PACKAGE_TABLE, State)).
+
+ignore_match_in_excluded_repo(Config) ->
+ State = ?config(state, Config),
+ Repos = ?config(repos, Config),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{1,4,6}, {[],[]}}, Hexpm},
+ <<"some checksum">>, #{reason := 'RETIRED_INVALID'}, []},
+ #{name := Hexpm,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined,
+ ?PACKAGE_TABLE, State)),
+
+ [_, Repo2 | _] = Repos,
+ ?assertMatch({ok,{package,{<<"A">>, {{0,1,1}, {[],[]}}, Repo2},
+ <<"good checksum">>, false, []},
+ #{name := Repo2,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"A">>, <<"0.1.1">>, <<"good checksum">>,
+ ?PACKAGE_TABLE, State)).
+
+optional_prereleases(Config) ->
+ State = ?config(state, Config),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{1,5,0}, {[],[]}}, Hexpm},
+ <<"some checksum">>, false, []},
+ #{name := Hexpm,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"~> 1.5.0">>, undefined,
+ ?PACKAGE_TABLE, State)),
+
+ ?assertMatch({ok,{package,{<<"B">>, {{1,5,6}, {[<<"rc">>,0],[]}}, Hexpm},
+ <<"some checksum">>, true, []},
+ #{name := Hexpm,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"1.5.6-rc.0">>, <<"some checksum">>,
+ ?PACKAGE_TABLE, State)),
+
+ %% allow prerelease through configuration
+ State1 = rebar_state:set(State, deps_allow_prerelease, true),
+ ?assertMatch({ok,{package,{<<"B">>, {{1,5,6}, {[<<"rc">>,0],[]}}, Hexpm},
+ <<"some checksum">>, true, []},
+ #{name := Hexpm,
+ http_adapter_config := #{profile := rebar}}},
+ rebar_packages:resolve_version(<<"B">>, <<"~> 1.5.0">>, <<"some checksum">>,
+ ?PACKAGE_TABLE, State1)).
+
+%%
+
+setup_deps_and_repos(Deps, Repos) ->
+ catch ets:delete(?PACKAGE_TABLE),
+ true = rebar_packages:new_package_table(),
+ insert_deps(Deps),
+ State = rebar_state:new([{hex, [{repos, [#{name => R} || R <- Repos]}]}]),
+ rebar_state:create_resources([{pkg, rebar_pkg_resource}], State).
+
+
+insert_deps(Deps) ->
+ lists:foreach(fun({Name, Version, Repo, Retired}) ->
+ ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name),
+ ec_semver:parse(Version),
+ rebar_utils:to_binary(Repo)},
+ dependencies=[],
+ retired=Retired,
+ checksum = <<"some checksum">>});
+ ({Name, Version, Checksum, Repo, Retired}) ->
+ ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name),
+ ec_semver:parse(Version),
+ rebar_utils:to_binary(Repo)},
+ dependencies=[],
+ retired=Retired,
+ checksum = Checksum})
+ end, Deps).
diff --git a/test/rebar_plugins_SUITE.erl b/test/rebar_plugins_SUITE.erl
index a313683..c7a5d51 100644
--- a/test/rebar_plugins_SUITE.erl
+++ b/test/rebar_plugins_SUITE.erl
@@ -14,7 +14,8 @@
upgrade_project_plugin/1,
sub_app_plugins/1,
sub_app_plugin_overrides/1,
- project_plugins/1]).
+ project_plugins/1,
+ use_checkout_plugins/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -37,7 +38,7 @@ end_per_testcase(_, _Config) ->
all() ->
[compile_plugins, compile_global_plugins, complex_plugins, list, upgrade, upgrade_project_plugin,
- sub_app_plugins, sub_app_plugin_overrides, project_plugins].
+ sub_app_plugins, sub_app_plugin_overrides, project_plugins, use_checkout_plugins].
%% Tests that compiling a project installs and compiles the plugins of deps
compile_plugins(Config) ->
@@ -334,7 +335,7 @@ project_plugins(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
DepName = rebar_test_utils:create_random_name("dep1_"),
- PluginName = "compile",
+ PluginName = "compile_plugin",
PluginName2 = "release",
Plugins = rebar_test_utils:expand_deps(git, [{PluginName, Vsn, []}, {PluginName2, Vsn, []}]),
@@ -370,3 +371,26 @@ project_plugins(Config) ->
?assertEqual(length(Release), 2),
?assertEqual(length(Compile), 1).
+
+use_checkout_plugins(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ PluginName = "checkedout",
+ CheckoutsDir = filename:join(AppDir, "_checkouts/checkedout"),
+ rebar_test_utils:create_plugin(CheckoutsDir, PluginName, "1.0.0", []),
+
+ RConfFile =
+ rebar_test_utils:create_config(AppDir,
+ [{deps, []},
+ {plugins, [list_to_atom(PluginName)]}]),
+ {ok, RConf} = file:consult(RConfFile),
+
+ %% Verify we can run the plugin
+ ?assertMatch({ok, _}, rebar_test_utils:run_and_check(
+ Config, RConf, ["checkedout"],
+ {ok, []}
+ )).
diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl
index a31a4c9..512832a 100644
--- a/test/rebar_profiles_SUITE.erl
+++ b/test/rebar_profiles_SUITE.erl
@@ -7,6 +7,7 @@
all/0,
profile_new_key/1,
profile_merge_keys/1,
+ profile_merge_umbrella_keys/1,
explicit_profile_deduplicate_deps/1,
implicit_profile_deduplicate_deps/1,
all_deps_code_paths/1,
@@ -20,14 +21,23 @@
test_profile_applied_at_completion/1,
test_profile_applied_before_compile/1,
test_profile_applied_before_eunit/1,
- test_profile_applied_to_apps/1]).
+ test_profile_applied_to_apps/1,
+ test_profile_erl_opts_order_1/1,
+ test_profile_erl_opts_order_2/1,
+ test_profile_erl_opts_order_3/1,
+ test_profile_erl_opts_order_4/1,
+ test_profile_erl_opts_order_5/1,
+ test_erl_opts_debug_info/1,
+ test_profile_erl_opts_precedence/1,
+ first_files_exception/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("kernel/include/file.hrl").
all() ->
- [profile_new_key, profile_merge_keys, all_deps_code_paths, profile_merges,
+ [profile_new_key, profile_merge_keys, profile_merge_umbrella_keys,
+ all_deps_code_paths, profile_merges,
explicit_profile_deduplicate_deps, implicit_profile_deduplicate_deps,
same_profile_deduplication, stack_deduplication,
add_to_profile, add_to_existing_profile,
@@ -36,7 +46,15 @@ all() ->
test_profile_applied_at_completion,
test_profile_applied_before_compile,
test_profile_applied_before_eunit,
- test_profile_applied_to_apps].
+ test_profile_applied_to_apps,
+ test_profile_erl_opts_order_1,
+ test_profile_erl_opts_order_2,
+ test_profile_erl_opts_order_3,
+ test_profile_erl_opts_order_4,
+ test_profile_erl_opts_order_5,
+ test_erl_opts_debug_info,
+ test_profile_erl_opts_precedence,
+ first_files_exception].
init_per_suite(Config) ->
application:start(meck),
@@ -106,6 +124,35 @@ profile_merge_keys(Config) ->
,{dep, "a", "1.0.0"}
,{dep, "b", "2.0.0"}]}).
+profile_merge_umbrella_keys(Config) ->
+ AppDir = ?config(apps, Config),
+ ct:pal("Path: ~s", [AppDir]),
+ Name = rebar_test_utils:create_random_name("profile_merge_umbrella_keys"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ SubAppDir = filename:join([AppDir, "apps", Name]),
+
+ RebarConfig = [{vals, [{a,1},{b,1}]},
+ {profiles,
+ [{ct,
+ [{vals, [{a,1},{b,2}]}]}]}],
+
+ SubRebarConfig = [{vals, []},
+ {profiles, [{ct, [{vals, [{c,1}]}]}]}],
+
+ rebar_test_utils:create_app(SubAppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_config(SubAppDir, SubRebarConfig),
+ {ok, RebarConfigRead} = file:consult(rebar_test_utils:create_config(AppDir, RebarConfig)),
+
+ {ok, State} = rebar_test_utils:run_and_check(
+ Config, RebarConfigRead, ["as", "ct", "compile"], return
+ ),
+
+ [ProjectApp] = rebar_state:project_apps(State),
+ ?assertEqual(Name, binary_to_list(rebar_app_info:name(ProjectApp))),
+ Opts = rebar_app_info:opts(ProjectApp),
+ ?assertEqual([{a,1},{b,2},{b,1},{c,1}], dict:fetch(vals, Opts)),
+ ok.
+
explicit_profile_deduplicate_deps(Config) ->
AppDir = ?config(apps, Config),
@@ -166,7 +213,7 @@ implicit_profile_deduplicate_deps(Config) ->
rebar_test_utils:run_and_check(Config, RebarConfig,
["as", "test,bar", "eunit"], {ok, [{app, Name}
,{dep, "a", "1.0.0"}
- ,{dep, "b", "2.0.0"}]}).
+ ,{dep, "b", "1.0.0"}]}).
all_deps_code_paths(Config) ->
AppDir = ?config(apps, Config),
@@ -432,3 +479,166 @@ test_profile_applied_to_apps(Config) ->
ErlOpts = dict:fetch(erl_opts, Opts),
true = lists:member({d, 'TEST'}, ErlOpts)
end, Apps).
+
+test_profile_erl_opts_order_1(Config) ->
+ Opts = get_compiled_profile_erl_opts([default], Config),
+ Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
+ undefined = Opt.
+
+test_profile_erl_opts_order_2(Config) ->
+ Opts = get_compiled_profile_erl_opts([strict], Config),
+ Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
+ warn_export_all = Opt.
+
+test_profile_erl_opts_order_3(Config) ->
+ Opts = get_compiled_profile_erl_opts([loose], Config),
+ Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
+ nowarn_export_all = Opt.
+
+test_profile_erl_opts_order_4(Config) ->
+ Opts = get_compiled_profile_erl_opts([strict, loose], Config),
+ Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
+ nowarn_export_all = Opt.
+
+test_profile_erl_opts_order_5(Config) ->
+ Opts = get_compiled_profile_erl_opts([loose, strict], Config),
+ Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
+ warn_export_all = Opt.
+
+test_erl_opts_debug_info(_Config) ->
+ ToOpts = fun(List) -> rebar_opts:erl_opts(dict:from_list([{erl_opts, List}])) end,
+ ?assertEqual([debug_info,a,b,c],
+ ToOpts([a,b,c])),
+ ?assertEqual([{debug_info,{mod,123}},a,b,c,debug_info],
+ ToOpts([{debug_info,{mod,123}},a,b,c,debug_info])),
+ ?assertEqual([a,b,debug_info,c],
+ ToOpts([no_debug_info,a,b,debug_info,c])),
+ ?assertEqual([a,b,c],
+ ToOpts([debug_info,a,b,no_debug_info,c])),
+ ?assertEqual([a,b,c,debug_info],
+ ToOpts([{debug_info_key, "12345"},a,b,
+ no_debug_info,c,debug_info])),
+ ?assertEqual([a,b,c],
+ ToOpts([{debug_info,{mod,123}},{debug_info_key, "12345"},
+ a,no_debug_info,b,c,debug_info,no_debug_info])),
+ ?assertEqual([a,b,c,{debug_info_key,"123"}],
+ ToOpts([{debug_info_key, "12345"},a,b,no_debug_info,debug_info,
+ c,{debug_info_key, "123"}])),
+ ?assertEqual([{debug_info_key,"12345"},a,b,c,{debug_info,{mod,"123"}}],
+ ToOpts([debug_info,{debug_info_key,"12345"},a,
+ no_debug_info,b,c,{debug_info,{mod,"123"}}])),
+ ok.
+
+test_profile_erl_opts_precedence(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = rebar_test_utils:create_random_name("profile_new_key_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ RebarConfig = [{erl_opts, [no_debug_info]},
+ {profiles, [
+ {test, [{erl_opts, [debug_info, {d,'HI'}]}]},
+ {other, [{erl_opts, [debug_info, {d,'HI'}]}]}
+ ]}],
+ {ok, State1} = rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "test", "compile"], return
+ ),
+ {ok, State2} = rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "other", "compile"], return
+ ),
+ {ok, State3} = rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"], return
+ ),
+ Opts1 = rebar_state:opts(State1),
+ Opts2 = rebar_state:opts(State2),
+ Opts3 = rebar_state:opts(State3),
+ ErlOpts1 = rebar_opts:erl_opts(Opts1),
+ ErlOpts2 = rebar_opts:erl_opts(Opts2),
+ ErlOpts3 = rebar_opts:erl_opts(Opts3),
+ ?assertEqual([{d,'TEST'}, debug_info, {d,'HI'}], ErlOpts1),
+ ?assertEqual([debug_info, {d,'HI'}], ErlOpts2),
+ ?assertEqual([], ErlOpts3),
+ ok.
+
+first_files_exception(_Config) ->
+ RebarConfig = [{erl_first_files, ["c","a","b"]},
+ {mib_first_files, ["c","a","b"]},
+ {other, ["c","a","b"]},
+ {profiles,
+ [{profile2, [{erl_first_files, ["a","e"]},
+ {mib_first_files, ["a","e"]},
+ {other, ["a","e"]}
+ ]}]}],
+ State = rebar_state:new(RebarConfig),
+ State1 = rebar_state:apply_profiles(State, [profile2]),
+
+ %% Combine lists
+ ?assertEqual(["a","b","c","e"], rebar_state:get(State1, other)),
+ %% there is no specific reason not to dedupe "a" here aside from "this is how it is"
+ ?assertEqual(["c","a","b","a","e"], rebar_state:get(State1, erl_first_files)),
+ ?assertEqual(["c","a","b","a","e"], rebar_state:get(State1, mib_first_files)),
+ ok.
+
+get_compiled_profile_erl_opts(Profiles, Config) ->
+ AppDir = ?config(apps, Config),
+ PStrs = [atom_to_list(P) || P <- Profiles],
+
+ Name = rebar_test_utils:create_random_name(
+ lists:flatten(["erl_opts_order_" | [[S, $_] || S <- PStrs]])),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [
+ {erl_opts, [warnings_as_errors, {d, profile_default}]},
+ {profiles, [
+ {strict, [{erl_opts, [warn_export_all, {d, profile_strict}]}]},
+ {loose, [{erl_opts, [nowarn_export_all, {d, profile_loose}]}]} ]}],
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+
+ Command = case Profiles of
+ [] ->
+ ["compile"];
+ [default] ->
+ ["compile"];
+ _ ->
+ ["as", rebar_string:join(PStrs, ","), "compile"]
+ end,
+ {ok, State} = rebar_test_utils:run_and_check(
+ Config, RebarConfig, Command, {ok, [{app, Name}]}),
+ code:add_paths(rebar_state:code_paths(State, all_deps)),
+ Mod = list_to_atom(Name),
+ proplists:get_value(options, Mod:module_info(compile), []).
+
+% macro definitions get special handling
+last_erl_opt([{d, Macro} = Opt | Opts], Targets, Last) ->
+ case lists:any(erl_opt_macro_match_fun(Macro), Targets) of
+ true ->
+ last_erl_opt(Opts, Targets, Opt);
+ _ ->
+ last_erl_opt(Opts, Targets, Last)
+ end;
+last_erl_opt([{d, Macro, _} = Opt | Opts], Targets, Last) ->
+ case lists:any(erl_opt_macro_match_fun(Macro), Targets) of
+ true ->
+ last_erl_opt(Opts, Targets, Opt);
+ _ ->
+ last_erl_opt(Opts, Targets, Last)
+ end;
+last_erl_opt([Opt | Opts], Targets, Last) ->
+ case lists:member(Opt, Targets) of
+ true ->
+ last_erl_opt(Opts, Targets, Opt);
+ _ ->
+ last_erl_opt(Opts, Targets, Last)
+ end;
+last_erl_opt([], _, Last) ->
+ Last.
+
+erl_opt_macro_match_fun(Macro) ->
+ fun({d, M}) ->
+ M == Macro;
+ ({d, M, _}) ->
+ M == Macro;
+ (_) ->
+ false
+ end.
+
diff --git a/test/rebar_release_SUITE.erl b/test/rebar_release_SUITE.erl
index 1125a7e..1bcc61e 100644
--- a/test/rebar_release_SUITE.erl
+++ b/test/rebar_release_SUITE.erl
@@ -11,6 +11,7 @@ all() -> [release,
profile_ordering_sys_config_extend_3_tuple_merge,
extend_release,
user_output_dir, profile_overlays,
+ profile_overlay_merge,
overlay_vars].
init_per_testcase(Case, Config0) ->
@@ -199,13 +200,34 @@ profile_overlays(Config) ->
AppDir = ?config(apps, Config),
Name = ?config(name, Config),
Vsn = "1.0.0",
+ file:write_file(filename:join(AppDir, "dev.file"), "dev.\n"),
+ file:write_file(filename:join(AppDir, "prod.file"), "prod.\n"),
+ file:write_file(filename:join(AppDir, "dev.vars"), "{env, \"dev\"}.\n"),
+ file:write_file(filename:join(AppDir, "prod.vars"), "{env, \"prod\"}.\n"),
{ok, RebarConfig} =
- file:consult(rebar_test_utils:create_config(AppDir,
- [{relx, [{release, {list_to_atom(Name), Vsn},
- [list_to_atom(Name)]},
- {overlay, [{mkdir, "randomdir"}]},
- {lib_dirs, [AppDir]}]},
- {profiles, [{prod, [{relx, [{overlay, [{mkdir, "otherrandomdir"}]}]}]}]}])),
+ file:consult(rebar_test_utils:create_config(AppDir,
+ %% Paths are relative, but to cwd in relx, not the project root as
+ %% seen by rebar3 (in non-test cases, they're the same).
+ %% Work around by being explicit.
+ [{relx, [{release, {list_to_atom(Name), Vsn},
+ [list_to_atom(Name)]},
+ {overlay_vars, filename:join(AppDir, "dev.vars")},
+ {overlay, [{mkdir, "randomdir"},
+ {copy, filename:join(AppDir,"./dev.file"), "profile.file"},
+ {copy, filename:join(AppDir,"./dev.file"), "{{env}}.file"},
+ {chmod, 8#00770, "profile.file"}]},
+ {lib_dirs, [AppDir]}]},
+ {profiles, [{prod,
+ [{relx, [
+ {overlay_vars, filename:join(AppDir, "prod.vars")},
+ {overlay, [{mkdir, "otherrandomdir"},
+ {copy, filename:join(AppDir, "./prod.file"), "{{env}}.file"},
+ {copy, filename:join(AppDir, "./prod.file"), "profile.file"},
+ {chmod, 8#00770, "profile.file"}]}
+
+ ]}]
+ }]}
+ ])),
ReleaseDir = filename:join([AppDir, "./_build/prod/rel/", Name]),
@@ -215,7 +237,36 @@ profile_overlays(Config) ->
{ok, [{release, list_to_atom(Name), Vsn, false},
{dir, filename:join(ReleaseDir, "otherrandomdir")},
{dir, filename:join(ReleaseDir, "randomdir")}]}
- ).
+ ),
+ ?assertMatch({ok,[prod]},
+ file:consult(filename:join(ReleaseDir, "profile.file"))),
+ ?assertMatch({ok,[prod]},
+ file:consult(filename:join(ReleaseDir, "prod.file"))),
+ ok.
+
+profile_overlay_merge (_Config) ->
+ % when profile and relx overlays both exist, the profile overlays should be
+ % first, then the relx overlays, all the rest of the config should come
+ % after, rebar_relx:merge_overlays/1 should do this.
+ RelxOverlay = [{mkdir, "1_from_relx"}, {mkdir, "2_from_relx"}],
+ ProfileOverlay = [{mkdir, "0_from_other_profile"}],
+ OtherConfig = [{other1, config}, {other2, config}],
+
+ % test with no overlays
+ ?assertEqual([{overlay,[]}] ++ OtherConfig,
+ rebar_relx:merge_overlays(OtherConfig)),
+
+ % test with relx only, just move overlays to the top
+ RelxOnly = OtherConfig ++ [{overlay, RelxOverlay}],
+ ?assertEqual([{overlay, RelxOverlay}]++OtherConfig,
+ rebar_relx:merge_overlays(RelxOnly)),
+
+ % now test with a profile (profiles end up after relx overlays
+ ProfilesToMerge = OtherConfig ++
+ [{overlay, RelxOverlay},
+ {overlay, ProfileOverlay}],
+ ?assertEqual([{overlay, ProfileOverlay ++ RelxOverlay}] ++ OtherConfig,
+ rebar_relx:merge_overlays(ProfilesToMerge)).
overlay_vars(Config) ->
AppDir = ?config(apps, Config),
diff --git a/test/rebar_resource_SUITE.erl b/test/rebar_resource_SUITE.erl
index 15f14db..ddacb91 100644
--- a/test/rebar_resource_SUITE.erl
+++ b/test/rebar_resource_SUITE.erl
@@ -29,12 +29,15 @@ init_per_testcase(change_type_upgrade, Config) ->
TypeStr = atom_to_list(Type),
DirName = filename:join([?config(priv_dir, Config), "resource_"++TypeStr]),
ec_file:mkdir_path(DirName),
- [{path, DirName} | Config].
+
+ {ok, AppInfo} = rebar_app_info:new(test_app, "0.0.1", DirName),
+ AppInfo1 = rebar_app_info:source(AppInfo, ?config(resource, Config)),
+
+ [{app, AppInfo1} | Config].
end_per_testcase(_, Config) ->
Config.
change_type_upgrade(Config) ->
- ?assert(rebar_fetch:needs_update(?config(path, Config),
- ?config(resource, Config),
+ ?assert(rebar_fetch:needs_update(?config(app, Config),
?config(state, Config))).
diff --git a/test/rebar_src_dirs_SUITE.erl b/test/rebar_src_dirs_SUITE.erl
index f854a94..bc22160 100644
--- a/test/rebar_src_dirs_SUITE.erl
+++ b/test/rebar_src_dirs_SUITE.erl
@@ -11,12 +11,16 @@
src_dirs_in_erl_opts/1,
extra_src_dirs_in_erl_opts/1,
src_dirs_at_root_and_in_erl_opts/1,
+ dupe_src_dirs_at_root_and_in_erl_opts/1,
extra_src_dirs_at_root_and_in_erl_opts/1,
build_basic_app/1,
build_multi_apps/1,
- src_dir_takes_precedence_over_extra/1]).
+ src_dir_takes_precedence_over_extra/1,
+ src_dir_checkout_dep/1,
+ app_src_info/1]).
-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
suite() ->
[].
@@ -35,8 +39,11 @@ end_per_testcase(_, _Config) -> ok.
all() ->
[src_dirs_at_root, extra_src_dirs_at_root,
src_dirs_in_erl_opts, extra_src_dirs_in_erl_opts,
- src_dirs_at_root_and_in_erl_opts, extra_src_dirs_at_root_and_in_erl_opts,
- build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra].
+ src_dirs_at_root_and_in_erl_opts,
+ dupe_src_dirs_at_root_and_in_erl_opts,
+ extra_src_dirs_at_root_and_in_erl_opts,
+ build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra,
+ src_dir_checkout_dep, app_src_info].
src_dirs_at_root(Config) ->
AppDir = ?config(apps, Config),
@@ -93,15 +100,47 @@ extra_src_dirs_in_erl_opts(Config) ->
src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
- Name = rebar_test_utils:create_random_name("app1_"),
+ Name = rebar_test_utils:create_random_name("src_dirs_root_erlopts_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ filename:join([AppDir, "qux", Name ++ ".app.src"])),
+
{ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
- ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []).
+ ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{app, Name}]}),
+ ok.
+
+dupe_src_dirs_at_root_and_in_erl_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("dupe_src_dirs_root_erlopts_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ filelib:ensure_dir(filename:join([AppDir, "foo", "fake"])),
+ Src1 = filename:join([AppDir, "qux", Name ++ ".app.src"]),
+ Src2 = filename:join([AppDir, "foo", Name ++ ".app.src"]),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ Src1),
+ %% Then copy it over to create a conflict with dupes
+ file:copy(Src1, Src2),
+
+ {error, {rebar_prv_app_discovery, {multiple_app_files, [Src2, Src1]}}} =
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
+
+ ok.
extra_src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
@@ -236,3 +275,52 @@ src_dir_takes_precedence_over_extra(Config) ->
[{application, _, KVs}] = App,
Mods = proplists:get_value(modules, KVs),
true = lists:member(extra, Mods).
+
+src_dir_checkout_dep(Config) ->
+ AppDir = ?config(apps, Config),
+ AppName = rebar_test_utils:create_random_name("src_dir_checkout_app"),
+ DepName = rebar_test_utils:create_random_name("src_dir_checkout_dep"),
+ AtomDep = list_to_atom(DepName),
+
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, AppName, Vsn, [kernel, stdlib]),
+ RebarConfig = [{deps, [AtomDep]}],
+
+ DepDir = filename:join([?config(checkouts, Config), DepName]),
+ ct:pal("checkouts dir: ~p", [DepDir]),
+ rebar_test_utils:create_app(DepDir, DepName, Vsn, [kernel, stdlib]),
+
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ rebar_file_utils:mv(filename:join([DepDir, "src"]),
+ filename:join([DepDir, "qux"])),
+ DepRebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]},
+ {src_dirs, ["baz", "qux"]}],
+ file:write_file(filename:join([DepDir, "rebar.config"]),
+ io_lib:format("~p.~n~p.~n", DepRebarConfig)),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{checkout, DepName}, {app, AppName}]}
+ ),
+ ok.
+
+app_src_info(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ AppName1 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir1 = filename:join(PrivDir, AppName1),
+ {ok, Info1} = rebar_app_info:new(AppName1, "1.0.0", AppDir1),
+ AppSrc1 = filename:join([AppDir1, "src", AppName1 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc1),
+ ok = file:write_file(AppSrc1, "[]."),
+ ?assertEqual(AppSrc1, rebar_app_info:app_file_src(Info1)),
+
+ AppName2 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir2 = filename:join(PrivDir, AppName2),
+ {ok, Info2Tmp} = rebar_app_info:new(AppName2, "1.0.0", AppDir2),
+ Info2 = rebar_app_info:set(Info2Tmp, src_dirs, ["foo", "bar", "baz"]),
+ AppSrc2 = filename:join([AppDir2, "bar", AppName2 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc2),
+ ok = file:write_file(AppSrc2, "[]."),
+ ?assertEqual(AppSrc2, rebar_app_info:app_file_src(Info2)),
+ ok.
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index 8c177c9..944efa0 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -1,11 +1,12 @@
-module(rebar_test_utils).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
--export([init_rebar_state/1, init_rebar_state/2, run_and_check/4, check_results/3]).
+-export([init_rebar_state/1, init_rebar_state/2, run_and_check/3, run_and_check/4, check_results/3]).
-export([expand_deps/2, flat_deps/1, top_level_deps/1]).
-export([create_app/4, create_plugin/4, create_eunit_app/4, create_empty_app/4,
- create_config/2, create_config/3, package_app/3]).
--export([create_random_name/1, create_random_vsn/0, write_src_file/2]).
+ create_config/2, create_config/3, package_app/4]).
+-export([create_random_name/1, create_random_vsn/0, write_src_file/2,
+ random_element/1]).
%% Pick the right random module
-ifdef(rand_only).
@@ -34,8 +35,10 @@ init_rebar_state(Config, Name) ->
Verbosity = rebar3:log_level(),
rebar_log:init(command_line, Verbosity),
GlobalDir = filename:join([DataDir, "cache"]),
+ Repos = proplists:get_value(repos, Config, []),
State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
,{global_rebar_dir, GlobalDir}
+ ,{hex, [{repos, [#{name => R} || R <- Repos]}]}
,{root_dir, AppsDir}]),
[{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, State} | Config].
@@ -79,6 +82,33 @@ run_and_check(Config, RebarConfig, Command, Expect) ->
rebar_abort when Expect =:= rebar_abort -> rebar_abort
end.
+run_and_check(Config, Command, Expect) ->
+ %% Assumes init_rebar_state has run first
+ AppDir = ?config(apps, Config),
+ {ok, Cwd} = file:get_cwd(),
+ try
+ ok = file:set_cwd(AppDir),
+ Res = rebar3:run(Command),
+ case Expect of
+ {error, Reason} ->
+ ?assertEqual({error, Reason}, Res);
+ {ok, Expected} ->
+ {ok, _} = Res,
+ check_results(AppDir, Expected, "*"),
+ Res;
+ {ok, Expected, ProfileRun} ->
+ {ok, _} = Res,
+ check_results(AppDir, Expected, ProfileRun),
+ Res;
+ return ->
+ Res
+ end
+ catch
+ rebar_abort when Expect =:= rebar_abort -> rebar_abort
+ after
+ ok = file:set_cwd(Cwd)
+ end.
+
%% @doc Creates a dummy application including:
%% - src/<file>.erl
%% - src/<file>.app.src
@@ -167,14 +197,14 @@ expand_deps(pkg, [{Name, Vsn, Deps} | Rest]) ->
[{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
expand_deps(mixed, [{Name, Deps} | Rest]) ->
Dep = if hd(Name) >= $a, hd(Name) =< $z ->
- {pkg, string:to_upper(Name), "0.0.0", undefined}
+ {pkg, rebar_string:uppercase(Name), "0.0.0", undefined}
; hd(Name) >= $A, hd(Name) =< $Z ->
{Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}}
end,
[{Dep, expand_deps(mixed, Deps)} | expand_deps(mixed, Rest)];
expand_deps(mixed, [{Name, Vsn, Deps} | Rest]) ->
Dep = if hd(Name) >= $a, hd(Name) =< $z ->
- {pkg, string:to_upper(Name), Vsn, undefined}
+ {pkg, rebar_string:uppercase(Name), Vsn, undefined}
; hd(Name) >= $A, hd(Name) =< $Z ->
{Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}}
end,
@@ -218,7 +248,7 @@ check_results(AppDir, Expected, ProfileRun) ->
BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "lib", "*"])),
PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "plugins", "*"])),
GlobalPluginDirs = filelib:wildcard(filename:join([AppDir, "global", "plugins", "*"])),
- CheckoutsDir = filename:join([AppDir, "_checkouts", "*"]),
+ CheckoutsDirs = filelib:wildcard(filename:join([AppDir, "_checkouts", "*"])),
LockFile = filename:join([AppDir, "rebar.lock"]),
Locks = lists:flatten(rebar_config:consult_lock_file(LockFile)),
@@ -230,7 +260,7 @@ check_results(AppDir, Expected, ProfileRun) ->
Deps = rebar_app_discover:find_apps(BuildDirs, all),
DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
- Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all),
+ Checkouts = rebar_app_discover:find_apps(CheckoutsDirs, all),
CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
Plugins = rebar_app_discover:find_apps(PluginDirs, all),
PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],
@@ -263,6 +293,14 @@ check_results(AppDir, Expected, ProfileRun) ->
ok
end
; ({dep_not_exist, Name}) ->
+ ct:pal("Dep Not Exist Name: ~p", [Name]),
+ case lists:keyfind(Name, 1, DepsNames) of
+ false ->
+ ok;
+ {Name, _App} ->
+ error({app_found, Name})
+ end
+ ; ({app_not_exist, Name}) ->
ct:pal("App Not Exist Name: ~p", [Name]),
case lists:keyfind(Name, 1, DepsNames) of
false ->
@@ -349,7 +387,7 @@ check_results(AppDir, Expected, ProfileRun) ->
iolist_to_binary(LockVsn))
end
; ({release, Name, Vsn, ExpectedDevMode}) ->
- ct:pal("Release: ~p-~s", [Name, Vsn]),
+ ct:pal("Release: ~p-~ts", [Name, Vsn]),
{ok, Cwd} = file:get_cwd(),
try
file:set_cwd(AppDir),
@@ -377,14 +415,14 @@ check_results(AppDir, Expected, ProfileRun) ->
file:set_cwd(Cwd)
end
; ({tar, Name, Vsn}) ->
- ct:pal("Tarball: ~s-~s", [Name, Vsn]),
+ ct:pal("Tarball: ~ts-~ts", [Name, Vsn]),
Tarball = filename:join([AppDir, "_build", "rel", Name, Name++"-"++Vsn++".tar.gz"]),
?assertNotEqual([], filelib:is_file(Tarball))
; ({file, Filename}) ->
- ct:pal("Filename: ~s", [Filename]),
+ ct:pal("Filename: ~ts", [Filename]),
?assert(filelib:is_file(Filename))
; ({dir, Dirname}) ->
- ct:pal("Directory: ~s", [Dirname]),
+ ct:pal("Directory: ~ts", [Dirname]),
?assert(filelib:is_dir(Dirname))
end, Expected).
@@ -425,15 +463,16 @@ erl_src_file(Name) ->
plugin_src_file(Name) ->
io_lib:format("-module('~s').\n"
- "-export([init/1]).\n"
+ "-export([init/1, do/1]).\n"
"init(State) -> \n"
"Provider = providers:create([\n"
"{name, '~s'},\n"
"{module, '~s'}\n"
"]),\n"
- "{ok, rebar_state:add_provider(State, Provider)}.\n", [filename:basename(Name, ".erl"),
- filename:basename(Name, ".erl"),
- filename:basename(Name, ".erl")]).
+ "{ok, rebar_state:add_provider(State, Provider)}.\n"
+ "do(State) -> {ok, State}.\n", [filename:basename(Name, ".erl"),
+ filename:basename(Name, ".erl"),
+ filename:basename(Name, ".erl")]).
erl_eunitized_src_file(Name) ->
io_lib:format("-module('~s').\n"
@@ -466,24 +505,25 @@ get_app_metadata(Name, Vsn, Deps) ->
{registered, []},
{applications, Deps}]}.
-package_app(AppDir, DestDir, PkgName) ->
- Name = PkgName++".tar",
- {ok, Fs} = rebar_utils:list_dir(AppDir),
- ok = erl_tar:create(filename:join(DestDir, "contents.tar.gz"),
- lists:zip(Fs, [filename:join(AppDir,F) || F <- Fs]),
- [compressed]),
- ok = file:write_file(filename:join(DestDir, "metadata.config"), "who cares"),
- ok = file:write_file(filename:join(DestDir, "VERSION"), "3"),
- {ok, Contents} = file:read_file(filename:join(DestDir, "contents.tar.gz")),
- Blob = <<"3who cares", Contents/binary>>,
- <<X:256/big-unsigned>> = crypto:hash(sha256, Blob),
- BinChecksum = list_to_binary(string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X])))),
- ok = file:write_file(filename:join(DestDir, "CHECKSUM"), BinChecksum),
- PkgFiles = ["contents.tar.gz", "VERSION", "metadata.config", "CHECKSUM"],
+package_app(AppDir, DestDir, PkgName, PkgVsn) ->
+ AppSrc = filename:join(AppDir, "src"),
+ {ok, Fs} = rebar_utils:list_dir(AppSrc),
+ Files = lists:zip([filename:join("src", F) || F <- Fs], [filename:join(AppSrc,F) || F <- Fs]),
+ Metadata = #{<<"app">> => list_to_binary(PkgName),
+ <<"version">> => list_to_binary(PkgVsn)},
+ {ok, {Tarball, <<Checksum:256/big-unsigned-integer>>}} = hex_tarball:create(Metadata, Files),
+
+ Name = PkgName++"-"++PkgVsn++".tar",
Archive = filename:join(DestDir, Name),
- ok = erl_tar:create(Archive,
- lists:zip(PkgFiles, [filename:join(DestDir,F) || F <- PkgFiles])),
- {ok, BinFull} = file:read_file(Archive),
- <<E:128/big-unsigned-integer>> = crypto:hash(md5, BinFull),
- Etag = string:to_lower(lists:flatten(io_lib:format("~32.16.0b", [E]))),
- {BinChecksum, Etag}.
+ file:write_file(Archive, Tarball),
+
+ <<E:128/big-unsigned-integer>> = crypto:hash(md5, Tarball),
+
+ Checksum1 = list_to_binary(
+ rebar_string:uppercase(
+ lists:flatten(io_lib:format("~64.16.0b", [Checksum])))),
+ {Checksum1, E}.
+
+random_element(Repos) ->
+ Index = ?random:uniform(length(Repos)),
+ lists:nth(Index, Repos).
diff --git a/test/rebar_unlock_SUITE.erl b/test/rebar_unlock_SUITE.erl
index 8dbdb3a..a8d1400 100644
--- a/test/rebar_unlock_SUITE.erl
+++ b/test/rebar_unlock_SUITE.erl
@@ -33,7 +33,7 @@ pkgunlock(Config) ->
rebar_test_utils:run_and_check(Config, [], ["unlock", "cf,certifi"], {ok, []}),
?assertEqual(Locks -- ["bbmustache","cf","certifi"], read_locks(Config)),
?assertEqual(Hashes -- ["bbmustache","cf","certifi"], read_hashes(Config)),
- rebar_test_utils:run_and_check(Config, [], ["unlock", string:join(Locks,",")], {ok, []}),
+ rebar_test_utils:run_and_check(Config, [], ["unlock", rebar_string:join(Locks,",")], {ok, []}),
?assertEqual({error, enoent}, read_locks(Config)),
?assertEqual({error, enoent}, read_hashes(Config)),
ok.
@@ -42,18 +42,21 @@ unlock(Config) ->
Locks = read_locks(Config),
rebar_test_utils:run_and_check(Config, [], ["unlock", "fakeapp"], {ok, []}),
Locks = read_locks(Config),
- rebar_test_utils:run_and_check(Config, [], ["unlock", "uuid"], {ok, []}),
+ {ok, State} = rebar_test_utils:run_and_check(Config, [], ["unlock", "uuid"], return),
?assertEqual(Locks -- ["uuid"], read_locks(Config)),
+ ?assert(false =:= lists:keyfind(<<"uuid">>, 1, rebar_state:get(State, {locks, default}))),
+ ?assert(false =/= lists:keyfind(<<"itc">>, 1, rebar_state:get(State, {locks, default}))),
rebar_test_utils:run_and_check(Config, [], ["unlock", "gproc,itc"], {ok, []}),
?assertEqual(Locks -- ["uuid","gproc","itc"], read_locks(Config)),
- rebar_test_utils:run_and_check(Config, [], ["unlock", string:join(Locks,",")], {ok, []}),
+ rebar_test_utils:run_and_check(Config, [], ["unlock", rebar_string:join(Locks,",")], {ok, []}),
?assertEqual({error, enoent}, read_locks(Config)),
ok.
unlock_all(Config) ->
[_|_] = read_locks(Config),
- rebar_test_utils:run_and_check(Config, [], ["unlock"], {ok, []}),
+ {ok, State} = rebar_test_utils:run_and_check(Config, [], ["unlock"], return),
?assertEqual({error, enoent}, read_locks(Config)),
+ ?assertEqual([], rebar_state:get(State, {locks, default})),
ok.
read_locks(Config) ->
diff --git a/test/rebar_unlock_SUITE_data/pkg.rebar.lock b/test/rebar_unlock_SUITE_data/pkg.rebar.lock
index 38e22e5..231e266 100644
--- a/test/rebar_unlock_SUITE_data/pkg.rebar.lock
+++ b/test/rebar_unlock_SUITE_data/pkg.rebar.lock
@@ -1,32 +1,24 @@
-{"1.1.0",[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.4">>},0},
- {<<"certifi">>,{pkg,<<"certifi">>,<<"0.4.0">>},0},
- {<<"cf">>,{pkg,<<"cf">>,<<"0.2.1">>},0},
- {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.2.2">>},0},
- {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"0.21.0">>},0},
- {<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.3.1">>},0},
- {<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0},
- {<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},0},
- {<<"relx">>,{pkg,<<"relx">>,<<"3.19.0">>},0},
- {<<"ssl_verify_hostname">>,
- {pkg,<<"ssl_verify_hostname">>,<<"1.0.5">>},
- 0}]}.
-[{pkg_hash,[{<<"bbmustache">>,
- <<"7BA94F971C5AFD7B6617918A4BB74705E36CAB36EB84B19B6A1B7EE06427AA38">>},
- {<<"certifi">>,
- <<"A7966EFB868B179023618D29A407548F70C52466BF1849B9E8EBD0E34B7EA11F">>},
- {<<"cf">>,
- <<"69D0B1349FD4D7D4DC55B7F407D29D7A840BF9A1EF5AF529F1EBE0CE153FC2AB">>},
- {<<"cth_readable">>,
- <<"983913A8E8572310B7EAF5F2631148B7D70B3C090D2120DCFE777A93AA4165FB">>},
- {<<"erlware_commons">>,
- <<"A04433071AD7D112EDEFC75AC77719DD3E6753E697AC09428FC83D7564B80B15">>},
- {<<"eunit_formatters">>,
- <<"7A6FC351EB5B873E2356B8852EB751E20C13A72FBCA03393CF682B8483509573">>},
- {<<"getopt">>,
- <<"B17556DB683000BA50370B16C0619DF1337E7AF7ECBF7D64FBF8D1D6BCE3109B">>},
- {<<"providers">>,
- <<"DB0E2F9043AE60C0155205FCD238D68516331D0E5146155E33D1E79DC452964A">>},
- {<<"relx">>,
- <<"286DD5244B4786F56AAC75D5C8E2D1FB4CFD306810D4EC8548F3AE1B3AADB8F7">>},
- {<<"ssl_verify_hostname">>,
- <<"2E73E068CD6393526F9FA6D399353D7C9477D6886BA005F323B592D389FB47BE">>}]}].
+{"1.1.0",
+[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.4">>},0},
+ {<<"certifi">>,{pkg,<<"certifi">>,<<"0.4.0">>},0},
+ {<<"cf">>,{pkg,<<"cf">>,<<"0.2.1">>},0},
+ {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.2.3">>},0},
+ {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"0.21.0">>},0},
+ {<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.3.1">>},0},
+ {<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0},
+ {<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},0},
+ {<<"relx">>,{pkg,<<"relx">>,<<"3.20.0">>},0},
+ {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.1">>},0}]}.
+[
+{pkg_hash,[
+ {<<"bbmustache">>, <<"7BA94F971C5AFD7B6617918A4BB74705E36CAB36EB84B19B6A1B7EE06427AA38">>},
+ {<<"certifi">>, <<"A7966EFB868B179023618D29A407548F70C52466BF1849B9E8EBD0E34B7EA11F">>},
+ {<<"cf">>, <<"69D0B1349FD4D7D4DC55B7F407D29D7A840BF9A1EF5AF529F1EBE0CE153FC2AB">>},
+ {<<"cth_readable">>, <<"293120673DFF82F0768612C5282E35C40CACC1B6F94FE99077438FD3749D0E27">>},
+ {<<"erlware_commons">>, <<"A04433071AD7D112EDEFC75AC77719DD3E6753E697AC09428FC83D7564B80B15">>},
+ {<<"eunit_formatters">>, <<"7A6FC351EB5B873E2356B8852EB751E20C13A72FBCA03393CF682B8483509573">>},
+ {<<"getopt">>, <<"B17556DB683000BA50370B16C0619DF1337E7AF7ECBF7D64FBF8D1D6BCE3109B">>},
+ {<<"providers">>, <<"DB0E2F9043AE60C0155205FCD238D68516331D0E5146155E33D1E79DC452964A">>},
+ {<<"relx">>, <<"B515B8317D25B3A1508699294C3D1FA6DC0527851DFFC87446661BCE21A36710">>},
+ {<<"ssl_verify_fun">>, <<"28A4D65B7F59893BC2C7DE786DEC1E1555BD742D336043FE644AE956C3497FBE">>}]}
+].
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 66e1fdf..c55456c 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -11,7 +11,8 @@ groups() ->
triplet_a, triplet_b, triplet_c,
tree_a, tree_b, tree_c, tree_c2, tree_cj, tree_ac, tree_all,
delete_d, promote, stable_lock, fwd_lock,
- compile_upgrade_parity, umbrella_config]},
+ compile_upgrade_parity, umbrella_config,
+ profiles, profiles_exclusion]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@@ -78,6 +79,23 @@ setup_project(Case=umbrella_config, Config0, Deps, UpDeps) ->
[{rebarconfig, TopConf},
{rebarumbrella, RebarConf},
{next_top_deps, rebar_test_utils:top_level_deps(UpDeps)} | Config];
+setup_project(Case, Config0, Deps, UpDeps) when Case == profiles;
+ Case == profiles_exclusion ->
+ DepsType = ?config(deps_type, Config0),
+ NameRoot = atom_to_list(Case)++"_"++atom_to_list(DepsType),
+ Config = rebar_test_utils:init_rebar_state(Config0, NameRoot++"_"),
+ AppDir = filename:join([?config(apps, Config), "apps", NameRoot]),
+ rebar_test_utils:create_app(AppDir, "Root", "0.0.0", [kernel, stdlib]),
+ [Top|ProfileDeps] = rebar_test_utils:top_level_deps(Deps),
+ RebarConf = rebar_test_utils:create_config(AppDir, [
+ {deps, [Top]},
+ {profiles, [{fake, [{deps, ProfileDeps}]}]}
+ ]),
+ [NextTop|NextPDeps] = rebar_test_utils:top_level_deps(UpDeps),
+ NextConfig = [{deps, [NextTop]},
+ {profiles, [{fake, [{deps, NextPDeps}]}]}],
+ [{rebarconfig, RebarConf},
+ {next_config, NextConfig} | Config];
setup_project(Case, Config0, Deps, UpDeps) ->
DepsType = ?config(deps_type, Config0),
Config = rebar_test_utils:init_rebar_state(
@@ -94,25 +112,25 @@ setup_project(Case, Config0, Deps, UpDeps) ->
upgrades(top_a) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
- {"A", [{"A","1"}, "B", "C", {"D","3"}]}};
+ {"A", [{"A","1.0.0"}, "B", "C", {"D","3.0.0"}]}};
upgrades(top_b) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
@@ -120,12 +138,12 @@ upgrades(top_b) ->
{"B", {error, {rebar_prv_upgrade, {transitive_dependency, <<"B">>}}}}};
upgrades(top_c) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
@@ -133,12 +151,12 @@ upgrades(top_c) ->
{"C", {error, {rebar_prv_upgrade, {transitive_dependency, <<"C">>}}}}};
upgrades(top_d1) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
@@ -146,12 +164,12 @@ upgrades(top_d1) ->
{"D", {error, {rebar_prv_upgrade, {transitive_dependency, <<"D">>}}}}};
upgrades(top_d2) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
@@ -159,302 +177,342 @@ upgrades(top_d2) ->
{"D", {error, {rebar_prv_upgrade, {transitive_dependency, <<"D">>}}}}};
upgrades(top_e) ->
%% Original tree
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Updated tree
- [{"A", "1", [{"B", [{"D", "3", []}]},
- {"C", [{"D", "2", []}]}]}
+ [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
%% Modified apps, gobally
["A","B","D"],
%% upgrade vs. new tree
{"E", {error, {rebar_prv_upgrade, {unknown_dependency, <<"E">>}}}}};
upgrades(pair_a) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
- {"A", [{"A","2"},{"C","2"},{"B","1"},{"D","1"}]}};
+ {"A", [{"A","2.0.0"},{"C","2.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}};
upgrades(pair_b) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
- {"B", [{"A","1"},{"C","1"},{"B","2"},{"D","2"}]}};
+ {"B", [{"A","1.0.0"},{"C","1.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}};
upgrades(pair_ab) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
- {"A,B", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}};
+ {"A,B", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}};
upgrades(pair_c) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
{"C", {error, {rebar_prv_upgrade, {transitive_dependency, <<"C">>}}}}};
upgrades(pair_all) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
- {"", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}};
+ {"", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}};
upgrades(triplet_a) ->
- {[{"A", "1", [{"D",[]},
- {"E","3",[]}]},
- {"B", "1", [{"F","1",[]},
+ {[{"A", "1.0.0", [{"D",[]},
+ {"E","3.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "0", [{"H","3",[]},
+ {"C", "0.0.0", [{"H","3.0.0",[]},
{"I",[]}]}],
- [{"A", "1", [{"D",[]},
- {"E","2",[]}]},
- {"B", "1", [{"F","1",[]},
+ [{"A", "1.0.0", [{"D",[]},
+ {"E","2.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "1", [{"H","4",[]},
+ {"C", "1.0.0", [{"H","4.0.0",[]},
{"I",[]}]}],
["A","C","E","H"],
- {"A", [{"A","1"}, "D", {"E","2"},
- {"B","1"}, {"F","1"}, "G",
- {"C","0"}, {"H","3"}, "I"]}};
+ {"A", [{"A","1.0.0"}, "D", {"E","2.0.0"},
+ {"B","1.0.0"}, {"F","1.0.0"}, "G",
+ {"C","0.0.0"}, {"H","3.0.0"}, "I"]}};
upgrades(triplet_b) ->
- {[{"A", "1", [{"D",[]},
- {"E","3",[]}]},
- {"B", "1", [{"F","1",[]},
+ {[{"A", "1.0.0", [{"D",[]},
+ {"E","3.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "0", [{"H","3",[]},
+ {"C", "0.0.0", [{"H","3.0.0",[]},
{"I",[]}]}],
- [{"A", "2", [{"D",[]},
- {"E","2",[]}]},
- {"B", "1", [{"F","1",[]},
+ [{"A", "2.0.0", [{"D",[]},
+ {"E","2.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "1", [{"H","4",[]},
+ {"C", "1.0.0", [{"H","4.0.0",[]},
{"I",[]}]}],
["A","C","E","H"],
- {"B", [{"A","1"}, "D", {"E","3"},
- {"B","1"}, {"F","1"}, "G",
- {"C","0"}, {"H","3"}, "I"]}};
+ {"B", [{"A","1.0.0"}, "D", {"E","3.0.0"},
+ {"B","1.0.0"}, {"F","1.0.0"}, "G",
+ {"C","0.0.0"}, {"H","3.0.0"}, "I"]}};
upgrades(triplet_c) ->
- {[{"A", "1", [{"D",[]},
- {"E","3",[]}]},
- {"B", "1", [{"F","1",[]},
+ {[{"A", "1.0.0", [{"D",[]},
+ {"E","3.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "0", [{"H","3",[]},
+ {"C", "0.0.0", [{"H","3.0.0",[]},
{"I",[]}]}],
- [{"A", "2", [{"D",[]},
- {"E","2",[]}]},
- {"B", "1", [{"F","1",[]},
+ [{"A", "2.0.0", [{"D",[]},
+ {"E","2.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
{"G",[]}]},
- {"C", "1", [{"H","4",[]},
+ {"C", "1.0.0", [{"H","4.0.0",[]},
{"I",[]}]}],
["A","C","E","H"],
- {"C", [{"A","1"}, "D", {"E","3"},
- {"B","1"}, {"F","1"}, "G",
- {"C","1"}, {"H","4"}, "I"]}};
+ {"C", [{"A","1.0.0"}, "D", {"E","3.0.0"},
+ {"B","1.0.0"}, {"F","1.0.0"}, "G",
+ {"C","1.0.0"}, {"H","4.0.0"}, "I"]}};
upgrades(tree_a) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "2", [{"H",[]}]}
+ {"C", "2.0.0", [{"H",[]}]}
],
["C"],
- {"A", [{"A","1"}, "D", "J", "E",
- {"B","1"}, "F", "G",
- {"C","1"}, "H", {"I","2"}]}};
+ {"A", [{"A","1.0.0"}, "D", "J", "E",
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H", {"I","2.0.0"}]}};
upgrades(tree_b) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "2", [{"H",[]}]}
+ {"C", "2.0.0", [{"H",[]}]}
],
["C"],
- {"B", [{"A","1"}, "D", "J", "E",
- {"B","1"}, "F", "G",
- {"C","1"}, "H", {"I","2"}]}};
+ {"B", [{"A","1.0.0"}, "D", "J", "E",
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H", {"I","2.0.0"}]}};
upgrades(tree_c) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]}]}
+ {"C", "1.0.0", [{"H",[]}]}
],
["C","I"],
- {"C", [{"A","1"}, "D", "J", "E", {"I","1"},
- {"B","1"}, "F", "G",
- {"C","1"}, "H"]}};
+ {"C", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"},
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H"]}};
upgrades(tree_c2) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[{"K",[]}]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[{"K",[]}]},
+ {"I","2.0.0",[]}]}
],
["C", "H"],
- {"C", [{"A","1"}, "D", "J", "E",
- {"B","1"}, "F", "G",
- {"C","1"}, "H", {"I", "2"}, "K"]}};
+ {"C", [{"A","1.0.0"}, "D", "J", "E",
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H", {"I", "2.0.0"}, "K"]}};
upgrades(tree_cj) ->
- {[{"A", "1", [{"D",[{"J", "1",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J", "1.0.0",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","1",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","1.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J", "2", []}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J", "2.0.0", []}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","1",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","1.0.0",[]}]}
],
["C","J"],
- {"C", [{"A","1"}, "D", {"J", "1"}, "E", {"I","1"},
- {"B","1"}, "F", "G",
- {"C","1"}, "H"]}};
+ {"C", [{"A","1.0.0"}, "D", {"J", "1.0.0"}, "E", {"I","1.0.0"},
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H"]}};
upgrades(tree_ac) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]}]}
+ {"C", "1.0.0", [{"H",[]}]}
],
["C","I"],
- {"C, A", [{"A","1"}, "D", "J", "E", {"I","1"},
- {"B","1"}, "F", "G",
- {"C","1"}, "H"]}};
+ {"C, A", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"},
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H"]}};
upgrades(tree_all) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
- [{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ [{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]}]}
+ {"C", "1.0.0", [{"H",[]}]}
],
["C","I"],
- {"", [{"A","1"}, "D", "J", "E", {"I","1"},
- {"B","1"}, "F", "G",
- {"C","1"}, "H"]}};
+ {"", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"},
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H"]}};
upgrades(delete_d) ->
- {[{"A", "1", [{"B", [{"D", "1", []}]},
- {"C", [{"D", "2", []}]}]}
+ {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]},
+ {"C", [{"D", "2.0.0", []}]}]}
],
- [{"A", "2", [{"B", []},
+ [{"A", "2.0.0", [{"B", []},
{"C", []}]}
],
["A","B", "C"],
%% upgrade vs. new tree
- {"", [{"A","2"}, "B", "C"]}};
+ {"", [{"A","2.0.0"}, "B", "C"]}};
upgrades(promote) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]},
- {"C", "3", []}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]},
+ {"C", "3.0.0", []}
],
["A","B","C","D"],
- {"C", [{"A","1"},{"C","3"},{"B","1"},{"D","1"}]}};
+ {"C", [{"A","1.0.0"},{"C","3.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}};
upgrades(stable_lock) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
], % lock after this
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
[],
%% Run a regular lock and no app should be upgraded
- {"any", [{"A","1"},{"C","1"},{"B","1"},{"D","1"}]}};
+ {"any", [{"A","1.0.0"},{"C","1.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}};
upgrades(fwd_lock) ->
- {[{"A", "1", [{"C", "1", []}]},
- {"B", "1", [{"D", "1", []}]}
+ {[{"A", "1.0.0", [{"C", "1.0.0", []}]},
+ {"B", "1.0.0", [{"D", "1.0.0", []}]}
],
- [{"A", "2", [{"C", "2", []}]},
- {"B", "2", [{"D", "2", []}]}
+ [{"A", "2.0.0", [{"C", "2.0.0", []}]},
+ {"B", "2.0.0", [{"D", "2.0.0", []}]}
],
["A","B","C","D"],
%% For this one, we should build, rewrite the lock
%% file to include the result post-upgrade, and then
%% run a regular lock to see that the lock file is respected
%% in deps.
- {"any", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}};
+ {"any", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}};
upgrades(compile_upgrade_parity) ->
- {[{"A", "1", [{"D",[{"J",[]}]},
- {"E",[{"I","1",[]}]}]},
- {"B", "1", [{"F",[]},
+ {[{"A", "1.0.0", [{"D",[{"J",[]}]},
+ {"E",[{"I","1.0.0",[]}]}]},
+ {"B", "1.0.0", [{"F",[]},
{"G",[]}]},
- {"C", "1", [{"H",[]},
- {"I","2",[]}]}
+ {"C", "1.0.0", [{"H",[]},
+ {"I","2.0.0",[]}]}
],
[],
[],
- {"", [{"A","1"}, "D", "J", "E", {"I","1"},
- {"B","1"}, "F", "G",
- {"C","1"}, "H"]}};
+ {"", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"},
+ {"B","1.0.0"}, "F", "G",
+ {"C","1.0.0"}, "H"]}};
upgrades(umbrella_config) ->
- {[{"A", "1", []}],
- [{"A", "2", []}],
+ {[{"A", "1.0.0", []}],
+ [{"A", "2.0.0", []}],
["A"],
- {"A", [{"A","2"}]}}.
+ {"A", [{"A","2.0.0"}]}};
+upgrades(profiles) ->
+ %% Ensure that we can unlock deps under a given profile;
+ %% B and C should both be in a custom profile
+ %% and must not be locked.
+ {[{"A", "1.0.0", [{"D",[]},
+ {"E","3.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
+ {"G",[]}]},
+ {"C", "0.0.0", [{"H","3.0.0",[]},
+ {"I",[]}]}],
+ [{"A", "2.0.0", [{"D",[]},
+ {"E","2.0.0",[]}]},
+ {"B", "2.0.0", [{"F","2.0.0",[]},
+ {"G",[]}]},
+ {"C", "1.0.0", [{"H","4.0.0",[]},
+ {"I",[]}]}],
+ ["A","B","C","E","F","H"],
+ {"C", [{"A","1.0.0"}, "D", {"E","3.0.0"},
+ {"B","2.0.0"}, {"F","2.0.0"}, "G",
+ {"C","1.0.0"}, {"H","4.0.0"}, "I"]}};
+upgrades(profiles_exclusion) ->
+ %% Ensure that we can unlock deps under a given profile;
+ %% B and C should both be in a custom profile
+ %% and must not be locked.
+ {[{"A", "1.0.0", [{"D",[]},
+ {"E","3.0.0",[]}]},
+ {"B", "1.0.0", [{"F","1.0.0",[]},
+ {"G",[]}]},
+ {"C", "0.0.0", [{"H","3.0.0",[]},
+ {"I",[]}]}],
+ [{"A", "2.0.0", [{"D",[]},
+ {"E","2.0.0",[]}]},
+ {"B", "2.0.0", [{"F","2.0.0",[]},
+ {"G",[]}]},
+ {"C", "1.0.0", [{"H","4.0.0",[]},
+ {"I",[]}]}],
+ ["A","B","C","E","F","H"],
+ {"A", [{"A","1.0.0"}, "D", {"E","3.0.0"},
+ {"B","2.0.0"}, {"F","2.0.0"}, "G",
+ {"C","1.0.0"}, {"H","4.0.0"}, "I"]}}.
%% TODO: add a test that verifies that unlocking files and then
%% running the upgrade code is enough to properly upgrade things.
@@ -613,6 +671,37 @@ umbrella_config(Config) ->
),
meck:unload(rebar_prv_upgrade).
+profiles(Config) ->
+ apply(?config(mock, Config), []),
+ {ok, TopConfig} = file:consult(?config(rebarconfig, Config)),
+ %% Install dependencies before re-mocking for an upgrade
+ rebar_test_utils:run_and_check(Config, TopConfig, ["lock"], {ok, []}),
+ %% Install test deps along with them
+ rebar_test_utils:run_and_check(Config, TopConfig, ["as","fake","lock"], {ok, []}),
+ {App, Unlocks} = ?config(expected, Config),
+ ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]),
+ Expectation = case Unlocks of
+ {error, Term} -> {error, Term};
+ _ -> {ok, [T || T <- Unlocks,
+ element(1,T) == dep orelse
+ lists:member(element(2,T), ["A","D","E"])]}
+ end,
+
+ meck:new(rebar_prv_app_discovery, [passthrough]),
+ meck:expect(rebar_prv_app_discovery, do, fun(S) ->
+ apply(?config(mock_update, Config), []),
+ meck:passthrough([S])
+ end),
+ NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
+ ?config(next_config, Config)),
+ {ok, NewRebarConfig} = file:consult(NewRebarConf),
+ rebar_test_utils:run_and_check(
+ Config, NewRebarConfig, ["as","fake","upgrade", App], Expectation
+ ),
+ meck:unload(rebar_prv_app_discovery).
+
+profiles_exclusion(Config) -> profiles(Config).
+
run(Config) ->
apply(?config(mock, Config), []),
ConfigPath = ?config(rebarconfig, Config),
diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl
index b32992d..233fcff 100644
--- a/test/rebar_utils_SUITE.erl
+++ b/test/rebar_utils_SUITE.erl
@@ -31,7 +31,9 @@
nonblacklisted_otp_version/1,
blacklisted_otp_version/1,
sh_does_not_miss_messages/1,
- tup_merge/1]).
+ tup_merge/1,
+ proxy_auth/1,
+ is_list_of_strings/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -46,7 +48,8 @@ end_per_testcase(_, _Config) ->
all() ->
[{group, args_to_tasks},
sh_does_not_miss_messages,
- tup_merge].
+ tup_merge,
+ proxy_auth, is_list_of_strings].
groups() ->
[{args_to_tasks, [], [empty_arglist,
@@ -272,3 +275,47 @@ tup_merge(_Config) ->
rebar_utils:tup_sort([{a,a},{a,a,a},a,{b,a,a},b,{z,a},{z,a,a},{b,a},z])
)
).
+
+proxy_auth(Config) ->
+ proxy_auth(Config, "http://", "http_proxy"),
+ proxy_auth(Config, "https://", "https_proxy"),
+ proxy_auth(Config, "", "http_proxy"),
+ proxy_auth(Config, "", "https_proxy").
+
+proxy_auth(_Config, Schema, ProxyEnvKey) ->
+ Host = "host:",
+ Port = "1234",
+
+ %% remember current proxy specification
+ OldProxySpec = os:getenv(ProxyEnvKey),
+
+ %% proxy auth not set
+ application:unset_env(rebar, proxy_auth),
+ ?assertEqual([], rebar_utils:get_proxy_auth()),
+
+ %% proxy auth with regular username/password
+ os:putenv(ProxyEnvKey, Schema++"Username:Password@" ++ Host ++ Port),
+ rebar_utils:set_httpc_options(),
+ ?assertEqual([{proxy_auth, {"Username", "Password"}}],
+ rebar_utils:get_proxy_auth()),
+
+ %% proxy auth with username missing and url encoded password
+ os:putenv(ProxyEnvKey, Schema++":%3F!abc%23%24@" ++ Host ++ Port),
+ rebar_utils:set_httpc_options(),
+ ?assertEqual([{proxy_auth, {"", "?!abc#$"}}],
+ rebar_utils:get_proxy_auth()),
+
+ %% restore original proxy specification if any
+ restore_proxy_env(ProxyEnvKey, OldProxySpec),
+ application:unset_env(rebar, proxy_auth).
+
+restore_proxy_env(ProxyEnvKey, false) ->
+ os:putenv(ProxyEnvKey, "");
+restore_proxy_env(ProxyEnvKey, ProxySpec) ->
+ os:putenv(ProxyEnvKey, ProxySpec).
+
+is_list_of_strings(_Config) ->
+ ?assert(rebar_utils:is_list_of_strings(["foo"])),
+ ?assert(rebar_utils:is_list_of_strings([])),
+ ?assert(rebar_utils:is_list_of_strings("")),
+ ?assert(rebar_utils:is_list_of_strings("foo") == false).
diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl
index 75d6786..9f4bc7d 100644
--- a/test/rebar_xref_SUITE.erl
+++ b/test/rebar_xref_SUITE.erl
@@ -9,7 +9,9 @@
end_per_testcase/2,
all/0,
xref_test/1,
- xref_ignore_test/1]).
+ xref_ignore_test/1,
+ xref_dep_hook/1,
+ xref_undef_behaviour/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -28,6 +30,15 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
+init_per_testcase(xref_dep_hook, Config) ->
+ Src = filename:join([?config(data_dir, Config), "recursive"]),
+ Dst = filename:join([?config(priv_dir, Config), "recursive"]),
+ ok = rebar_file_utils:cp_r([Src], Dst),
+ GlobalDir = filename:join([?config(priv_dir, Config), "cache"]),
+ State = rebar_state:new([{base_dir, filename:join([Dst, "_build"])}
+ ,{global_rebar_dir, GlobalDir}
+ ,{root_dir, Dst}]),
+ [{apps, Dst}, {state, State} | Config];
init_per_testcase(Case, Config) ->
UpdConfig = rebar_test_utils:init_rebar_state(Config),
AppDir = ?config(apps, UpdConfig),
@@ -35,9 +46,11 @@ init_per_testcase(Case, Config) ->
Name = rebar_test_utils:create_random_name("xrefapp_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_empty_app(AppDir, Name, Vsn, [kernel, stdlib]),
- AppModules = [behaviour1, behaviour2, mymod, othermod],
+ AppModules = [behaviour1, behaviour2, mymod, othermod, ignoremod, ignoremod2],
[write_src_file(AppDir, Name, Module, ignore_xref(Case)) || Module <- AppModules],
+ IgnoreMod = list_to_atom(Name ++ "_" ++ "ignoremod"),
RebarConfig = [{erl_opts, [debug_info]},
+ {xref_ignores, [IgnoreMod]},
{xref_checks, [deprecated_function_calls,deprecated_functions,
undefined_function_calls,undefined_functions,
exports_not_used,locals_not_used]}],
@@ -48,7 +61,7 @@ end_per_testcase(_, _Config) ->
ok.
all() ->
- [xref_test, xref_ignore_test].
+ [xref_test, xref_ignore_test, xref_dep_hook, xref_undef_behaviour].
%% ===================================================================
%% Test cases
@@ -70,6 +83,20 @@ xref_ignore_test(Config) ->
Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
verify_results(xref_ignore_test, Name, Result).
+xref_dep_hook(Config) ->
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, []}).
+
+xref_undef_behaviour(Config) ->
+ AppDir = ?config(apps, Config),
+ State = ?config(state, Config),
+ Name = ?config(app_name, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ %% delete one of the behaviours, which should create new warnings
+ delete_src_file(AppDir, Name, behaviour1),
+ %% just ensure this does not crash
+ Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
+ verify_results(xref_undef_behaviour, Name, Result).
+
%% ===================================================================
%% Helper functions
%% ===================================================================
@@ -110,9 +137,35 @@ verify_test_results(xref_test, AppName, XrefResults, _QueryResults) ->
?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
ok;
+verify_test_results(xref_undef_behaviour, AppName, XrefResults, _QueryResults) ->
+ AppModules = ["behaviour2", "mymod", "othermod", "somemod"],
+ [Behaviour2Mod, MyMod, OtherMod, SomeMod] =
+ [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
+ UndefFuns = proplists:get_value(undefined_functions, XrefResults),
+ UndefFunCalls = proplists:get_value(undefined_function_calls, XrefResults),
+ LocalsNotUsed = proplists:get_value(locals_not_used, XrefResults),
+ ExportsNotUsed = proplists:get_value(exports_not_used, XrefResults),
+ DeprecatedFuns = proplists:get_value(deprecated_functions, XrefResults),
+ DeprecatedFunCalls = proplists:get_value(deprecated_function_calls, XrefResults),
+ ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {SomeMod, notavailable, 1}},
+ UndefFunCalls)),
+ ?assert(lists:member({MyMod, fdeprecated, 0}, DeprecatedFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {MyMod, fdeprecated, 0}},
+ DeprecatedFunCalls)),
+ ?assert(lists:member({MyMod, localfunc2, 0}, LocalsNotUsed)),
+ ?assert(lists:member({Behaviour2Mod, behaviour_info, 1}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, other2, 1}, ExportsNotUsed)),
+ ?assert(lists:member({OtherMod, somefunc, 0}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, bh1_a, 1}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, bh1_b, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
+ ok;
verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) ->
- AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
- [_Behaviour1Mod, _Behaviour2Mod, _MyMod, _OtherMod, SomeMod] =
+ AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod",
+ "ignoremod", "ignoremod2"],
+ [_Behaviour1Mod, _Behaviour2Mod, _MyMod, _OtherMod, SomeMod, IgnoreMod, IgnoreMod2] =
[list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
UndefFuns = proplists:get_value(undefined_functions, XrefResults),
?assertNot(lists:keymember(undefined_function_calls, 1, XrefResults)),
@@ -120,6 +173,8 @@ verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) ->
?assertNot(lists:keymember(exports_not_used, 1, XrefResults)),
?assertNot(lists:keymember(deprecated_functions, 1, XrefResults)),
?assertNot(lists:keymember(deprecated_function_calls, 1, XrefResults)),
+ ?assertNot(lists:member({IgnoreMod, notavailable, 1}, UndefFuns)),
+ ?assertNot(lists:member({IgnoreMod2, notavailable, 1}, UndefFuns)),
?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
ok.
@@ -128,19 +183,25 @@ write_src_file(Dir, AppName, Module, IgnoreXref) ->
ok = filelib:ensure_dir(Erl),
ok = ec_file:write(Erl, get_module_body(Module, AppName, IgnoreXref)).
+delete_src_file(Dir, AppName, Module) ->
+ Erl = filename:join([Dir, "src", module_name(AppName, Module)]),
+ ok = file:delete(Erl).
+
module_name(AppName, Module) ->
lists:flatten([AppName, "_", atom_to_list(Module), ".erl"]).
get_module_body(behaviour1, AppName, IgnoreXref) ->
["-module(", AppName, "_behaviour1).\n",
"-export([behaviour_info/1]).\n",
- ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
+ ["-ignore_xref([ignoremod,{behaviour_info,1}]).\n"
+ || X <- [IgnoreXref], X =:= true],
"behaviour_info(callbacks) -> [{bh1_a,1},{bh1_b,1}];\n",
"behaviour_info(_Other) -> undefined.\n"];
get_module_body(behaviour2, AppName, IgnoreXref) ->
["-module(", AppName, "_behaviour2).\n",
"-export([behaviour_info/1]).\n",
- ["-ignore_xref({behaviour_info,1}).\n" || X <- [IgnoreXref], X =:= true],
+ ["-ignore_xref({behaviour_info,1}).\n"
+ || X <- [IgnoreXref], X =:= true],
"behaviour_info(callbacks) -> [{bh2_a,1},{bh2_b,1}];\n",
"behaviour_info(_Other) -> undefined.\n"];
get_module_body(mymod, AppName, IgnoreXref) ->
@@ -150,7 +211,7 @@ get_module_body(mymod, AppName, IgnoreXref) ->
["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"
|| X <- [IgnoreXref], X =:= true],
"-behaviour(", AppName, "_behaviour1).\n", % 2 behaviours
- "-behaviour(", AppName, "_behaviour2).\n",
+ "-behavior(", AppName, "_behaviour2).\n",
"-deprecated({fdeprecated,0}).\n", % deprecated function
"bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions
"bh1_b(A) -> localfunc1(bh1_b, A).\n",
@@ -162,6 +223,26 @@ get_module_body(mymod, AppName, IgnoreXref) ->
"localfunc2() -> ok.\n", % unused local
"fdeprecated() -> ok.\n" % deprecated function
];
+get_module_body(ignoremod, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_ignoremod).\n",
+ "-export([]).\n",
+ [["-ignore_xref(", AppName, "_ignoremod).\n"]
+ || X <- [IgnoreXref], X =:= true],
+ "localfunc1(A, B) -> {A, B}.\n", % used local
+ "localfunc2() -> ok.\n", % unused local
+ "fdeprecated() -> ok.\n" % deprecated function
+
+ ];
+get_module_body(ignoremod2, AppName, IgnoreXref) ->
+ ["-module(", AppName, "_ignoremod2).\n",
+ "-export([]).\n",
+ [["-ignore_xref(", AppName, "_ignoremod2).\n"]
+ || X <- [IgnoreXref], X =:= true],
+ "localfunc1(A, B) -> {A, B}.\n", % used local
+ "localfunc2() -> ok.\n", % unused local
+ "fdeprecated() -> ok.\n" % deprecated function
+
+ ];
get_module_body(othermod, AppName, IgnoreXref) ->
["-module(", AppName, "_othermod).\n",
"-export([somefunc/0]).\n",
@@ -171,4 +252,5 @@ get_module_body(othermod, AppName, IgnoreXref) ->
"somefunc() ->\n",
" ", AppName, "_mymod:other1(arg),\n",
" ", AppName, "_somemod:notavailable(arg),\n",
- " ", AppName, "_mymod:fdeprecated().\n"].
+ " ", AppName, "_mymod:fdeprecated(),\n",
+ " ", AppName, "_ignoremod:notavailable().\n"].
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config
new file mode 100644
index 0000000..cf48edf
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config
@@ -0,0 +1,12 @@
+{erl_opts, [debug_info]}.
+{deps, []}.
+
+{xref_checks,[
+ undefined_function_calls,
+ undefined_functions,
+ locals_not_used,
+ deprecated_function_calls,
+ deprecated_functions
+]}.
+
+{provider_hooks, [{post, [{compile, xref}]}]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src
new file mode 100644
index 0000000..b935082
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src
@@ -0,0 +1,16 @@
+{application, rebar_issue1,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { rebar_issue1_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl
new file mode 100644
index 0000000..78c88c1
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue1 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue1_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ rebar_issue1_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl
new file mode 100644
index 0000000..6e5a9f8
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue1 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src
new file mode 100644
index 0000000..59ffa35
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src
@@ -0,0 +1,17 @@
+{application, rebar_issue2,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { rebar_issue2_app, []}},
+ {applications,
+ [kernel,
+ stdlib,
+ rebar_issue1
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl
new file mode 100644
index 0000000..968966c
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue2 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue2_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ rebar_issue2_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl
new file mode 100644
index 0000000..3673548
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue2 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================