1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // REQUIRES: can-create-symlinks
10 // UNSUPPORTED: c++03, c++11, c++14
11 // UNSUPPORTED: no-filesystem
12 // UNSUPPORTED: availability-filesystem-missing
13 
14 // <filesystem>
15 
16 // path canonical(const path& p);
17 // path canonical(const path& p, error_code& ec);
18 
19 #include <filesystem>
20 #include <type_traits>
21 #include <cassert>
22 
23 #include "assert_macros.h"
24 #include "test_macros.h"
25 #include "filesystem_test_helper.h"
26 #include "../../class.path/path_helper.h"
27 namespace fs = std::filesystem;
28 using namespace fs;
29 
signature_test()30 static void signature_test()
31 {
32     const path p; ((void)p);
33     std::error_code ec; ((void)ec);
34     ASSERT_NOT_NOEXCEPT(canonical(p));
35     ASSERT_NOT_NOEXCEPT(canonical(p, ec));
36 }
37 
38 // There are 4 cases is the proposal for absolute path.
39 // Each scope tests one of the cases.
test_canonical()40 static void test_canonical()
41 {
42     static_test_env static_env;
43     CWDGuard guard;
44     // has_root_name() && has_root_directory()
45     const path Root = static_env.Root;
46     const path RootName = Root.filename();
47     const path DirName = static_env.Dir.filename();
48     const path SymlinkName = static_env.SymlinkToFile.filename();
49     struct TestCase {
50         path p;
51         path expect;
52         path base;
53         TestCase(path p1, path e, path b)
54             : p(p1), expect(e), base(b) {}
55     };
56     const TestCase testCases[] = {
57         { ".", Root, Root },
58         { DirName / ".." / "." / DirName, static_env.Dir, Root },
59         { static_env.Dir2 / "..",    static_env.Dir, Root },
60         { static_env.Dir3 / "../..", static_env.Dir, Root },
61         { static_env.Dir / ".",      static_env.Dir, Root },
62         { Root / "." / DirName / ".." / DirName, static_env.Dir, Root },
63         { path("..") / "." / RootName / DirName / ".." / DirName,
64           static_env.Dir,
65           Root },
66         { static_env.SymlinkToFile,  static_env.File, Root },
67         { SymlinkName, static_env.File, Root}
68     };
69     for (auto& TC : testCases) {
70         std::error_code ec = GetTestEC();
71         fs::current_path(TC.base);
72         const path ret = canonical(TC.p, ec);
73         assert(!ec);
74         const path ret2 = canonical(TC.p);
75         assert(PathEq(ret, TC.expect));
76         assert(PathEq(ret, ret2));
77         assert(ret.is_absolute());
78     }
79 }
80 
test_dne_path()81 static void test_dne_path()
82 {
83     static_test_env static_env;
84     std::error_code ec = GetTestEC();
85     {
86         const path ret = canonical(static_env.DNE, ec);
87         assert(ec != GetTestEC());
88         assert(ec);
89         assert(ret == path{});
90     }
91     {
92         TEST_THROWS_TYPE(filesystem_error, canonical(static_env.DNE));
93     }
94 }
95 
test_exception_contains_paths()96 static void test_exception_contains_paths()
97 {
98 #ifndef TEST_HAS_NO_EXCEPTIONS
99     static_test_env static_env;
100     CWDGuard guard;
101     const path p = "blabla/dne";
102     try {
103         (void)canonical(p);
104         assert(false);
105     } catch (filesystem_error const& err) {
106         assert(err.path1() == p);
107         // libc++ provides the current path as the second path in the exception
108         LIBCPP_ASSERT(err.path2() == current_path());
109     }
110     fs::current_path(static_env.Dir);
111     try {
112         (void)canonical(p);
113         assert(false);
114     } catch (filesystem_error const& err) {
115         assert(err.path1() == p);
116         LIBCPP_ASSERT(err.path2() == static_env.Dir);
117     }
118 #endif
119 }
120 
main(int,char **)121 int main(int, char**) {
122     signature_test();
123     test_canonical();
124     test_dne_path();
125     test_exception_contains_paths();
126 
127     return 0;
128 }
129