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 // UNSUPPORTED: c++03, c++11, c++14
10 // UNSUPPORTED: no-filesystem
11 // UNSUPPORTED: availability-filesystem-missing
12
13 // <filesystem>
14
15 // path temp_directory_path();
16 // path temp_directory_path(error_code& ec);
17
18 #include <filesystem>
19 #include <memory>
20 #include <cstdlib>
21 #include <cstring>
22 #include <cassert>
23
24 #include "test_macros.h"
25 #include "filesystem_test_helper.h"
26 namespace fs = std::filesystem;
27 using namespace fs;
28
PutEnv(std::string var,fs::path value)29 void PutEnv(std::string var, fs::path value) {
30 assert(utils::setenv(var.c_str(), value.string().c_str(), /* overwrite */ 1) == 0);
31 }
32
UnsetEnv(std::string var)33 void UnsetEnv(std::string var) {
34 assert(utils::unsetenv(var.c_str()) == 0);
35 }
36
signature_test()37 static void signature_test()
38 {
39 std::error_code ec; ((void)ec);
40 ASSERT_NOT_NOEXCEPT(temp_directory_path());
41 ASSERT_NOT_NOEXCEPT(temp_directory_path(ec));
42 }
43
basic_tests()44 static void basic_tests()
45 {
46 scoped_test_env env;
47 const path dne = env.make_env_path("dne");
48 const path file = env.create_file("file", 42);
49 #ifdef _WIN32
50 // Windows doesn't support setting perms::none to trigger failures
51 // reading directories; test using a special inaccessible directory
52 // instead.
53 const path inaccessible_dir = GetWindowsInaccessibleDir();
54 #else
55 const path dir_perms = env.create_dir("bad_perms_dir");
56 const path inaccessible_dir = env.create_dir("bad_perms_dir/nested");
57 permissions(dir_perms, perms::none);
58 #endif
59 LIBCPP_ONLY(const std::errc expect_errc = std::errc::not_a_directory);
60 struct TestCase {
61 std::string name;
62 path p;
63 } cases[] = {
64 #ifdef _WIN32
65 {"TMP", env.create_dir("dir1")},
66 {"TEMP", env.create_dir("dir2")},
67 {"USERPROFILE", env.create_dir("dir3")}
68 #else
69 {"TMPDIR", env.create_dir("dir1")},
70 {"TMP", env.create_dir("dir2")},
71 {"TEMP", env.create_dir("dir3")},
72 {"TEMPDIR", env.create_dir("dir4")}
73 #endif
74 };
75 TestCase ignored_cases[] = {
76 #ifdef _WIN32
77 {"TMPDIR", env.create_dir("dir5")},
78 {"TEMPDIR", env.create_dir("dir6")},
79 #else
80 {"USERPROFILE", env.create_dir("dir5")},
81 #endif
82 };
83 for (auto& TC : cases) {
84 PutEnv(TC.name, TC.p);
85 }
86 for (auto& TC : cases) {
87 std::error_code ec = GetTestEC();
88 path ret = temp_directory_path(ec);
89 assert(!ec);
90 assert(ret == TC.p);
91 assert(is_directory(ret));
92
93 // Set the env variable to a path that does not exist and check
94 // that it fails.
95 PutEnv(TC.name, dne);
96 ec = GetTestEC();
97 ret = temp_directory_path(ec);
98 LIBCPP_ASSERT(ErrorIs(ec, expect_errc));
99 assert(ec != GetTestEC());
100 assert(ec);
101 assert(ret == "");
102
103 // Set the env variable to point to a file and check that it fails.
104 PutEnv(TC.name, file);
105 ec = GetTestEC();
106 ret = temp_directory_path(ec);
107 LIBCPP_ASSERT(ErrorIs(ec, expect_errc));
108 assert(ec != GetTestEC());
109 assert(ec);
110 assert(ret == "");
111
112 if (!inaccessible_dir.empty()) {
113 // Set the env variable to point to a dir we can't access
114 PutEnv(TC.name, inaccessible_dir);
115 ec = GetTestEC();
116 ret = temp_directory_path(ec);
117 assert(ErrorIs(ec, std::errc::permission_denied));
118 assert(ret == "");
119 }
120
121 // Set the env variable to point to a non-existent dir
122 PutEnv(TC.name, TC.p / "does_not_exist");
123 ec = GetTestEC();
124 ret = temp_directory_path(ec);
125 assert(ec != GetTestEC());
126 assert(ec);
127 assert(ret == "");
128
129 // Finally erase this env variable
130 UnsetEnv(TC.name);
131 }
132 // No env variables are defined
133 path fallback;
134 {
135 std::error_code ec = GetTestEC();
136 path ret = temp_directory_path(ec);
137 assert(!ec);
138 #if defined(_WIN32)
139 // On Windows, the function falls back to the Windows folder.
140 wchar_t win_dir[MAX_PATH];
141 DWORD win_dir_sz = GetWindowsDirectoryW(win_dir, MAX_PATH);
142 assert(win_dir_sz > 0 && win_dir_sz < MAX_PATH);
143 assert(win_dir[win_dir_sz-1] != L'\\');
144 assert(ret == win_dir);
145 #elif defined(__ANDROID__)
146 assert(ret == "/data/local/tmp");
147 #else
148 assert(ret == "/tmp");
149 #endif
150 assert(is_directory(ret));
151 fallback = ret;
152 }
153 for (auto& TC : ignored_cases) {
154 // Check that certain variables are ignored
155 PutEnv(TC.name, TC.p);
156 std::error_code ec = GetTestEC();
157 path ret = temp_directory_path(ec);
158 assert(!ec);
159
160 // Check that we return the same as above when no vars were defined.
161 assert(ret == fallback);
162
163 // Finally erase this env variable
164 UnsetEnv(TC.name);
165 }
166 }
167
main(int,char **)168 int main(int, char**) {
169 signature_test();
170 basic_tests();
171 return 0;
172 }
173