1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(filename_SUITE).
21-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
22	 init_per_group/2,end_per_group/2]).
23-export([absname/1, absname_2/1,
24	 basename_1/1, basename_2/1,
25	 dirname/1, extension/1, join/1, t_nativename/1]).
26-export([pathtype/1,rootname/1,split/1]).
27-export([absname_bin/1, absname_bin_2/1,
28	 basename_bin_1/1, basename_bin_2/1,
29	 dirname_bin/1, extension_bin/1, join_bin/1, t_nativename_bin/1]).
30-export([pathtype_bin/1,rootname_bin/1,split_bin/1]).
31-export([t_basedir_api/1, t_basedir_xdg/1, t_basedir_windows/1]).
32-export([safe_relative_path/1]).
33
34-include_lib("common_test/include/ct.hrl").
35
36suite() ->
37    [{ct_hooks,[ts_install_cth]},
38     {timetrap,{minutes,1}}].
39
40all() ->
41    [absname, absname_2,
42     absname_bin, absname_bin_2,
43     {group,p},
44     t_basedir_xdg, t_basedir_windows,
45     safe_relative_path].
46
47groups() ->
48    [{p, [parallel],
49      [dirname,
50       extension, extension_bin,
51       join, pathtype, rootname, split, t_nativename,
52       basename_1, basename_2,
53       basename_bin_1, basename_bin_2, dirname_bin,
54       join_bin, pathtype_bin, rootname_bin, split_bin,
55       t_nativename_bin,
56       t_basedir_api]}].
57
58init_per_suite(Config) ->
59    Config.
60
61end_per_suite(_Config) ->
62    ok.
63
64init_per_group(_GroupName, Config) ->
65    Config.
66
67end_per_group(_GroupName, Config) ->
68    Config.
69
70
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
73absname(Config) when is_list(Config) ->
74    case os:type() of
75        {win32, _} ->
76            [Drive|_] = proplists:get_value(priv_dir, Config),
77            Temp = filename:join([Drive|":/"], "temp"),
78            case file:make_dir(Temp) of
79                ok -> ok;
80                {error,eexist} -> ok
81            end,
82            {ok,Cwd} = file:get_cwd(),
83            ok = file:set_cwd(Temp),
84            [Drive|":/temp/foo"] = filename:absname(foo),
85            [Drive|":/temp/foo"] = filename:absname("foo"),
86            [Drive|":/temp/../ebin"] = filename:absname("../ebin"),
87            [Drive|":/erlang"] = filename:absname("/erlang"),
88            [Drive|":/erlang/src"] = filename:absname("/erlang/src"),
89            [Drive|":/erlang/src"] = filename:absname("\\erlang\\src"),
90            [Drive|":/temp/erlang"] = filename:absname([Drive|":erlang"]),
91            [Drive|":/temp/erlang/src"] =
92                filename:absname([Drive|":erlang/src"]),
93            [Drive|":/temp/erlang/src"] =
94                filename:absname([Drive|":erlang\\src\\"]),
95            "a:/erlang" = filename:absname("a:erlang"),
96
97            file:set_cwd([Drive|":/"]),
98            [Drive|":/foo"] = filename:absname(foo),
99            [Drive|":/foo"] = filename:absname("foo"),
100            [Drive|":/../ebin"] = filename:absname("../ebin"),
101            [Drive|":/erlang"] = filename:absname("/erlang"),
102            [Drive|":/erlang/src"] = filename:absname("/erlang/src"),
103            [Drive|":/erlang/src"] = filename:absname(["/erlang",'/src']),
104            [Drive|":/erlang/src"] = filename:absname("\\erlang\\\\src"),
105            [Drive|":/erlang"] = filename:absname([Drive|":erlang"]),
106            [Drive|":/erlang/src"] = filename:absname([Drive|":erlang/src"]),
107            "a:/erlang" = filename:absname("a:erlang"),
108
109            "//foo" = filename:absname("//foo"),
110            "//foo/bar" = filename:absname("//foo/bar"),
111            "//foo/\bar" = filename:absname("//foo/\bar"),
112            "//foo/bar/baz" = filename:absname("//foo/bar\\baz"),
113            "//foo/bar/baz" = filename:absname("//foo\\bar/baz"),
114            "//foo" = filename:absname("\\\\foo"),
115            "//foo/bar" = filename:absname("\\\\foo/bar"),
116            "//foo/\bar" = filename:absname("\\\\foo/\bar"),
117            "//foo/bar/baz" = filename:absname("\\\\foo/bar\\baz"),
118            "//foo/bar/baz" = filename:absname("\\\\foo\\bar/baz"),
119
120            file:set_cwd(Cwd),
121            ok;
122        {unix, _} ->
123            ok = file:set_cwd("/usr"),
124            "/usr/foo" = filename:absname(foo),
125            "/usr/foo" = filename:absname("foo"),
126            "/usr/../ebin" = filename:absname("../ebin"),
127
128            file:set_cwd("/"),
129            "/foo" = filename:absname(foo),
130            "/foo" = filename:absname("foo"),
131            "/../ebin" = filename:absname("../ebin"),
132            "/erlang" = filename:absname("/erlang"),
133            "/erlang/src" = filename:absname("/erlang/src"),
134            "/erlang/src" = filename:absname(["/erl",'ang/s',"rc"]),
135            "/erlang/src" = filename:absname(["/erl",'a','ng',"/",'s',"rc"]),
136            "/erlang/src" = filename:absname("/erlang///src"),
137            "/file_sorter.erl" = filename:absname([file_sorter|'.erl']),
138            ok
139    end.
140
141
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
144absname_2(Config) when is_list(Config) ->
145    case os:type() of
146        {win32, _} ->
147            [Drive|_] = proplists:get_value(priv_dir, Config),
148            [Drive|":/temp/foo"] = filename:absname(foo, [Drive|":/temp"]),
149            [Drive|":/temp/foo"] = filename:absname("foo", [Drive|":/temp"]),
150            [Drive|":/temp/../ebin"] = filename:absname("../ebin",
151                                                        [Drive|":/temp"]),
152            [Drive|":/erlang"] = filename:absname("/erlang", [Drive|":/temp"]),
153            [Drive|":/erlang/src"] = filename:absname("/erlang/src",
154                                                      [Drive|":/temp"]),
155            [Drive|":/erlang/src"] = filename:absname("\\erlang\\src",
156                                                      [Drive|":/temp"]),
157            [Drive|":/temp/erlang"] = filename:absname([Drive|":erlang"],
158                                                       [Drive|":/temp"]),
159            [Drive|":/temp/erlang/src"] = filename:absname([Drive|":erlang/src"],
160                                                           [Drive|":/temp"]),
161            [Drive|":/temp/erlang/src"] =
162                filename:absname([Drive|":erlang\\src\\"], [Drive|":/temp"]),
163            "a:/erlang" = filename:absname("a:erlang", [Drive|":/temp"]),
164
165            file:set_cwd([Drive|":/"]),
166            [Drive|":/foo"] = filename:absname(foo, [Drive|":/"]),
167            [Drive|":/foo"] = filename:absname("foo", [Drive|":/"]),
168            [Drive|":/../ebin"] = filename:absname("../ebin", [Drive|":/"]),
169            [Drive|":/erlang"] = filename:absname("/erlang", [Drive|":/"]),
170            [Drive|":/erlang/src"] = filename:absname("/erlang/src",
171                                                      [Drive|":/"]),
172            [Drive|":/erlang/src"] = filename:absname("\\erlang\\\\src",
173                                                      [Drive|":/"]),
174            [Drive|":/erlang"] = filename:absname([Drive|":erlang"],
175                                                  [Drive|":/"]),
176            [Drive|":/erlang/src"] = filename:absname([Drive|":erlang/src"],
177                                                      [Drive|":/"]),
178            "a:/erlang" = filename:absname("a:erlang", [Drive|":/"]),
179
180            "//foo" = filename:absname("foo","//"),
181            "//foo/bar" = filename:absname("foo/bar", "//"),
182            "//foo/bar" = filename:absname("bar", "//foo"),
183            "//bar" = filename:absname("/bar", "//foo"),
184            "//foo/bar/baz" = filename:absname("bar/baz", "//foo"),
185            "//bar/baz" = filename:absname("//bar/baz", "//foo"),
186            "//\bar" = filename:absname("/\bar", "//foo"),
187            "//foo" = filename:absname("foo","\\\\"),
188            "//foo/bar" = filename:absname("foo/bar", "\\\\"),
189            "//foo/bar" = filename:absname("bar", "\\\\foo"),
190            "//bar" = filename:absname("/bar", "\\\\foo"),
191            "//foo/bar/baz" = filename:absname("bar/baz", "\\\\foo"),
192            "//bar/baz" = filename:absname("\\\\bar/baz", "\\\\foo"),
193            "//\bar" = filename:absname("/\bar", "\\\\foo"),
194            "//bar/baz" = filename:absname("\\\\bar/baz", "//foo"),
195            "//bar/baz" = filename:absname("//bar/baz", "\\\\foo"),
196
197            ok;
198        _ ->
199            "/usr/foo" = filename:absname(foo, "/usr"),
200            "/usr/foo" = filename:absname("foo", "/usr"),
201            "/usr/../ebin" = filename:absname("../ebin", "/usr"),
202
203            "/foo" = filename:absname(foo, "/"),
204            "/foo" = filename:absname("foo", "/"),
205            "/../ebin" = filename:absname("../ebin", "/"),
206            "/erlang" = filename:absname("/erlang", "/"),
207            "/erlang/src" = filename:absname("/erlang/src", "/"),
208            "/erlang/src" = filename:absname("/erlang///src", "/"),
209            ok
210    end.
211
212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213
214basename_1(Config) when is_list(Config) ->
215    "." = filename:basename("."),
216    "foo" = filename:basename("foo"),
217    "foo" = filename:basename("/usr/foo"),
218    "foo.erl" = filename:basename("A:usr/foo.erl"),
219    "foo" = filename:basename('/usr/foo'),
220    "foo" = filename:basename(["/usr","/","f","o","o"]),
221    "foo" = filename:basename(["/usr/",foo]),
222    "foo" = filename:basename(["/usr/f",oo]),
223    "foo" = filename:basename(["usr/", "foo"]),
224    "foo" = filename:basename(["usr/"|foo]),
225    "foo" = filename:basename(["usr/foo/"]),
226    case os:type() of
227        {win32, _} ->
228            "foo" = filename:basename(["usr\\foo\\"]),
229            "foo" = filename:basename("A:\\usr\\foo"),
230            "foo" = filename:basename("A:foo");
231        _ ->
232            "strange\\but\\true" =
233                filename:basename("strange\\but\\true")
234    end,
235    ok.
236
237basename_2(Config) when is_list(Config) ->
238    "." = filename:basename(".", ".erl"),
239    "foo" = filename:basename("foo.erl", ".erl"),
240    "foo" = filename:basename('foo.erl', ".erl"),
241    "foo" = filename:basename("foo.erl", '.erl'),
242    "foo" = filename:basename(["/usr","/","f","oo"], ".erl"),
243    "foo.erl" = filename:basename("/usr/foo.erl", ".hrl"),
244    "foo.erl" = filename:basename("/usr.hrl/foo.erl", ".hrl"),
245    "foo" = filename:basename("/usr.hrl/foo", ".hrl"),
246    "foo" = filename:basename("usr/foo/", ".erl"),
247    "foo.erl" = filename:basename("usr/foo.erl/", ".erl"),
248    "foo.erl" = filename:basename("usr/foo.erl/", '.erl'),
249    "foo" = filename:basename(["/usr",'/','f','oo'], ".erl"),
250    "foo.erl" = filename:basename(["usr/foo.e",'rl/'], ".erl"),
251    case os:type() of
252        {win32, _} ->
253            "foo" = filename:basename("A:foo", ".erl"),
254            "foo.erl" = filename:basename("a:\\usr\\foo.erl", ".hrl"),
255            "foo.erl" = filename:basename("c:\\usr.hrl\\foo.erl", ".hrl"),
256            "foo" = filename:basename("A:\\usr\\foo", ".hrl");
257        _ ->
258            "strange\\but\\true" =
259                filename:basename("strange\\but\\true.erl", ".erl"),
260            "strange\\but\\true" =
261                filename:basename("strange\\but\\true", ".erl")
262    end,
263    ok.
264
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266
267dirname(Config) when is_list(Config) ->
268    case os:type() of
269        {win32,_} ->
270            "A:/usr" = filename:dirname("A:/usr/foo.erl"),
271            "A:usr" = filename:dirname("A:usr/foo.erl"),
272            "/usr" = filename:dirname("\\usr\\foo.erl"),
273            "/" = filename:dirname("\\usr"),
274            "//foo/bar" = filename:dirname("//foo/bar/baz.erl"),
275            "//foo/\bar" = filename:dirname("//foo/\bar/baz.erl"),
276            "//foo/bar" = filename:dirname("//foo\\bar/baz.erl"),
277            "//foo/bar" = filename:dirname("\\\\foo/bar/baz.erl"),
278            "//foo/\bar" = filename:dirname("\\\\foo/\bar/baz.erl"),
279            "//foo/bar" = filename:dirname("\\\\foo\\bar/baz.erl"),
280            "//foo" = filename:dirname("//foo/baz.erl"),
281            "//foo" = filename:dirname("//foo/\baz.erl"),
282            "//foo" = filename:dirname("//foo\\baz.erl"),
283            "//foo" = filename:dirname("\\\\foo/baz.erl"),
284            "//foo" = filename:dirname("\\\\foo/\baz.erl"),
285            "//foo" = filename:dirname("\\\\foo\\baz.erl"),
286            "A:" = filename:dirname("A:");
287        _ -> true
288    end,
289    "usr" = filename:dirname("usr///foo.erl"),
290    "." = filename:dirname("foo.erl"),
291    "." = filename:dirname("."),
292    "usr" = filename:dirname('usr/foo.erl'),
293    "usr" = filename:dirname(['usr','/foo.erl']),
294    "usr" = filename:dirname(['us','r/foo.erl']),
295    "usr" = filename:dirname(['usr/','/foo.erl']),
296    "usr" = filename:dirname(['usr/','foo.erl']),
297    "usr" = filename:dirname(['usr/'|'foo.erl']),
298    "usr" = filename:dirname(['usr/f','oo.erl']),
299    "/" = filename:dirname("/"),
300    "/" = filename:dirname("/usr"),
301    ok.
302
303
304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305
306extension(Config) when is_list(Config) ->
307    ".erl" = filename:extension("A:/usr/foo.erl"),
308    ".erl" = filename:extension("A:/usr/foo.nisse.erl"),
309    ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.erl"]),
310    ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.e", 'rl']),
311    ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.e"|'rl']),
312    ".erl" = filename:extension("A:/usr.bar/foo.nisse.erl"),
313    "" = filename:extension("A:/usr.bar/foo"),
314    "" = filename:extension("A:/usr/foo"),
315    "" = filename:extension(".gitignore"),
316    "" = filename:extension("A:/usr/.gitignore"),
317    ".ignore" = filename:extension("A:/usr/..ignore"),
318    ".ignore" = filename:extension("A:/usr/.git.ignore"),
319    case os:type() of
320        {win32, _} ->
321            "" = filename:extension("A:\\usr\\foo"),
322            ".erl" = filename:extension("A:/usr.bar/foo.nisse.erl"),
323            "" = filename:extension("A:/usr.bar/foo"),
324            "" = filename:extension("A:\\usr\\.gitignore"),
325            ".ignore" = filename:extension("A:\\usr\\..ignore"),
326            ".ignore" = filename:extension("A:\\usr\\.git.ignore"),
327            ok;
328        _ -> ok
329    end.
330
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332
333join(Config) when is_list(Config) ->
334    %% Whenever joining two elements, test the equivalence between
335    %% join/1 and join/2 (OTP-12158) by using help function
336    %% filename_join/2.
337    "/" = filename:join(["/"]),
338    "usr/foo.erl" = filename_join("usr","foo.erl"),
339    "/src/foo.erl" = filename_join(usr, "/src/foo.erl"),
340    "/src/foo.erl" = filename_join("/src/",'foo.erl'),
341    "/src/foo.erl" = filename_join(usr, ["/sr", 'c/foo.erl']),
342    "/src/foo.erl" = filename_join("usr", "/src/foo.erl"),
343
344    %% Make sure that redundant slashes work too.
345    "a/b/c/d/e/f/g" = filename:join(["a//b/c/////d//e/f/g"]),
346    "a/b/c/d/e/f/g" = filename_join("a//b/c/", "d//e/f/g"),
347    "a/b/c/d/e/f/g" = filename_join("a//b/c", "d//e/f/g"),
348    "/d/e/f/g" = filename_join("a//b/c", "/d//e/f/g"),
349
350    "foo/bar" = filename_join([$f,$o,$o,$/,[]], "bar"),
351
352    %% Single dots - should be removed if in the middle of the path,
353    %% but not at the end of the path.
354    "/." = filename:join(["/."]),
355    "/" = filename:join(["/./"]),
356    "/." = filename:join(["/./."]),
357    "./." = filename:join(["./."]),
358
359    "/a/b" = filename_join("/a/.","b"),
360    "/a/b/." = filename_join("/a/.","b/."),
361    "/a/." = filename_join("/a/.","."),
362    "/a/." = filename_join("/a","."),
363    "/a/." = filename_join("/a/.",""),
364    "./." = filename_join("./.","."),
365    "./." = filename_join("./","."),
366    "./." = filename_join("./.",""),
367    "." = filename_join(".",""),
368    "./." = filename_join(".","."),
369
370    %% Trailing slash shall be removed - except the root
371    "/" = filename:join(["/"]),
372    "/" = filename:join(["/./"]),
373    "/a" = filename:join(["/a/"]),
374    "/b" = filename_join("/a/","/b/"),
375    "/a/b" = filename_join("/a/","b/"),
376
377    case os:type() of
378        {win32, _} ->
379            "//" = filename:join(["//"]),
380            "d:/" = filename:join(["D:/"]),
381            "d:/" = filename:join(["D:\\"]),
382            "d:/abc" = filename_join("D:/", "abc"),
383            "d:abc" = filename_join("D:", "abc"),
384            "a/b/c/d/e/f/g" = filename:join(["a//b\\c//\\/\\d/\\e/f\\g"]),
385            "a:usr/foo.erl" = filename:join(["A:","usr","foo.erl"]),
386            "/usr/foo.erl" = filename:join(["A:","/usr","foo.erl"]),
387            "c:usr" = filename_join("A:","C:usr"),
388            "a:usr" = filename_join("A:","usr"),
389            "c:/usr" = filename_join("A:", "C:/usr"),
390            "c:/usr/foo.erl" = filename:join(["A:","C:/usr","foo.erl"]),
391            "c:usr/foo.erl" = filename:join(["A:","C:usr","foo.erl"]),
392            "d:/foo" = filename:join([$D, $:, $/, []], "foo"),
393            "//" = filename:join("\\\\", ""),
394            "//foo" = filename:join("\\\\", "foo"),
395            "//foo/bar" = filename:join("\\\\", "foo\\\\bar"),
396            "//foo/bar/baz" = filename:join("\\\\foo", "bar\\\\baz"),
397            "//foo/bar/baz" = filename:join("\\\\foo", "bar\\baz"),
398            "//foo/bar/baz" = filename:join("\\\\foo\\bar", baz),
399            "//foo/\bar/baz" = filename:join("\\\\foo/\bar", baz),
400            "//foo/bar/baz" = filename:join("\\\\foo/bar", baz),
401            "//bar/baz" = filename:join("\\\\foo", "\\\\bar\\baz"),
402            "//bar/baz" = filename:join("\\\\foo", "//bar\\baz"),
403            "//bar/baz" = filename:join("\\\\foo", "//bar/baz"),
404            "//bar/baz" = filename:join("\\\\foo", "\\\\bar/baz"),
405            "//d/e/f/g" = filename:join("a//b/c", "//d//e/f/g"),
406            "//" = filename:join("//", ""),
407            "//foo" = filename:join("//", "foo"),
408            "//foo/bar" = filename:join("//", "foo\\\\bar"),
409            "//foo/bar/baz" = filename:join("//foo", "bar\\\\baz"),
410            "//foo/bar/baz" = filename:join("//foo", "bar\\baz"),
411            "//foo/bar/baz" = filename:join("//foo\\bar", baz),
412            "//foo/\bar/baz" = filename:join("//foo/\bar", baz),
413            "//foo/bar/baz" = filename:join("//foo/bar", baz),
414            "//bar/baz" = filename:join("//foo", "\\\\bar\\baz"),
415            "//bar/baz" = filename:join("//foo", "//bar\\baz"),
416            "//bar/baz" = filename:join("//foo", "//bar/baz"),
417            "//bar/baz" = filename:join("//foo", "\\\\bar/baz"),
418            ok;
419        _ ->
420            "/" = filename:join(["//"]),
421            "/d/e/f/g" = filename:join("a//b/c", "//d//e/f/g"),
422            ok
423    end.
424
425%% Make sure join([A,B]) is equivalent to join(A,B) (OTP-12158)
426filename_join(A,B) ->
427    Res = filename:join(A,B),
428    Res = filename:join([A,B]).
429
430pathtype(Config) when is_list(Config) ->
431    relative = filename:pathtype(".."),
432    relative = filename:pathtype("foo"),
433    relative = filename:pathtype("foo/bar"),
434    relative = filename:pathtype('foo/bar'),
435    relative = filename:pathtype(['f','oo',"/bar"]),
436    case os:type() of
437        {win32, _} ->
438            volumerelative = filename:pathtype("/usr/local/bin"),
439            volumerelative = filename:pathtype("A:usr/local/bin"),
440            ok;
441        _ ->
442            absolute = filename:pathtype("/"),
443            absolute = filename:pathtype("/usr/local/bin"),
444            ok
445    end.
446
447rootname(Config) when is_list(Config) ->
448    "/jam.src/kalle" = filename:rootname("/jam.src/kalle"),
449    "/jam.src/foo" = filename:rootname("/jam.src/foo.erl"),
450    "/jam.src/.gitignore" = filename:rootname("/jam.src/.gitignore"),
451    "/jam.src/.git" = filename:rootname("/jam.src/.git.ignore"),
452    "/jam.src/." = filename:rootname("/jam.src/..gitignore"),
453    "/jam.src/foo" = filename:rootname(["/ja",'m.sr',"c/foo.erl"]),
454    "/jam.src/foo" = filename:rootname("/jam.src/foo.erl", ".erl"),
455    "/jam.src/.gitignore" = filename:rootname("/jam.src/.gitignore", ".gitignore"),
456    "/jam.src/.git" = filename:rootname("/jam.src/.git.ignore", ".ignore"),
457    "/jam.src/." = filename:rootname("/jam.src/..gitignore", ".gitignore"),
458    "/jam.src/foo.jam" = filename:rootname("/jam.src/foo.jam", ".erl"),
459    "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j',"am"],".erl"),
460    "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j'|am],".erl"),
461    ok.
462
463split(Config) when is_list(Config) ->
464    ["/","usr","local","bin"] = filename:split("/usr/local/bin"),
465    ["foo","bar"]= filename:split("foo/bar"),
466    ["foo", "bar", "hello"]= filename:split("foo////bar//hello"),
467    ["foo", "bar", "hello"]= filename:split(["foo//",'//bar//h',"ello"]),
468    ["foo", "bar", "hello"]= filename:split(["foo//",'//bar//h'|ello]),
469    ["/"] = filename:split("/"),
470    [] = filename:split(""),
471    case os:type() of
472        {win32,_} ->
473            ["a:/","msdev","include"] =
474                filename:split("a:/msdev/include"),
475            ["a:/","msdev","include"] =
476                filename:split("A:/msdev/include"),
477            ["msdev","include"] =
478                filename:split("msdev\\include"),
479            ["a:/","msdev","include"] =
480                filename:split("a:\\msdev\\include"),
481            ["a:","msdev","include"] =
482                filename:split("a:msdev\\include"),
483            ["//","foo"] =
484                filename:split("\\\\foo"),
485            ["//","foo"] =
486                filename:split("//foo"),
487            ["//","foo","bar"] =
488                filename:split("\\\\foo\\\\bar"),
489            ["//","foo","baz"] =
490                filename:split("\\\\foo\\baz"),
491            ["//","foo","baz"] =
492                filename:split("//foo\\baz"),
493            ok;
494        _ ->
495	    ok
496    end.
497
498t_nativename(Config) when is_list(Config) ->
499    "abcedf" = filename:nativename(abcedf),
500    "abcedf" = filename:nativename(["abc", "edf"]),
501    "abcgluff" = filename:nativename(["abc", gluff]),
502    case os:type() of
503        {win32, _} ->
504            "a:\\temp\\arne.exe" =
505                filename:nativename("A:/temp//arne.exe/");
506        _ ->
507            "/usr/tmp/arne" =
508                filename:nativename("/usr/tmp//arne/")
509    end.
510
511%%
512%%
513%% With binaries
514%%
515%%
516
517absname_bin(Config) when is_list(Config) ->
518    case os:type() of
519        {win32, _} ->
520            [Drive|_] = proplists:get_value(priv_dir, Config),
521            Temp = filename:join([Drive|":/"], "temp"),
522            case file:make_dir(Temp) of
523                ok -> ok;
524                {error,eexist} -> ok
525            end,
526            {ok,Cwd} = file:get_cwd(),
527            ok = file:set_cwd(Temp),
528            <<Drive:8,":/temp/foo">> = filename:absname(<<"foo">>),
529            <<Drive:8,":/temp/../ebin">> = filename:absname(<<"../ebin">>),
530            <<Drive:8,":/erlang">> = filename:absname(<<"/erlang">>),
531            <<Drive:8,":/erlang/src">> = filename:absname(<<"/erlang/src">>),
532            <<Drive:8,":/erlang/src">> = filename:absname(<<"\\erlang\\src">>),
533            <<Drive:8,":/temp/erlang">> = filename:absname(<<Drive:8,":erlang">>),
534            <<Drive:8,":/temp/erlang/src">> =
535            filename:absname(<<Drive:8,":erlang/src">>),
536            <<Drive:8,":/temp/erlang/src">> =
537            filename:absname(<<Drive:8,":erlang\\src\\">>),
538            <<"a:/erlang">> = filename:absname(<<"a:erlang">>),
539
540            file:set_cwd(<<Drive:8,":/">>),
541            <<Drive:8,":/foo">> = filename:absname(<<"foo">>),
542            <<Drive:8,":/../ebin">> = filename:absname(<<"../ebin">>),
543            <<Drive:8,":/erlang">> = filename:absname(<<"/erlang">>),
544            <<Drive:8,":/erlang/src">> = filename:absname(<<"/erlang/src">>),
545            <<Drive:8,":/erlang/src">> = filename:absname(<<"\\erlang\\\\src">>),
546            <<Drive:8,":/erlang">> = filename:absname(<<Drive:8,":erlang">>),
547            <<Drive:8,":/erlang/src">> = filename:absname(<<Drive:8,":erlang/src">>),
548            <<"a:/erlang">> = filename:absname(<<"a:erlang">>),
549
550            file:set_cwd(Cwd),
551            ok;
552        {unix,_} ->
553            ok = file:set_cwd(<<"/usr">>),
554            <<"/usr/foo">> = filename:absname(<<"foo">>),
555            <<"/usr/../ebin">> = filename:absname(<<"../ebin">>),
556
557            file:set_cwd(<<"/">>),
558            <<"/foo">> = filename:absname(<<"foo">>),
559            <<"/../ebin">> = filename:absname(<<"../ebin">>),
560            <<"/erlang">> = filename:absname(<<"/erlang">>),
561            <<"/erlang/src">> = filename:absname(<<"/erlang/src">>),
562            <<"/erlang/src">> = filename:absname(<<"/erlang///src">>),
563            ok
564    end.
565
566
567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568
569absname_bin_2(Config) when is_list(Config) ->
570    case os:type() of
571        {win32, _} ->
572            [Drive|_] = proplists:get_value(priv_dir, Config),
573            <<Drive:8,":/temp/foo">> = filename:absname(<<"foo">>, <<Drive:8,":/temp">>),
574            <<Drive:8,":/temp/../ebin">> = filename:absname(<<"../ebin">>,
575                                                            <<Drive:8,":/temp">>),
576            <<Drive:8,":/erlang">> = filename:absname(<<"/erlang">>, <<Drive:8,":/temp">>),
577            <<Drive:8,":/erlang/src">> = filename:absname(<<"/erlang/src">>,
578                                                          <<Drive:8,":/temp">>),
579            <<Drive:8,":/erlang/src">> = filename:absname(<<"\\erlang\\src">>,
580                                                          <<Drive:8,":/temp">>),
581            <<Drive:8,":/temp/erlang">> = filename:absname(<<Drive:8,":erlang">>,
582                                                           <<Drive:8,":/temp">>),
583            <<Drive:8,":/temp/erlang/src">> = filename:absname(<<Drive:8,":erlang/src">>,
584                                                               <<Drive:8,":/temp">>),
585            <<Drive:8,":/temp/erlang/src">> =
586                filename:absname(<<Drive:8,":erlang\\src\\">>, <<Drive:8,":/temp">>),
587            <<"a:/erlang">> = filename:absname(<<"a:erlang">>, <<Drive:8,":/temp">>),
588
589            file:set_cwd(<<Drive:8,":/">>),
590            <<Drive:8,":/foo">> = filename:absname(foo, <<Drive:8,":/">>),
591            <<Drive:8,":/foo">> = filename:absname(<<"foo">>, <<Drive:8,":/">>),
592            <<Drive:8,":/../ebin">> = filename:absname(<<"../ebin">>, <<Drive:8,":/">>),
593            <<Drive:8,":/erlang">> = filename:absname(<<"/erlang">>, <<Drive:8,":/">>),
594            <<Drive:8,":/erlang/src">> = filename:absname(<<"/erlang/src">>,
595                                                          <<Drive:8,":/">>),
596            <<Drive:8,":/erlang/src">> = filename:absname(<<"\\erlang\\\\src">>,
597                                                          <<Drive:8,":/">>),
598            <<Drive:8,":/erlang">> = filename:absname(<<Drive:8,":erlang">>,
599                                                      <<Drive:8,":/">>),
600            <<Drive:8,":/erlang/src">> = filename:absname(<<Drive:8,":erlang/src">>,
601                                                          <<Drive:8,":/">>),
602            <<"a:/erlang">> = filename:absname(<<"a:erlang">>, <<Drive:8,":/">>),
603
604            ok;
605        _ ->
606            <<"/usr/foo">> = filename:absname(<<"foo">>, <<"/usr">>),
607            <<"/usr/../ebin">> = filename:absname(<<"../ebin">>, <<"/usr">>),
608            <<"/foo">> = filename:absname(<<"foo">>, <<"/">>),
609            <<"/../ebin">> = filename:absname(<<"../ebin">>, <<"/">>),
610            <<"/erlang">> = filename:absname(<<"/erlang">>, <<"/">>),
611            <<"/erlang/src">> = filename:absname(<<"/erlang/src">>, <<"/">>),
612            <<"/erlang/src">> = filename:absname(<<"/erlang///src">>, <<"/">>),
613            ok
614    end.
615
616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617
618basename_bin_1(Config) when is_list(Config) ->
619    <<".">> = filename:basename(<<".">>),
620    <<"foo">> = filename:basename(<<"foo">>),
621    <<"foo">> = filename:basename(<<"/usr/foo">>),
622    <<"foo.erl">> = filename:basename(<<"A:usr/foo.erl">>),
623    case os:type() of
624        {win32, _} ->
625            <<"foo">> = filename:basename(<<"A:\\usr\\foo">>),
626            <<"foo">> = filename:basename(<<"A:foo">>);
627        _ ->
628            <<"strange\\but\\true">> = filename:basename(<<"strange\\but\\true">>)
629    end,
630    ok.
631
632basename_bin_2(Config) when is_list(Config) ->
633    <<".">> = filename:basename(<<".">>, <<".erl">>),
634    <<"foo">> = filename:basename(<<"foo.erl">>, <<".erl">>),
635    <<"foo.erl">> = filename:basename(<<"/usr/foo.erl">>, <<".hrl">>),
636    <<"foo.erl">> = filename:basename(<<"/usr.hrl/foo.erl">>, <<".hrl">>),
637    <<"foo">> = filename:basename(<<"/usr.hrl/foo">>, <<".hrl">>),
638    <<"foo">> = filename:basename(<<"usr/foo/">>, <<".erl">>),
639    <<"foo.erl">> = filename:basename(<<"usr/foo.erl/">>, <<".erl">>),
640    case os:type() of
641        {win32, _} ->
642            <<"foo">> = filename:basename(<<"A:foo">>, <<".erl">>),
643            <<"foo.erl">> = filename:basename(<<"a:\\usr\\foo.erl">>, <<".hrl">>),
644            <<"foo.erl">> = filename:basename(<<"c:\\usr.hrl\\foo.erl">>, <<".hrl">>),
645            <<"foo">> = filename:basename(<<"A:\\usr\\foo">>, <<".hrl">>);
646        _ ->
647            <<"strange\\but\\true">> =
648                filename:basename(<<"strange\\but\\true.erl">>, <<".erl">>),
649            <<"strange\\but\\true">> =
650                filename:basename(<<"strange\\but\\true">>, <<".erl">>)
651    end,
652    ok.
653
654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
655
656dirname_bin(Config) when is_list(Config) ->
657    case os:type() of
658        {win32,_} ->
659            <<"A:/usr">> = filename:dirname(<<"A:/usr/foo.erl">>),
660            <<"A:usr">> = filename:dirname(<<"A:usr/foo.erl">>),
661            <<"/usr">> = filename:dirname(<<"\\usr\\foo.erl">>),
662            <<"/">> = filename:dirname(<<"\\usr">>),
663            <<"A:">> = filename:dirname(<<"A:">>);
664        _ -> true
665    end,
666    <<"usr">> = filename:dirname(<<"usr///foo.erl">>),
667    <<".">> = filename:dirname(<<"foo.erl">>),
668    <<".">> = filename:dirname(<<".">>),
669    <<"/">> = filename:dirname(<<"/">>),
670    <<"/">> = filename:dirname(<<"/usr">>),
671    ok.
672
673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674
675extension_bin(Config) when is_list(Config) ->
676    <<".erl">> = filename:extension(<<"A:/usr/foo.erl">>),
677    <<".erl">> = filename:extension(<<"A:/usr/foo.nisse.erl">>),
678    <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>),
679    <<"">> = filename:extension(<<"A:/usr.bar/foo">>),
680    <<"">> = filename:extension(<<"A:/usr/foo">>),
681    <<"">> = filename:extension(<<".gitignore">>),
682    <<"">> = filename:extension(<<"A:/usr/.gitignore">>),
683    <<".ignore">> = filename:extension(<<"A:/usr/..ignore">>),
684    <<".ignore">> = filename:extension(<<"A:/usr/.git.ignore">>),
685    case os:type() of
686        {win32, _} ->
687            <<"">> = filename:extension(<<"A:\\usr\\foo">>),
688            <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>),
689            <<"">> = filename:extension(<<"A:/usr.bar/foo">>),
690            <<"">> = filename:extension(<<"A:/usr/.gitignore">>),
691            <<".ignore">> = filename:extension(<<"A:/usr/..ignore">>),
692            <<".ignore">> = filename:extension(<<"A:/usr/.git.ignore">>),
693            ok;
694        _ -> ok
695    end.
696
697%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698
699join_bin(Config) when is_list(Config) ->
700    <<"/">> = filename:join([<<"/">>]),
701    <<"usr/foo.erl">> = filename:join(<<"usr">>,<<"foo.erl">>),
702    <<"/src/foo.erl">> = filename:join(usr, <<"/src/foo.erl">>),
703    <<"/src/foo.erl">> = filename:join([<<"/src/">>,'foo.erl']),
704    <<"/src/foo.erl">> = filename:join(<<"usr">>, ["/sr", 'c/foo.erl']),
705    <<"/src/foo.erl">> = filename:join(<<"usr">>, <<"/src/foo.erl">>),
706
707    %% Make sure that redundant slashes work too.
708    <<"a/b/c/d/e/f/g">> = filename:join([<<"a//b/c/////d//e/f/g">>]),
709    <<"a/b/c/d/e/f/g">> = filename:join([<<"a//b/c/">>, <<"d//e/f/g">>]),
710    <<"a/b/c/d/e/f/g">> = filename:join([<<"a//b/c">>, <<"d//e/f/g">>]),
711    <<"/d/e/f/g">> = filename:join([<<"a//b/c">>, <<"/d//e/f/g">>]),
712
713    <<"foo/bar">> = filename:join([$f,$o,$o,$/,[]], <<"bar">>),
714
715    %% Single dots - should be removed if in the middle of the path,
716    %% but not at the end of the path.
717    %% Also test equivalence between join/1 and join/2 (OTP-12158)
718    <<"/.">> = filename:join([<<"/.">>]),
719    <<"/">> = filename:join([<<"/./">>]),
720    <<"/.">> = filename:join([<<"/./.">>]),
721    <<"./.">> = filename:join([<<"./.">>]),
722
723    <<"/a/b">> = filename:join([<<"/a/.">>,<<"b">>]),
724    <<"/a/b">> = filename:join(<<"/a/.">>,<<"b">>),
725
726    <<"/a/b/.">> = filename:join([<<"/a/.">>,<<"b/.">>]),
727    <<"/a/b/.">> = filename:join(<<"/a/.">>,<<"b/.">>),
728
729    <<"/a/.">> = filename:join([<<"/a/.">>,<<".">>]),
730    <<"/a/.">> = filename:join(<<"/a/.">>,<<".">>),
731
732    <<"/a/.">> = filename:join([<<"/a">>,<<".">>]),
733    <<"/a/.">> = filename:join(<<"/a">>,<<".">>),
734
735    <<"/a/.">> = filename:join([<<"/a/.">>,<<"">>]),
736    <<"/a/.">> = filename:join(<<"/a/.">>,<<"">>),
737
738    <<"./.">> = filename:join([<<"./.">>,<<".">>]),
739    <<"./.">> = filename:join(<<"./.">>,<<".">>),
740
741    <<"./.">> = filename:join([<<"./">>,<<".">>]),
742    <<"./.">> = filename:join(<<"./">>,<<".">>),
743
744    <<"./.">> = filename:join([<<"./.">>,<<"">>]),
745    <<"./.">> = filename:join(<<"./.">>,<<"">>),
746
747    <<".">> = filename:join([<<".">>,<<"">>]),
748    <<".">> = filename:join(<<".">>,<<"">>),
749
750    <<"./.">> = filename:join([<<".">>,<<".">>]),
751    <<"./.">> = filename:join(<<".">>,<<".">>),
752
753    %% Trailing slash shall be removed - except the root
754    <<"/">> = filename:join([<<"/">>]),
755    <<"/">> = filename:join([<<"/./">>]),
756    <<"/a">> = filename:join([<<"/a/">>]),
757    <<"/b">> = filename:join([<<"/a/">>,<<"/b/">>]),
758    <<"/b">> = filename:join(<<"/a/">>,<<"/b/">>),
759    <<"/a/b">> = filename:join([<<"/a/">>,<<"b/">>]),
760    <<"/a/b">> = filename:join(<<"/a/">>,<<"b/">>),
761
762    case os:type() of
763        {win32, _} ->
764            <<"//">> = filename:join([<<"//">>]),
765            <<"d:/">> = filename:join([<<"D:/">>]),
766            <<"d:/">> = filename:join([<<"D:\\">>]),
767            <<"d:/abc">> = filename:join([<<"D:/">>, <<"abc">>]),
768            <<"d:abc">> = filename:join([<<"D:">>, <<"abc">>]),
769            <<"a/b/c/d/e/f/g">> = filename:join([<<"a//b\\c//\\/\\d/\\e/f\\g">>]),
770            <<"a:usr/foo.erl">> = filename:join([<<"A:">>,<<"usr">>,<<"foo.erl">>]),
771            <<"/usr/foo.erl">> = filename:join([<<"A:">>,<<"/usr">>,<<"foo.erl">>]),
772            <<"c:usr">> = filename:join(<<"A:">>,<<"C:usr">>),
773            <<"a:usr">> = filename:join(<<"A:">>,<<"usr">>),
774            <<"c:/usr">> = filename:join(<<"A:">>, <<"C:/usr">>),
775            <<"c:/usr/foo.erl">> = filename:join([<<"A:">>,<<"C:/usr">>,<<"foo.erl">>]),
776            <<"c:usr/foo.erl">> = filename:join([<<"A:">>,<<"C:usr">>,<<"foo.erl">>]),
777            <<"d:/foo">> = filename:join([$D, $:, $/, []], <<"foo">>),
778            <<"//">> = filename:join(<<"\\\\">>, <<"">>),
779            <<"//foo">> = filename:join(<<"\\\\">>, <<"foo">>),
780            <<"//foo/bar">> = filename:join(<<"\\\\">>, <<"foo\\\\bar">>),
781            <<"//foo/bar/baz">> = filename:join(<<"\\\\foo">>, <<"bar\\\\baz">>),
782            <<"//bar/baz">> = filename:join(<<"\\\\foo">>, <<"\\\\bar\\baz">>),
783            <<"//foo/bar/baz">> = filename:join(<<"\\\\foo\\bar">>, baz),
784            <<"//foo/\bar/baz">> = filename:join(<<"\\\\foo/\bar">>, baz),
785            <<"//foo/bar/baz">> = filename:join(<<"\\\\foo/bar">>, baz),
786            <<"//bar/baz">> = filename:join(<<"\\\\foo">>, <<"\\\\bar\\baz">>),
787            <<"//bar/baz">> = filename:join(<<"\\\\foo">>, <<"//bar\\baz">>),
788            <<"//bar/baz">> = filename:join(<<"\\\\foo">>, <<"//bar/baz">>),
789            <<"//bar/baz">> = filename:join(<<"\\\\foo">>, <<"\\\\bar/baz">>),
790            <<"//d/e/f/g">> = filename:join([<<"a//b/c">>, <<"//d//e/f/g">>]),
791            <<"//">> = filename:join(<<"//">>, <<"">>),
792            <<"//foo">> = filename:join(<<"//">>, <<"foo">>),
793            <<"//foo/bar">> = filename:join(<<"//">>, <<"foo\\\\bar">>),
794            <<"//foo/bar/baz">> = filename:join(<<"//foo">>, <<"bar\\\\baz">>),
795            <<"//bar/baz">> = filename:join(<<"//foo">>, <<"\\\\bar\\baz">>),
796            <<"//foo/bar/baz">> = filename:join(<<"//foo\\bar">>, baz),
797            <<"//foo/\bar/baz">> = filename:join(<<"//foo/\bar">>, baz),
798            <<"//foo/bar/baz">> = filename:join(<<"//foo/bar">>, baz),
799            <<"//bar/baz">> = filename:join(<<"//foo">>, <<"\\\\bar\\baz">>),
800            <<"//bar/baz">> = filename:join(<<"//foo">>, <<"//bar\\baz">>),
801            <<"//bar/baz">> = filename:join(<<"//foo">>, <<"//bar/baz">>),
802            <<"//bar/baz">> = filename:join(<<"//foo">>, <<"\\\\bar/baz">>),
803            ok;
804        _ ->
805            <<"/">> = filename:join([<<"//">>]),
806            <<"/d/e/f/g">> = filename:join([<<"a//b/c">>, <<"//d//e/f/g">>]),
807            ok
808    end.
809
810pathtype_bin(Config) when is_list(Config) ->
811    relative = filename:pathtype(<<"..">>),
812    relative = filename:pathtype(<<"foo">>),
813    relative = filename:pathtype(<<"foo/bar">>),
814    relative = filename:pathtype('foo/bar'),
815    case os:type() of
816        {win32, _} ->
817            volumerelative = filename:pathtype(<<"/usr/local/bin">>),
818            volumerelative = filename:pathtype(<<"A:usr/local/bin">>),
819            ok;
820        _ ->
821            absolute = filename:pathtype(<<"/">>),
822            absolute = filename:pathtype(<<"/usr/local/bin">>),
823            ok
824    end.
825
826rootname_bin(Config) when is_list(Config) ->
827    <<"/jam.src/kalle">> = filename:rootname(<<"/jam.src/kalle">>),
828    <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>),
829    <<"/jam.src/foo">> = filename:rootname(<<"/jam.src/foo.erl">>, <<".erl">>),
830    <<"/jam.src/foo.jam">> = filename:rootname(<<"/jam.src/foo.jam">>, <<".erl">>),
831    <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j',"am"],<<".erl">>),
832    <<"/jam.src/foo.jam">> = filename:rootname(["/jam.sr",'c/foo.j'|am],<<".erl">>),
833    ok.
834
835split_bin(Config) when is_list(Config) ->
836    [<<"/">>,<<"usr">>,<<"local">>,<<"bin">>] = filename:split(<<"/usr/local/bin">>),
837    [<<"foo">>,<<"bar">>]= filename:split(<<"foo/bar">>),
838    [<<"foo">>, <<"bar">>, <<"hello">>]= filename:split(<<"foo////bar//hello">>),
839    [<<"/">>] = filename:split(<<"/">>),
840    [] = filename:split(<<"">>),
841    case os:type() of
842        {win32,_} ->
843            [<<"a:/">>,<<"msdev">>,<<"include">>] =
844                filename:split(<<"a:/msdev/include">>),
845            [<<"a:/">>,<<"msdev">>,<<"include">>] =
846                filename:split(<<"A:/msdev/include">>),
847            [<<"msdev">>,<<"include">>] =
848                filename:split(<<"msdev\\include">>),
849            [<<"a:/">>,<<"msdev">>,<<"include">>] =
850                filename:split(<<"a:\\msdev\\include">>),
851            [<<"a:">>,<<"msdev">>,<<"include">>] =
852                filename:split(<<"a:msdev\\include">>),
853            [<<"//">>,<<"foo">>] =
854                filename:split(<<"\\\\foo">>),
855            [<<"//">>,<<"foo">>] =
856                filename:split(<<"//foo">>),
857            [<<"//">>,<<"foo">>,<<"bar">>] =
858                filename:split(<<"\\\\foo\\\\bar">>),
859            [<<"//">>,<<"foo">>,<<"baz">>] =
860                filename:split(<<"\\\\foo\\baz">>),
861            [<<"//">>,<<"foo">>,<<"baz">>] =
862                filename:split(<<"//foo\\baz">>),
863            ok;
864        _ ->
865            ok
866    end.
867
868t_nativename_bin(Config) when is_list(Config) ->
869    <<"abcedf">> = filename:nativename(<<"abcedf">>),
870    case os:type() of
871        {win32, _} ->
872            <<"a:\\temp\\arne.exe">> =
873                filename:nativename(<<"A:/temp//arne.exe/">>);
874        _ ->
875            <<"/usr/tmp/arne">> =
876                filename:nativename(<<"/usr/tmp//arne/">>)
877    end.
878
879safe_relative_path(Config) ->
880    PrivDir = proplists:get_value(priv_dir, Config),
881    Root = filename:join(PrivDir, "filename_SUITE_safe_relative_path"),
882    ok = file:make_dir(Root),
883    ok = file:set_cwd(Root),
884
885    ok = file:make_dir("a"),
886    ok = file:set_cwd("a"),
887    ok = file:make_dir("b"),
888    ok = file:set_cwd("b"),
889    ok = file:make_dir("c"),
890
891    ok = file:set_cwd(Root),
892
893    "a" = test_srp("a"),
894    "a/b" = test_srp("a/b"),
895    "a/b" = test_srp("a/./b"),
896    "a/b" = test_srp("a/./b/."),
897
898    "" = test_srp("a/.."),
899    "" = test_srp("a/./.."),
900    "" = test_srp("a/../."),
901    "a" = test_srp("a/b/.."),
902    "a" = test_srp("a/../a"),
903    "a" = test_srp("a/../a/../a"),
904    "a/b/c" = test_srp("a/../a/b/c"),
905
906    unsafe = test_srp("a/../.."),
907    unsafe = test_srp("a/../../.."),
908    unsafe = test_srp("a/./../.."),
909    unsafe = test_srp("a/././../../.."),
910    unsafe = test_srp("a/b/././../../.."),
911
912    unsafe = test_srp(PrivDir),                 %Absolute path.
913
914    ok.
915
916test_srp(RelPath) ->
917    Res = do_test_srp(RelPath),
918    Res = case do_test_srp(list_to_binary(RelPath)) of
919              Bin when is_binary(Bin) ->
920                  binary_to_list(Bin);
921              Other ->
922                  Other
923          end.
924
925do_test_srp(RelPath) ->
926    {ok,Root} = file:get_cwd(),
927    ok = file:set_cwd(RelPath),
928    {ok,Cwd} = file:get_cwd(),
929    ok = file:set_cwd(Root),
930    case filename:safe_relative_path(RelPath) of
931        unsafe ->
932            true = length(Cwd) < length(Root),
933            unsafe;
934        "" ->
935            "";
936        SafeRelPath ->
937            ok = file:set_cwd(SafeRelPath),
938            {ok,Cwd} = file:get_cwd(),
939            true = length(Cwd) >= length(Root),
940            ok = file:set_cwd(Root),
941            SafeRelPath
942    end.
943
944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945%% basedirs
946t_basedir_api(Config) when is_list(Config) ->
947    true = is_list(filename:basedir(site_data, "My App")),
948    true = is_list(filename:basedir(site_config, "My App")),
949    true = is_list(filename:basedir(user_data, "My App")),
950    true = is_list(filename:basedir(user_log, "My App")),
951    true = is_list(filename:basedir(user_config, "My App")),
952    true = is_list(filename:basedir(user_cache, "My App")),
953
954    true = is_list(filename:basedir(site_data, <<"My App">>)),
955    true = is_list(filename:basedir(site_config, <<"My App">>)),
956    true = is_binary(filename:basedir(user_data, <<"My App">>)),
957    true = is_binary(filename:basedir(user_log, <<"My App">>)),
958    true = is_binary(filename:basedir(user_config, <<"My App">>)),
959    true = is_binary(filename:basedir(user_cache, <<"My App">>)),
960
961    %% simulate for windows
962    case os:type() of
963        {win32,_} -> ok;
964        _ ->
965            os:putenv("APPDATA", "C:\\Documents and Settings\\otptest\\Application Data")
966    end,
967
968    true = is_list(filename:basedir(site_data, "My App", #{})),
969    true = is_list(filename:basedir(site_config, "My App", #{os=>linux})),
970    true = is_list(filename:basedir(user_data, "My App", #{os=>darwin})),
971    true = is_list(filename:basedir(user_log, "My App", #{os=>windows})),
972    true = is_list(filename:basedir(user_config, "My App",#{author=>"Erl"})),
973    true = is_list(filename:basedir(user_config, "My App",#{os=>darwin,
974                                                            author=>"Erl"})),
975    true = is_list(filename:basedir(user_config, "My App",#{os=>linux,
976                                                            author=>"Erl"})),
977    true = is_list(filename:basedir(user_cache, "My App",#{os=>windows,
978                                                           author=>"Erl"})),
979    true = is_list(filename:basedir(user_config, "My App",#{os=>darwin,
980                                                            author=>"Erla",
981                                                            version=>"1.0"})),
982    true = is_list(filename:basedir(user_config, "My App",#{os=>linux,
983                                                            version=>"2.0.1",
984                                                            author=>"Erl"})),
985    true = is_list(filename:basedir(user_cache, "My App",#{os=>windows,
986                                                           version=>"3.1.2",
987                                                           author=>"Erl"})),
988    true = is_binary(filename:basedir(user_config, "My App",#{os=>darwin,
989                                                              author=>"Erla",
990                                                              version=><<"1.0">>})),
991    true = is_binary(filename:basedir(user_config, "My App",#{os=>windows,
992                                                              version=>"2.0.1",
993                                                              author=><<"Erl">>})),
994    true = is_binary(filename:basedir(user_cache, "My App",#{os=>linux,
995                                                             version=><<"3.1.2">>,
996                                                             author=>"Erl"})),
997    %% simulate for windows
998    case os:type() of
999        {win32,_} -> ok;
1000        _ -> os:unsetenv("APPDATA")
1001    end,
1002
1003    {'EXIT', _} = (catch filename:basedir(wrong_config, "My App")),
1004    {'EXIT', _} = (catch filename:basedir(user_cache, {bad,name})),
1005    {'EXIT', _} = (catch filename:basedir(user_cache, "My App", badopts)),
1006    {'EXIT', _} = (catch filename:basedir(user_cache, "My App", [])),
1007    ok.
1008
1009t_basedir_windows(Config) when is_list(Config) ->
1010    Types = [user_data,user_log,user_config,user_cache],
1011    case os:type() of
1012        {win32,_} ->
1013            ok = check_basedir_windows(Types, #{});
1014        _ ->
1015            %% Windows 7 and beyond
1016            os:putenv("APPDATA", "C:\\Users\\otptest\\AppData\\Roaming"),
1017            os:putenv("LOCALAPPDATA", "C:\\Users\\otptest\\AppData\\Local"),
1018            io:format("APPDATA ~p~n", [os:getenv("APPDATA")]),
1019            io:format("LOCALAPPDATA ~p~n", [os:getenv("LOCALAPPDATA")]),
1020            ok = check_basedir_windows(Types,#{os=>windows}),
1021            %% Windows XP
1022            os:unsetenv("LOCALAPPDATA"),
1023            os:putenv("APPDATA", "C:\\Documents and Settings\\otptest\\Application Data"),
1024            io:format("APPDATA ~p~n", [os:getenv("APPDATA")]),
1025            io:format("APPLOCALDATA ~p~n", [os:getenv("APPLOCALDATA")]),
1026            ok = check_basedir_windows(Types,#{os=>windows}),
1027            os:unsetenv("APPDATA")
1028    end,
1029    ok.
1030
1031check_basedir_windows([],_) -> ok;
1032check_basedir_windows([Type|Types],Opt) ->
1033    Name = "Some Application",
1034    io:format("type: ~p~n", [Type]),
1035    ok = check_basedir_windows_path(Type,
1036                                    [Name],
1037                                    filename:basedir(Type, Name, Opt)),
1038    ok = check_basedir_windows_path(Type,
1039                                    ["Erl",Name],
1040                                    filename:basedir(Type, Name, Opt#{author=>"Erl"})),
1041    ok = check_basedir_windows_path(Type,
1042                                    [Name,"1.0"],
1043                                    filename:basedir(Type, Name, Opt#{version=>"1.0"})),
1044    ok = check_basedir_windows_path(Type,
1045                                    ["Erl",Name,"1.0"],
1046                                    filename:basedir(Type, Name, Opt#{author=>"Erl",
1047                                                                      version=>"1.0"})),
1048    check_basedir_windows(Types, Opt).
1049
1050check_basedir_windows_path(Type,Check0,Basedir) ->
1051    BDR = lists:reverse(filename:split(Basedir)),
1052    Check = lists:reverse(Check0),
1053    io:format("~w: ~p ~p~n", [Type,Check,BDR]),
1054    case Type of
1055        user_log -> check_basedir_windows_path_split(["Logs"|Check],BDR);
1056        user_cache -> check_basedir_windows_path_split(["Cache"|Check],BDR);
1057        _ -> check_basedir_windows_path_split(Check,BDR)
1058    end.
1059
1060check_basedir_windows_path_split([],_) -> ok;
1061check_basedir_windows_path_split([Same|Check],[Same|BDR]) ->
1062    check_basedir_windows_path_split(Check,BDR).
1063
1064
1065t_basedir_xdg(Config) when is_list(Config) ->
1066    check_basedir_xdg([user_data,user_log,user_config,user_cache,
1067                       site_data,site_config]),
1068    ok.
1069
1070check_basedir_xdg([]) -> ok;
1071check_basedir_xdg([Type|Types]) ->
1072    Name = "some_app",
1073    Opt  = #{os=>linux},
1074    Key  = basedir_xdg_env(Type),
1075    io:format("type: ~p~n", [Type]),
1076    Home = case os:getenv("WSLENV") of
1077               false -> os:getenv("HOME");
1078               _ -> os:getenv("USERPROFILE")
1079           end,
1080    NDir = "/some/absolute/path",
1081    DefPath = basedir_xdg_def(Type,Home,Name),
1082    EnvPath = case Type of
1083                  user_log    -> filename:join([NDir,Name,"log"]);
1084                  site_data   -> [filename:join([NDir,Name])];
1085                  site_config -> [filename:join([NDir,Name])];
1086                  _           -> filename:join([NDir,Name])
1087              end,
1088    os:unsetenv(Key),
1089    ok = check_basedir(Type, DefPath, filename:basedir(Type, Name, Opt)),
1090    os:putenv(Key, NDir),
1091    ok = check_basedir(Type, EnvPath, filename:basedir(Type, Name, Opt)),
1092    os:unsetenv(Key),
1093    ok = check_basedir(Type, DefPath, filename:basedir(Type, Name, Opt)),
1094    check_basedir_xdg(Types).
1095
1096check_basedir(Type, Path, Basedir) ->
1097    io:format("~w: ~p = ~p~n", [Type,Path,Basedir]),
1098    Path = Basedir,
1099    ok.
1100
1101basedir_xdg_env(Type) ->
1102    case Type of
1103        user_data   -> "XDG_DATA_HOME";
1104        user_config -> "XDG_CONFIG_HOME";
1105        user_cache  -> "XDG_CACHE_HOME";
1106        user_log    -> "XDG_CACHE_HOME";
1107        site_data   -> "XDG_DATA_DIRS";
1108        site_config -> "XDG_CONFIG_DIRS"
1109    end.
1110
1111basedir_xdg_def(Type,Home,Name) ->
1112    case Type of
1113        user_data   -> filename:join([Home,".local","share",Name]);
1114        user_config -> filename:join([Home,".config",Name]);
1115        user_cache  -> filename:join([Home,".cache",Name]);
1116        user_log    -> filename:join([Home,".cache",Name,"log"]);
1117        site_data   -> [filename:join([Dir,Name]) ||
1118                        Dir <- ["/usr/local/share/","/usr/share/"]];
1119        site_config -> [filename:join(["/etc/xdg",Name])]
1120    end.
1121