From 03e4ebee8d1579fbbc6157c1e9be4537bcad0c62 Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Thu, 8 May 2014 14:42:06 +0100 Subject: [PATCH] Add fpos_t tests. Bug: 13077905 Change-Id: I86bb0ee95660f69f9971231c6f828a3a067d1ac8 --- tests/stdio_test.cpp | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 8f6ee2b0e..4725350fa 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -24,6 +24,9 @@ #include #include #include +#include + +#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(fputwc(mb_one_bytes, fp))); + ASSERT_EQ(mb_two_bytes, static_cast(fputwc(mb_two_bytes, fp))); + ASSERT_EQ(mb_three_bytes, static_cast(fputwc(mb_three_bytes, fp))); + ASSERT_EQ(mb_four_bytes, static_cast(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(fgetwc(fp))); + EXPECT_EQ(0, fgetpos(fp, &pos2)); + ASSERT_EQ(mb_two_bytes, static_cast(fgetwc(fp))); + EXPECT_EQ(0, fgetpos(fp, &pos3)); + ASSERT_EQ(mb_three_bytes, static_cast(fgetwc(fp))); + EXPECT_EQ(0, fgetpos(fp, &pos4)); + ASSERT_EQ(mb_four_bytes, static_cast(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(pos1)); + ASSERT_EQ(1, static_cast(pos2)); + ASSERT_EQ(3, static_cast(pos3)); + ASSERT_EQ(6, static_cast(pos4)); + ASSERT_EQ(10, static_cast(pos5)); +#endif + + // Exercise back and forth movements of the position. + ASSERT_EQ(0, fsetpos(fp, &pos2)); + ASSERT_EQ(mb_two_bytes, static_cast(fgetwc(fp))); + ASSERT_EQ(0, fsetpos(fp, &pos1)); + ASSERT_EQ(mb_one_bytes, static_cast(fgetwc(fp))); + ASSERT_EQ(0, fsetpos(fp, &pos4)); + ASSERT_EQ(mb_four_bytes, static_cast(fgetwc(fp))); + ASSERT_EQ(0, fsetpos(fp, &pos3)); + ASSERT_EQ(mb_three_bytes, static_cast(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(fputwc(mb_two_bytes, fp))); + ASSERT_EQ(mb_three_bytes, static_cast(fputwc(mb_three_bytes, fp))); + ASSERT_EQ(mb_four_bytes, static_cast(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(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(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); +}