Don't die on Windows.

This commit is contained in:
Victor Zverovich 2014-05-05 07:11:54 -07:00
parent 3555341ab4
commit 5434b0282c
2 changed files with 33 additions and 20 deletions

View File

@ -175,10 +175,23 @@ TEST(ErrorCodeTest, Ctor) {
EXPECT_EQ(42, ErrorCode(42).get()); EXPECT_EQ(42, ErrorCode(42).get());
} }
TEST(BufferedFileTest, DefaultCtor) { class BufferedFileTest : public ::testing::Test {
BufferedFile f; #ifdef _WIN32
EXPECT_TRUE(f.get() == 0); private:
} _invalid_parameter_handler original_handler_;
static void InvalidParameterHandler(const wchar_t *,
const wchar_t *, const wchar_t *, unsigned , uintptr_t) {}
public:
BufferedFileTest()
: original_handler_(_set_invalid_parameter_handler(InvalidParameterHandler)) {
}
~BufferedFileTest() {
_set_invalid_parameter_handler(original_handler_);
}
#endif // _WIN32
};
BufferedFile OpenFile(const char *name, FILE **fp = 0) { BufferedFile OpenFile(const char *name, FILE **fp = 0) {
BufferedFile f = File(".travis.yml", File::RDONLY).fdopen("r"); BufferedFile f = File(".travis.yml", File::RDONLY).fdopen("r");
@ -187,7 +200,12 @@ BufferedFile OpenFile(const char *name, FILE **fp = 0) {
return f; return f;
} }
TEST(BufferedFileTest, MoveCtor) { TEST_F(BufferedFileTest, DefaultCtor) {
BufferedFile f;
EXPECT_TRUE(f.get() == 0);
}
TEST_F(BufferedFileTest, MoveCtor) {
BufferedFile bf = OpenFile(".travis.yml"); BufferedFile bf = OpenFile(".travis.yml");
FILE *fp = bf.get(); FILE *fp = bf.get();
EXPECT_TRUE(fp != 0); EXPECT_TRUE(fp != 0);
@ -196,7 +214,7 @@ TEST(BufferedFileTest, MoveCtor) {
EXPECT_TRUE(bf.get() == 0); EXPECT_TRUE(bf.get() == 0);
} }
TEST(BufferedFileTest, MoveAssignment) { TEST_F(BufferedFileTest, MoveAssignment) {
BufferedFile bf = OpenFile(".travis.yml"); BufferedFile bf = OpenFile(".travis.yml");
FILE *fp = bf.get(); FILE *fp = bf.get();
EXPECT_TRUE(fp != 0); EXPECT_TRUE(fp != 0);
@ -206,7 +224,7 @@ TEST(BufferedFileTest, MoveAssignment) {
EXPECT_TRUE(bf.get() == 0); EXPECT_TRUE(bf.get() == 0);
} }
TEST(BufferedFileTest, MoveAssignmentClosesFile) { TEST_F(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 = fileno(bf2.get());
@ -214,27 +232,27 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
EXPECT_CLOSED(old_fd); EXPECT_CLOSED(old_fd);
} }
TEST(BufferedFileTest, MoveFromTemporaryInCtor) { TEST_F(BufferedFileTest, MoveFromTemporaryInCtor) {
FILE *fp = 0; FILE *fp = 0;
BufferedFile f(OpenFile(".travis.yml", &fp)); BufferedFile f(OpenFile(".travis.yml", &fp));
EXPECT_EQ(fp, f.get()); EXPECT_EQ(fp, f.get());
} }
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) { TEST_F(BufferedFileTest, MoveFromTemporaryInAssignment) {
FILE *fp = 0; FILE *fp = 0;
BufferedFile f; BufferedFile f;
f = OpenFile(".travis.yml", &fp); f = OpenFile(".travis.yml", &fp);
EXPECT_EQ(fp, f.get()); EXPECT_EQ(fp, f.get());
} }
TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) { TEST_F(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
BufferedFile f = OpenFile(".travis.yml"); BufferedFile f = OpenFile(".travis.yml");
int old_fd = fileno(f.get()); int old_fd = fileno(f.get());
f = OpenFile(".travis.yml"); f = OpenFile(".travis.yml");
EXPECT_CLOSED(old_fd); EXPECT_CLOSED(old_fd);
} }
TEST(BufferedFileTest, CloseFileInDtor) { TEST_F(BufferedFileTest, CloseFileInDtor) {
int fd = 0; int fd = 0;
{ {
BufferedFile f = OpenFile(".travis.yml"); BufferedFile f = OpenFile(".travis.yml");
@ -243,20 +261,14 @@ TEST(BufferedFileTest, CloseFileInDtor) {
EXPECT_CLOSED(fd); EXPECT_CLOSED(fd);
} }
TEST(BufferedFileTest, CloseErrorInDtor) { TEST_F(BufferedFileTest, CloseErrorInDtor) {
BufferedFile *f = new BufferedFile(OpenFile(".travis.yml")); BufferedFile *f = new BufferedFile(OpenFile(".travis.yml"));
#ifndef _WIN32
// The close function must be called inside EXPECT_STDERR, otherwise // The close function must be called inside EXPECT_STDERR, otherwise
// 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.
EXPECT_STDERR(close(fileno(f->get())); delete f, EXPECT_STDERR(close(fileno(f->get())); delete f,
FormatSystemErrorMessage(EBADF, "cannot close file") + "\n"); FormatSystemErrorMessage(EBADF, "cannot close file") + "\n");
#else
FMT_POSIX(close(fileno(f->get())));
// Closing file twice causes death on Windows.
EXPECT_DEATH(delete f, "");
#endif
} }
TEST(FileTest, DefaultCtor) { TEST(FileTest, DefaultCtor) {
@ -591,7 +603,7 @@ TEST(OutputRedirectTest, ErrorInDtor) {
// TODO: test EXPECT_STDOUT and EXPECT_STDERR // TODO: test EXPECT_STDOUT and EXPECT_STDERR
// TODO: compile both with C++11 & C++98 mode // TODO: compile both in C++11 & C++98 mode
#endif #endif
} // namespace } // namespace

View File

@ -188,7 +188,8 @@ class BufferedFile {
// Methods that are not declared with FMT_NOEXCEPT(true) may throw // Methods that are not declared with FMT_NOEXCEPT(true) may throw
// fmt::SystemError in case of failure. Note that some errors such as // fmt::SystemError in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather // closing the file multiple times will cause a crash on Windows rather
// than an exception. // than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File { class File {
private: private:
int fd_; // File descriptor. int fd_; // File descriptor.