1%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
2%% ex: ts=4 sw=4 et
3%% -------------------------------------------------------------------
4%%
5%% rebar: Erlang Build Tools
6%%
7%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
8%%
9%% Permission is hereby granted, free of charge, to any person obtaining a copy
10%% of this software and associated documentation files (the "Software"), to deal
11%% in the Software without restriction, including without limitation the rights
12%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13%% copies of the Software, and to permit persons to whom the Software is
14%% furnished to do so, subject to the following conditions:
15%%
16%% The above copyright notice and this permission notice shall be included in
17%% all copies or substantial portions of the Software.
18%%
19%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25%% THE SOFTWARE.
26%% -------------------------------------------------------------------
27%% @author Juhani Rankimies <juhani@juranki.com>
28%% @doc Tests functionality of rebar_file_utils module.
29%% @copyright 2009, 2010 Dave Smith
30%% -------------------------------------------------------------------
31-module(rebar_file_utils_tests).
32
33-include_lib("eunit/include/eunit.hrl").
34
35-define(TMP_DIR, "tmp_file_utils").
36
37-define(SRC, "source dir").
38-define(DST, "dest (dir)").
39-define(FILE1, "file 1").
40-define(FILE2, "file(2)").
41-define(DIR_TREE, [{d,?SRC,[{f,?FILE1},
42                            {f,?FILE2}]},
43                   {d,?DST,[]}]).
44-define(FILE_CONTENT, <<"1234567890">>).
45
46%% ====================================================================
47%% delete_each tests
48%% ====================================================================
49
50delete_bogus_test_() ->
51    {"delete_each survives nonexisting files",
52     [?_assertMatch(ok, rebar_file_utils:delete_each(["bogus"])),
53      ?_assertMatch(ok, rebar_file_utils:delete_each(["bogus1","bogus2"]))]}.
54
55delete_each_test_() ->
56    {"delete_each removes files",
57     setup,
58     fun() ->
59             setup(),
60             rebar_file_utils:delete_each(file_list())
61     end,
62     fun teardown/1,
63     [assert_files_not_in(?SRC, file_list())]}.
64
65%% ====================================================================
66%% rm_rf tests
67%% ====================================================================
68
69rm_rf_wildcard_test_() ->
70    {"rm_rf removes files based on wildcard spec",
71     setup,
72     fun() ->
73             setup(),
74             rebar_file_utils:rm_rf(filename:join([?TMP_DIR,?SRC,"file*"]))
75     end,
76     fun teardown/1,
77     [assert_files_not_in(?SRC, file_list())]}.
78
79rm_rf_dir_test_() ->
80    {"rm_rf removes directory tree",
81     setup,
82     fun() ->
83             setup(),
84             rebar_file_utils:rm_rf(filename:join([?TMP_DIR,?SRC]))
85     end,
86     fun teardown/1,
87     [?_assertNot(filelib:is_dir(filename:join([?TMP_DIR,?SRC])))]}.
88
89%% ====================================================================
90%% cp_r tests
91%% ====================================================================
92
93cp_r_file_to_file_test_() ->
94    {"cp_r copies a file to file",
95     setup,
96     fun() ->
97             setup(),
98             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC,?FILE1])],
99                                   filename:join([?TMP_DIR,?DST,"new_file"]))
100     end,
101     fun teardown/1,
102     [?_assert(filelib:is_regular(filename:join([?TMP_DIR,?DST,"new_file"])))]}.
103
104cp_r_file_to_dir_test_() ->
105    {"cp_r copies a file to directory",
106     setup,
107     fun() ->
108             setup(),
109             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC,?FILE1])],
110                                   filename:join([?TMP_DIR,?DST]))
111     end,
112     fun teardown/1,
113     [?_assert(filelib:is_regular(filename:join([?TMP_DIR,?DST,?FILE1])))]}.
114
115cp_r_dir_to_dir_test_() ->
116    {"cp_r copies a directory to directory",
117     setup,
118     fun() ->
119             setup(),
120             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC])],
121                                   filename:join([?TMP_DIR,?DST]))
122     end,
123     fun teardown/1,
124     [?_assert(filelib:is_dir(filename:join([?TMP_DIR,?DST,?SRC]))),
125      assert_files_in("dest/source",
126                      [filename:join([?TMP_DIR,?DST,?SRC,F]) ||
127                          F <- [?FILE1,?FILE2]])]}.
128
129cp_r_wildcard_file_to_dir_test_() ->
130    {"cp_r copies wildcard files to directory",
131     setup,
132     fun() ->
133             setup(),
134             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC,"*1"])],
135                                   filename:join([?TMP_DIR,?DST]))
136     end,
137     fun teardown/1,
138     [?_assert(filelib:is_regular(filename:join([?TMP_DIR,?DST,?FILE1])))]}.
139
140cp_r_wildcard_dir_to_dir_test_() ->
141    {"cp_r copies wildcard directory to directory",
142     setup,
143     fun() ->
144             setup(),
145             rebar_file_utils:cp_r([filename:join([?TMP_DIR,"sour*"])],
146                                   filename:join([?TMP_DIR,?DST]))
147     end,
148     fun teardown/1,
149     [?_assert(filelib:is_dir(filename:join([?TMP_DIR,?DST,?SRC]))),
150      assert_files_in("dest/source",
151                      [filename:join([?TMP_DIR,?DST,?SRC,F]) ||
152                          F <- [?FILE1,?FILE2]])]}.
153
154cp_r_overwrite_file_test_() ->
155    {"cp_r overwrites destination file",
156     setup,
157     fun() ->
158             setup(),
159             ok = file:write_file(filename:join([?TMP_DIR,?DST,?FILE1]),
160                                  <<"test">>),
161             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC,?FILE1])],
162                                   filename:join([?TMP_DIR,?DST]))
163     end,
164     fun teardown/1,
165     [?_assertMatch({ok,?FILE_CONTENT},
166                    file:read_file(
167                      filename:join([?TMP_DIR,?DST,?FILE1])))]}.
168
169cp_r_overwrite_dir_test_() ->
170    {"cp_r overwrites destination file (xcopy case on win32)",
171     setup,
172     fun() ->
173             setup(),
174             ok = file:make_dir(filename:join([?TMP_DIR,?DST,?SRC])),
175             ok = file:write_file(
176                    filename:join([?TMP_DIR,?DST,?SRC,?FILE1]),
177                    <<"test">>),
178             rebar_file_utils:cp_r([filename:join([?TMP_DIR,?SRC])],
179                                   filename:join([?TMP_DIR,?DST]))
180     end,
181     fun teardown/1,
182     [?_assertMatch({ok,?FILE_CONTENT},
183                    file:read_file(
184                      filename:join([?TMP_DIR,?DST,?SRC,?FILE1])))]}.
185
186cp_r_overwrite_file_fail_test_() ->
187    {"cp_r fails to fs permission errors (file:copy/2 case on win32)",
188     setup,
189     fun() ->
190             setup(),
191             ok = file:write_file(
192                    filename:join([?TMP_DIR,?DST,?FILE1]),<<"test">>),
193             ok = file:change_mode(
194                    filename:join([?TMP_DIR,?DST,?FILE1]),0)
195     end,
196     fun teardown/1,
197     [?_assertThrow(rebar_abort,
198                    rebar_file_utils:cp_r(
199                      [filename:join([?TMP_DIR,?SRC,?FILE1])],
200                      filename:join([?TMP_DIR,?DST])))]}.
201
202cp_r_overwrite_dir_fail_test_() ->
203    {"cp_r fails to fs permission error (xcopy case on win32)",
204     setup,
205     fun() ->
206             setup(),
207             ok = file:make_dir(
208                    filename:join([?TMP_DIR,?DST,?SRC])),
209             ok = file:write_file(
210                    filename:join([?TMP_DIR,?DST,?SRC,?FILE1]),
211                    <<"test">>),
212             ok = file:change_mode(
213                    filename:join([?TMP_DIR,?DST,?SRC,?FILE1]),0)
214     end,
215     fun teardown/1,
216     [?_assertThrow(rebar_abort,
217                    rebar_file_utils:cp_r(
218                      [filename:join([?TMP_DIR,?SRC])],
219                      filename:join([?TMP_DIR,?DST])))]}.
220
221mv_file_test_() ->
222    {"move a file to folder",
223     setup,
224     fun() ->
225             setup(),
226             rebar_file_utils:mv(filename:join([?TMP_DIR,?SRC,?FILE1]),
227                                 filename:join([?TMP_DIR,?DST]))
228     end,
229     fun teardown/1,
230     [?_assert(filelib:is_regular(filename:join([?TMP_DIR,?DST,?FILE1]))),
231      ?_assertNot(filelib:is_regular(
232                    filename:join([?TMP_DIR,?SRC,?FILE1])))]}.
233
234%% ====================================================================
235%% Utilities
236%% ====================================================================
237
238file_list() ->
239    [filename:join([?TMP_DIR,?SRC,F]) || F <- [?FILE1,?FILE2]].
240
241%% ====================================================================
242%% Setup and Teardown
243%% ====================================================================
244
245setup() ->
246    make_dir_tree(?TMP_DIR,?DIR_TREE).
247
248make_dir_tree(Parent, [{d,Dir,Contents} | Rest]) ->
249    NewDir = filename:join(Parent,Dir),
250    ok = filelib:ensure_dir(filename:join(NewDir, "tmp")),
251    ok = make_dir_tree(NewDir,Contents),
252    ok = make_dir_tree(Parent,Rest);
253make_dir_tree(Parent, [{f,File} | Rest]) ->
254    ok = file:write_file(filename:join(Parent,File),?FILE_CONTENT),
255    ok = make_dir_tree(Parent,Rest);
256make_dir_tree(_,[]) ->
257    ok.
258
259teardown(_) ->
260    case os:type() of
261        {unix, _} ->
262            os:cmd("rm -rf " ++ ?TMP_DIR ++ " 2>/dev/null");
263        {win32, _} ->
264            os:cmd("rmdir /S /Q " ++ filename:nativename(?TMP_DIR))
265    end.
266
267%% ====================================================================
268%% Assert helpers
269%% ====================================================================
270
271assert_files_in(Name, [File|T]) ->
272    [{Name ++ " has file: " ++ File, ?_assert(filelib:is_regular(File))} |
273     assert_files_in(Name, T)];
274assert_files_in(_, []) -> [].
275
276assert_files_not_in(Name, [File|T]) ->
277    [{Name ++ " does not have file: " ++ File,
278      ?_assertNot(filelib:is_regular(File))} |
279     assert_files_not_in(Name, T)];
280assert_files_not_in(_, []) -> [].
281