Merge "Add fpos_t tests."

This commit is contained in:
Calin Juravle 2014-05-13 09:37:07 +00:00 committed by Gerrit Code Review
commit 38967f3d1f

View File

@ -24,6 +24,9 @@
#include <sys/stat.h>
#include <unistd.h>
#include <wchar.h>
#include <locale.h>
#include "TemporaryFile.h"
TEST(stdio, tmpfile_fileno_fprintf_rewind_fgets) {
FILE* fp = tmpfile();
@ -479,3 +482,127 @@ TEST(stdio, cantwrite_EBADF) {
EXPECT_EQ(EBADF, errno);
#endif
}
// Tests that we can only have a consistent and correct fpos_t when using
// f*pos functions (i.e. fpos doesn't get inside a multi byte character).
TEST(stdio, consistent_fpos_t) {
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
FILE* fp = tmpfile();
ASSERT_TRUE(fp != NULL);
wchar_t mb_one_bytes = L'h';
wchar_t mb_two_bytes = 0x00a2;
wchar_t mb_three_bytes = 0x20ac;
wchar_t mb_four_bytes = 0x24b62;
// Write to file.
ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fputwc(mb_one_bytes, fp)));
ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fputwc(mb_two_bytes, fp)));
ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fputwc(mb_three_bytes, fp)));
ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fputwc(mb_four_bytes, fp)));
rewind(fp);
// Record each character position.
fpos_t pos1;
fpos_t pos2;
fpos_t pos3;
fpos_t pos4;
fpos_t pos5;
EXPECT_EQ(0, fgetpos(fp, &pos1));
ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fgetwc(fp)));
EXPECT_EQ(0, fgetpos(fp, &pos2));
ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
EXPECT_EQ(0, fgetpos(fp, &pos3));
ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fgetwc(fp)));
EXPECT_EQ(0, fgetpos(fp, &pos4));
ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fgetwc(fp)));
EXPECT_EQ(0, fgetpos(fp, &pos5));
#ifdef __BIONIC__
// Bionic's fpos_t is just an alias for off_t. This is inherited from OpenBSD
// upstream. Glibc differs by storing the mbstate_t inside its fpos_t. In
// Bionic (and upstream OpenBSD) the mbstate_t is stored inside the FILE
// structure.
ASSERT_EQ(0, static_cast<off_t>(pos1));
ASSERT_EQ(1, static_cast<off_t>(pos2));
ASSERT_EQ(3, static_cast<off_t>(pos3));
ASSERT_EQ(6, static_cast<off_t>(pos4));
ASSERT_EQ(10, static_cast<off_t>(pos5));
#endif
// Exercise back and forth movements of the position.
ASSERT_EQ(0, fsetpos(fp, &pos2));
ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
ASSERT_EQ(0, fsetpos(fp, &pos1));
ASSERT_EQ(mb_one_bytes, static_cast<wchar_t>(fgetwc(fp)));
ASSERT_EQ(0, fsetpos(fp, &pos4));
ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fgetwc(fp)));
ASSERT_EQ(0, fsetpos(fp, &pos3));
ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fgetwc(fp)));
ASSERT_EQ(0, fsetpos(fp, &pos5));
ASSERT_EQ(WEOF, fgetwc(fp));
fclose(fp);
}
// Exercise the interaction between fpos and seek.
TEST(stdio, fpos_t_and_seek) {
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
// For glibc we need to close and re-open the file in order for fseek to work
// after using setlocale(LC_CTYPE, "C.UTF-8") and fputwc.
// TODO: find out if this is expected or a bug in glibc.
TemporaryFile tf;
FILE* fp = fdopen(tf.fd, "w+");
ASSERT_TRUE(fp != NULL);
wchar_t mb_two_bytes = 0x00a2;
wchar_t mb_three_bytes = 0x20ac;
wchar_t mb_four_bytes = 0x24b62;
// Write to file.
ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fputwc(mb_two_bytes, fp)));
ASSERT_EQ(mb_three_bytes, static_cast<wchar_t>(fputwc(mb_three_bytes, fp)));
ASSERT_EQ(mb_four_bytes, static_cast<wchar_t>(fputwc(mb_four_bytes, fp)));
fflush(fp);
fclose(fp);
fp = fopen(tf.filename, "r");
ASSERT_TRUE(fp != NULL);
// Store a valid position.
fpos_t mb_two_bytes_pos;
ASSERT_EQ(0, fgetpos(fp, &mb_two_bytes_pos));
// Move inside mb_four_bytes with fseek.
long offset_inside_mb = 6;
ASSERT_EQ(0, fseek(fp, offset_inside_mb, SEEK_SET));
// Store the "inside multi byte" position.
fpos_t pos_inside_mb;
ASSERT_EQ(0, fgetpos(fp, &pos_inside_mb));
#ifdef __BIONIC__
ASSERT_EQ(offset_inside_mb, static_cast<off_t>(pos_inside_mb));
#endif
// Reading from within a byte should produce an error.
ASSERT_EQ(WEOF, fgetwc(fp));
ASSERT_EQ(EILSEQ, errno);
// Reverting to a valid position should work.
ASSERT_EQ(0, fsetpos(fp, &mb_two_bytes_pos));
ASSERT_EQ(mb_two_bytes, static_cast<wchar_t>(fgetwc(fp)));
// Moving withing a multi byte with fsetpos should work but reading should
// produce an error.
ASSERT_EQ(0, fsetpos(fp, &pos_inside_mb));
ASSERT_EQ(WEOF, fgetwc(fp));
ASSERT_EQ(EILSEQ, errno);
fclose(fp);
}