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"
27namespace fs = std::filesystem;
28using namespace fs;
29
30static void signature_test()
31{
32 const path p; ((void)p);
33 std::error_code ec; ((void)ec);
34 ASSERT_NOT_NOEXCEPT(canonical(p: p));
35 ASSERT_NOT_NOEXCEPT(canonical(p: p, ec&: ec));
36}
37
38// There are 4 cases is the proposal for absolute path.
39// Each scope tests one of the cases.
40static 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
81static 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
96static 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: 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: 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
121int main(int, char**) {
122 signature_test();
123 test_canonical();
124 test_dne_path();
125 test_exception_contains_paths();
126
127 return 0;
128}
129

source code of libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp