summaryrefslogtreecommitdiff
path: root/src/rebar_prv_eunit.erl
diff options
context:
space:
mode:
authorTristan Sloughter <tristan.sloughter@gmail.com>2015-03-03 07:32:57 -0600
committerTristan Sloughter <tristan.sloughter@gmail.com>2015-03-03 07:32:57 -0600
commit358046b0957fc7211f5dab7d76f0bc365d00c439 (patch)
treef13157852e061f5184ce9727dd6051d1a85e56d9 /src/rebar_prv_eunit.erl
parent4c70d16e505c05695e902bea502855d8383fbe82 (diff)
parent6c421e543373aaf41a6ed10719f5da19b0cafd93 (diff)
Merge pull request #202 from talentdeficit/cover
`cover` task
Diffstat (limited to 'src/rebar_prv_eunit.erl')
-rw-r--r--src/rebar_prv_eunit.erl153
1 files changed, 74 insertions, 79 deletions
diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl
index cd1b0f8..d841f26 100644
--- a/src/rebar_prv_eunit.erl
+++ b/src/rebar_prv_eunit.erl
@@ -30,35 +30,20 @@ init(State) ->
{opts, eunit_opts(State)},
{profiles, [test]}]),
State1 = rebar_state:add_provider(State, Provider),
- {ok, State1}.
+ State2 = rebar_state:add_to_profile(State1, test, test_state(State1)),
+ {ok, State2}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
?INFO("Performing EUnit tests...", []),
- {RawOpts, _} = rebar_state:command_parsed_args(State),
- Opts = transform_opts(RawOpts, State),
- TestApps = filter_checkouts(rebar_state:project_apps(State)),
- OutDir = proplists:get_value(outdir, Opts, default_test_dir(State)),
- ?DEBUG("Compiling EUnit instrumented modules in: ~p", [OutDir]),
- lists:foreach(fun(App) ->
- AppDir = rebar_app_info:dir(App),
- AppOutDir = rebar_app_info:out_dir(App),
- C = rebar_config:consult(AppDir),
- S = rebar_state:new(State, C, AppDir),
- %% combine `erl_first_files` and `eunit_first_files` and adjust
- %% compile opts to include `eunit_compile_opts`, `{d, 'TEST'}`
- %% and `{src_dirs, "test"}`
- TestState = first_files(test_state(S, OutDir)),
- ok = rebar_erlc_compiler:compile(TestState, AppDir, AppOutDir)
- end, TestApps),
- ok = maybe_compile_extra_tests(TestApps, State, OutDir),
- Path = code:get_path(),
- true = code:add_patha(OutDir),
+ {Opts, _} = rebar_state:command_parsed_args(State),
EUnitOpts = resolve_eunit_opts(State, Opts),
- AppsToTest = [{application, erlang:binary_to_atom(rebar_app_info:name(App), unicode)}
- || App <- TestApps],
+ TestApps = filter_checkouts(rebar_state:project_apps(State)),
+ ok = compile_tests(State, TestApps),
+ ok = maybe_cover_compile(State, Opts),
+ AppsToTest = test_dirs(State, TestApps),
Result = eunit:test(AppsToTest, EUnitOpts),
- true = code:set_path(Path),
+ ok = rebar_prv_cover:maybe_write_coverdata(State, ?PROVIDER),
case handle_results(Result) of
{error, Reason} ->
{error, {?MODULE, Reason}};
@@ -73,24 +58,12 @@ format_error({error_running_tests, Reason}) ->
io_lib:format("Error running tests: ~p", [Reason]).
eunit_opts(_State) ->
- [{outdir, $o, "outdir", string, help(outdir)},
+ [{cover, $c, "cover", boolean, help(cover)},
{verbose, $v, "verbose", boolean, help(verbose)}].
-help(outdir) -> "Output directory for EUnit compiled modules";
+help(cover) -> "Generate cover data";
help(verbose) -> "Verbose output".
-transform_opts(Opts, State) -> transform_opts(Opts, State, []).
-
-transform_opts([], _State, Acc) -> Acc;
-transform_opts([{outdir, Path}|Rest], State, Acc) ->
- NewAcc = case filename:pathtype(Path) of
- absolute -> [{outdir, Path}] ++ Acc;
- _ -> [{outdir, filename:join([rebar_state:dir(State), Path])}] ++ Acc
- end,
- transform_opts(Rest, State, NewAcc);
-transform_opts([{Key, Val}|Rest], State, Acc) ->
- transform_opts(Rest, State, [{Key, Val}|Acc]).
-
filter_checkouts(Apps) -> filter_checkouts(Apps, []).
filter_checkouts([], Acc) -> lists:reverse(Acc);
@@ -102,30 +75,33 @@ filter_checkouts([App|Rest], Acc) ->
false -> filter_checkouts(Rest, [App|Acc])
end.
-default_test_dir(State) ->
- Tmp = rebar_file_utils:system_tmpdir(),
- Root = filename:join([rebar_state:dir(State), Tmp]),
- Project = filename:basename(rebar_state:dir(State)),
- OutDir = filename:join([Root, Project ++ "_rebar3_eunit"]),
- ok = rebar_file_utils:reset_dir(OutDir),
- OutDir.
-
-test_state(State, TmpDir) ->
- ErlOpts = rebar_state:get(State, eunit_compile_opts, []) ++
- rebar_utils:erl_opts(State),
- ErlOpts1 = [{outdir, TmpDir}] ++
- add_test_dir(ErlOpts),
- TestOpts = safe_define_test_macro(ErlOpts1),
- rebar_state:set(State, erl_opts, TestOpts).
-
-add_test_dir(Opts) ->
- %% if no src_dirs are set we have to specify `src` or it won't
- %% be built
- case proplists:append_values(src_dirs, Opts) of
- [] -> [{src_dirs, ["src", "test"]} | Opts];
- _ -> [{src_dirs, ["test"]} | Opts]
+resolve_eunit_opts(State, Opts) ->
+ EUnitOpts = rebar_state:get(State, eunit_opts, []),
+ case proplists:get_value(verbose, Opts, false) of
+ true -> set_verbose(EUnitOpts);
+ false -> EUnitOpts
+ end.
+
+test_dirs(State, TestApps) ->
+ %% we need to add "./ebin" if it exists but only if it's not already
+ %% due to be added
+ F = fun(App) -> rebar_app_info:dir(App) =/= rebar_dir:get_cwd() end,
+ BareEbin = filename:join([rebar_dir:base_dir(State), "ebin"]),
+ case lists:any(F, TestApps) andalso filelib:is_dir(BareEbin) of
+ false -> application_dirs(TestApps, []);
+ true -> [{dir, BareEbin}|application_dirs(TestApps, [])]
end.
+application_dirs([], Acc) -> lists:reverse(Acc);
+application_dirs([App|Rest], Acc) ->
+ AppName = list_to_atom(binary_to_list(rebar_app_info:name(App))),
+ application_dirs(Rest, [{application, AppName}|Acc]).
+
+test_state(State) ->
+ ErlOpts = rebar_state:get(State, eunit_compile_opts, []),
+ TestOpts = safe_define_test_macro(ErlOpts),
+ first_files(State) ++ [{erl_opts, TestOpts}].
+
safe_define_test_macro(Opts) ->
%% defining a compile macro twice results in an exception so
%% make sure 'TEST' is only defined once
@@ -140,39 +116,58 @@ test_defined([_|Rest]) -> test_defined(Rest);
test_defined([]) -> false.
first_files(State) ->
- BaseFirst = rebar_state:get(State, erl_first_files, []),
EUnitFirst = rebar_state:get(State, eunit_first_files, []),
- rebar_state:set(State, erl_first_files, BaseFirst ++ EUnitFirst).
-
-resolve_eunit_opts(State, Opts) ->
- EUnitOpts = rebar_state:get(State, eunit_opts, []),
- case lists:member({verbose, true}, Opts) of
- true -> set_verbose(EUnitOpts);
- false -> EUnitOpts
- end.
+ [{erl_first_files, EUnitFirst}].
set_verbose(Opts) ->
+ %% if `verbose` is already set don't set it again
case lists:member(verbose, Opts) of
true -> Opts;
false -> [verbose] ++ Opts
end.
-maybe_compile_extra_tests(TestApps, State, OutDir) ->
+compile_tests(State, TestApps) ->
+ State1 = replace_src_dirs(State),
+ F = fun(AppInfo) ->
+ AppDir = rebar_app_info:dir(AppInfo),
+ S = case rebar_app_info:state(AppInfo) of
+ undefined ->
+ C = rebar_config:consult(AppDir),
+ rebar_state:new(State1, C, AppDir);
+ AppState ->
+ AppState
+ end,
+ ok = rebar_erlc_compiler:compile(S,
+ ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
+ ec_cnv:to_list(rebar_app_info:out_dir(AppInfo)))
+ end,
+ lists:foreach(F, TestApps),
+ compile_bare_tests(State1, TestApps).
+
+compile_bare_tests(State, TestApps) ->
F = fun(App) -> rebar_app_info:dir(App) == rebar_dir:get_cwd() end,
case lists:filter(F, TestApps) of
- %% compile just the `test` and extra test directories of the base dir
- [] ->
- ErlOpts = rebar_state:get(State, common_test_compile_opts, []) ++
- rebar_utils:erl_opts(State),
- TestOpts = [{outdir, OutDir}] ++
- [{src_dirs, ["test"]}] ++
- safe_define_test_macro(lists:keydelete(src_dirs, 1, ErlOpts)),
- TestState = first_files(rebar_state:set(State, erl_opts, TestOpts)),
- rebar_erlc_compiler:compile(TestState, rebar_dir:get_cwd(), rebar_dir:get_cwd());
+ %% compile just the `test` directory of the base dir
+ [] -> rebar_erlc_compiler:compile(State,
+ rebar_dir:get_cwd(),
+ rebar_dir:base_dir(State));
%% already compiled `./test` so do nothing
- _ -> ok
+ _ -> ok
end.
+replace_src_dirs(State) ->
+ %% replace any `src_dirs` with just the `test` dir
+ ErlOpts = rebar_state:get(State, erl_opts, []),
+ StrippedOpts = lists:keydelete(src_dirs, 1, ErlOpts),
+ rebar_state:set(State, erl_opts, [{src_dirs, ["test"]}|StrippedOpts]).
+
+maybe_cover_compile(State, Opts) ->
+ State1 = case proplists:get_value(cover, Opts, false) of
+ true -> rebar_state:set(State, cover_enabled, true);
+ false -> State
+ end,
+ rebar_prv_cover:maybe_cover_compile(State1).
+
handle_results(ok) -> ok;
handle_results(error) ->
{error, unknown_error};