|
|
@ -4,16 +4,24 @@ |
|
|
|
-include_lib("eunit/include/eunit.hrl"). |
|
|
|
-include_lib("kernel/include/file.hrl"). |
|
|
|
|
|
|
|
all() -> [{group, git}, {group, pkg}]. |
|
|
|
all() -> [{group, git}, {group, pkg}, {group, mixed}]. |
|
|
|
|
|
|
|
groups() -> |
|
|
|
[{all, [], [flat, pick_highest_left, pick_highest_right, |
|
|
|
pick_smallest1, pick_smallest2, |
|
|
|
circular1, circular2, circular_skip, |
|
|
|
fail_conflict, default_profile, nondefault_profile, |
|
|
|
nondefault_pick_highest]}, |
|
|
|
{git, [], [{group, all}]}, |
|
|
|
{pkg, [], [{group, all}]}]. |
|
|
|
[{unique, [], [flat, pick_highest_left, pick_highest_right, |
|
|
|
pick_smallest1, pick_smallest2, |
|
|
|
circular1, circular2, circular_skip, |
|
|
|
fail_conflict, default_profile, nondefault_profile, |
|
|
|
nondefault_pick_highest]}, |
|
|
|
{git, [], [{group, unique}]}, |
|
|
|
{pkg, [], [{group, unique}]}, |
|
|
|
{mixed, [], [ |
|
|
|
m_flat1, m_flat2, m_circular1, m_circular2, m_circular3, |
|
|
|
m_pick_source1, m_pick_source2, m_pick_source3, |
|
|
|
m_pick_source4, m_pick_source5, m_source_to_pkg, |
|
|
|
m_pkg_level1, m_pkg_level2, |
|
|
|
m_pkg_src_override |
|
|
|
]} |
|
|
|
]. |
|
|
|
|
|
|
|
init_per_suite(Config) -> |
|
|
|
application:start(meck), |
|
|
@ -26,19 +34,33 @@ init_per_group(git, Config) -> |
|
|
|
[{deps_type, git} | Config]; |
|
|
|
init_per_group(pkg, Config) -> |
|
|
|
[{deps_type, pkg} | Config]; |
|
|
|
init_per_group(mixed, Config) -> |
|
|
|
[{deps_type, mixed} | Config]; |
|
|
|
init_per_group(_, Config) -> |
|
|
|
Config. |
|
|
|
|
|
|
|
end_per_group(_, Config) -> |
|
|
|
Config. |
|
|
|
|
|
|
|
init_per_testcase(Case, Config) -> |
|
|
|
init_per_testcase(Case, Config) when is_atom(Case) -> |
|
|
|
DepsType = ?config(deps_type, Config), |
|
|
|
init_per_testcase({DepsType, Case}, Config); |
|
|
|
init_per_testcase({mixed, Case}, Config) -> |
|
|
|
{Deps, Warnings, Expect} = mdeps(Case), |
|
|
|
Expected = case Expect of |
|
|
|
{ok, List} -> {ok, format_expected_mdeps(List)}; |
|
|
|
Other -> Other |
|
|
|
end, |
|
|
|
mock_warnings(), |
|
|
|
[{expect, Expected}, |
|
|
|
{warnings, format_expected_mixed_warnings(Warnings)} |
|
|
|
| setup_project(Case, Config, rebar_test_utils:expand_deps(mixed, Deps))]; |
|
|
|
init_per_testcase({DepsType, Case}, Config) -> |
|
|
|
{Deps, Warnings, Expect} = deps(Case), |
|
|
|
Expected = case Expect of |
|
|
|
{ok, List} -> {ok, format_expected_deps(List)}; |
|
|
|
Other -> Other |
|
|
|
end, |
|
|
|
DepsType = ?config(deps_type, Config), |
|
|
|
mock_warnings(), |
|
|
|
[{expect, Expected}, |
|
|
|
{warnings, Warnings} |
|
|
@ -54,6 +76,32 @@ format_expected_deps(Deps) -> |
|
|
|
N -> [{dep, N}, {lock, N}] |
|
|
|
end || Dep <- Deps]). |
|
|
|
|
|
|
|
format_expected_mdeps(Deps) -> |
|
|
|
%% for mixed deps, lowercase is a package, uppercase is source. |
|
|
|
%% We can't check which was used from the dep, but the lock contains |
|
|
|
%% the type and we can use that information. |
|
|
|
lists:append([ |
|
|
|
case Dep of |
|
|
|
{N,V} when hd(N) >= $a, hd(N) =< $z -> |
|
|
|
UN = string:to_upper(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), |
|
|
|
[{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(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 -> {src, 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 -> {src, N, "0.0.0"} |
|
|
|
end || W <- Warnings]. |
|
|
|
|
|
|
|
%% format: |
|
|
|
%% {Spec, |
|
|
|
%% [Warning], |
|
|
@ -131,6 +179,79 @@ deps(nondefault_pick_highest) -> |
|
|
|
%% This is all handled in setup_project |
|
|
|
{[],[],{ok,[]}}. |
|
|
|
|
|
|
|
%% format: |
|
|
|
%% Same as `deps/1' except "A" is a source dep |
|
|
|
%% and "a" is a package dep. |
|
|
|
mdeps(m_flat1) -> |
|
|
|
{[{"c", []}, |
|
|
|
{"B", []}], |
|
|
|
[], |
|
|
|
{ok, ["B","c"]}}; |
|
|
|
mdeps(m_flat2) -> |
|
|
|
{[{"B", []}, |
|
|
|
{"c", []}], |
|
|
|
[], |
|
|
|
{ok, ["B","c"]}}; |
|
|
|
mdeps(m_circular1) -> |
|
|
|
{[{"b", [{"a",[]}]}], % "A" is the top app |
|
|
|
[], |
|
|
|
{error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}}; |
|
|
|
mdeps(m_circular2) -> |
|
|
|
{[{"B", [{"c", [{"b", []}]}]}], |
|
|
|
[], |
|
|
|
{error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}}; |
|
|
|
mdeps(m_circular3) -> |
|
|
|
%% Spot the circular dep due to being to low in the deps tree |
|
|
|
%% but as a source dep, taking precedence over packages |
|
|
|
{[{"B", [{"C", "2", [{"B", []}]}]}, |
|
|
|
{"c", "1", [{"d",[]}]}], |
|
|
|
[], |
|
|
|
{error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}}; |
|
|
|
mdeps(m_pick_source1) -> |
|
|
|
{[{"B", [{"D", []}]}, |
|
|
|
{"c", [{"d", []}]}], |
|
|
|
["d"], |
|
|
|
{ok, ["B", "c", "D"]}}; |
|
|
|
mdeps(m_pick_source2) -> |
|
|
|
{[{"b", [{"d", []}]}, |
|
|
|
{"C", [{"D", []}]}], |
|
|
|
["d"], |
|
|
|
{ok, ["b", "C", "D"]}}; |
|
|
|
mdeps(m_pick_source3) -> |
|
|
|
%% The order of declaration is important. |
|
|
|
{[{"b", []}, |
|
|
|
{"B", []}], |
|
|
|
["B"], |
|
|
|
{ok, ["b"]}}; |
|
|
|
mdeps(m_pick_source4) -> |
|
|
|
{[{"B", []}, |
|
|
|
{"b", []}], |
|
|
|
["b"], |
|
|
|
{ok, ["B"]}}; |
|
|
|
mdeps(m_pick_source5) -> |
|
|
|
{[{"B", [{"d", []}]}, |
|
|
|
{"C", [{"D", []}]}], |
|
|
|
["d"], |
|
|
|
{ok, ["B", "C", "D"]}}; |
|
|
|
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"}]}}; |
|
|
|
mdeps(m_pkg_level2) -> |
|
|
|
{[{"B", [{"e", "1", []}]}, |
|
|
|
{"C", [{"D", [{"e", "2", []}]}]}], |
|
|
|
[{"e","2"}], |
|
|
|
{ok, ["B","C","D",{"e","1"}]}}; |
|
|
|
mdeps(m_pkg_src_override) -> |
|
|
|
%% This is all handled in setup_project |
|
|
|
{[],[],{ok,[]}}. |
|
|
|
|
|
|
|
|
|
|
|
setup_project(fail_conflict, Config0, Deps) -> |
|
|
|
DepsType = ?config(deps_type, Config0), |
|
|
|
Config = rebar_test_utils:init_rebar_state( |
|
|
@ -142,12 +263,9 @@ setup_project(fail_conflict, Config0, Deps) -> |
|
|
|
TopDeps = rebar_test_utils:top_level_deps(Deps), |
|
|
|
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}, |
|
|
|
{deps_error_on_conflict, true}]), |
|
|
|
case DepsType of |
|
|
|
git -> |
|
|
|
mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]); |
|
|
|
pkg -> |
|
|
|
mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}]) |
|
|
|
end, |
|
|
|
{SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps), |
|
|
|
mock_git_resource:mock([{deps, SrcDeps}]), |
|
|
|
mock_pkg_resource:mock([{pkgdeps, PkgDeps}]), |
|
|
|
[{rebarconfig, RebarConf} | Config]; |
|
|
|
setup_project(nondefault_profile, Config0, Deps) -> |
|
|
|
DepsType = ?config(deps_type, Config0), |
|
|
@ -161,12 +279,9 @@ setup_project(nondefault_profile, Config0, Deps) -> |
|
|
|
RebarConf = rebar_test_utils:create_config(AppDir, [{profiles, [ |
|
|
|
{nondef, [{deps, TopDeps}]} |
|
|
|
]}]), |
|
|
|
case DepsType of |
|
|
|
git -> |
|
|
|
mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]); |
|
|
|
pkg -> |
|
|
|
mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}]) |
|
|
|
end, |
|
|
|
{SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps), |
|
|
|
mock_git_resource:mock([{deps, SrcDeps}]), |
|
|
|
mock_pkg_resource:mock([{pkgdeps, PkgDeps}]), |
|
|
|
[{rebarconfig, RebarConf} | Config]; |
|
|
|
setup_project(nondefault_pick_highest, Config0, _) -> |
|
|
|
DepsType = ?config(deps_type, Config0), |
|
|
@ -187,15 +302,30 @@ setup_project(nondefault_pick_highest, Config0, _) -> |
|
|
|
), |
|
|
|
case DepsType of |
|
|
|
git -> |
|
|
|
mock_git_resource:mock( |
|
|
|
[{deps, rebar_test_utils:flat_deps(DefaultDeps ++ ProfileDeps)}] |
|
|
|
); |
|
|
|
{SrcDeps, _} = rebar_test_utils:flat_deps(DefaultDeps++ProfileDeps), |
|
|
|
mock_git_resource:mock([{deps, SrcDeps}]); |
|
|
|
pkg -> |
|
|
|
mock_pkg_resource:mock( |
|
|
|
[{pkgdeps, rebar_test_utils:flat_pkgdeps(DefaultDeps ++ ProfileDeps)}] |
|
|
|
) |
|
|
|
{_, PkgDeps} = rebar_test_utils:flat_deps(DefaultDeps++ProfileDeps), |
|
|
|
mock_pkg_resource:mock([{pkgdeps, PkgDeps}]) |
|
|
|
end, |
|
|
|
[{rebarconfig, RebarConf} | Config]; |
|
|
|
setup_project(m_pkg_src_override, Config0, _) -> |
|
|
|
Config = rebar_test_utils:init_rebar_state(Config0, "m_pkg_src_override_mixed_"), |
|
|
|
AppDir = ?config(apps, Config), |
|
|
|
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), |
|
|
|
DefaultDeps = rebar_test_utils:expand_deps(mixed, [{"b", [{"c", []}]}]), |
|
|
|
OverrideDeps = rebar_test_utils:expand_deps(mixed, [{"C", []}]), |
|
|
|
DefaultTop = rebar_test_utils:top_level_deps(DefaultDeps), |
|
|
|
OverrideTop = rebar_test_utils:top_level_deps(OverrideDeps), |
|
|
|
RebarConf = rebar_test_utils:create_config( |
|
|
|
AppDir, |
|
|
|
[{deps, DefaultTop}, |
|
|
|
{overrides, [{override, b, [{deps, OverrideTop}]}]}] |
|
|
|
), |
|
|
|
{SrcDeps,PkgDeps} = rebar_test_utils:flat_deps(DefaultDeps++OverrideDeps), |
|
|
|
mock_git_resource:mock([{deps, SrcDeps}]), |
|
|
|
mock_pkg_resource:mock([{pkgdeps, PkgDeps}]), |
|
|
|
[{rebarconfig, RebarConf} | Config]; |
|
|
|
setup_project(Case, Config0, Deps) -> |
|
|
|
DepsType = ?config(deps_type, Config0), |
|
|
|
Config = rebar_test_utils:init_rebar_state( |
|
|
@ -206,12 +336,9 @@ setup_project(Case, Config0, Deps) -> |
|
|
|
rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), |
|
|
|
TopDeps = rebar_test_utils:top_level_deps(Deps), |
|
|
|
RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]), |
|
|
|
case DepsType of |
|
|
|
git -> |
|
|
|
mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]); |
|
|
|
pkg -> |
|
|
|
mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}]) |
|
|
|
end, |
|
|
|
{SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps), |
|
|
|
mock_git_resource:mock([{deps, SrcDeps}]), |
|
|
|
mock_pkg_resource:mock([{pkgdeps, PkgDeps}]), |
|
|
|
[{rebarconfig, RebarConf} | Config]. |
|
|
|
|
|
|
|
mock_warnings() -> |
|
|
@ -319,6 +446,33 @@ nondefault_pick_highest(Config) -> |
|
|
|
{ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "2"}], "nondef"} |
|
|
|
). |
|
|
|
|
|
|
|
m_flat1(Config) -> run(Config). |
|
|
|
m_flat2(Config) -> run(Config). |
|
|
|
m_circular1(Config) -> run(Config). |
|
|
|
m_circular2(Config) -> run(Config). |
|
|
|
m_circular3(Config) -> run(Config). |
|
|
|
m_pick_source1(Config) -> run(Config). |
|
|
|
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_source_to_pkg(Config) -> run(Config). |
|
|
|
m_pkg_level1(Config) -> run(Config). |
|
|
|
m_pkg_level2(Config) -> run(Config). |
|
|
|
|
|
|
|
|
|
|
|
m_pkg_src_override(Config) -> |
|
|
|
%% Detect the invalid override where a package dep's are overriden |
|
|
|
%% with source dependencies. We only test with overrides because |
|
|
|
%% we trust the package index to be correct there and not introduce |
|
|
|
%% that kind of error. |
|
|
|
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), |
|
|
|
rebar_test_utils:run_and_check( |
|
|
|
Config, RebarConfig, ["lock"], |
|
|
|
{error, {rebar_prv_install_deps, |
|
|
|
{package_dep_override, <<"b">>}}} |
|
|
|
). |
|
|
|
|
|
|
|
run(Config) -> |
|
|
|
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), |
|
|
|
rebar_test_utils:run_and_check( |
|
|
@ -336,6 +490,10 @@ error_calls() -> |
|
|
|
|
|
|
|
check_warnings(_, [], _) -> |
|
|
|
ok; |
|
|
|
check_warnings(Warns, [{Type, Name, Vsn} | Rest], mixed) -> |
|
|
|
ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]), |
|
|
|
?assert(in_warnings(Type, Warns, Name, Vsn)), |
|
|
|
check_warnings(Warns, 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)), |
|
|
|