summaryrefslogtreecommitdiff
path: root/test/rebar_compile_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'test/rebar_compile_SUITE.erl')
-rw-r--r--test/rebar_compile_SUITE.erl1226
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]).
+">>.