1: -module(gen_mod_deps_SUITE).
    2: -compile([export_all, nowarn_export_all]).
    3: 
    4: -include_lib("eunit/include/eunit.hrl").
    5: 
    6: -define(MODS, [mod_a, mod_b, mod_c, mod_d]).
    7: 
    8: all() ->
    9:     [
   10:      no_dependencies,
   11:      dependency,
   12:      dependency_chain,
   13:      dependency_dag,
   14:      fails_on_dependency_cycle,
   15:      succeeds_on_cycle_with_soft_dep_in_path,
   16:      succeeds_on_adding_soft_dependency_cycle_edge,
   17:      forces_dependency_opts,
   18:      appends_dependencies_opts,
   19:      optional_dependencies_are_not_started_by_themselves,
   20:      optional_dependencies_add_opts,
   21:      overrides_dependency_opts,
   22:      merges_dependency_opts
   23:     ].
   24: 
   25: %% Fixtures
   26: 
   27: init_per_testcase(_, C) ->
   28:     meck:new(?MODS, [non_strict]),
   29:     C.
   30: 
   31: end_per_testcase(_, _C) ->
   32:     meck:unload(?MODS).
   33: 
   34: %% Tests
   35: 
   36: no_dependencies(_Config) ->
   37:     Modules = #{mod_a => #{}, mod_b => #{}},
   38:     ?assertEqual(Modules, maps:from_list(add_deps(Modules))).
   39: 
   40: dependency(_Config) ->
   41:     set_deps(#{mod_a => [{mod_b, #{}, hard}]}),
   42:     ?assertMatch([{mod_b, _}, {mod_a, _}], add_deps(#{mod_a => #{}})).
   43: 
   44: dependency_chain(_Config) ->
   45:     set_deps(#{mod_a => [{mod_b, #{}, hard}], mod_b => [{mod_c, #{}, hard}]}),
   46:     ?assertMatch([{mod_c, _}, {mod_b, _}, {mod_a, _}], add_deps(#{mod_a => #{}})).
   47: 
   48: dependency_dag(_Config) ->
   49:     set_deps(#{mod_a => [{mod_b, #{}, hard}, {mod_c, #{}, hard}],
   50:                mod_b => [{mod_c, #{}, hard}]}),
   51:     ?assertMatch([{mod_c, _}, {mod_b, _}, {mod_a, _}], add_deps(#{mod_a => #{}})).
   52: 
   53: fails_on_dependency_cycle(_Config) ->
   54:     set_deps(#{mod_a => [{mod_b, #{}, hard}],
   55:                mod_b => [{mod_c, #{}, hard}],
   56:                mod_c => [{mod_a, #{}, hard}]}),
   57:     ?assertError(_, add_deps(#{mod_a => #{}})).
   58: 
   59: succeeds_on_cycle_with_soft_dep_in_path(_Config) ->
   60:     set_deps(#{mod_a => [{mod_b, #{}, hard}],
   61:                mod_b => [{mod_c, #{}, soft}],
   62:                mod_c => [{mod_a, #{}, hard}]}),
   63:     ?assertMatch([{mod_b, _}, {mod_a, _}, {mod_c, _}], add_deps(#{mod_a => #{}})).
   64: 
   65: succeeds_on_adding_soft_dependency_cycle_edge(_Config) ->
   66:     set_deps(#{mod_a => [{mod_b, #{}, hard}], mod_b => [{mod_a, #{}, soft}]}),
   67:     ?assertMatch([{mod_b, _}, {mod_a, _}], add_deps(#{mod_a => #{}})).
   68: 
   69: forces_dependency_opts(_Config) ->
   70:     set_deps(#{mod_a => [{mod_b, #{opt1 => 1, opt2 => 2}, hard}]}),
   71:     ?assertEqual([{mod_b, #{opt1 => 1, opt2 => 2}}, {mod_a, #{}}], add_deps(#{mod_a => #{}})).
   72: 
   73: appends_dependencies_opts(_Config) ->
   74:     set_deps(#{mod_a => [{mod_b, #{}, hard}, {mod_c, #{opt1 => 1}, hard}],
   75:                mod_b => [{mod_c, #{opt2 => 2}, hard}]}),
   76:     ?assertEqual([{mod_c, #{opt1 => 1, opt2 => 2}}, {mod_b, #{}}, {mod_a, #{}}],
   77:                  add_deps(#{mod_a => #{}})).
   78: 
   79: optional_dependencies_are_not_started_by_themselves(_Config) ->
   80:     set_deps(#{mod_a => [{mod_b, #{}, optional}]}),
   81:     ?assertMatch([{mod_a, _}], add_deps(#{mod_a => #{}})).
   82: 
   83: optional_dependencies_add_opts(_Config) ->
   84:     set_deps(#{mod_a => [{mod_b, #{opt1 => 1}, optional}], mod_c => [{mod_b, #{}, hard}]}),
   85:     ?assertMatch([{mod_b, #{opt1 := 1}}, {mod_a, _}, {mod_c, _}],
   86:                  add_deps(#{mod_a => #{}, mod_c => #{}})).
   87: 
   88: overrides_dependency_opts(_Config) ->
   89:     set_deps(#{mod_a => [{mod_b, #{}, hard}, {mod_c, #{opt1 => 2}, hard}],
   90:                mod_b => [{mod_c, #{opt1 => 1}, hard}]}),
   91:     ?assertMatch([{mod_c, #{opt1 := 2}}, {mod_b, _}, {mod_a, _}], add_deps(#{mod_a => #{}})).
   92: 
   93: merges_dependency_opts(_Config) ->
   94:     set_deps(#{mod_a => [{mod_b, #{}, hard}, {mod_c, #{opt1 => 1}, hard}],
   95:                mod_b => [{mod_c, #{opt1 => 1, opt2 => 2}, hard}]}),
   96:     ?assertMatch([{mod_c, #{opt1 := 1, opt2 := 2}}, {mod_b, _}, {mod_a, _}],
   97:                  add_deps(#{mod_a => #{}})).
   98: 
   99: %% Helpers
  100: 
  101: set_deps(DepsMap) ->
  102:     maps:fold(fun(Mod, Deps, _) -> meck:expect(Mod, deps, fun(_, _) -> Deps end) end,
  103:               undefined, DepsMap).
  104: 
  105: add_deps(Modules) ->
  106:     gen_mod_deps:add_deps(<<"host">>, Modules).