diff options
Diffstat (limited to 'test/rebar_compile_SUITE.erl')
-rw-r--r-- | test/rebar_compile_SUITE.erl | 1226 |
1 files changed, 1142 insertions, 84 deletions
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index d9b75e4..ddaad0c 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -1,48 +1,6 @@ -module(rebar_compile_SUITE). --export([suite/0, - init_per_suite/1, - end_per_suite/1, - init_per_testcase/2, - end_per_testcase/2, - init_per_group/2, - end_per_group/2, - all/0, - groups/0, - build_basic_app/1, paths_basic_app/1, clean_basic_app/1, - build_release_apps/1, paths_release_apps/1, clean_release_apps/1, - build_checkout_apps/1, paths_checkout_apps/1, - build_checkout_deps/1, paths_checkout_deps/1, - build_basic_srcdirs/1, paths_basic_srcdirs/1, - build_release_srcdirs/1, paths_release_srcdirs/1, - build_unbalanced_srcdirs/1, paths_unbalanced_srcdirs/1, - build_basic_extra_dirs/1, paths_basic_extra_dirs/1, clean_basic_extra_dirs/1, - build_release_extra_dirs/1, paths_release_extra_dirs/1, clean_release_extra_dirs/1, - build_unbalanced_extra_dirs/1, paths_unbalanced_extra_dirs/1, - build_extra_dirs_in_project_root/1, - paths_extra_dirs_in_project_root/1, - clean_extra_dirs_in_project_root/1, - recompile_when_hrl_changes/1, - recompile_when_included_hrl_changes/1, - recompile_when_opts_change/1, - dont_recompile_when_opts_dont_change/1, - dont_recompile_yrl_or_xrl/1, - deps_in_path/1, - delete_beam_if_source_deleted/1, - checkout_priority/1, - highest_version_of_pkg_dep/1, - parse_transform_test/1, - erl_first_files_test/1, - mib_test/1, - umbrella_mib_first_test/1, - only_default_transitive_deps/1, - clean_all/1, - override_deps/1, - profile_override_deps/1, - deps_build_in_prod/1, - include_file_relative_to_working_directory/1, - include_file_in_src/1, - always_recompile_when_erl_compiler_options_set/1]). +-compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -58,18 +16,30 @@ all() -> {group, basic_extras}, {group, release_extras}, {group, unbalanced_extras}, {group, root_extras}, recompile_when_hrl_changes, recompile_when_included_hrl_changes, + recompile_when_opts_included_hrl_changes, recompile_when_opts_change, dont_recompile_when_opts_dont_change, dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted, deps_in_path, checkout_priority, highest_version_of_pkg_dep, parse_transform_test, erl_first_files_test, mib_test, - umbrella_mib_first_test, only_default_transitive_deps, - clean_all, override_deps, profile_override_deps, deps_build_in_prod, - include_file_relative_to_working_directory, include_file_in_src] ++ - case erlang:function_exported(os, unsetenv, 1) of - true -> [always_recompile_when_erl_compiler_options_set]; - false -> [] - end. + umbrella_mib_first_test, only_default_transitive_deps, clean_all, + profile_deps, deps_build_in_prod, only_deps, + override_deps, override_add_deps, override_del_deps, + override_opts, override_add_opts, override_del_opts, + apply_overrides_exactly_once, + profile_override_deps, profile_override_add_deps, profile_override_del_deps, + profile_override_opts, profile_override_add_opts, profile_override_del_opts, + include_file_relative_to_working_directory, include_file_in_src, + include_file_relative_to_working_directory_test, include_file_in_src_test, + include_file_in_src_test_multiapp, + recompile_when_parse_transform_as_opt_changes, + recompile_when_parse_transform_inline_changes, + regex_filter_skip, regex_filter_regression, + recursive, no_recursive, + always_recompile_when_erl_compiler_options_set, + dont_recompile_when_erl_compiler_options_env_does_not_change, + recompile_when_erl_compiler_options_env_changes, + rebar_config_os_var]. groups() -> [{basic_app, [], [build_basic_app, paths_basic_app, clean_basic_app]}, @@ -243,7 +213,31 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. -init_per_testcase(_, Config) -> +init_per_testcase(Test, Config) when + Test == dont_recompile_when_erl_compiler_options_env_does_not_change + orelse + Test == recompile_when_erl_compiler_options_env_changes -> + _ = code:ensure_loaded(os), + UnSetEnv = erlang:function_exported(os, unsetenv, 1), + _ = code:ensure_loaded(compile), + EnvOpts = erlang:function_exported(compile, env_compiler_options, 0), + case {UnSetEnv, EnvOpts} of + {true, true} -> maybe_init_config(Config); + _ -> {skip, "compile:env_compiler_options/0 unavailable"} + end; +init_per_testcase(always_recompile_when_erl_compiler_options_set, Config) -> + _ = code:ensure_loaded(os), + UnSetEnv = erlang:function_exported(os, unsetenv, 1), + _ = code:ensure_loaded(compile), + EnvOpts = erlang:function_exported(compile, env_compiler_options, 0), + case {UnSetEnv, EnvOpts} of + {true, true} -> {skip, "compile:env_compiler_options/0 available"}; + {true, false} -> maybe_init_config(Config); + _ -> {skip, "os:unsetenv/1 unavailable"} + end; +init_per_testcase(_, Config) -> maybe_init_config(Config). + +maybe_init_config(Config) -> case ?config(apps, Config) of undefined -> rebar_test_utils:init_rebar_state(Config); _ -> Config @@ -253,7 +247,6 @@ end_per_testcase(_, _Config) -> catch meck:unload(). - %% test cases build_basic_app(Config) -> @@ -717,6 +710,53 @@ recompile_when_included_hrl_changes(Config) -> ?assert(ModTime =/= NewModTime). +recompile_when_opts_included_hrl_changes(Config) -> + AppsDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + AppDir = filename:join([AppsDir, "apps", Name]), + + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + ExtraSrc = <<"-module(test_header_include).\n" + "-export([main/0]).\n" + "-include(\"test_header_include.hrl\").\n" + "main() -> ?SOME_DEFINE.\n">>, + + ExtraHeader = <<"-define(SOME_DEFINE, true).\n">>, + ok = filelib:ensure_dir(filename:join([AppsDir, "include", "dummy"])), + HeaderFile = filename:join([AppsDir, "include", "test_header_include.hrl"]), + ok = file:write_file(filename:join([AppDir, "src", "test_header_include.erl"]), ExtraSrc), + ok = file:write_file(HeaderFile, ExtraHeader), + + %% Using relative path from the project root + RebarConfig = [{erl_opts, [{i, "include/"}]}], + {ok,Cwd} = file:get_cwd(), + ok = file:set_cwd(AppsDir), + + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppsDir, "_build", "default", "lib", Name, "ebin"]), + {ok, Files} = rebar_utils:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:extension(F) == ".beam"], + + timer:sleep(1000), + + NewExtraHeader = <<"-define(SOME_DEFINE, false).\n">>, + ok = file:write_file(HeaderFile, NewExtraHeader), + + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = rebar_utils:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:extension(F) == ".beam"], + + ok = file:set_cwd(Cwd), + + ?assert(ModTime =/= NewModTime). + recompile_when_opts_change(Config) -> AppDir = ?config(apps, Config), @@ -735,7 +775,7 @@ recompile_when_opts_change(Config) -> rebar_test_utils:create_config(AppDir, [{erl_opts, [{d, some_define}]}]), - rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + rebar_test_utils:run_and_check(Config, [{erl_opts, [{d, some_define}]}], ["compile"], {ok, [{app, Name}]}), {ok, NewFiles} = rebar_utils:list_dir(EbinDir), NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) @@ -765,7 +805,7 @@ dont_recompile_when_opts_dont_change(Config) -> NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) || F <- NewFiles, filename:extension(F) == ".beam"], - ?assert(ModTime == NewModTime). + ?assertEqual(ModTime, NewModTime). dont_recompile_yrl_or_xrl(Config) -> AppDir = ?config(apps, Config), @@ -792,19 +832,55 @@ dont_recompile_yrl_or_xrl(Config) -> "Erlang code.", ok = ec_file:write(Xrl, XrlBody), - XrlBeam = filename:join([AppDir, "ebin", filename:basename(Xrl, ".xrl") ++ ".beam"]), + Yrl = filename:join([AppDir, "src", "not_a_real_yrl_" ++ Name ++ ".yrl"]), + ok = filelib:ensure_dir(Yrl), + YrlBody = ["Nonterminals E T F.\n" + "Terminals '+' '*' '(' ')' number.\n" + "Rootsymbol E.\n" + "E -> E '+' T: {'$2', '$1', '$3'}.\n" + "E -> T : '$1'.\n" + "T -> T '*' F: {'$2', '$1', '$3'}.\n" + "T -> F : '$1'.\n" + "F -> '(' E ')' : '$2'.\n" + "F -> number : '$1'.\n"], + ok = ec_file:write(Yrl, YrlBody), + + XrlErl = filename:join([AppDir, "src", filename:basename(Xrl, ".xrl") ++ ".erl"]), + YrlErl = filename:join([AppDir, "src", filename:basename(Yrl, ".yrl") ++ ".erl"]), - rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + XrlBeam = filename:join([EbinDir, filename:basename(Xrl, ".xrl") ++ ".beam"]), + YrlBeam = filename:join([EbinDir, filename:basename(Yrl, ".yrl") ++ ".beam"]), + + Hrl = filename:join([AppDir, "include", "some_header.hrl"]), + ok = filelib:ensure_dir(Hrl), + HrlBody = yeccpre_hrl(), + ok = ec_file:write(Hrl, HrlBody), + RebarConfig = [{yrl_opts, [{includefile, "include/some_header.hrl"}]}], + + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), - ModTime = filelib:last_modified(XrlBeam), + XrlModTime = filelib:last_modified(XrlErl), + YrlModTime = filelib:last_modified(YrlErl), + + XrlBeamModTime = filelib:last_modified(XrlBeam), + YrlBeamModTime = filelib:last_modified(YrlBeam), timer:sleep(1000), - rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + NewXrlModTime = filelib:last_modified(XrlErl), + NewYrlModTime = filelib:last_modified(YrlErl), - NewModTime = filelib:last_modified(XrlBeam), + NewXrlBeamModTime = filelib:last_modified(XrlBeam), + NewYrlBeamModTime = filelib:last_modified(YrlBeam), - ?assert(ModTime == NewModTime). + ?assert(XrlBeamModTime == NewXrlBeamModTime), + ?assert(YrlBeamModTime == NewYrlBeamModTime), + + ?assert(XrlModTime == NewXrlModTime), + ?assert(YrlModTime == NewYrlModTime). delete_beam_if_source_deleted(Config) -> AppDir = ?config(apps, Config), @@ -1085,17 +1161,19 @@ umbrella_mib_first_test(Config) -> rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), - MibsSrc = <<"-- SIMPLE-MIB.\n" + BExporterSrc = <<"-- BEXPORTER-MIB.\n" "-- This is just a simple MIB used for testing!\n" "--\n" -"SIMPLE-MIB DEFINITIONS ::= BEGIN\n" +"BEXPORTER-MIB DEFINITIONS ::= BEGIN\n" "IMPORTS\n" +" TEXTUAL-CONVENTION\n" +" FROM SNMPv2-TC\n" " MODULE-IDENTITY, enterprises\n" " FROM SNMPv2-SMI;\n" "\n" "ericsson MODULE-IDENTITY\n" " LAST-UPDATED\n" -" \"201403060000Z\"\n" +" \"201812050000Z\"\n" " ORGANIZATION\n" " \"rebar\"\n" " CONTACT-INFO\n" @@ -1107,25 +1185,71 @@ umbrella_mib_first_test(Config) -> " \"This very small module is made available\n" " for mib-compilation testing.\"\n" " ::= { enterprises 999 }\n" +"\n" +"Something ::= TEXTUAL-CONVENTION\n" +" STATUS current\n" +" DESCRIPTION \"\"\n" +" SYNTAX OCTET STRING (SIZE (4))\n" +"END\n">>, + + AImporterSrc = <<"-- AIMPORTER-MIB.\n" +"-- This is just a simple MIB used for testing!\n" +"--\n" +"AIMPORTER-MIB DEFINITIONS ::= BEGIN\n" +"IMPORTS\n" +" Something\n" +" FROM BEXPORTER-MIB\n" +" MODULE-IDENTITY, enterprises\n" +" FROM SNMPv2-SMI;\n" +"\n" +"ericsson MODULE-IDENTITY\n" +" LAST-UPDATED\n" +" \"201812050000Z\"\n" +" ORGANIZATION\n" +" \"rebar\"\n" +" CONTACT-INFO\n" +" \"rebar <rebar@example.com>\n" +" or\n" +" whoever is currently responsible for the SIMPLE\n" +" enterprise MIB tree branch (enterprises.999).\"\n" +" DESCRIPTION\n" +" \"This very small module is made available\n" +" for mib-compilation testing.\"\n" +" ::= { enterprises 1000 }\n" "END\n">>, + + ok = filelib:ensure_dir(filename:join([AppDir, "mibs", "dummy"])), - ok = file:write_file(filename:join([AppDir, "mibs", "SIMPLE-MIB.mib"]), MibsSrc), + ok = file:write_file(filename:join([AppDir, "mibs", "AIMPORTER-MIB.mib"]), AImporterSrc), + ok = file:write_file(filename:join([AppDir, "mibs", "BEXPORTER-MIB.mib"]), BExporterSrc), - RebarConfig = [{mib_first_files, ["mibs/SIMPLE-MIB.mib"]}], + FailureRebarConfig = [{mib_first_files, ["mibs/AIMPORTER-MIB.mib"]}], + SuccessRebarConfig = [{mib_first_files, ["mibs/BEXPORTER-MIB.mib"]}], - rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + PrivMibsDir = filename:join([AppsDir, "_build", "default", "lib", Name, "priv", "mibs"]), + + FailureRebarConfig = [{mib_first_files, ["mibs/AIMPORTER-MIB.mib"]}], + catch ( + rebar_test_utils:run_and_check(Config, FailureRebarConfig, ["compile"], {ok, [{app, Name}]}) ), + + %% check that the bin file was NOT cretated + false = filelib:is_file(filename:join([PrivMibsDir, "AIMPORTER-MIB.bin"])), + + + SuccessRebarConfig = [{mib_first_files, ["mibs/BEXPORTER-MIB.mib"]}], + rebar_test_utils:run_and_check(Config, SuccessRebarConfig, ["compile"], {ok, [{app, Name}]}), %% check a bin corresponding to the mib in the mibs dir exists in priv/mibs - PrivMibsDir = filename:join([AppsDir, "_build", "default", "lib", Name, "priv", "mibs"]), - true = filelib:is_file(filename:join([PrivMibsDir, "SIMPLE-MIB.bin"])), + true = filelib:is_file(filename:join([PrivMibsDir, "AIMPORTER-MIB.bin"])), %% check a hrl corresponding to the mib in the mibs dir exists in include - true = filelib:is_file(filename:join([AppDir, "include", "SIMPLE-MIB.hrl"])), + true = filelib:is_file(filename:join([AppDir, "include", "AIMPORTER-MIB.hrl"])), %% check the mibs dir was linked into the _build dir true = filelib:is_dir(filename:join([AppsDir, "_build", "default", "lib", Name, "mibs"])). + only_default_transitive_deps(Config) -> AppDir = ?config(apps, Config), @@ -1184,41 +1308,455 @@ clean_all(Config) -> {app, PkgName, invalid}]}). override_deps(Config) -> - mock_git_resource:mock([{deps, [{some_dep, "0.0.1"},{other_dep, "0.0.1"}]}]), Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), TopDeps = rebar_test_utils:top_level_deps(Deps), + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + RebarConfig = [ {deps, TopDeps}, {overrides, [ {override, some_dep, [ - {deps, []} - ]} - ]} - ], + {deps, []} + ]} + ]} + ], rebar_test_utils:run_and_check( Config, RebarConfig, ["compile"], - {ok, [{dep, "some_dep"},{dep_not_exist, "other_dep"}]} + {ok, [{dep, "some_dep"}, + {dep_not_exist, "other_dep"}]} ). +override_add_deps(Config) -> + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + DepA = {dep_a, "0.0.1", {git, "http://site.com/dep_a.git", {tag, "0.0.1"}}}, + DepB = {dep_b, "0.0.1", {git, "http://site.com/dep_b.git", {tag, "0.0.1"}}}, + DepC = {dep_c, "0.0.1", {git, "http://site.com/dep_c.git", {tag, "0.0.1"}}}, + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, [DepA, DepB, DepC | SrcDeps]}]), + + RebarConfig = [ + {deps, TopDeps}, + {overrides, [ + {add, some_dep, [ + {deps, [DepA, DepB]} + ]}, + {add, [ + {deps, [DepC]} + ]} + ]} + ], + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], + {ok, [{dep, "some_dep"}, + {dep, "other_dep"}, + {dep, "dep_a"}, + {dep, "dep_b"}, + {dep, "dep_c"}]} + ). + +override_del_deps(Config) -> + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"dep_a", "0.0.1", []}, + {"dep_b", "0.0.1", []}, + {"dep_c", "0.0.1", []}]}, + {"other_dep", "0.0.1", [{"dep_c", "0.0.1", []}, + {"dep_d", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + DepA = {dep_a, "0.0.1", {git, "https://example.org/user/dep_a.git", {tag, "0.0.1"}}}, + DepB = {dep_b, "0.0.1", {git, "https://example.org/user/dep_b.git", {tag, "0.0.1"}}}, + DepC = {dep_c, "0.0.1", {git, "https://example.org/user/dep_c.git", {tag, "0.0.1"}}}, + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + RebarConfig = [ + {deps, TopDeps}, + {overrides, [ + {del, some_dep, [ + {deps, [DepA, DepB]} + ]}, + {del, [ + {deps, [DepC]} + ]} + ]} + ], + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], + {ok, [{dep, "some_dep"}, + {dep, "other_dep"}, + {dep_not_exist, "dep_a"}, + {dep_not_exist, "dep_b"}, + {dep_not_exist, "dep_c"}, + {dep, "dep_d"}]} + ). + +override_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + compressed, + warn_missing_spec + ]}, + {overrides, [ + {override, [ + {erl_opts, [compressed]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + +%% test for fix of https://github.com/erlang/rebar3/issues/1801 +%% only apply overrides once +%% verify by having an override add the macro TEST to the dep some_dep +%% building under `ct` will fail if the `add` is applied more than once +apply_overrides_exactly_once(Config) -> + AppDir = ?config(apps, Config), + + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [{deps, TopDeps}, + {overrides, [ + {add, some_dep, [ + {erl_opts, [{d, 'TEST'}]} + ]} + ]}], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["ct", "--compile_only"], {ok, [{app, Name}, {dep, "some_dep"}], "test"}). + +override_add_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + warn_missing_spec + ]}, + {overrides, [ + {add, [ + {erl_opts, [compressed]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + true = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + +override_del_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + compressed, + warn_missing_spec + ]}, + {overrides, [ + {del, [ + {erl_opts, [warn_missing_spec]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + profile_override_deps(Config) -> - mock_git_resource:mock([{deps, [{some_dep, "0.0.1"},{other_dep, "0.0.1"}]}]), Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), TopDeps = rebar_test_utils:top_level_deps(Deps), + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + RebarConfig = [ {deps, TopDeps}, - {profiles, [{a, - [{overrides, [ - {override, some_dep, [ - {deps, []} - ]} - ]} + {profiles, [ + {a, [ + {overrides, [ + {override, some_dep, [ + {deps, []} ]} + ]} + ]} ]}], rebar_test_utils:run_and_check( Config, RebarConfig, ["as", "a", "compile"], - {ok, [{dep, "some_dep"},{dep_not_exist, "other_dep"}]} + {ok, [{dep, "some_dep"}, + {dep_not_exist, "other_dep"}]} + ). + +profile_override_add_deps(Config) -> + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + DepA = {dep_a, "0.0.1", {git, "http://site.com/dep_a.git", {tag, "0.0.1"}}}, + DepB = {dep_b, "0.0.1", {git, "http://site.com/dep_b.git", {tag, "0.0.1"}}}, + DepC = {dep_c, "0.0.1", {git, "http://site.com/dep_c.git", {tag, "0.0.1"}}}, + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, [DepA, DepB, DepC | SrcDeps]}]), + + RebarConfig = [ + {deps, TopDeps}, + {profiles, [ + {a, [ + {overrides, [ + {add, some_dep, [ + {deps, [DepA, DepB]} + ]}, + {add, [ + {deps, [DepC]} + ]} + ]} + ]} + ]} + ], + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], + {ok, [{dep, "some_dep"}, + {dep, "other_dep"}, + {dep, "dep_a"}, + {dep, "dep_b"}, + {dep, "dep_c"}]} + ). + +profile_override_del_deps(Config) -> + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"dep_a", "0.0.1", []}, + {"dep_b", "0.0.1", []}, + {"dep_c", "0.0.1", []}]}, + {"other_dep", "0.0.1", [{"dep_c", "0.0.1", []}, + {"dep_d", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + DepA = {dep_a, "0.0.1", {git, "https://example.org/user/dep_a.git", {tag, "0.0.1"}}}, + DepB = {dep_b, "0.0.1", {git, "https://example.org/user/dep_b.git", {tag, "0.0.1"}}}, + DepC = {dep_c, "0.0.1", {git, "https://example.org/user/dep_c.git", {tag, "0.0.1"}}}, + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + RebarConfig = [ + {deps, TopDeps}, + {profiles, [ + {a, [ + {overrides, [ + {del, some_dep, [ + {deps, [DepA, DepB]} + ]}, + {del, [ + {deps, [DepC]} + ]} + ]} + ]} + ]} + ], + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], + {ok, [{dep, "some_dep"}, + {dep, "other_dep"}, + {dep_not_exist, "dep_a"}, + {dep_not_exist, "dep_b"}, + {dep_not_exist, "dep_c"}, + {dep, "dep_d"}]} + ). + +profile_override_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + compressed, + warn_missing_spec + ]}, + {profiles, [ + {a, [ + {overrides, [ + {override, [ + {erl_opts, [compressed]} + ]} + ]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + +profile_override_add_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + warn_missing_spec + ]}, + {profiles, [ + {a, [ + {overrides, [ + {add, [ + {erl_opts, [compressed]} + ]} + ]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + true = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + +profile_override_del_opts(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [ + {erl_opts, [ + compressed, + warn_missing_spec + ]}, + {profiles, [ + {a, [ + {overrides, [ + {del, [ + {erl_opts, [warn_missing_spec]} + ]} + ]} + ]} + ]} + ], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "a", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). + +profile_deps(Config) -> + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + RebarConfig = [ + {deps, TopDeps}, + {profiles, [{a, []}]}], + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "a", "compile"], + {ok, [{dep, "some_dep"},{dep, "other_dep"}]} + ). + +only_deps(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + RConfFile = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]), + {ok, RConf} = file:consult(RConfFile), + rebar_test_utils:run_and_check( + Config, RConf, ["compile", "--deps_only"], + {ok, [{app_not_exist, Name}, {dep, "some_dep"},{dep, "other_dep"}]} ). %% verify a deps prod profile is used @@ -1310,7 +1848,151 @@ include_file_in_src(Config) -> ["compile"], {ok, [{app, Name}]}). -always_recompile_when_erl_compiler_options_set(Config) -> +%% verify that the proper include path is defined +%% according the erlang doc which states: +%% If the filename File is absolute (possibly after variable substitution), +%% the include file with that name is included. Otherwise, the specified file +%% is searched for in the following directories, and in this order: +%% * The current working directory +%% * The directory where the module is being compiled +%% * The directories given by the include option +%% +%% This test ensures that things keep working when additional directories +%% are used for apps, such as the test/ directory within the test profile. +include_file_relative_to_working_directory_test(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + Src = <<"-module(test).\n" +"\n" +"-include(\"include/test.hrl\").\n" +"\n" +"test() -> ?TEST_MACRO.\n" +"\n">>, + Include = <<"-define(TEST_MACRO, test).\n">>, + + ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])), + ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])), + ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src), + + ok = filelib:ensure_dir(filename:join([AppDir, "include", "dummy"])), + ok = file:write_file(filename:join([AppDir, "include", "test.hrl"]), Include), + + RebarConfig = [], + rebar_test_utils:run_and_check(Config, RebarConfig, + ["as", "test", "compile"], + {ok, [{app, Name}]}). + +%% Same as `include_file_in_src/1' but using the `test/' directory +%% within the test profile. +include_file_in_src_test(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + Src = <<"-module(test).\n" +"\n" +"-include(\"test.hrl\").\n" +"\n" +"test() -> ?TEST_MACRO.\n" +"\n">>, + Include = <<"-define(TEST_MACRO, test).\n">>, + + ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])), + ok = filelib:ensure_dir(filename:join([AppDir, "test", "dummy"])), + ok = file:write_file(filename:join([AppDir, "test", "test.erl"]), Src), + + ok = file:write_file(filename:join([AppDir, "src", "test.hrl"]), Include), + + RebarConfig = [], + rebar_test_utils:run_and_check(Config, RebarConfig, + ["as", "test", "compile"], + {ok, [{app, Name}]}). + +%% Same as `include_file_in_src_test/1' but using multiple top-level +%% apps as dependencies. +include_file_in_src_test_multiapp(Config) -> + + Name1 = rebar_test_utils:create_random_name("app2_"), + Name2 = rebar_test_utils:create_random_name("app1_"), + AppDir1 = filename:join([?config(apps, Config), "lib", Name1]), + AppDir2 = filename:join([?config(apps, Config), "lib", Name2]), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir1, Name1, Vsn, [kernel, stdlib, list_to_atom(Name2)]), + rebar_test_utils:create_app(AppDir2, Name2, Vsn, [kernel, stdlib]), + + Src = "-module(test).\n" +"\n" +"-include_lib(\"" ++ Name2 ++ "/include/test.hrl\").\n" +"\n" +"test() -> ?TEST_MACRO.\n" +"\n", + Include = <<"-define(TEST_MACRO, test).\n">>, + + ok = filelib:ensure_dir(filename:join([AppDir1, "src", "dummy"])), + ok = filelib:ensure_dir(filename:join([AppDir1, "test", "dummy"])), + ok = filelib:ensure_dir(filename:join([AppDir2, "src", "dummy"])), + ok = filelib:ensure_dir(filename:join([AppDir2, "include", "dummy"])), + ok = file:write_file(filename:join([AppDir1, "test", "test.erl"]), Src), + + ok = file:write_file(filename:join([AppDir2, "include", "test.hrl"]), Include), + + RebarConfig = [], + rebar_test_utils:run_and_check(Config, RebarConfig, + ["as", "test", "compile"], + {ok, [{app, Name1}]}), + ok. + +%% this test sets the env var, compiles, records the file last modified timestamp, +%% recompiles and compares the file last modified timestamp to ensure it hasn't +%% changed. this test should run on 19.x+ +dont_recompile_when_erl_compiler_options_env_does_not_change(Config) -> + %% save existing env to restore after test + ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"), + + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("erl_compiler_options_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + true = os:unsetenv("ERL_COMPILER_OPTIONS"), + + true = os:putenv("ERL_COMPILER_OPTIONS", "[{d, some_macro}]"), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + + {ok, Files} = rebar_utils:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:extension(F) == ".beam"], + + timer:sleep(1000), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = rebar_utils:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:extension(F) == ".beam"], + + ?assert(ModTime == NewModTime), + + %% restore existing env + case ExistingEnv of + false -> ok; + _ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv) + end. + +%% this test compiles, records the file last modified timestamp, sets the env +%% var, recompiles and compares the file last modified timestamp to ensure it +%% has changed. this test should run on 19.x+ +recompile_when_erl_compiler_options_env_changes(Config) -> %% save existing env to restore after test ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"), @@ -1348,5 +2030,381 @@ always_recompile_when_erl_compiler_options_set(Config) -> _ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv) end. +rebar_config_os_var(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("rebar_config_os_var_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + rebar_test_utils:create_config(AppDir, [{erl_opts, []}]), + + AltConfig = filename:join(AppDir, "test.rebar.config"), + file:write_file(AltConfig, "{erl_opts, [compressed]}."), + true = os:putenv("REBAR_CONFIG", AltConfig), + + rebar_test_utils:run_and_check(Config, ["compile"], {ok, [{app, Name}]}), + + Path = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + code:add_patha(Path), + + Mod = list_to_atom("not_a_real_src_" ++ Name), + + true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), + ok. + +%% this test sets the env var, compiles, records the file last modified +%% timestamp, recompiles and compares the file last modified timestamp to +%% ensure it has changed. this test should run on 18.x +always_recompile_when_erl_compiler_options_set(Config) -> + %% save existing env to restore after test + ExistingEnv = os:getenv("ERL_COMPILER_OPTIONS"), + + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("erl_compiler_options_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + true = os:unsetenv("ERL_COMPILER_OPTIONS"), + + true = os:putenv("ERL_COMPILER_OPTIONS", "[{d, some_macro}]"), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + + {ok, Files} = rebar_utils:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:extension(F) == ".beam"], + + timer:sleep(1000), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = rebar_utils:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:extension(F) == ".beam"], + + ?assert(ModTime =/= NewModTime), + + %% restore existing env + case ExistingEnv of + false -> ok; + _ -> os:putenv("ERL_COMPILER_OPTIONS", ExistingEnv) + end. + +recompile_when_parse_transform_inline_changes(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("parse_transform_inline_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])), + + ModSrc = <<"-module(example).\n" + "-export([foo/2]).\n" + "-compile([{parse_transform, example_parse_transform}]).\n" + "foo(_, _) -> ok.">>, + + ok = file:write_file(filename:join([AppDir, "src", "example.erl"]), + ModSrc), + + ParseTransform = <<"-module(example_parse_transform).\n" + "-export([parse_transform/2]).\n" + "parse_transform(AST, _) -> AST.\n">>, + + ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]), + ParseTransform), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + {ok, Files} = rebar_utils:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:basename(F, ".beam") == "example"], + + timer:sleep(1000), + + NewParseTransform = <<"-module(example_parse_transform).\n" + "-export([parse_transform/2]).\n" + "parse_transform(AST, _) -> identity(AST).\n" + "identity(AST) -> AST.\n">>, + + ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]), + NewParseTransform), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = rebar_utils:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:basename(F, ".beam") == "example"], + + ?assert(ModTime =/= NewModTime). + +recompile_when_parse_transform_as_opt_changes(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("parse_transform_opt_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + ok = filelib:ensure_dir(filename:join([AppDir, "src", "dummy"])), + + ModSrc = <<"-module(example).\n" + "-export([foo/2]).\n" + "foo(_, _) -> ok.">>, + ok = file:write_file(filename:join([AppDir, "src", "example.erl"]), + ModSrc), + + ParseTransform = <<"-module(example_parse_transform).\n" + "-export([parse_transform/2]).\n" + "parse_transform(AST, _) -> AST.">>, + + ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]), + ParseTransform), + + RebarConfig = [{erl_opts, [{parse_transform, example_parse_transform}]}], + + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + {ok, Files} = rebar_utils:list_dir(EbinDir), + ModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- Files, filename:basename(F, ".beam") == "example"], + + timer:sleep(1000), + + NewParseTransform = <<"-module(example_parse_transform).\n" + "-export([parse_transform/2]).\n" + "parse_transform(AST, _) -> identity(AST).\n" + "identity(AST) -> AST.">>, + + ok = file:write_file(filename:join([AppDir, "src", "example_parse_transform.erl"]), + NewParseTransform), + + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}), + + {ok, NewFiles} = rebar_utils:list_dir(EbinDir), + NewModTime = [filelib:last_modified(filename:join([EbinDir, F])) + || F <- NewFiles, filename:basename(F, ".beam") == "example"], + + ?assert(ModTime =/= NewModTime). + +recursive(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + rebar_test_utils:write_src_file(filename:join(AppDir,src),"rec.erl"), + + rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}), + + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + {ok, Files} = rebar_utils:list_dir(EbinDir), + ?assert(lists:member("rec.beam",Files)), + + %% check that rec is in modules list of .app file + AppFile = filename:join(EbinDir, Name++".app"), + {ok, [{application, _, List}]} = file:consult(AppFile), + {modules, Modules} = lists:keyfind(modules, 1, List), + ?assert(lists:member(rec, Modules)). + +no_recursive(Config) -> + AppDir = ?config(apps, Config), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + rebar_test_utils:write_src_file(filename:join(AppDir,src),"rec.erl"), + + RebarConfig1 = [{erlc_compiler,[{recursive,false}]}], + rebar_test_utils:run_and_check(Config, RebarConfig1, ["compile"], + {ok, [{app, Name}]}), + EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]), + {ok, Files1} = rebar_utils:list_dir(EbinDir), + ?assert(false==lists:member("rec.beam",Files1)), + + RebarConfig2 = [{src_dirs,[{"src",[{recursive,false}]}]}], + rebar_test_utils:run_and_check(Config, RebarConfig2, ["compile"], + {ok, [{app, Name}]}), + {ok, Files2} = rebar_utils:list_dir(EbinDir), + ?assert(false==lists:member("rec.beam",Files2)), + ok. + +regex_filter_skip(Config) -> + AppDir = ?config(apps, Config), + Name = rebar_test_utils:create_random_name("regex_skip"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + rebar_test_utils:write_src_file(filename:join(AppDir,src),"._rec.erl"), + Expected = filename:join([AppDir, "_build", "default", "lib", Name, "ebin","._rec.beam"]), + + RebarConfig = [], + try + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], + {ok, [{file, Expected}]}), + throw(should_not_be_found) + catch + %% the file was not found, as desired! + error:{assertion_failed,_} -> %% OTP =< 17 + ok; + error:{assert,_} -> %% OTP >= 18 + ok + end. + +regex_filter_regression(Config) -> + AppDir = ?config(apps, Config), + Name = rebar_test_utils:create_random_name("regex_regression"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + rebar_test_utils:write_src_file(filename:join(AppDir,src),"r_f.erl"), + Expected = filename:join([AppDir, "_build", "default", "lib", Name, "ebin","r_f.beam"]), + RebarConfig = [], + rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], + {ok, [{file, Expected}]}), + ok. + +%% + +%% a copy of lib/parsetools/include/yeccpre.hrl so we can test yrl includefile +yeccpre_hrl() -> + <<"-type yecc_ret() :: {'error', _} | {'ok', _}. + +-spec parse(Tokens :: list()) -> yecc_ret(). +parse(Tokens) -> + yeccpars0(Tokens, {no_func, no_line}, 0, [], []). + +-spec parse_and_scan({function() | {atom(), atom()}, [_]} + | {atom(), atom(), [_]}) -> yecc_ret(). +parse_and_scan({F, A}) -> + yeccpars0([], {{F, A}, no_line}, 0, [], []); +parse_and_scan({M, F, A}) -> + Arity = length(A), + yeccpars0([], {{fun M:F/Arity, A}, no_line}, 0, [], []). + +-spec format_error(any()) -> [char() | list()]. +format_error(Message) -> + case io_lib:deep_char_list(Message) of + true -> + Message; + _ -> + io_lib:write(Message) + end. + +%% To be used in grammar files to throw an error message to the parser +%% toplevel. Doesn't have to be exported! +-compile({nowarn_unused_function, return_error/2}). +-spec return_error(integer(), any()) -> no_return(). +return_error(Line, Message) -> + throw({error, {Line, ?MODULE, Message}}). + +-define(CODE_VERSION, \"1.4\"). + +yeccpars0(Tokens, Tzr, State, States, Vstack) -> + try yeccpars1(Tokens, Tzr, State, States, Vstack) + catch + error:Error -> + try yecc_error_type(Error, []) of + Desc -> + erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc}, + []) + catch _:_ -> erlang:raise(error, Error, []) + end; + %% Probably thrown from return_error/2: + throw: {error, {_Line, ?MODULE, _M}} = Error -> + Error + end. + +yecc_error_type(function_clause, _) -> + not_implemented. + +yeccpars1([Token | Tokens], Tzr, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr); +yeccpars1([], {{F, A},_Line}, State, States, Vstack) -> + case apply(F, A) of + {ok, Tokens, Endline} -> + yeccpars1(Tokens, {{F, A}, Endline}, State, States, Vstack); + {eof, Endline} -> + yeccpars1([], {no_func, Endline}, State, States, Vstack); + {error, Descriptor, _Endline} -> + {error, Descriptor} + end; +yeccpars1([], {no_func, no_line}, State, States, Vstack) -> + Line = 999999, + yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [], + {no_func, Line}); +yeccpars1([], {no_func, Endline}, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, yecc_end(Endline), [], + {no_func, Endline}). + +%% yeccpars1/7 is called from generated code. +%% +%% When using the {includefile, Includefile} option, make sure that +%% yeccpars1/7 can be found by parsing the file without following +%% include directives. yecc will otherwise assume that an old +%% yeccpre.hrl is included (one which defines yeccpars1/5). +yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) -> + yeccpars2(State, element(1, Token), [State1 | States], + [Token0 | Vstack], Token, Tokens, Tzr); +yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Line}=Tzr) -> + yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_line}) -> + Line = yecctoken_end_location(Token0), + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Line), [], {no_func, Line}); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Line}) -> + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Line), [], {no_func, Line}). + +%% For internal use only. +yecc_end({Line,_Column}) -> + {'$end', Line}; +yecc_end(Line) -> + {'$end', Line}. + +yecctoken_end_location(Token) -> + try erl_anno:end_location(element(2, Token)) of + undefined -> yecctoken_location(Token); + Loc -> Loc + catch _:_ -> yecctoken_location(Token) + end. + +-compile({nowarn_unused_function, yeccerror/1}). +yeccerror(Token) -> + Text = yecctoken_to_string(Token), + Location = yecctoken_location(Token), + {error, {Location, ?MODULE, [\"syntax error before: \", Text]}}. + +-compile({nowarn_unused_function, yecctoken_to_string/1}). +yecctoken_to_string(Token) -> + try erl_scan:text(Token) of + undefined -> yecctoken2string(Token); + Txt -> Txt + catch _:_ -> yecctoken2string(Token) + end. + +yecctoken_location(Token) -> + try erl_scan:location(Token) + catch _:_ -> element(2, Token) + end. +-compile({nowarn_unused_function, yecctoken2string/1}). +yecctoken2string({atom, _, A}) -> io_lib:write_atom(A); +yecctoken2string({integer,_,N}) -> io_lib:write(N); +yecctoken2string({float,_,F}) -> io_lib:write(F); +yecctoken2string({char,_,C}) -> io_lib:write_char(C); +yecctoken2string({var,_,V}) -> io_lib:format(\"~s\", [V]); +yecctoken2string({string,_,S}) -> io_lib:write_string(S); +yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A); +yecctoken2string({_Cat, _, Val}) -> io_lib:format(\"~p\", [Val]); +yecctoken2string({dot, _}) -> \"'.'\"; +yecctoken2string({'$end', _}) -> []; +yecctoken2string({Other, _}) when is_atom(Other) -> + io_lib:write_atom(Other); +yecctoken2string(Other) -> + io_lib:format(\"~p\", [Other]). +">>. |