Bump version to 19.1.2
[llvm-project.git] / flang / unittests / Runtime / AccessTest.cpp
blob66f19f78c7cfb671ca8a5039d7646705be76bf90
1 //===-- flang/unittests/Runtime/AccessTest.cpp ----------------------------===//
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 //===----------------------------------------------------------------------===//
9 // TODO: ACCESS is not yet implemented on Windows
10 #ifndef _WIN32
12 #include "CrashHandlerFixture.h"
13 #include "gtest/gtest.h"
14 #include "flang/Runtime/extensions.h"
15 #include "llvm/ADT/Twine.h"
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
22 namespace {
24 struct AccessTests : public CrashHandlerFixture {};
26 struct AccessType {
27 bool read{false};
28 bool write{false};
29 bool execute{false};
30 bool exists{false};
33 } // namespace
35 static std::string addPIDSuffix(const char *name) {
36 std::stringstream ss;
37 ss << name;
38 ss << '.';
40 ss << getpid();
42 return ss.str();
45 static bool exists(const std::string &path) {
46 return access(path.c_str(), F_OK) == 0;
49 // Implementation of std::filesystem::temp_directory_path adapted from libcxx
50 // See llvm-project/libcxx/src/filesystem/operations.cpp
51 // Using std::filesystem is inconvenient because the required flags are not
52 // consistent accross compilers and CMake doesn't have built in support to
53 // determine the correct flags.
54 static const char *temp_directory_path() {
55 // TODO: Windows
56 const char *env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
57 const char *ret = nullptr;
59 for (auto &ep : env_paths) {
60 if ((ret = getenv(ep))) {
61 break;
65 if (ret == nullptr) {
66 #if defined(__ANDROID__)
67 ret = "/data/local/tmp";
68 #else
69 ret = "/tmp";
70 #endif
73 assert(exists(ret));
74 return ret;
77 static std::string createTemporaryFile(
78 const char *name, const AccessType &accessType) {
79 std::string path =
80 (llvm::Twine{temp_directory_path()} + "/" + addPIDSuffix(name)).str();
82 // O_CREAT | O_EXCL enforces that this file is newly created by this call.
83 // This feels risky. If we don't have permission to create files in the
84 // temporary directory or if the files already exist, the test will fail.
85 // But we can't use std::tmpfile() because we need a path to the file and
86 // to control the filesystem permissions
87 mode_t mode{0};
88 if (accessType.read) {
89 mode |= S_IRUSR;
91 if (accessType.write) {
92 mode |= S_IWUSR;
94 if (accessType.execute) {
95 mode |= S_IXUSR;
98 int file = open(path.c_str(), O_CREAT | O_EXCL, mode);
99 if (file == -1) {
100 return {};
103 close(file);
105 return path;
108 static std::int64_t callAccess(
109 const std::string &path, const AccessType &accessType) {
110 const char *cpath{path.c_str()};
111 std::int64_t pathlen = std::strlen(cpath);
113 std::string mode;
114 if (accessType.read) {
115 mode += 'r';
117 if (accessType.write) {
118 mode += 'w';
120 if (accessType.execute) {
121 mode += 'x';
123 if (accessType.exists) {
124 mode += ' ';
127 const char *cmode = mode.c_str();
128 std::int64_t modelen = std::strlen(cmode);
130 return FORTRAN_PROCEDURE_NAME(access)(cpath, pathlen, cmode, modelen);
133 TEST(AccessTests, TestExists) {
134 AccessType accessType;
135 accessType.exists = true;
137 std::string path = createTemporaryFile(__func__, accessType);
138 ASSERT_FALSE(path.empty());
140 std::int64_t res = callAccess(path, accessType);
142 ASSERT_EQ(unlink(path.c_str()), 0);
144 ASSERT_EQ(res, 0);
147 TEST(AccessTests, TestNotExists) {
148 std::string nonExistant{addPIDSuffix(__func__)};
149 ASSERT_FALSE(exists(nonExistant));
151 AccessType accessType;
152 accessType.exists = true;
153 std::int64_t res = callAccess(nonExistant, accessType);
155 ASSERT_NE(res, 0);
158 TEST(AccessTests, TestRead) {
159 AccessType accessType;
160 accessType.read = true;
162 std::string path = createTemporaryFile(__func__, accessType);
163 ASSERT_FALSE(path.empty());
165 std::int64_t res = callAccess(path, accessType);
167 ASSERT_EQ(unlink(path.c_str()), 0);
169 ASSERT_EQ(res, 0);
172 TEST(AccessTests, TestNotRead) {
173 AccessType accessType;
174 accessType.read = false;
176 std::string path = createTemporaryFile(__func__, accessType);
177 ASSERT_FALSE(path.empty());
179 accessType.read = true;
180 std::int64_t res = callAccess(path, accessType);
182 ASSERT_EQ(unlink(path.c_str()), 0);
184 ASSERT_NE(res, 0);
187 TEST(AccessTests, TestWrite) {
188 AccessType accessType;
189 accessType.write = true;
191 std::string path = createTemporaryFile(__func__, accessType);
192 ASSERT_FALSE(path.empty());
194 std::int64_t res = callAccess(path, accessType);
196 ASSERT_EQ(unlink(path.c_str()), 0);
198 ASSERT_EQ(res, 0);
201 TEST(AccessTests, TestNotWrite) {
202 AccessType accessType;
203 accessType.write = false;
205 std::string path = createTemporaryFile(__func__, accessType);
206 ASSERT_FALSE(path.empty());
208 accessType.write = true;
209 std::int64_t res = callAccess(path, accessType);
211 ASSERT_EQ(unlink(path.c_str()), 0);
213 ASSERT_NE(res, 0);
216 TEST(AccessTests, TestReadWrite) {
217 AccessType accessType;
218 accessType.read = true;
219 accessType.write = true;
221 std::string path = createTemporaryFile(__func__, accessType);
222 ASSERT_FALSE(path.empty());
224 std::int64_t res = callAccess(path, accessType);
226 ASSERT_EQ(unlink(path.c_str()), 0);
228 ASSERT_EQ(res, 0);
231 TEST(AccessTests, TestNotReadWrite0) {
232 AccessType accessType;
233 accessType.read = false;
234 accessType.write = false;
236 std::string path = createTemporaryFile(__func__, accessType);
237 ASSERT_FALSE(path.empty());
239 accessType.read = true;
240 accessType.write = true;
241 std::int64_t res = callAccess(path, accessType);
243 ASSERT_EQ(unlink(path.c_str()), 0);
245 ASSERT_NE(res, 0);
248 TEST(AccessTests, TestNotReadWrite1) {
249 AccessType accessType;
250 accessType.read = true;
251 accessType.write = false;
253 std::string path = createTemporaryFile(__func__, accessType);
254 ASSERT_FALSE(path.empty());
256 accessType.read = true;
257 accessType.write = true;
258 std::int64_t res = callAccess(path, accessType);
260 ASSERT_EQ(unlink(path.c_str()), 0);
262 ASSERT_NE(res, 0);
265 TEST(AccessTests, TestNotReadWrite2) {
266 AccessType accessType;
267 accessType.read = false;
268 accessType.write = true;
270 std::string path = createTemporaryFile(__func__, accessType);
271 ASSERT_FALSE(path.empty());
273 accessType.read = true;
274 accessType.write = true;
275 std::int64_t res = callAccess(path, accessType);
277 ASSERT_EQ(unlink(path.c_str()), 0);
279 ASSERT_NE(res, 0);
282 TEST(AccessTests, TestExecute) {
283 AccessType accessType;
284 accessType.execute = true;
286 std::string path = createTemporaryFile(__func__, accessType);
287 ASSERT_FALSE(path.empty());
289 std::int64_t res = callAccess(path, accessType);
291 ASSERT_EQ(unlink(path.c_str()), 0);
293 ASSERT_EQ(res, 0);
296 TEST(AccessTests, TestNotExecute) {
297 AccessType accessType;
298 accessType.execute = false;
300 std::string path = createTemporaryFile(__func__, accessType);
301 ASSERT_FALSE(path.empty());
303 accessType.execute = true;
304 std::int64_t res = callAccess(path, accessType);
306 ASSERT_EQ(unlink(path.c_str()), 0);
308 ASSERT_NE(res, 0);
311 TEST(AccessTests, TestRWX) {
312 AccessType accessType;
313 accessType.read = true;
314 accessType.write = true;
315 accessType.execute = true;
317 std::string path = createTemporaryFile(__func__, accessType);
318 ASSERT_FALSE(path.empty());
320 std::int64_t res = callAccess(path, accessType);
322 ASSERT_EQ(unlink(path.c_str()), 0);
324 ASSERT_EQ(res, 0);
327 TEST(AccessTests, TestNotRWX0) {
328 AccessType accessType;
329 accessType.read = false;
330 accessType.write = false;
331 accessType.execute = false;
333 std::string path = createTemporaryFile(__func__, accessType);
334 ASSERT_FALSE(path.empty());
336 accessType.read = true;
337 accessType.write = true;
338 accessType.execute = true;
339 std::int64_t res = callAccess(path, accessType);
341 ASSERT_EQ(unlink(path.c_str()), 0);
343 ASSERT_NE(res, 0);
346 TEST(AccessTests, TestNotRWX1) {
347 AccessType accessType;
348 accessType.read = true;
349 accessType.write = false;
350 accessType.execute = false;
352 std::string path = createTemporaryFile(__func__, accessType);
353 ASSERT_FALSE(path.empty());
355 accessType.read = true;
356 accessType.write = true;
357 accessType.execute = true;
358 std::int64_t res = callAccess(path, accessType);
360 ASSERT_EQ(unlink(path.c_str()), 0);
362 ASSERT_NE(res, 0);
365 TEST(AccessTests, TestNotRWX2) {
366 AccessType accessType;
367 accessType.read = true;
368 accessType.write = true;
369 accessType.execute = false;
371 std::string path = createTemporaryFile(__func__, accessType);
372 ASSERT_FALSE(path.empty());
374 accessType.read = true;
375 accessType.write = true;
376 accessType.execute = true;
377 std::int64_t res = callAccess(path, accessType);
379 ASSERT_EQ(unlink(path.c_str()), 0);
381 ASSERT_NE(res, 0);
384 TEST(AccessTests, TestNotRWX3) {
385 AccessType accessType;
386 accessType.read = true;
387 accessType.write = false;
388 accessType.execute = true;
390 std::string path = createTemporaryFile(__func__, accessType);
391 ASSERT_FALSE(path.empty());
393 accessType.read = true;
394 accessType.write = true;
395 accessType.execute = true;
396 std::int64_t res = callAccess(path, accessType);
398 ASSERT_EQ(unlink(path.c_str()), 0);
400 ASSERT_NE(res, 0);
403 TEST(AccessTests, TestNotRWX4) {
404 AccessType accessType;
405 accessType.read = false;
406 accessType.write = true;
407 accessType.execute = true;
409 std::string path = createTemporaryFile(__func__, accessType);
410 ASSERT_FALSE(path.empty());
412 accessType.read = true;
413 accessType.write = true;
414 accessType.execute = true;
415 std::int64_t res = callAccess(path, accessType);
417 ASSERT_EQ(unlink(path.c_str()), 0);
419 ASSERT_NE(res, 0);
422 #endif // !_WIN32