]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/fmt/test/posix-test.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / fmt / test / posix-test.cc
1 // Formatting library for C++ - tests of the C++ interface to POSIX functions
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7
8 #include <cstdlib> // std::exit
9 #include <cstring>
10
11 #include "fmt/posix.h"
12 #include "gtest-extra.h"
13 #include "util.h"
14
15 #ifdef fileno
16 # undef fileno
17 #endif
18
19 using fmt::buffered_file;
20 using fmt::error_code;
21 using fmt::file;
22
23 using testing::internal::scoped_ptr;
24
25 // Checks if the file is open by reading one character from it.
26 static bool isopen(int fd) {
27 char buffer;
28 return FMT_POSIX(read(fd, &buffer, 1)) == 1;
29 }
30
31 static bool isclosed(int fd) {
32 char buffer;
33 std::streamsize result = 0;
34 SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
35 return result == -1 && errno == EBADF;
36 }
37
38 // Opens a file for reading.
39 static file open_file() {
40 file read_end, write_end;
41 file::pipe(read_end, write_end);
42 write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
43 write_end.close();
44 return read_end;
45 }
46
47 // Attempts to write a string to a file.
48 static void write(file &f, fmt::string_view s) {
49 std::size_t num_chars_left = s.size();
50 const char *ptr = s.data();
51 do {
52 std::size_t count = f.write(ptr, num_chars_left);
53 ptr += count;
54 // We can't write more than size_t bytes since num_chars_left
55 // has type size_t.
56 num_chars_left -= count;
57 } while (num_chars_left != 0);
58 }
59
60 TEST(BufferedFileTest, DefaultCtor) {
61 buffered_file f;
62 EXPECT_TRUE(f.get() == nullptr);
63 }
64
65 TEST(BufferedFileTest, MoveCtor) {
66 buffered_file bf = open_buffered_file();
67 FILE *fp = bf.get();
68 EXPECT_TRUE(fp != nullptr);
69 buffered_file bf2(std::move(bf));
70 EXPECT_EQ(fp, bf2.get());
71 EXPECT_TRUE(bf.get() == nullptr);
72 }
73
74 TEST(BufferedFileTest, MoveAssignment) {
75 buffered_file bf = open_buffered_file();
76 FILE *fp = bf.get();
77 EXPECT_TRUE(fp != nullptr);
78 buffered_file bf2;
79 bf2 = std::move(bf);
80 EXPECT_EQ(fp, bf2.get());
81 EXPECT_TRUE(bf.get() == nullptr);
82 }
83
84 TEST(BufferedFileTest, MoveAssignmentClosesFile) {
85 buffered_file bf = open_buffered_file();
86 buffered_file bf2 = open_buffered_file();
87 int old_fd = bf2.fileno();
88 bf2 = std::move(bf);
89 EXPECT_TRUE(isclosed(old_fd));
90 }
91
92 TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
93 FILE *fp = nullptr;
94 buffered_file f(open_buffered_file(&fp));
95 EXPECT_EQ(fp, f.get());
96 }
97
98 TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
99 FILE *fp = nullptr;
100 buffered_file f;
101 f = open_buffered_file(&fp);
102 EXPECT_EQ(fp, f.get());
103 }
104
105 TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
106 buffered_file f = open_buffered_file();
107 int old_fd = f.fileno();
108 f = open_buffered_file();
109 EXPECT_TRUE(isclosed(old_fd));
110 }
111
112 TEST(BufferedFileTest, CloseFileInDtor) {
113 int fd = 0;
114 {
115 buffered_file f = open_buffered_file();
116 fd = f.fileno();
117 }
118 EXPECT_TRUE(isclosed(fd));
119 }
120
121 TEST(BufferedFileTest, CloseErrorInDtor) {
122 scoped_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
123 EXPECT_WRITE(stderr, {
124 // The close function must be called inside EXPECT_WRITE, otherwise
125 // the system may recycle closed file descriptor when redirecting the
126 // output in EXPECT_STDERR and the second close will break output
127 // redirection.
128 FMT_POSIX(close(f->fileno()));
129 SUPPRESS_ASSERT(f.reset(nullptr));
130 }, format_system_error(EBADF, "cannot close file") + "\n");
131 }
132
133 TEST(BufferedFileTest, Close) {
134 buffered_file f = open_buffered_file();
135 int fd = f.fileno();
136 f.close();
137 EXPECT_TRUE(f.get() == nullptr);
138 EXPECT_TRUE(isclosed(fd));
139 }
140
141 TEST(BufferedFileTest, CloseError) {
142 buffered_file f = open_buffered_file();
143 FMT_POSIX(close(f.fileno()));
144 EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
145 EXPECT_TRUE(f.get() == nullptr);
146 }
147
148 TEST(BufferedFileTest, Fileno) {
149 buffered_file f;
150 #ifndef __COVERITY__
151 // fileno on a null FILE pointer either crashes or returns an error.
152 // Disable Coverity because this is intentional.
153 EXPECT_DEATH_IF_SUPPORTED({
154 try {
155 f.fileno();
156 } catch (const fmt::system_error&) {
157 std::exit(1);
158 }
159 }, "");
160 #endif
161 f = open_buffered_file();
162 EXPECT_TRUE(f.fileno() != -1);
163 file copy = file::dup(f.fileno());
164 EXPECT_READ(copy, FILE_CONTENT);
165 }
166
167 TEST(FileTest, DefaultCtor) {
168 file f;
169 EXPECT_EQ(-1, f.descriptor());
170 }
171
172 TEST(FileTest, OpenBufferedFileInCtor) {
173 FILE *fp = safe_fopen("test-file", "w");
174 std::fputs(FILE_CONTENT, fp);
175 std::fclose(fp);
176 file f("test-file", file::RDONLY);
177 ASSERT_TRUE(isopen(f.descriptor()));
178 }
179
180 TEST(FileTest, OpenBufferedFileError) {
181 EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY),
182 ENOENT, "cannot open file nonexistent");
183 }
184
185 TEST(FileTest, MoveCtor) {
186 file f = open_file();
187 int fd = f.descriptor();
188 EXPECT_NE(-1, fd);
189 file f2(std::move(f));
190 EXPECT_EQ(fd, f2.descriptor());
191 EXPECT_EQ(-1, f.descriptor());
192 }
193
194 TEST(FileTest, MoveAssignment) {
195 file f = open_file();
196 int fd = f.descriptor();
197 EXPECT_NE(-1, fd);
198 file f2;
199 f2 = std::move(f);
200 EXPECT_EQ(fd, f2.descriptor());
201 EXPECT_EQ(-1, f.descriptor());
202 }
203
204 TEST(FileTest, MoveAssignmentClosesFile) {
205 file f = open_file();
206 file f2 = open_file();
207 int old_fd = f2.descriptor();
208 f2 = std::move(f);
209 EXPECT_TRUE(isclosed(old_fd));
210 }
211
212 static file OpenBufferedFile(int &fd) {
213 file f = open_file();
214 fd = f.descriptor();
215 return f;
216 }
217
218 TEST(FileTest, MoveFromTemporaryInCtor) {
219 int fd = 0xdead;
220 file f(OpenBufferedFile(fd));
221 EXPECT_EQ(fd, f.descriptor());
222 }
223
224 TEST(FileTest, MoveFromTemporaryInAssignment) {
225 int fd = 0xdead;
226 file f;
227 f = OpenBufferedFile(fd);
228 EXPECT_EQ(fd, f.descriptor());
229 }
230
231 TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
232 int fd = 0xdead;
233 file f = open_file();
234 int old_fd = f.descriptor();
235 f = OpenBufferedFile(fd);
236 EXPECT_TRUE(isclosed(old_fd));
237 }
238
239 TEST(FileTest, CloseFileInDtor) {
240 int fd = 0;
241 {
242 file f = open_file();
243 fd = f.descriptor();
244 }
245 EXPECT_TRUE(isclosed(fd));
246 }
247
248 TEST(FileTest, CloseErrorInDtor) {
249 scoped_ptr<file> f(new file(open_file()));
250 EXPECT_WRITE(stderr, {
251 // The close function must be called inside EXPECT_WRITE, otherwise
252 // the system may recycle closed file descriptor when redirecting the
253 // output in EXPECT_STDERR and the second close will break output
254 // redirection.
255 FMT_POSIX(close(f->descriptor()));
256 SUPPRESS_ASSERT(f.reset(nullptr));
257 }, format_system_error(EBADF, "cannot close file") + "\n");
258 }
259
260 TEST(FileTest, Close) {
261 file f = open_file();
262 int fd = f.descriptor();
263 f.close();
264 EXPECT_EQ(-1, f.descriptor());
265 EXPECT_TRUE(isclosed(fd));
266 }
267
268 TEST(FileTest, CloseError) {
269 file f = open_file();
270 FMT_POSIX(close(f.descriptor()));
271 EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
272 EXPECT_EQ(-1, f.descriptor());
273 }
274
275 TEST(FileTest, Read) {
276 file f = open_file();
277 EXPECT_READ(f, FILE_CONTENT);
278 }
279
280 TEST(FileTest, ReadError) {
281 file f("test-file", file::WRONLY);
282 char buf;
283 // We intentionally read from a file opened in the write-only mode to
284 // cause error.
285 EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file");
286 }
287
288 TEST(FileTest, Write) {
289 file read_end, write_end;
290 file::pipe(read_end, write_end);
291 write(write_end, "test");
292 write_end.close();
293 EXPECT_READ(read_end, "test");
294 }
295
296 TEST(FileTest, WriteError) {
297 file f("test-file", file::RDONLY);
298 // We intentionally write to a file opened in the read-only mode to
299 // cause error.
300 EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file");
301 }
302
303 TEST(FileTest, Dup) {
304 file f = open_file();
305 file copy = file::dup(f.descriptor());
306 EXPECT_NE(f.descriptor(), copy.descriptor());
307 EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT)));
308 }
309
310 #ifndef __COVERITY__
311 TEST(FileTest, DupError) {
312 int value = -1;
313 EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value),
314 EBADF, "cannot duplicate file descriptor -1");
315 }
316 #endif
317
318 TEST(FileTest, Dup2) {
319 file f = open_file();
320 file copy = open_file();
321 f.dup2(copy.descriptor());
322 EXPECT_NE(f.descriptor(), copy.descriptor());
323 EXPECT_READ(copy, FILE_CONTENT);
324 }
325
326 TEST(FileTest, Dup2Error) {
327 file f = open_file();
328 EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF,
329 fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor()));
330 }
331
332 TEST(FileTest, Dup2NoExcept) {
333 file f = open_file();
334 file copy = open_file();
335 error_code ec;
336 f.dup2(copy.descriptor(), ec);
337 EXPECT_EQ(0, ec.get());
338 EXPECT_NE(f.descriptor(), copy.descriptor());
339 EXPECT_READ(copy, FILE_CONTENT);
340 }
341
342 TEST(FileTest, Dup2NoExceptError) {
343 file f = open_file();
344 error_code ec;
345 SUPPRESS_ASSERT(f.dup2(-1, ec));
346 EXPECT_EQ(EBADF, ec.get());
347 }
348
349 TEST(FileTest, Pipe) {
350 file read_end, write_end;
351 file::pipe(read_end, write_end);
352 EXPECT_NE(-1, read_end.descriptor());
353 EXPECT_NE(-1, write_end.descriptor());
354 write(write_end, "test");
355 EXPECT_READ(read_end, "test");
356 }
357
358 TEST(FileTest, Fdopen) {
359 file read_end, write_end;
360 file::pipe(read_end, write_end);
361 int read_fd = read_end.descriptor();
362 EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
363 }
364
365 TEST(FileTest, FdopenError) {
366 file f;
367 EXPECT_SYSTEM_ERROR_NOASSERT(
368 f.fdopen("r"), EBADF, "cannot associate stream with file descriptor");
369 }
370
371 #ifdef FMT_LOCALE
372 TEST(LocaleTest, Strtod) {
373 fmt::Locale locale;
374 const char *start = "4.2", *ptr = start;
375 EXPECT_EQ(4.2, locale.strtod(ptr));
376 EXPECT_EQ(start + 3, ptr);
377 }
378 #endif