forked from fmtlib/fmt
More posix tests.
This commit is contained in:
@ -136,8 +136,9 @@ std::streamsize File::write(const void *buffer, std::size_t count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
File File::dup(int fd) {
|
File File::dup(int fd) {
|
||||||
int new_fd = 0;
|
// Don't retry as dup doesn't return EINTR.
|
||||||
FMT_RETRY(new_fd, FMT_POSIX_CALL(dup(fd)));
|
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||||
|
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||||
if (new_fd == -1)
|
if (new_fd == -1)
|
||||||
fmt::ThrowSystemError(errno, "cannot duplicate file descriptor {}") << fd;
|
fmt::ThrowSystemError(errno, "cannot duplicate file descriptor {}") << fd;
|
||||||
return File(new_fd);
|
return File(new_fd);
|
||||||
@ -168,10 +169,11 @@ void File::pipe(File &read_end, File &write_end) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||||
enum { DEFAULT_CAPACITY = 65536 };
|
enum { DEFAULT_CAPACITY = 65536 };
|
||||||
int result = _pipe(fds, DEFAULT_CAPACITY, _O_BINARY);
|
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
||||||
#else
|
#else
|
||||||
// The pipe function doesn't return EINTR, so no need to retry.
|
// Don't retry as the pipe function doesn't return EINTR.
|
||||||
int result = ::pipe(fds);
|
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||||
|
int result = FMT_POSIX_CALL(pipe(fds));
|
||||||
#endif
|
#endif
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
fmt::ThrowSystemError(errno, "cannot create pipe");
|
fmt::ThrowSystemError(errno, "cannot create pipe");
|
||||||
@ -182,9 +184,15 @@ void File::pipe(File &read_end, File &write_end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BufferedFile File::fdopen(const char *mode) {
|
BufferedFile File::fdopen(const char *mode) {
|
||||||
BufferedFile f(FMT_POSIX_CALL(fdopen(fd_, mode)));
|
// Don't retry as fdopen doesn't return EINTR.
|
||||||
|
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||||
|
if (!f) {
|
||||||
|
fmt::ThrowSystemError(errno,
|
||||||
|
"cannot associate stream with file descriptor");
|
||||||
|
}
|
||||||
|
BufferedFile file(f);
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
return f;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutputRedirect::Flush() {
|
void OutputRedirect::Flush() {
|
||||||
|
@ -41,6 +41,7 @@ int fdopen_count;
|
|||||||
int fileno_count;
|
int fileno_count;
|
||||||
int read_count;
|
int read_count;
|
||||||
int write_count;
|
int write_count;
|
||||||
|
int pipe_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EMULATE_EINTR(func, error_result) \
|
#define EMULATE_EINTR(func, error_result) \
|
||||||
@ -101,6 +102,11 @@ test::ssize_t test::write(int fildes, const void *buf, test::size_t nbyte) {
|
|||||||
return ::write(fildes, buf, nbyte);
|
return ::write(fildes, buf, nbyte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test::pipe(int fildes[2]) {
|
||||||
|
EMULATE_EINTR(pipe, -1);
|
||||||
|
return ::pipe(fildes);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define EXPECT_RETRY(statement, func, message) \
|
# define EXPECT_RETRY(statement, func, message) \
|
||||||
func##_count = 1; \
|
func##_count = 1; \
|
||||||
@ -180,10 +186,12 @@ TEST(FileTest, WriteRetry) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTest, DupRetry) {
|
TEST(FileTest, DupNoRetry) {
|
||||||
int stdout_fd = fileno(stdout);
|
int stdout_fd = fileno(stdout);
|
||||||
EXPECT_RETRY(File::dup(stdout_fd), dup,
|
dup_count = 1;
|
||||||
|
EXPECT_SYSTEM_ERROR(File::dup(stdout_fd), EINTR,
|
||||||
str(fmt::Format("cannot duplicate file descriptor {}") << stdout_fd));
|
str(fmt::Format("cannot duplicate file descriptor {}") << stdout_fd));
|
||||||
|
dup_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTest, Dup2Retry) {
|
TEST(FileTest, Dup2Retry) {
|
||||||
@ -193,5 +201,35 @@ TEST(FileTest, Dup2Retry) {
|
|||||||
<< f1.descriptor() << f2.descriptor()));
|
<< f1.descriptor() << f2.descriptor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test retry on EINTR in dup2, pipe, fdopen
|
TEST(FileTest, Dup2NoExceptRetry) {
|
||||||
|
File f1 = File::dup(fileno(stdout)), f2 = File::dup(fileno(stdout));
|
||||||
|
ErrorCode ec;
|
||||||
|
dup2_count = 1;
|
||||||
|
f1.dup2(f2.descriptor(), ec);
|
||||||
|
#ifndef _WIN32
|
||||||
|
EXPECT_EQ(4, dup2_count);
|
||||||
|
#else
|
||||||
|
EXPECT_EQ(EINTR, ec.get());
|
||||||
|
#endif
|
||||||
|
dup2_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileTest, PipeNoRetry) {
|
||||||
|
File read_end, write_end;
|
||||||
|
pipe_count = 1;
|
||||||
|
EXPECT_SYSTEM_ERROR(
|
||||||
|
File::pipe(read_end, write_end), EINTR, "cannot create pipe");
|
||||||
|
pipe_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FileTest, FdopenNoRetry) {
|
||||||
|
File read_end, write_end;
|
||||||
|
File::pipe(read_end, write_end);
|
||||||
|
fdopen_count = 1;
|
||||||
|
EXPECT_SYSTEM_ERROR(read_end.fdopen("r"),
|
||||||
|
EINTR, "cannot associate stream with file descriptor");
|
||||||
|
fdopen_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test retry on EINTR in fclose & fileno
|
||||||
// TODO: test ConvertRWCount
|
// TODO: test ConvertRWCount
|
||||||
|
@ -56,6 +56,8 @@ int fileno(FILE *stream);
|
|||||||
ssize_t read(int fildes, void *buf, size_t nbyte);
|
ssize_t read(int fildes, void *buf, size_t nbyte);
|
||||||
ssize_t write(int fildes, const void *buf, size_t nbyte);
|
ssize_t write(int fildes, const void *buf, size_t nbyte);
|
||||||
|
|
||||||
|
int pipe(int fildes[2]);
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
#define FMT_POSIX_CALL(call) test::call
|
#define FMT_POSIX_CALL(call) test::call
|
||||||
|
Reference in New Issue
Block a user