Commit fb4ccac9 authored by Victor Zverovich's avatar Victor Zverovich

Add BufferedFile::fileno.

parent d286efd3
...@@ -255,6 +255,32 @@ bool IsClosed(int fd) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -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 { ...@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment