From e8ec6810b88ede7f252715e9bfc19d87238818ae Mon Sep 17 00:00:00 2001 From: mopp Date: Wed, 14 Nov 2018 16:22:09 +0900 Subject: Add --generator option for eunit --- src/rebar_prv_eunit.erl | 44 +++++++++++++++++++++++++++++++++----------- test/rebar_eunit_SUITE.erl | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index f120926..d8136a2 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -40,14 +40,18 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - Tests = prepare_tests(State), - %% inject `eunit_first_files`, `eunit_compile_opts` and any - %% directories required by tests into the applications - NewState = inject_eunit_state(State, Tests), - case compile(NewState) of - %% successfully compiled apps - {ok, S} -> do(S, Tests); - Error -> Error + try + Tests = prepare_tests(State), + %% inject `eunit_first_files`, `eunit_compile_opts` and any + %% directories required by tests into the applications + NewState = inject_eunit_state(State, Tests), + case compile(NewState) of + %% successfully compiled apps + {ok, S} -> do(S, Tests); + Error -> Error + end + catch + throw:Reason -> {error, Reason} end. do(State, Tests) -> @@ -134,17 +138,28 @@ resolve_tests(State) -> Files = resolve(file, RawOpts), Modules = resolve(module, RawOpts), Suites = resolve(suite, module, RawOpts), - Apps ++ Applications ++ Dirs ++ Files ++ Modules ++ Suites. + Generator = resolve(generator, RawOpts), + Apps ++ Applications ++ Dirs ++ Files ++ Modules ++ Suites ++ Generator. resolve(Flag, RawOpts) -> resolve(Flag, Flag, RawOpts). resolve(Flag, EUnitKey, RawOpts) -> case proplists:get_value(Flag, RawOpts) of undefined -> []; - Args -> lists:map(fun(Arg) -> normalize(EUnitKey, Arg) end, - rebar_string:lexemes(Args, [$,])) + Args -> + lists:flatten(lists:map(fun(Arg) -> normalize(EUnitKey, Arg) end, + rebar_string:lexemes(Args, [$,]))) end. +normalize(generator, Value) -> + case string:tokens(Value, [$:]) of + [Module0, Functions] -> + Module = list_to_atom(Module0), + lists:map(fun(F) -> {generator, Module, list_to_atom(F)} end, + string:tokens(Functions, [$;])); + _ -> + throw(lists:concat(["Generator `", Value, "' is invalid format."])) + end; normalize(Key, Value) when Key == dir; Key == file -> {Key, Value}; normalize(Key, Value) -> {Key, list_to_atom(Value)}. @@ -353,6 +368,8 @@ validate(State, {module, Module}) -> validate_module(State, Module); validate(State, {suite, Module}) -> validate_module(State, Module); +validate(State, {generator, Module, Function}) -> + validate_generator(State, Module, Function); validate(State, Module) when is_atom(Module) -> validate_module(State, Module); validate(State, Path) when is_list(Path) -> @@ -395,6 +412,9 @@ validate_module(_State, Module) -> _ -> ok end. +validate_generator(State, Module, _Function) -> + validate_module(State, Module). + resolve_eunit_opts(State) -> {Opts, _} = rebar_state:command_parsed_args(State), EUnitOpts = rebar_state:get(State, eunit_opts, []), @@ -490,6 +510,7 @@ eunit_opts(_State) -> {file, $f, "file", string, help(file)}, {module, $m, "module", string, help(module)}, {suite, $s, "suite", string, help(module)}, + {generator, $g, "generator", string, help(generator)}, {verbose, $v, "verbose", boolean, help(verbose)}, {name, undefined, "name", atom, help(name)}, {sname, undefined, "sname", atom, help(sname)}, @@ -501,6 +522,7 @@ help(cover_export_name) -> "Base name of the coverdata file to write"; help(dir) -> "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`."; help(file) -> "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`."; help(module) -> "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`."; +help(generator) -> "Comma separated list of generators (the format is `module:function`) to load tests from. Equivalent to `[{generator, Module, Function}]`."; help(verbose) -> "Verbose output. Defaults to false."; help(name) -> "Gives a long name to the node"; help(sname) -> "Gives a short name to the node"; diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl index 1a8bade..87dd3ed 100644 --- a/test/rebar_eunit_SUITE.erl +++ b/test/rebar_eunit_SUITE.erl @@ -13,6 +13,7 @@ -export([single_application_arg/1, multi_application_arg/1, missing_application_arg/1]). -export([single_module_arg/1, multi_module_arg/1, missing_module_arg/1]). -export([single_suite_arg/1, multi_suite_arg/1, missing_suite_arg/1]). +-export([single_generator_arg/1, multi_generator_arg/1, missing_generator_arg/1]). -export([single_file_arg/1, multi_file_arg/1, missing_file_arg/1]). -export([single_dir_arg/1, multi_dir_arg/1, missing_dir_arg/1]). -export([multiple_arg_composition/1, multiple_arg_errors/1]). @@ -47,6 +48,7 @@ groups() -> single_application_arg, multi_application_arg, missing_application_arg, single_module_arg, multi_module_arg, missing_module_arg, single_suite_arg, multi_suite_arg, missing_suite_arg, + single_generator_arg, multi_generator_arg, missing_generator_arg, single_file_arg, multi_file_arg, missing_file_arg, single_dir_arg, multi_dir_arg, missing_dir_arg, multiple_arg_composition, multiple_arg_errors]}]. @@ -239,7 +241,7 @@ multi_app_testset(Config) -> Set = {ok, [{application, multi_app_baz}, {application, multi_app_bar}, {module, multi_app_bar_tests_helper}, - {module, multi_app_baz_tests_helper}, + {module, multi_app_baz_tests_helper}, {module, multi_app_tests}, {module, multi_app_tests_helper}]}, Set = rebar_prv_eunit:prepare_tests(Result). @@ -404,6 +406,37 @@ missing_suite_arg(Config) -> Error = {error, {rebar_prv_eunit, {eunit_test_errors, ["Module `missing_app' not found in project."]}}}, Error = rebar_prv_eunit:validate_tests(State, rebar_prv_eunit:prepare_tests(State)). +%% check that the --generator cmd line opt generates the correct test set +single_generator_arg(Config) -> + S = ?config(result, Config), + + {ok, Args} = getopt:parse(rebar_prv_eunit:eunit_opts(S), ["--generator=module_name:function_name"]), + State = rebar_state:command_parsed_args(S, Args), + + {ok, [{generator, module_name, function_name}]} = rebar_prv_eunit:prepare_tests(State). + +multi_generator_arg(Config) -> + S = ?config(result, Config), + + {ok, Args} = getopt:parse(rebar_prv_eunit:eunit_opts(S), ["--generator=module1:func1;func2,module2:func1;func2"]), + State = rebar_state:command_parsed_args(S, Args), + + Generators = [{generator, module1, func1}, + {generator, module1, func2}, + {generator, module2, func1}, + {generator, module2, func2}], + {ok, Generators} = rebar_prv_eunit:prepare_tests(State). + +%% check that an invalid --suite cmd line opt generates an error +missing_generator_arg(Config) -> + S = ?config(result, Config), + + {ok, Args} = getopt:parse(rebar_prv_eunit:eunit_opts(S), ["--generator=missing_module:func1"]), + State = rebar_state:command_parsed_args(S, Args), + + Error = {error, {rebar_prv_eunit, {eunit_test_errors, ["Module `missing_module' not found in project."]}}}, + Error = rebar_prv_eunit:validate_tests(State, rebar_prv_eunit:prepare_tests(State)). + %% check that the --file cmd line opt generates the correct test set single_file_arg(Config) -> S = ?config(result, Config), -- cgit v1.1 From 088487bab570ee59e6e262d703735fea681c341c Mon Sep 17 00:00:00 2001 From: mopp Date: Sat, 29 Dec 2018 19:09:11 +0900 Subject: Append --generator option to completion files --- priv/shell-completion/bash/rebar3 | 4 ++-- priv/shell-completion/fish/rebar3.fish | 1 + priv/shell-completion/zsh/_rebar3 | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/priv/shell-completion/bash/rebar3 b/priv/shell-completion/bash/rebar3 index be9af44..41c45f2 100644 --- a/priv/shell-completion/bash/rebar3 +++ b/priv/shell-completion/bash/rebar3 @@ -93,8 +93,8 @@ _rebar3() elif [[ ${prev} == escriptize ]] ; then : elif [[ ${prev} == eunit ]] ; then - sopts="-c -e -v -d -f -m -s" - lopts="--app --application --cover --dir --error_on_warning --file --module --suite --verbose" + sopts="-c -e -v -d -f -m -s -g" + lopts="--app --application --cover --dir --error_on_warning --file --module --suite --generator --verbose" elif [[ ${prev} == help ]] ; then : elif [[ ${prev} == new ]] ; then diff --git a/priv/shell-completion/fish/rebar3.fish b/priv/shell-completion/fish/rebar3.fish index 9cd2c82..e578b96 100644 --- a/priv/shell-completion/fish/rebar3.fish +++ b/priv/shell-completion/fish/rebar3.fish @@ -136,6 +136,7 @@ complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunut' -s e -l error_on_ complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s f -l file -d "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s m -l module -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s s -l suite -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" +complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s g -l generator -d "Comma separated list of generators (the format is `module:function`) to load tests from. Equivalent to `[{generator, Module, Function}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s v -l verbose -d "Verbose output" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l suite -d "Lists of test suites to run" diff --git a/priv/shell-completion/zsh/_rebar3 b/priv/shell-completion/zsh/_rebar3 index 490a824..8ae8777 100644 --- a/priv/shell-completion/zsh/_rebar3 +++ b/priv/shell-completion/zsh/_rebar3 @@ -95,6 +95,7 @@ _rebar3 () { '(-f --file)'{-f,--file}'[Comma separated list of files to load tests from]:files' \ '(-m --module)'{-m,--module}'[Comma separated list of modules to load tests from]:modules' \ '(-s --suite)'{-s,--suite}'[Comma separated list of modules to load tests from]:modules' \ + '(-g --generator)'{-g,--generator}'[Comma separated list of generators (the format is `module:function`) to load tests from.]:{generator, Module, Function}' \ '(-v --verbose)'{-v,--verbose}'[Verbose output]' \ && ret=0 ;; -- cgit v1.1 From 3071319c43c6a8e06f1536bf573584cc402c388e Mon Sep 17 00:00:00 2001 From: mopp Date: Sun, 30 Dec 2018 00:48:58 +0900 Subject: Use ?PRV_ERROR instead of throwing error --- src/rebar_prv_eunit.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index d8136a2..fe0caa2 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -158,7 +158,7 @@ normalize(generator, Value) -> lists:map(fun(F) -> {generator, Module, list_to_atom(F)} end, string:tokens(Functions, [$;])); _ -> - throw(lists:concat(["Generator `", Value, "' is invalid format."])) + ?PRV_ERROR({generator, {"Generator `~p` is invalid format", {Value}}}) end; normalize(Key, Value) when Key == dir; Key == file -> {Key, Value}; normalize(Key, Value) -> {Key, list_to_atom(Value)}. -- cgit v1.1 From ab68f3df269a9254ac08806b34a6f826f0177e02 Mon Sep 17 00:00:00 2001 From: mopp Date: Sun, 30 Dec 2018 00:59:41 +0900 Subject: Revert try-catch --- src/rebar_prv_eunit.erl | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index fe0caa2..4cb982e 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -40,18 +40,14 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - try - Tests = prepare_tests(State), - %% inject `eunit_first_files`, `eunit_compile_opts` and any - %% directories required by tests into the applications - NewState = inject_eunit_state(State, Tests), - case compile(NewState) of - %% successfully compiled apps - {ok, S} -> do(S, Tests); - Error -> Error - end - catch - throw:Reason -> {error, Reason} + Tests = prepare_tests(State), + %% inject `eunit_first_files`, `eunit_compile_opts` and any + %% directories required by tests into the applications + NewState = inject_eunit_state(State, Tests), + case compile(NewState) of + %% successfully compiled apps + {ok, S} -> do(S, Tests); + Error -> Error end. do(State, Tests) -> -- cgit v1.1 From 44b250c174a2e5c0e0c671c958951a2c280a0524 Mon Sep 17 00:00:00 2001 From: mopp Date: Sun, 30 Dec 2018 02:59:29 +0900 Subject: Use format_error/1 --- src/rebar_prv_eunit.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 4cb982e..b2f307e 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -105,6 +105,8 @@ format_error({eunit_test_errors, Errors}) -> lists:map(fun(Error) -> "~n " ++ Error end, Errors)), []); format_error({badconfig, {Msg, {Value, Key}}}) -> io_lib:format(Msg, [Value, Key]); +format_error({generator, Value}) -> + io_lib:format("Generator ~p has an invalid format", [Value]); format_error({error, Error}) -> format_error({error_running_tests, Error}). @@ -154,7 +156,7 @@ normalize(generator, Value) -> lists:map(fun(F) -> {generator, Module, list_to_atom(F)} end, string:tokens(Functions, [$;])); _ -> - ?PRV_ERROR({generator, {"Generator `~p` is invalid format", {Value}}}) + ?PRV_ERROR({generator, Value}) end; normalize(Key, Value) when Key == dir; Key == file -> {Key, Value}; normalize(Key, Value) -> {Key, list_to_atom(Value)}. -- cgit v1.1 From ecd5e1342a99241e71d809b2172fc1a6f4dd41ba Mon Sep 17 00:00:00 2001 From: mopp Date: Sun, 30 Dec 2018 04:04:03 +0900 Subject: Refactor normalize --- src/rebar_prv_eunit.erl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index b2f307e..0b00e89 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -144,12 +144,16 @@ resolve(Flag, RawOpts) -> resolve(Flag, Flag, RawOpts). resolve(Flag, EUnitKey, RawOpts) -> case proplists:get_value(Flag, RawOpts) of undefined -> []; - Args -> - lists:flatten(lists:map(fun(Arg) -> normalize(EUnitKey, Arg) end, - rebar_string:lexemes(Args, [$,]))) + Args -> normalize(EUnitKey, + rebar_string:lexemes(Args, [$,])) end. -normalize(generator, Value) -> +normalize(generator, Args) -> + lists:flatmap(fun(Value) -> normalize_(generator, Value) end, Args); +normalize(EUnitKey, Args) -> + lists:map(fun(Arg) -> normalize_(EUnitKey, Arg) end, Args). + +normalize_(generator, Value) -> case string:tokens(Value, [$:]) of [Module0, Functions] -> Module = list_to_atom(Module0), @@ -158,8 +162,8 @@ normalize(generator, Value) -> _ -> ?PRV_ERROR({generator, Value}) end; -normalize(Key, Value) when Key == dir; Key == file -> {Key, Value}; -normalize(Key, Value) -> {Key, list_to_atom(Value)}. +normalize_(Key, Value) when Key == dir; Key == file -> {Key, Value}; +normalize_(Key, Value) -> {Key, list_to_atom(Value)}. cfg_tests(State) -> case rebar_state:get(State, eunit_tests, []) of -- cgit v1.1