xref: /llvm-project/flang/unittests/Runtime/AccessTest.cpp (revision f220d26eb1ab5b588215acf538ca82bb3c8798cc)
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 //===----------------------------------------------------------------------===//
8 
9 // TODO: ACCESS is not yet implemented on Windows
10 #ifndef _WIN32
11 
12 #include "CrashHandlerFixture.h"
13 #include "gtest/gtest.h"
14 #include "flang/Runtime/extensions.h"
15 
16 #include <fcntl.h>
17 #include <filesystem>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 namespace {
23 
24 struct AccessTests : public CrashHandlerFixture {};
25 
26 struct AccessType {
27   bool read{false};
28   bool write{false};
29   bool execute{false};
30   bool exists{false};
31 };
32 
33 } // namespace
34 
35 static std::string addPIDSuffix(const char *name) {
36   std::stringstream ss;
37   ss << name;
38   ss << '.';
39 
40   ss << getpid();
41 
42   return ss.str();
43 }
44 
45 static std::filesystem::path createTemporaryFile(
46     const char *name, const AccessType &accessType) {
47   std::filesystem::path path{
48       std::filesystem::temp_directory_path() / addPIDSuffix(name)};
49 
50   // O_CREAT | O_EXCL enforces that this file is newly created by this call.
51   // This feels risky. If we don't have permission to create files in the
52   // temporary directory or if the files already exist, the test will fail.
53   // But we can't use std::tmpfile() because we need a path to the file and
54   // to control the filesystem permissions
55   mode_t mode{0};
56   if (accessType.read) {
57     mode |= S_IRUSR;
58   }
59   if (accessType.write) {
60     mode |= S_IWUSR;
61   }
62   if (accessType.execute) {
63     mode |= S_IXUSR;
64   }
65 
66   int file = open(path.c_str(), O_CREAT | O_EXCL, mode);
67   if (file == -1) {
68     return {};
69   }
70 
71   close(file);
72 
73   return path;
74 }
75 
76 static std::int64_t callAccess(
77     const std::filesystem::path &path, const AccessType &accessType) {
78   const char *cpath{path.c_str()};
79   std::int64_t pathlen = std::strlen(cpath);
80 
81   std::string mode;
82   if (accessType.read) {
83     mode += 'r';
84   }
85   if (accessType.write) {
86     mode += 'w';
87   }
88   if (accessType.execute) {
89     mode += 'x';
90   }
91   if (accessType.exists) {
92     mode += ' ';
93   }
94 
95   const char *cmode = mode.c_str();
96   std::int64_t modelen = std::strlen(cmode);
97 
98   return FORTRAN_PROCEDURE_NAME(access)(cpath, pathlen, cmode, modelen);
99 }
100 
101 TEST(AccessTests, TestExists) {
102   AccessType accessType;
103   accessType.exists = true;
104 
105   std::filesystem::path path = createTemporaryFile(__func__, accessType);
106   ASSERT_FALSE(path.empty());
107 
108   std::int64_t res = callAccess(path, accessType);
109 
110   std::filesystem::remove(path);
111 
112   ASSERT_EQ(res, 0);
113 }
114 
115 TEST(AccessTests, TestNotExists) {
116   std::filesystem::path nonExistant{addPIDSuffix(__func__)};
117   ASSERT_FALSE(std::filesystem::exists(nonExistant));
118 
119   AccessType accessType;
120   accessType.exists = true;
121   std::int64_t res = callAccess(nonExistant, accessType);
122 
123   ASSERT_NE(res, 0);
124 }
125 
126 TEST(AccessTests, TestRead) {
127   AccessType accessType;
128   accessType.read = true;
129 
130   std::filesystem::path path = createTemporaryFile(__func__, accessType);
131   ASSERT_FALSE(path.empty());
132 
133   std::int64_t res = callAccess(path, accessType);
134 
135   std::filesystem::remove(path);
136 
137   ASSERT_EQ(res, 0);
138 }
139 
140 TEST(AccessTests, TestNotRead) {
141   AccessType accessType;
142   accessType.read = false;
143 
144   std::filesystem::path path = createTemporaryFile(__func__, accessType);
145   ASSERT_FALSE(path.empty());
146 
147   accessType.read = true;
148   std::int64_t res = callAccess(path, accessType);
149 
150   std::filesystem::remove(path);
151 
152   ASSERT_NE(res, 0);
153 }
154 
155 TEST(AccessTests, TestWrite) {
156   AccessType accessType;
157   accessType.write = true;
158 
159   std::filesystem::path path = createTemporaryFile(__func__, accessType);
160   ASSERT_FALSE(path.empty());
161 
162   std::int64_t res = callAccess(path, accessType);
163 
164   std::filesystem::remove(path);
165 
166   ASSERT_EQ(res, 0);
167 }
168 
169 TEST(AccessTests, TestNotWrite) {
170   AccessType accessType;
171   accessType.write = false;
172 
173   std::filesystem::path path = createTemporaryFile(__func__, accessType);
174   ASSERT_FALSE(path.empty());
175 
176   accessType.write = true;
177   std::int64_t res = callAccess(path, accessType);
178 
179   std::filesystem::remove(path);
180 
181   ASSERT_NE(res, 0);
182 }
183 
184 TEST(AccessTests, TestReadWrite) {
185   AccessType accessType;
186   accessType.read = true;
187   accessType.write = true;
188 
189   std::filesystem::path path = createTemporaryFile(__func__, accessType);
190   ASSERT_FALSE(path.empty());
191 
192   std::int64_t res = callAccess(path, accessType);
193 
194   std::filesystem::remove(path);
195 
196   ASSERT_EQ(res, 0);
197 }
198 
199 TEST(AccessTests, TestNotReadWrite0) {
200   AccessType accessType;
201   accessType.read = false;
202   accessType.write = false;
203 
204   std::filesystem::path path = createTemporaryFile(__func__, accessType);
205   ASSERT_FALSE(path.empty());
206 
207   accessType.read = true;
208   accessType.write = true;
209   std::int64_t res = callAccess(path, accessType);
210 
211   std::filesystem::remove(path);
212 
213   ASSERT_NE(res, 0);
214 }
215 
216 TEST(AccessTests, TestNotReadWrite1) {
217   AccessType accessType;
218   accessType.read = true;
219   accessType.write = false;
220 
221   std::filesystem::path path = createTemporaryFile(__func__, accessType);
222   ASSERT_FALSE(path.empty());
223 
224   accessType.read = true;
225   accessType.write = true;
226   std::int64_t res = callAccess(path, accessType);
227 
228   std::filesystem::remove(path);
229 
230   ASSERT_NE(res, 0);
231 }
232 
233 TEST(AccessTests, TestNotReadWrite2) {
234   AccessType accessType;
235   accessType.read = false;
236   accessType.write = true;
237 
238   std::filesystem::path path = createTemporaryFile(__func__, accessType);
239   ASSERT_FALSE(path.empty());
240 
241   accessType.read = true;
242   accessType.write = true;
243   std::int64_t res = callAccess(path, accessType);
244 
245   std::filesystem::remove(path);
246 
247   ASSERT_NE(res, 0);
248 }
249 
250 TEST(AccessTests, TestExecute) {
251   AccessType accessType;
252   accessType.execute = true;
253 
254   std::filesystem::path path = createTemporaryFile(__func__, accessType);
255   ASSERT_FALSE(path.empty());
256 
257   std::int64_t res = callAccess(path, accessType);
258 
259   std::filesystem::remove(path);
260 
261   ASSERT_EQ(res, 0);
262 }
263 
264 TEST(AccessTests, TestNotExecute) {
265   AccessType accessType;
266   accessType.execute = false;
267 
268   std::filesystem::path path = createTemporaryFile(__func__, accessType);
269   ASSERT_FALSE(path.empty());
270 
271   accessType.execute = true;
272   std::int64_t res = callAccess(path, accessType);
273 
274   std::filesystem::remove(path);
275 
276   ASSERT_NE(res, 0);
277 }
278 
279 TEST(AccessTests, TestRWX) {
280   AccessType accessType;
281   accessType.read = true;
282   accessType.write = true;
283   accessType.execute = true;
284 
285   std::filesystem::path path = createTemporaryFile(__func__, accessType);
286   ASSERT_FALSE(path.empty());
287 
288   std::int64_t res = callAccess(path, accessType);
289 
290   std::filesystem::remove(path);
291 
292   ASSERT_EQ(res, 0);
293 }
294 
295 TEST(AccessTests, TestNotRWX0) {
296   AccessType accessType;
297   accessType.read = false;
298   accessType.write = false;
299   accessType.execute = false;
300 
301   std::filesystem::path path = createTemporaryFile(__func__, accessType);
302   ASSERT_FALSE(path.empty());
303 
304   accessType.read = true;
305   accessType.write = true;
306   accessType.execute = true;
307   std::int64_t res = callAccess(path, accessType);
308 
309   std::filesystem::remove(path);
310 
311   ASSERT_NE(res, 0);
312 }
313 
314 TEST(AccessTests, TestNotRWX1) {
315   AccessType accessType;
316   accessType.read = true;
317   accessType.write = false;
318   accessType.execute = false;
319 
320   std::filesystem::path path = createTemporaryFile(__func__, accessType);
321   ASSERT_FALSE(path.empty());
322 
323   accessType.read = true;
324   accessType.write = true;
325   accessType.execute = true;
326   std::int64_t res = callAccess(path, accessType);
327 
328   std::filesystem::remove(path);
329 
330   ASSERT_NE(res, 0);
331 }
332 
333 TEST(AccessTests, TestNotRWX2) {
334   AccessType accessType;
335   accessType.read = true;
336   accessType.write = true;
337   accessType.execute = false;
338 
339   std::filesystem::path path = createTemporaryFile(__func__, accessType);
340   ASSERT_FALSE(path.empty());
341 
342   accessType.read = true;
343   accessType.write = true;
344   accessType.execute = true;
345   std::int64_t res = callAccess(path, accessType);
346 
347   std::filesystem::remove(path);
348 
349   ASSERT_NE(res, 0);
350 }
351 
352 TEST(AccessTests, TestNotRWX3) {
353   AccessType accessType;
354   accessType.read = true;
355   accessType.write = false;
356   accessType.execute = true;
357 
358   std::filesystem::path path = createTemporaryFile(__func__, accessType);
359   ASSERT_FALSE(path.empty());
360 
361   accessType.read = true;
362   accessType.write = true;
363   accessType.execute = true;
364   std::int64_t res = callAccess(path, accessType);
365 
366   std::filesystem::remove(path);
367 
368   ASSERT_NE(res, 0);
369 }
370 
371 TEST(AccessTests, TestNotRWX4) {
372   AccessType accessType;
373   accessType.read = false;
374   accessType.write = true;
375   accessType.execute = true;
376 
377   std::filesystem::path path = createTemporaryFile(__func__, accessType);
378   ASSERT_FALSE(path.empty());
379 
380   accessType.read = true;
381   accessType.write = true;
382   accessType.execute = true;
383   std::int64_t res = callAccess(path, accessType);
384 
385   std::filesystem::remove(path);
386 
387   ASSERT_NE(res, 0);
388 }
389 
390 #endif // !_WIN32
391