1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2005-2013. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(filelib_SUITE).
   21: 
   22: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   23: 	 init_per_group/2,end_per_group/2,
   24: 	 init_per_testcase/2,end_per_testcase/2,
   25: 	 wildcard_one/1,wildcard_two/1,wildcard_errors/1,
   26: 	 fold_files/1,otp_5960/1,ensure_dir_eexist/1]).
   27: 
   28: -import(lists, [foreach/2]).
   29: 
   30: -include_lib("test_server/include/test_server.hrl").
   31: -include_lib("kernel/include/file.hrl").
   32: 
   33: init_per_testcase(_Case, Config) ->
   34:     ?line Dog = ?t:timetrap(?t:minutes(5)),
   35:     [{watchdog,Dog}|Config].
   36: 
   37: end_per_testcase(_Case, Config) ->
   38:     Dog = ?config(watchdog, Config),
   39:     test_server:timetrap_cancel(Dog),
   40:     ok.
   41: 
   42: suite() -> [{ct_hooks,[ts_install_cth]}].
   43: 
   44: all() -> 
   45:     [wildcard_one, wildcard_two, wildcard_errors,
   46:      fold_files, otp_5960, ensure_dir_eexist].
   47: 
   48: groups() -> 
   49:     [].
   50: 
   51: init_per_suite(Config) ->
   52:     Config.
   53: 
   54: end_per_suite(_Config) ->
   55:     ok.
   56: 
   57: init_per_group(_GroupName, Config) ->
   58:     Config.
   59: 
   60: end_per_group(_GroupName, Config) ->
   61:     Config.
   62: 
   63: 
   64: wildcard_one(Config) when is_list(Config) ->
   65:     ?line {ok,OldCwd} = file:get_cwd(),
   66:     ?line Dir = filename:join(?config(priv_dir, Config), "wildcard_one"),
   67:     ?line ok = file:make_dir(Dir),
   68:     do_wildcard_1(Dir,
   69: 		  fun(Wc) ->
   70: 			  filelib:wildcard(Wc, Dir, erl_prim_loader)
   71: 		  end),
   72:     ?line file:set_cwd(Dir),
   73:     do_wildcard_1(Dir,
   74: 		  fun(Wc) ->
   75: 			  L = filelib:wildcard(Wc),
   76: 			  L = filelib:wildcard(Wc, erl_prim_loader),
   77: 			  L = filelib:wildcard(Wc, "."),
   78: 			  L = filelib:wildcard(Wc, Dir)
   79: 		  end),
   80:     ?line file:set_cwd(OldCwd),
   81:     ?line ok = file:del_dir(Dir),
   82:     ok.
   83: 
   84: wildcard_two(Config) when is_list(Config) ->
   85:     ?line Dir = filename:join(?config(priv_dir, Config), "wildcard_two"),
   86:     ?line ok = file:make_dir(Dir),
   87:     ?line do_wildcard_1(Dir, fun(Wc) -> io:format("~p~n",[{Wc,Dir, X = filelib:wildcard(Wc, Dir)}]),X  end),
   88:     ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc, Dir++"/") end),
   89:     case os:type() of
   90: 	{win32,_} ->
   91: 	    ok;
   92: 	_ ->
   93: 	    ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc, "//"++Dir) end)
   94:     end,
   95:     ?line ok = file:del_dir(Dir),
   96:     ok.
   97: 
   98: wildcard_errors(Config) when is_list(Config) ->
   99:     ?line wcc("{", missing_delimiter),
  100:     ?line wcc("{a", missing_delimiter),
  101:     ?line wcc("{a,", missing_delimiter),
  102:     ?line wcc("{a,b", missing_delimiter),
  103:     ok.
  104: 
  105: wcc(Wc, Error) ->
  106:     {'EXIT',{{badpattern,Error},
  107: 	     [{filelib,compile_wildcard,1,_}|_]}} =
  108: 	(catch filelib:compile_wildcard(Wc)),
  109:     {'EXIT',{{badpattern,Error},
  110: 	     [{filelib,wildcard,1,_}|_]}} = (catch filelib:wildcard(Wc)),
  111:     {'EXIT',{{badpattern,Error},
  112: 	     [{filelib,wildcard,2,_}|_]}} = (catch filelib:wildcard(Wc, ".")).
  113: 
  114: do_wildcard_1(Dir, Wcf0) ->
  115:     do_wildcard_2(Dir, Wcf0),
  116:     Wcf = fun(Wc0) ->
  117: 		  Wc = filename:join(Dir, Wc0),
  118: 		  L = Wcf0(Wc),
  119: 		  [subtract_dir(N, Dir) || N <- L]
  120: 	  end,
  121:     do_wildcard_2(Dir, Wcf).
  122: 
  123: subtract_dir([C|Cs], [C|Dir]) -> subtract_dir(Cs, Dir);
  124: subtract_dir("/"++Cs, []) -> Cs.
  125: 
  126: do_wildcard_2(Dir, Wcf) ->
  127:     %% Basic wildcards.
  128:     All = ["abc","abcdef","glurf"],
  129:     ?line Files = mkfiles(lists:reverse(All), Dir),
  130:     ?line All = Wcf("*"),
  131:     ?line ["abc","abcdef"] = Wcf("a*"),
  132:     ?line ["abc","abcdef"] = Wcf("abc*"),
  133:     ?line ["abcdef"] = Wcf("abc???"),
  134:     ?line ["abcdef"] = Wcf("abcd*"),
  135:     ?line ["abcdef"] = Wcf("*def"),
  136:     ?line ["abcdef","glurf"] = Wcf("{*def,gl*}"),
  137:     ?line ["abc","abcdef"] = Wcf("a*{def,}"),
  138:     ?line ["abc","abcdef"] = Wcf("a*{,def}"),
  139: 
  140:     %% Constant wildcard.
  141:     ["abcdef"] = Wcf("abcdef"),
  142: 
  143:     %% Negative tests.
  144:     ?line [] = Wcf("b*"),
  145:     ?line [] = Wcf("bufflig"),
  146: 
  147:     ?line del(Files),
  148:     do_wildcard_3(Dir, Wcf).
  149:     
  150: do_wildcard_3(Dir, Wcf) ->
  151:     %% Some character sets.
  152:     All = ["a01","a02","a03","b00","c02","d19"],
  153:     ?line Files = mkfiles(lists:reverse(All), Dir),
  154:     ?line All = Wcf("[a-z]*"),
  155:     ?line All = Wcf("[a-d]*"),
  156:     ?line All = Wcf("[adbc]*"),
  157:     ?line All = Wcf("?[0-9][0-9]"),
  158:     ?line All = Wcf("?[0-1][0-39]"),
  159:     ?line All = Wcf("[abcdefgh][10][01239]"),
  160:     ?line ["a01","a02","a03","b00","c02"] = Wcf("[a-z]0[0-3]"),
  161:     ?line [] = Wcf("?[a-z][0-39]"),
  162:     ?line del(Files),
  163:     do_wildcard_4(Dir, Wcf).
  164: 
  165: do_wildcard_4(Dir, Wcf) ->
  166:     %% More character sets: tricky characters.
  167:     All = ["a-","aA","aB","aC","a[","a]"],
  168:     ?line Files = mkfiles(lists:reverse(All), Dir),
  169:     ?line All = Wcf("a[][A-C-]"),
  170:     ["a-"] = Wcf("a[-]"),
  171:     ["a["] = Wcf("a["),
  172:     ?line del(Files),
  173:     do_wildcard_5(Dir, Wcf).
  174: 
  175: do_wildcard_5(Dir, Wcf) ->
  176:     Dirs = ["xa","blurf","yyy"],
  177:     ?line foreach(fun(D) -> ok = file:make_dir(filename:join(Dir, D)) end, Dirs),
  178:     All = ["blurf/nisse","xa/arne","xa/kalle","yyy/arne"],
  179:     ?line Files = mkfiles(lists:reverse(All), Dir),
  180: 
  181:     %% Test.
  182:     ?line All = Wcf("*/*"),
  183:     ?line ["blurf/nisse","xa/arne","xa/kalle"] = Wcf("{blurf,xa}/*"),
  184:     ?line ["xa/arne","yyy/arne"] = Wcf("*/arne"),
  185:     ?line ["blurf/nisse"] = Wcf("*/nisse"),
  186:     ?line [] = Wcf("mountain/*"),
  187:     ?line [] = Wcf("xa/gurka"),
  188:     ["blurf/nisse"] = Wcf("blurf/nisse"),
  189: 
  190:     %% Cleanup
  191:     ?line del(Files),
  192:     ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs),
  193:     do_wildcard_6(Dir, Wcf).
  194: 
  195: do_wildcard_6(Dir, Wcf) ->
  196:     ok = file:make_dir(filename:join(Dir, "xbin")),
  197:     All = ["xbin/a.x","xbin/b.x","xbin/c.x"],
  198:     Files = mkfiles(All, Dir),
  199:     All = Wcf("xbin/*.x"),
  200:     All = Wcf("xbin/*"),
  201:     ["xbin"] = Wcf("*"),
  202:     All = Wcf("*/*"),
  203:     del(Files),
  204:     ok = file:del_dir(filename:join(Dir, "xbin")),
  205:     do_wildcard_7(Dir, Wcf).
  206: 
  207: do_wildcard_7(Dir, Wcf) ->
  208:     Dirs = ["blurf","xa","yyy"],
  209:     SubDirs = ["blurf/nisse"],
  210:     foreach(fun(D) ->
  211: 		    ok = file:make_dir(filename:join(Dir, D))
  212: 	    end, Dirs ++ SubDirs),
  213:     All = ["blurf/nisse/baz","xa/arne","xa/kalle","yyy/arne"],
  214:     Files = mkfiles(lists:reverse(All), Dir),
  215: 
  216:     %% Test.
  217:     Listing = Wcf("**"),
  218:     ["blurf","blurf/nisse","blurf/nisse/baz",
  219:      "xa","xa/arne","xa/kalle","yyy","yyy/arne"] = Listing,
  220:     Listing = Wcf("**/*"),
  221:     ["xa/arne","yyy/arne"] = Wcf("**/arne"),
  222:     ["blurf/nisse"] = Wcf("**/nisse"),
  223:     [] = Wcf("mountain/**"),
  224: 
  225:     %% Cleanup
  226:     del(Files),
  227:     foreach(fun(D) ->
  228: 		    ok = file:del_dir(filename:join(Dir, D))
  229: 	    end, SubDirs ++ Dirs),
  230:     do_wildcard_8(Dir, Wcf).
  231: 
  232: do_wildcard_8(Dir, Wcf) ->
  233:     Dirs0 = ["blurf"],
  234:     Dirs1 = ["blurf/nisse"],
  235:     Dirs2 = ["blurf/nisse/a", "blurf/nisse/b"],
  236:     foreach(fun(D) ->
  237: 		    ok = file:make_dir(filename:join(Dir, D))
  238: 	    end, Dirs0 ++ Dirs1 ++ Dirs2),
  239:     All = ["blurf/nisse/a/1.txt", "blurf/nisse/b/2.txt", "blurf/nisse/b/3.txt"],
  240:     Files = mkfiles(lists:reverse(All), Dir),
  241: 
  242:     %% Test.
  243:     All = Wcf("**/blurf/**/*.txt"),
  244: 
  245:     %% Cleanup
  246:     del(Files),
  247:     foreach(fun(D) ->
  248: 		    ok = file:del_dir(filename:join(Dir, D))
  249: 	    end, Dirs2 ++ Dirs1 ++ Dirs0),
  250:     do_wildcard_9(Dir, Wcf).
  251: 
  252: do_wildcard_9(Dir, Wcf) ->
  253:     Dirs0 = ["lib","lib/app","lib/app/ebin"],
  254:     Dirs = [filename:join(Dir, D) || D <- Dirs0],
  255:     [ok = file:make_dir(D) || D <- Dirs],
  256:     Files0 = [filename:join("lib/app/ebin", F++".bar") ||
  257: 		 F <- ["abc","foo","foobar"]],
  258:     Files = [filename:join(Dir, F) || F <- Files0],
  259:     [ok = file:write_file(F, <<"some content\n">>) || F <- Files],
  260:     Files0 = Wcf("lib/app/ebin/*.bar"),
  261: 
  262:     %% Cleanup.
  263:     del(Files),
  264:     [ok = file:del_dir(D) || D <- lists:reverse(Dirs)],
  265:     ok.
  266: 
  267: 
  268: fold_files(Config) when is_list(Config) ->
  269:     ?line Dir = filename:join(?config(priv_dir, Config), "fold_files"),
  270:     ?line ok = file:make_dir(Dir),
  271:     ?line Dirs = [filename:join(Dir, D) || D <- ["blurf","blurf/blarf"]],
  272:     ?line foreach(fun(D) -> ok = file:make_dir(D) end, Dirs),
  273:     All = ["fb.txt","ko.txt",
  274: 	   "blurf/nisse.text","blurf/blarf/aaa.txt","blurf/blarf/urfa.txt"],
  275:     ?line Files = mkfiles(lists:reverse(All), Dir),
  276: 
  277:     %% Test.
  278:     ?line Files0 = filelib:fold_files(Dir, "^", false,
  279: 				      fun(H, T) -> [H|T] end, []),
  280:     ?line same_lists(["fb.txt","ko.txt"], Files0, Dir),
  281: 
  282:     ?line Files1 = filelib:fold_files(Dir, "^", true,
  283: 				      fun(H, T) -> [H|T] end, []),
  284:     ?line same_lists(All, Files1, Dir),
  285: 
  286:     ?line Files2 = filelib:fold_files(Dir, "[.]text$", true,
  287: 				      fun(H, T) -> [H|T] end, []),
  288:     ?line same_lists(["blurf/nisse.text"], Files2, Dir),
  289: 
  290: 
  291:     ?line Files3 = filelib:fold_files(Dir, "^..[.]", true,
  292: 				      fun(H, T) -> [H|T] end, []),
  293:     ?line same_lists(["fb.txt","ko.txt"], Files3, Dir),
  294: 
  295:     ?line Files4 = filelib:fold_files(Dir, "^ko[.]txt$", true,
  296: 				  fun(H, T) -> [H|T] end, []),
  297:     ?line same_lists(["ko.txt"], Files4, Dir),
  298:     ?line Files4 = filelib:fold_files(Dir, "^ko[.]txt$", false,
  299: 				      fun(H, T) -> [H|T] end, []),
  300: 
  301:     ?line [] = filelib:fold_files(Dir, "^$", true,
  302: 				  fun(H, T) -> [H|T] end, []),
  303: 
  304:     %% Cleanup
  305:     ?line del(Files),
  306:     ?line foreach(fun(D) -> ok = file:del_dir(D) end, lists:reverse(Dirs)),
  307:     ?line ok = file:del_dir(Dir).
  308: 
  309: same_lists(Expected0, Actual0, BaseDir) ->
  310:     Expected = [filename:absname(N, BaseDir) || N <- lists:sort(Expected0)],
  311:     Actual = lists:sort(Actual0),
  312:     Expected = Actual.
  313: 
  314: mkfiles([H|T], Dir) ->
  315:     Name = filename:join(Dir, H),
  316:     Garbage = [31+random:uniform(95) || _ <- lists:seq(1, random:uniform(1024))],
  317:     file:write_file(Name, Garbage),
  318:     [Name|mkfiles(T, Dir)];
  319: mkfiles([], _) -> [].
  320: 
  321: del([H|T]) ->
  322:     ok = file:delete(H),
  323:     del(T);
  324: del([]) -> ok.
  325: 
  326: otp_5960(suite) ->
  327:     [];
  328: otp_5960(doc) ->
  329:     ["Test that filelib:ensure_dir/1 returns ok or {error,Reason}"];
  330: otp_5960(Config) when is_list(Config) ->
  331:     ?line PrivDir = ?config(priv_dir, Config),
  332:     ?line Dir = filename:join(PrivDir, "otp_5960_dir"),
  333:     ?line Name1 = filename:join(Dir, name1),
  334:     ?line Name2 = filename:join(Dir, name2),
  335:     ?line ok = filelib:ensure_dir(Name1), % parent is created
  336:     ?line ok = filelib:ensure_dir(Name1), % repeating it should be OK
  337:     ?line ok = filelib:ensure_dir(Name2), % parent already exists
  338:     ?line ok = filelib:ensure_dir(Name2), % repeating it should be OK
  339:     ?line Name3 = filename:join(Name1, name3),
  340:     ?line {ok, FileInfo} = file:read_file_info(Dir),
  341:     case os:type() of
  342: 	{win32,_} ->
  343: 	    %% Not possibly to write protect directories on Windows
  344: 	    %% (at least not using file:write_file_info/2).
  345: 	    ok;
  346: 	_ ->
  347: 	    ?line Mode = FileInfo#file_info.mode,
  348: 	    ?line NoWriteMode = Mode - 8#00200 - 8#00020 - 8#00002,
  349: 	    ?line ok = file:write_file_info(Dir, #file_info{mode=NoWriteMode}), 
  350: 	    ?line {error, _} = filelib:ensure_dir(Name3),
  351: 	    ?line ok = file:write_file_info(Dir, #file_info{mode=Mode}),
  352: 	    ok
  353:     end.
  354: 
  355: ensure_dir_eexist(Config) when is_list(Config) ->
  356:     ?line PrivDir = ?config(priv_dir, Config),
  357:     ?line Dir = filename:join(PrivDir, "ensure_dir_eexist"),
  358:     ?line Name = filename:join(Dir, "same_name_as_file_and_dir"),
  359:     ?line ok = filelib:ensure_dir(Name),
  360:     ?line ok = file:write_file(Name, <<"some string\n">>),
  361: 
  362:     %% There already is a file with the name of the directory
  363:     %% we want to create.
  364:     ?line NeedFile = filename:join(Name, "file"),
  365:     ?line NeedFileB = filename:join(Name, <<"file">>),
  366:     ?line {error, eexist} = filelib:ensure_dir(NeedFile),
  367:     ?line {error, eexist} = filelib:ensure_dir(NeedFileB),
  368:     ok.