@ -12,9 +12,7 @@
- include ( " rebar.hrl " ) .
- include ( " rebar.hrl " ) .
- define ( PROVIDER , eunit ) .
- define ( PROVIDER , eunit ) .
- define ( DEPS , [ compile ] ) .
- define ( DEPS , [ compile ] ) .
- define ( EUNIT_DIR , " .eunit " ) .
% % == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
% % == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == =
% % Public API
% % Public API
@ -22,507 +20,126 @@
- spec init ( rebar_state : t ( ) ) - > { ok , rebar_state : t ( ) } .
- spec init ( rebar_state : t ( ) ) - > { ok , rebar_state : t ( ) } .
init ( State ) - >
init ( State ) - >
State1 = rebar_state : add_provider ( State , providers : create ( [ { name , ? PROVIDER } ,
{ module , ? MODULE } ,
{ bare , false } ,
{ deps , ? DEPS } ,
{ example , " rebar eunit " } ,
{ short_desc , " Run eunit tests on project apps. " } ,
{ desc , " " } ,
{ opts , [ ] } ] ) ) ,
Provider = providers : create ( [ { name , ? PROVIDER } ,
{ module , ? MODULE } ,
{ deps , ? DEPS } ,
{ bare , false } ,
{ example , " rebar eunit " } ,
{ short_desc , " Run EUnit Tests. " } ,
{ desc , " " } ,
{ opts , eunit_opts ( State ) } ,
{ profile , test } ] ) ,
State1 = rebar_state : add_provider ( State , Provider ) ,
{ ok , State1 } .
{ ok , State1 } .
- spec do ( rebar_state : t ( ) ) - > { ok , rebar_state : t ( ) } | { error , string ( ) } .
- spec do ( rebar_state : t ( ) ) - > { ok , rebar_state : t ( ) } | { error , string ( ) } .
do ( State ) - >
do ( State ) - >
ok = ensure_dirs ( ) ,
% % Save code path
CodePath = setup_code_path ( ) ,
CompileOnly = rebar_state : get ( State , compile_only , false ) ,
{ ok , SrcErls } = rebar_erlc_compiler : test_compile ( State , " eunit " ,
? EUNIT_DIR ) ,
case CompileOnly of
" true " - >
true = rebar_utils : cleanup_code_path ( CodePath ) ,
? CONSOLE ( " Compiled modules for eunit ~n " , [ ] ) ;
false - >
run_eunit ( State , CodePath , SrcErls )
? INFO ( " Performing EUnit tests... " , [ ] ) ,
{ RawOpts , _ } = rebar_state : command_parsed_args ( State ) ,
Opts = transform_opts ( RawOpts , State ) ,
ProjectApps = rebar_state : project_apps ( State ) ,
OutDir = case proplists : get_value ( outdir , Opts , undefined ) of
undefined - > filename : join ( [ rebar_state : dir ( State ) ,
ec_file : insecure_mkdtemp ( ) ] ) ;
Path - > Path
end ,
end ,
{ ok , State } .
? DEBUG ( " Compiling EUnit instrumented modules in: ~p " , [ OutDir ] ) ,
lists : foreach ( fun ( App ) - >
AppDir = rebar_app_info : 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_opts ( S , OutDir ) ) ,
ok = rebar_erlc_compiler : compile ( TestState , AppDir )
end , ProjectApps ) ,
true = code : add_patha ( OutDir ) ,
EUnitOpts = resolve_eunit_opts ( State , Opts ) ,
AppsToTest = [ { application , erlang : binary_to_atom ( rebar_app_info : name ( App ) , unicode ) }
| | App < - ProjectApps ] ,
case handle_results ( eunit : test ( AppsToTest , EUnitOpts ) ) of
{ error , Reason } - >
{ error , { ? MODULE , Reason } } ;
ok - >
{ ok , State }
end .
- spec format_error ( any ( ) ) - > iolist ( ) .
- spec format_error ( any ( ) ) - > iolist ( ) .
format_error ( Reason ) - >
io_lib : format ( " ~p " , [ Reason ] ) .
format_error ( unknown_error ) - >
io_lib : format ( " Error running tests " , [ ] ) ;
format_error ( { error_running_tests , Reason } ) - >
io_lib : format ( " Error running tests: ~p " , [ Reason ] ) .
run_eunit ( Config , CodePath , SrcErls ) - >
% % Build a list of all the . beams in ? EUNIT_DIR -- use this for
% % cover and eunit testing . Normally you can just tell cover
% % and / or eunit to scan the directory for you , but eunit does a
% % code : purge in conjunction with that scan and causes any cover
% % compilation info to be lost .
AllBeamFiles = rebar_utils : beams ( ? EUNIT_DIR ) ,
{ BeamFiles , TestBeamFiles } =
lists : partition ( fun ( N ) - > string : str ( N , " _tests.beam " ) =:= 0 end ,
AllBeamFiles ) ,
OtherBeamFiles = TestBeamFiles --
[ filename : rootname ( N ) ++ " _tests.beam " | | N < - AllBeamFiles ] ,
ModuleBeamFiles = randomize_suites ( Config , BeamFiles ++ OtherBeamFiles ) ,
% % Get matching tests and modules
AllModules = [ rebar_utils : beam_to_mod ( ? EUNIT_DIR , N ) | | N < - AllBeamFiles ] ,
{ Tests , FilteredModules } =
get_tests_and_modules ( Config , ModuleBeamFiles , AllModules ) ,
SrcModules = [ rebar_utils : erl_to_mod ( M ) | | M < - SrcErls ] ,
{ ok , CoverLog } = rebar_cover_utils : init ( Config , ModuleBeamFiles ,
eunit_dir ( ) ) ,
StatusBefore = status_before_eunit ( ) ,
EunitResult = perform_eunit ( Config , Tests ) ,
rebar_cover_utils : perform_cover ( Config , FilteredModules , SrcModules ,
eunit_dir ( ) ) ,
rebar_cover_utils : close ( CoverLog ) ,
case proplists : get_value ( reset_after_eunit , get_eunit_opts ( Config ) ,
true ) of
true - >
reset_after_eunit ( StatusBefore ) ;
false - >
ok
end ,
% % Stop cover to clean the cover_server state . This is important if we want
% % eunit + cover to not slow down when analyzing many Erlang modules .
ok = rebar_cover_utils : exit ( ) ,
case EunitResult of
ok - >
ok ;
_ - >
? ABORT ( " One or more eunit tests failed. " , [ ] )
eunit_opts ( _ State ) - >
[ { outdir , $o , " outdir " , string , help ( outdir ) } ,
{ verbose , $v , " verbose " , boolean , help ( verbose ) } ] .
help ( outdir ) - > " Output directory for EUnit compiled modules " ;
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 ,
end ,
% % Restore code path
true = rebar_utils : cleanup_code_path ( CodePath ) ,
ok .
ensure_dirs ( ) - >
% % Make sure ? EUNIT_DIR / and ebin / directory exists ( append dummy module )
ok = filelib : ensure_dir ( filename : join ( eunit_dir ( ) , " dummy " ) ) ,
ok = filelib : ensure_dir ( filename : join ( rebar_dir : ebin_dir ( ) , " dummy " ) ) .
eunit_dir ( ) - >
filename : join ( rebar_dir : get_cwd ( ) , ? EUNIT_DIR ) .
setup_code_path ( ) - >
% % Setup code path prior to compilation so that parse_transforms
% % and the like work properly . Also , be sure to add ebin_dir ( )
% % to the END of the code path so that we don ' t have to jump
% % through hoops to access the . app file
CodePath = code : get_path ( ) ,
true = code : add_patha ( eunit_dir ( ) ) ,
true = code : add_pathz ( rebar_dir : ebin_dir ( ) ) ,
CodePath .
% %
% % == get matching tests ==
% %
get_tests_and_modules ( Config , ModuleBeamFiles , AllModules ) - >
SelectedSuites = get_selected_suites ( Config , AllModules ) ,
{ Tests , QualifiedTests } = get_qualified_and_unqualified_tests ( Config ) ,
Modules = get_test_modules ( SelectedSuites , Tests ,
QualifiedTests , ModuleBeamFiles ) ,
FilteredModules = get_matching_modules ( AllModules , Modules , QualifiedTests ) ,
MatchedTests = get_matching_tests ( Modules , Tests , QualifiedTests ) ,
{ MatchedTests , FilteredModules } .
% %
% % == get suites specified via 'suites' option ==
% %
get_selected_suites ( Config , Modules ) - >
RawSuites = get_suites ( Config ) ,
Suites = [ list_to_atom ( Suite ) | | Suite < - string : tokens ( RawSuites , " , " ) ] ,
[ M | | M < - Suites , lists : member ( M , Modules ) ] .
get_suites ( Config ) - >
case rebar_state : get ( Config , suites , " " ) of
" " - >
rebar_state : get ( Config , suite , " " ) ;
Suites - >
Suites
end .
get_qualified_and_unqualified_tests ( Config ) - >
RawFunctions = rebar_state : get ( Config , tests , " " ) ,
FunctionNames = [ FunctionName | |
FunctionName < - string : tokens ( RawFunctions , " , " ) ] ,
get_qualified_and_unqualified_tests1 ( FunctionNames , [ ] , [ ] ) .
get_qualified_and_unqualified_tests1 ( [ ] , Functions , QualifiedFunctions ) - >
{ Functions , QualifiedFunctions } ;
get_qualified_and_unqualified_tests1 ( [ TestName | TestNames ] , Functions ,
QualifiedFunctions ) - >
case string : tokens ( TestName , " : " ) of
[ TestName ] - >
Function = list_to_atom ( TestName ) ,
get_qualified_and_unqualified_tests1 (
TestNames , [ Function | Functions ] , QualifiedFunctions ) ;
[ ModuleName , FunctionName ] - >
M = list_to_atom ( ModuleName ) ,
F = list_to_atom ( FunctionName ) ,
get_qualified_and_unqualified_tests1 ( TestNames , Functions ,
[ { M , F } | QualifiedFunctions ] ) ;
_ - >
? ABORT ( " Unsupported test function specification: ~s " , [ TestName ] )
end .
% % Provide modules which are to be searched for tests .
% % Several scenarios are possible :
% %
% % == randomize suites ==
% %
randomize_suites ( Config , Modules ) - >
case rebar_state : get ( Config , random_suite_order , undefined ) of
undefined - >
Modules ;
" true " - >
Seed = crypto : rand_uniform ( 1 , 65535 ) ,
randomize_suites1 ( Modules , Seed ) ;
String - >
try list_to_integer ( String ) of
Seed - >
randomize_suites1 ( Modules , Seed )
catch
error : badarg - >
? ERROR ( " Bad random seed provided: ~p " , [ String ] ) ,
? FAIL
end
end .
randomize_suites1 ( Modules , Seed ) - >
_ = random : seed ( 35 , Seed , 1337 ) ,
? CONSOLE ( " Randomizing suite order with seed ~b ~n " , [ Seed ] ) ,
[ X | | { _ , X } < - lists : sort ( [ { random : uniform ( ) , M } | | M < - Modules ] ) ] .
% %
% % == get matching tests ==
% % 1 ) Specific tests have been provided and / or
% % no unqualified tests have been specified and
% % there were some qualified tests , then we can search for
% % functions in specified suites ( or in empty set of suites ) .
% %
% % 2 ) Neither specific suites nor qualified test names have been
% % provided use ModuleBeamFiles which filters out " *_tests "
% % modules so EUnit won ' t doubly run them and cover only
% % calculates coverage on production code . However ,
% % keep " *_tests " modules that are not automatically
% % included by EUnit .
% %
% % From 'Primitives' in the EUnit User ' s Guide
% % http : / / www . erlang . org / doc / apps / eunit / chapter . html
% % " In addition, EUnit will also look for another
% % module whose name is ModuleName plus the suffix
% % _ tests , and if it exists , all the tests from that
% % module will also be added . ( If ModuleName already
% % contains the suffix _ tests , this is not done . ) E . g . ,
% % the specification { module , mymodule } will run all
% % tests in the modules mymodule and mymodule_tests .
% % Typically , the _ tests module should only contain
% % test cases that use the public interface of the main
% % module ( and no other code ) . "
get_test_modules ( SelectedSuites , Tests , QualifiedTests , ModuleBeamFiles ) - >
SuitesProvided = SelectedSuites =/= [ ] ,
OnlyQualifiedTestsProvided = QualifiedTests =/= [ ] andalso Tests =:= [ ] ,
if
SuitesProvided orelse OnlyQualifiedTestsProvided - >
SelectedSuites ;
true - >
[ rebar_utils : beam_to_mod ( ? EUNIT_DIR , N ) | |
N < - ModuleBeamFiles ]
end .
get_matching_modules ( AllModules , Modules , QualifiedTests ) - >
ModuleFilterMapper =
fun ( { M , _ } ) - >
case lists : member ( M , AllModules ) of
true - > { true , M } ;
_ - > false
end
end ,
ModulesFromQualifiedTests = lists : zf ( ModuleFilterMapper , QualifiedTests ) ,
lists : usort ( Modules ++ ModulesFromQualifiedTests ) .
get_matching_tests ( Modules , [ ] , [ ] ) - >
Modules ;
get_matching_tests ( Modules , [ ] , QualifiedTests ) - >
FilteredQualifiedTests = filter_qualified_tests ( Modules , QualifiedTests ) ,
lists : merge ( Modules , make_test_primitives ( FilteredQualifiedTests ) ) ;
get_matching_tests ( Modules , Tests , QualifiedTests ) - >
AllTests = lists : merge ( QualifiedTests ,
get_matching_tests1 ( Modules , Tests , [ ] ) ) ,
make_test_primitives ( AllTests ) .
filter_qualified_tests ( Modules , QualifiedTests ) - >
TestsFilter = fun ( { Module , _ Function } ) - >
lists : all ( fun ( M ) - > M =/= Module end , Modules ) end ,
lists : filter ( TestsFilter , QualifiedTests ) .
get_matching_tests1 ( [ ] , _ Functions , TestFunctions ) - >
TestFunctions ;
get_matching_tests1 ( [ Module | TModules ] , Functions , TestFunctions ) - >
% % Get module exports
ModuleStr = atom_to_list ( Module ) ,
ModuleExports = get_beam_test_exports ( ModuleStr ) ,
% % Get module _ tests exports
TestModuleStr = string : concat ( ModuleStr , " _tests " ) ,
TestModuleExports = get_beam_test_exports ( TestModuleStr ) ,
% % Build tests { M , F } list
Tests = get_matching_tests2 ( Functions , { Module , ModuleExports } ,
{ list_to_atom ( TestModuleStr ) ,
TestModuleExports } ) ,
get_matching_tests1 ( TModules , Functions ,
lists : merge ( [ TestFunctions , Tests ] ) ) .
get_matching_tests2 ( Functions , { Mod , ModExports } , { TestMod , TestModExports } ) - >
% % Look for matching functions into ModExports
ModExportsStr = [ atom_to_list ( E1 ) | | E1 < - ModExports ] ,
TestModExportsStr = [ atom_to_list ( E2 ) | | E2 < - TestModExports ] ,
get_matching_exports ( Functions , { Mod , ModExportsStr } ,
{ TestMod , TestModExportsStr } , [ ] ) .
get_matching_exports ( [ ] , _ , _ , Matched ) - >
Matched ;
get_matching_exports ( [ Function | TFunctions ] , { Mod , ModExportsStr } ,
{ TestMod , TestModExportsStr } , Matched ) - >
FunctionStr = atom_to_list ( Function ) ,
% % Get matching Function in module , otherwise look in _ tests module
NewMatch = case get_matching_export ( FunctionStr , ModExportsStr ) of
[ ] - >
{ TestMod , get_matching_export ( FunctionStr ,
TestModExportsStr ) } ;
MatchingExport - >
{ Mod , MatchingExport }
end ,
case NewMatch of
{ _ , [ ] } - >
get_matching_exports ( TFunctions , { Mod , ModExportsStr } ,
{ TestMod , TestModExportsStr } , Matched ) ;
_ - >
get_matching_exports ( TFunctions , { Mod , ModExportsStr } ,
{ TestMod , TestModExportsStr } ,
[ NewMatch | Matched ] )
end .
get_matching_export ( _ FunctionStr , [ ] ) - >
[ ] ;
get_matching_export ( FunctionStr , [ ExportStr | TExportsStr ] ) - >
case string : str ( ExportStr , FunctionStr ) of
1 - >
list_to_atom ( ExportStr ) ;
_ - >
get_matching_export ( FunctionStr , TExportsStr )
end .
get_beam_test_exports ( ModuleStr ) - >
FilePath = filename : join ( eunit_dir ( ) ,
string : concat ( ModuleStr , " .beam " ) ) ,
case filelib : is_regular ( FilePath ) of
true - >
{ beam_file , _ , Exports0 , _ , _ , _ } = beam_disasm : file ( FilePath ) ,
Exports1 = [ FunName | | { FunName , FunArity , _ } < - Exports0 ,
FunArity =:= 0 ] ,
F = fun ( FName ) - >
FNameStr = atom_to_list ( FName ) ,
re : run ( FNameStr , " _test(_)? " ) =/= nomatch
end ,
lists : filter ( F , Exports1 ) ;
_ - >
[ ]
transform_opts ( Rest , State , NewAcc ) ;
transform_opts ( [ { Key , Val } | Rest ] , State , Acc ) - >
transform_opts ( Rest , State , [ { Key , Val } | Acc ] ) .
test_opts ( State , TmpDir ) - >
ErlOpts = rebar_state : get ( State , eunit_compile_opts , [ ] ) ++
rebar_utils : erl_opts ( State ) ,
TestOpts = [ { outdir , TmpDir } ] ++
add_test_dir ( ErlOpts ) ++
safe_define_test_macro ( ErlOpts ) ,
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 " ] } ] ;
_ - > [ { src_dirs , [ " test " ] } ]
end .
end .
make_test_primitives ( RawTests ) - >
% % Use { test , M , F } and { generator , M , F } if at least R15B02 . Otherwise ,
% % use eunit_test : function_wrapper / 2 fallback .
% % eunit_test : function_wrapper / 2 was renamed to eunit_test : mf_wrapper / 2
% % in R15B02 ; use that as > = R15B02 check .
% % TODO : remove fallback and use only { test , M , F } and { generator , M , F }
% % primitives once at least R15B02 is required .
{ module , eunit_test } = code : ensure_loaded ( eunit_test ) ,
MakePrimitive = case erlang : function_exported ( eunit_test , mf_wrapper , 2 ) of
true - > fun eunit_primitive / 3 ;
false - > fun pre15b02_eunit_primitive / 3
end ,
? CONSOLE ( " Running test function(s): ~n " , [ ] ) ,
F = fun ( { M , F2 } , Acc ) - >
? CONSOLE ( " ~p : ~p /0 ~n " , [ M , F2 ] ) ,
FNameStr = atom_to_list ( F2 ) ,
NewFunction =
case re : run ( FNameStr , " _test_ " ) of
nomatch - >
% % Normal test
MakePrimitive ( test , M , F2 ) ;
_ - >
% % Generator
MakePrimitive ( generator , M , F2 )
end ,
[ NewFunction | Acc ]
end ,
lists : foldl ( F , [ ] , RawTests ) .
eunit_primitive ( Type , M , F ) - >
{ Type , M , F } .
pre15b02_eunit_primitive ( test , M , F ) - >
eunit_test : function_wrapper ( M , F ) ;
pre15b02_eunit_primitive ( generator , M , F ) - >
{ generator , eunit_test : function_wrapper ( M , F ) } .
% %
% % == run tests ==
% %
perform_eunit ( Config , Tests ) - >
EunitOpts = get_eunit_opts ( Config ) ,
% % Move down into ? EUNIT_DIR while we run tests so any generated files
% % are created there ( versus in the source dir )
Cwd = rebar_dir : get_cwd ( ) ,
ok = file : set_cwd ( ? EUNIT_DIR ) ,
EunitResult = ( catch eunit : test ( Tests , EunitOpts ) ) ,
% % Return to original working dir
ok = file : set_cwd ( Cwd ) ,
EunitResult .
get_eunit_opts ( Config ) - >
% % Enable verbose in eunit if so requested . .
BaseOpts = case rebar_log : is_verbose ( Config ) of
true - >
[ verbose ] ;
false - >
[ ]
end ,
BaseOpts ++ rebar_state : get ( Config , eunit_opts , [ ] ) .
% %
% % == reset_after_eunit ==
% %
status_before_eunit ( ) - >
Apps = get_app_names ( ) ,
AppEnvs = [ { App , application : get_all_env ( App ) } | | App < - Apps ] ,
{ erlang : processes ( ) , erlang : is_alive ( ) , AppEnvs , ets : tab2list ( ac_tab ) } .
get_app_names ( ) - >
[ AppName | | { AppName , _ , _ } < - application : loaded_applications ( ) ] .
reset_after_eunit ( { OldProcesses , WasAlive , OldAppEnvs , _ OldACs } ) - >
IsAlive = erlang : is_alive ( ) ,
if not WasAlive andalso IsAlive - >
? DEBUG ( " Stopping net kernel.... \n " , [ ] ) ,
erl_epmd : stop ( ) ,
_ = net_kernel : stop ( ) ,
pause_until_net_kernel_stopped ( ) ;
true - >
ok
end ,
OldApps = [ App | | { App , _ } < - OldAppEnvs ] ,
Apps = get_app_names ( ) ,
_ = [ begin
_ = case lists : member ( App , OldApps ) of
true - > ok ;
false - > application : stop ( App )
end ,
ok = application : unset_env ( App , K )
end | | App < - Apps , App / = rebar ,
{ K , _ V } < - application : get_all_env ( App ) ,
K =/= included_applications ] ,
reconstruct_app_env_vars ( Apps ) ,
Processes = erlang : processes ( ) ,
_ = kill_extras ( Processes -- OldProcesses ) ,
ok .
kill_extras ( Pids ) - >
% % Killing any of the procs below will either :
% % 1 . Interfere with stuff that we don ' t want interfered with , or
% % 2 . May / will force the 'kernel' app to shutdown , which * will *
% % interfere with rebar ' s ability To Do Useful Stuff ( tm ) .
% % This list may require changes as OTP versions and / or
% % rebar use cases change .
KeepProcs = [ cover_server , eunit_server ,
eqc , eqc_license , eqc_locked ,
% % inet_gethost_native is started on demand , when
% % doing name lookups . It is under kernel_sup , under
% % a supervisor_bridge .
inet_gethost_native ] ,
Killed = [ begin
Info = case erlang : process_info ( Pid ) of
undefined - > [ ] ;
Else - > Else
end ,
Keep1 = case proplists : get_value ( registered_name , Info ) of
undefined - >
false ;
Name - >
lists : member ( Name , KeepProcs )
end ,
Keep2 = case proplists : get_value ( dictionary , Info ) of
undefined - >
false ;
Ds - >
case proplists : get_value ( '$ancestors' , Ds ) of
undefined - >
false ;
As - >
lists : member ( kernel_sup , As )
end
end ,
if Keep1 orelse Keep2 - >
ok ;
true - >
? DEBUG ( " Kill ~p ~p \n " , [ Pid , Info ] ) ,
exit ( Pid , kill ) ,
Pid
end
end | | Pid < - Pids ] ,
case lists : usort ( Killed ) -- [ ok ] of
[ ] - >
? DEBUG ( " No processes to kill \n " , [ ] ) ,
[ ] ;
Else - >
lists : foreach ( fun ( Pid ) - > wait_until_dead ( Pid ) end , Else ) ,
Else
safe_define_test_macro ( Opts ) - >
% % defining a compile macro twice results in an exception so
% % make sure 'TEST' is only defined once
case test_defined ( Opts ) of
true - > Opts ;
false - > [ { d , 'TEST' } ] ++ Opts
end .
end .
reconstruct_app_env_vars ( [ App | Apps ] ) - >
CmdLine0 = proplists : get_value ( App , init : get_arguments ( ) , [ ] ) ,
CmdVars = [ { list_to_atom ( K ) , list_to_atom ( V ) } | | { K , V } < - CmdLine0 ] ,
AppFile = ( catch filename : join ( [ code : lib_dir ( App ) ,
" ebin " ,
atom_to_list ( App ) ++ " .app " ] ) ) ,
AppVars = case file : consult ( AppFile ) of
{ ok , [ { application , App , Ps } ] } - >
proplists : get_value ( env , Ps , [ ] ) ;
_ - >
[ ]
end ,
% % App vars specified in config files override those in the . app file .
% % Config files later in the args list override earlier ones .
AppVars1 = case init : get_argument ( config ) of
{ ok , ConfigFiles } - >
{ App , MergedAppVars } = lists : foldl ( fun merge_app_vars / 2 ,
{ App , AppVars } ,
ConfigFiles ) ,
MergedAppVars ;
error - >
AppVars
end ,
AllVars = CmdVars ++ AppVars1 ,
? DEBUG ( " Reconstruct ~p ~p \n " , [ App , AllVars ] ) ,
lists : foreach ( fun ( { K , V } ) - > application : set_env ( App , K , V ) end , AllVars ) ,
reconstruct_app_env_vars ( Apps ) ;
reconstruct_app_env_vars ( [ ] ) - >
ok .
merge_app_vars ( ConfigFile , { App , AppVars } ) - >
File = ensure_config_extension ( ConfigFile ) ,
FileAppVars = app_vars_from_config_file ( File , App ) ,
Dict1 = dict : from_list ( AppVars ) ,
Dict2 = dict : from_list ( FileAppVars ) ,
Dict3 = dict : merge ( fun ( _ Key , _ Value1 , Value2 ) - > Value2 end , Dict1 , Dict2 ) ,
{ App , dict : to_list ( Dict3 ) } .
ensure_config_extension ( File ) - >
% % config files must end with . config on disk but when specifying them
% % via the - config option the extension is optional
BaseFileName = filename : basename ( File , " .config " ) ,
DirName = filename : dirname ( File ) ,
filename : join ( DirName , BaseFileName ++ " .config " ) .
app_vars_from_config_file ( File , App ) - >
case file : consult ( File ) of
{ ok , [ Env ] } - >
proplists : get_value ( App , Env , [ ] ) ;
_ - >
[ ]
test_defined ( [ { d , 'TEST' } | _ ] ) - > true ;
test_defined ( [ { d , 'TEST' , true } | _ ] ) - > true ;
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_modules , 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 .
end .
wait_until_dead ( Pid ) when is_pid ( Pid ) - >
Ref = erlang : monitor ( process , Pid ) ,
receive
{ 'DOWN' , Ref , process , _ Obj , Info } - >
Info
after 10 * 1000 - >
exit ( { timeout_waiting_for , Pid } )
end ;
wait_until_dead ( _ ) - >
ok .
pause_until_net_kernel_stopped ( ) - >
pause_until_net_kernel_stopped ( 10 ) .
pause_until_net_kernel_stopped ( 0 ) - >
exit ( net_kernel_stop_failed ) ;
pause_until_net_kernel_stopped ( N ) - >
case node ( ) of
'nonode@nohost' - >
? DEBUG ( " Stopped net kernel. \n " , [ ] ) ,
ok ;
_ - >
timer : sleep ( 100 ) ,
pause_until_net_kernel_stopped ( N - 1 )
set_verbose ( Opts ) - >
case lists : member ( verbose , Opts ) of
true - > Opts ;
false - > [ verbose ] ++ Opts
end .
end .
handle_results ( ok ) - > ok ;
handle_results ( error ) - >
{ error , unknown_error } ;
handle_results ( { error , Reason } ) - >
{ error , { error_running_tests , Reason } } .