forked from fmtlib/fmt
Add BufferedFile::fileno.
This commit is contained in:
@@ -255,6 +255,32 @@ bool IsClosed(int fd) {
|
|||||||
return result == -1 && errno == EBADF;
|
return result == -1 && errno == EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempts to read count characters from a file.
|
||||||
|
std::string Read(File &f, std::size_t count) {
|
||||||
|
std::string buffer(count, '\0');
|
||||||
|
std::streamsize offset = 0, n = 0;
|
||||||
|
do {
|
||||||
|
n = f.read(&buffer[offset], count - offset);
|
||||||
|
offset += n;
|
||||||
|
} while (offset < count && n != 0);
|
||||||
|
buffer.resize(offset);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempts to write a string to a file.
|
||||||
|
void Write(File &f, fmt::StringRef s) {
|
||||||
|
std::size_t num_chars_left = s.size();
|
||||||
|
const char *ptr = s.c_str();
|
||||||
|
do {
|
||||||
|
std::streamsize count = f.write(ptr, num_chars_left);
|
||||||
|
ptr += count;
|
||||||
|
num_chars_left -= count;
|
||||||
|
} while (num_chars_left != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_READ(file, expected_content) \
|
||||||
|
EXPECT_EQ(expected_content, Read(file, std::strlen(expected_content)))
|
||||||
|
|
||||||
TEST(ErrorCodeTest, Ctor) {
|
TEST(ErrorCodeTest, Ctor) {
|
||||||
EXPECT_EQ(0, ErrorCode().get());
|
EXPECT_EQ(0, ErrorCode().get());
|
||||||
EXPECT_EQ(42, ErrorCode(42).get());
|
EXPECT_EQ(42, ErrorCode(42).get());
|
||||||
@@ -294,7 +320,7 @@ TEST(BufferedFileTest, MoveAssignment) {
|
|||||||
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
||||||
BufferedFile bf = OpenFile(".travis.yml");
|
BufferedFile bf = OpenFile(".travis.yml");
|
||||||
BufferedFile bf2 = OpenFile("CMakeLists.txt");
|
BufferedFile bf2 = OpenFile("CMakeLists.txt");
|
||||||
int old_fd = fileno(bf2.get());
|
int old_fd = bf2.fileno();
|
||||||
bf2 = std::move(bf);
|
bf2 = std::move(bf);
|
||||||
EXPECT_TRUE(IsClosed(old_fd));
|
EXPECT_TRUE(IsClosed(old_fd));
|
||||||
}
|
}
|
||||||
@@ -314,7 +340,7 @@ TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
|
|||||||
|
|
||||||
TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
|
TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
|
||||||
BufferedFile f = OpenFile(".travis.yml");
|
BufferedFile f = OpenFile(".travis.yml");
|
||||||
int old_fd = fileno(f.get());
|
int old_fd = f.fileno();
|
||||||
f = OpenFile(".travis.yml");
|
f = OpenFile(".travis.yml");
|
||||||
EXPECT_TRUE(IsClosed(old_fd));
|
EXPECT_TRUE(IsClosed(old_fd));
|
||||||
}
|
}
|
||||||
@@ -323,7 +349,7 @@ TEST(BufferedFileTest, CloseFileInDtor) {
|
|||||||
int fd = 0;
|
int fd = 0;
|
||||||
{
|
{
|
||||||
BufferedFile f = OpenFile(".travis.yml");
|
BufferedFile f = OpenFile(".travis.yml");
|
||||||
fd = fileno(f.get());
|
fd = f.fileno();
|
||||||
}
|
}
|
||||||
EXPECT_TRUE(IsClosed(fd));
|
EXPECT_TRUE(IsClosed(fd));
|
||||||
}
|
}
|
||||||
@@ -335,14 +361,14 @@ TEST(BufferedFileTest, CloseErrorInDtor) {
|
|||||||
// the system may recycle closed file descriptor when redirecting the
|
// the system may recycle closed file descriptor when redirecting the
|
||||||
// output in EXPECT_STDERR and the second close will break output
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
// redirection.
|
// redirection.
|
||||||
close(fileno(f->get()));
|
close(f->fileno());
|
||||||
SUPPRESS_ASSERT(delete f);
|
SUPPRESS_ASSERT(delete f);
|
||||||
}, FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
}, FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, Close) {
|
TEST(BufferedFileTest, Close) {
|
||||||
BufferedFile f = OpenFile(".travis.yml");
|
BufferedFile f = OpenFile(".travis.yml");
|
||||||
int fd = fileno(f.get());
|
int fd = f.fileno();
|
||||||
f.close();
|
f.close();
|
||||||
EXPECT_TRUE(f.get() == 0);
|
EXPECT_TRUE(f.get() == 0);
|
||||||
EXPECT_TRUE(IsClosed(fd));
|
EXPECT_TRUE(IsClosed(fd));
|
||||||
@@ -350,11 +376,20 @@ TEST(BufferedFileTest, Close) {
|
|||||||
|
|
||||||
TEST(BufferedFileTest, CloseError) {
|
TEST(BufferedFileTest, CloseError) {
|
||||||
BufferedFile f = OpenFile(".travis.yml");
|
BufferedFile f = OpenFile(".travis.yml");
|
||||||
close(fileno(f.get()));
|
close(f.fileno());
|
||||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
||||||
EXPECT_TRUE(f.get() == 0);
|
EXPECT_TRUE(f.get() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BufferedFileTest, Fileno) {
|
||||||
|
BufferedFile f;
|
||||||
|
EXPECT_DEATH(f.fileno(), "");
|
||||||
|
f = OpenFile(".travis.yml");
|
||||||
|
EXPECT_TRUE(f.fileno() != -1);
|
||||||
|
File dup = File::dup(f.fileno());
|
||||||
|
EXPECT_READ(dup, "language: cpp");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FileTest, DefaultCtor) {
|
TEST(FileTest, DefaultCtor) {
|
||||||
File f;
|
File f;
|
||||||
EXPECT_EQ(-1, f.descriptor());
|
EXPECT_EQ(-1, f.descriptor());
|
||||||
@@ -460,32 +495,6 @@ TEST(FileTest, CloseError) {
|
|||||||
EXPECT_EQ(-1, f.descriptor());
|
EXPECT_EQ(-1, f.descriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to read count characters from a file.
|
|
||||||
std::string Read(File &f, std::size_t count) {
|
|
||||||
std::string buffer(count, '\0');
|
|
||||||
std::streamsize offset = 0, n = 0;
|
|
||||||
do {
|
|
||||||
n = f.read(&buffer[offset], count - offset);
|
|
||||||
offset += n;
|
|
||||||
} while (offset < count && n != 0);
|
|
||||||
buffer.resize(offset);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to write a string to a file.
|
|
||||||
void Write(File &f, fmt::StringRef s) {
|
|
||||||
std::size_t num_chars_left = s.size();
|
|
||||||
const char *ptr = s.c_str();
|
|
||||||
do {
|
|
||||||
std::streamsize count = f.write(ptr, num_chars_left);
|
|
||||||
ptr += count;
|
|
||||||
num_chars_left -= count;
|
|
||||||
} while (num_chars_left != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXPECT_READ(file, expected_content) \
|
|
||||||
EXPECT_EQ(expected_content, Read(file, std::strlen(expected_content)))
|
|
||||||
|
|
||||||
TEST(FileTest, Read) {
|
TEST(FileTest, Read) {
|
||||||
File f(".travis.yml", File::RDONLY);
|
File f(".travis.yml", File::RDONLY);
|
||||||
EXPECT_READ(f, "language: cpp");
|
EXPECT_READ(f, "language: cpp");
|
||||||
@@ -601,7 +610,7 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
|
|||||||
|
|
||||||
TEST(OutputRedirectTest, DupErrorInCtor) {
|
TEST(OutputRedirectTest, DupErrorInCtor) {
|
||||||
BufferedFile f = OpenFile(".travis.yml");
|
BufferedFile f = OpenFile(".travis.yml");
|
||||||
int fd = fileno(f.get());
|
int fd = f.fileno();
|
||||||
File dup = File::dup(fd);
|
File dup = File::dup(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
OutputRedirect *redir = 0;
|
OutputRedirect *redir = 0;
|
||||||
|
@@ -65,6 +65,13 @@ void BufferedFile::close() {
|
|||||||
fmt::ThrowSystemError(errno, "cannot close file");
|
fmt::ThrowSystemError(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BufferedFile::fileno() const {
|
||||||
|
int fd = ::FMT_POSIX(fileno(file_));
|
||||||
|
if (fd == -1)
|
||||||
|
fmt::ThrowSystemError(errno, "cannot get file descriptor");
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
File::File(const char *path, int oflag) {
|
File::File(const char *path, int oflag) {
|
||||||
int mode = S_IRUSR | S_IWUSR;
|
int mode = S_IRUSR | S_IWUSR;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@@ -191,6 +191,8 @@ class BufferedFile {
|
|||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
std::FILE *get() const { return file_; }
|
std::FILE *get() const { return file_; }
|
||||||
|
|
||||||
|
int fileno() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A file. Closed file is represented by a File object with descriptor -1.
|
// A file. Closed file is represented by a File object with descriptor -1.
|
||||||
|
Reference in New Issue
Block a user