Fix wchar tests for zero length conversions.

Same as the previous change for the uchar tests: the tests are wrong
to match bionic's wrong implementation. Fix the test to encode the bug
for now while I get the tests into good shape, then I'll be back to
fix the bugs and remove the test differences.

Bug: None
Test: this is a test
Change-Id: I1123660994f755f8bac1f2656f6890d5a43310b3
This commit is contained in:
Dan Albert 2023-08-03 19:34:42 +00:00
parent 686e67d077
commit 512469a858

View file

@ -38,6 +38,31 @@ static locale_t SAFE_LC_GLOBAL_LOCALE = duplocale(LC_GLOBAL_LOCALE);
static locale_t SAFE_LC_GLOBAL_LOCALE = LC_GLOBAL_LOCALE;
#endif
// C23 7.31.6.3.2 (mbrtowc) says:
//
// Returns:
//
// 0 if the next n or fewer bytes complete the multibyte character that
// corresponds to the null wide character (which is the value stored).
//
// (size_t)(-2) if the next n bytes contribute to an incomplete (but
// potentially valid) multibyte character, and all n bytes have been
// processed (no value is stored).
//
// Bionic historically interpreted the behavior when n is 0 to be the next 0
// bytes decoding to the null. That's a pretty bad interpretation, and both
// glibc and musl return -2 for that case.
//
// The tests currently checks the incorrect behavior for bionic because gtest
// doesn't support explicit xfail annotations. The behavior difference here
// should be fixed, but danalbert wants to add more tests before tackling the
// bugs.
#ifdef __ANDROID__
constexpr size_t kExpectedResultForZeroLength = 0U;
#else
constexpr size_t kExpectedResultForZeroLength = static_cast<size_t>(-2);
#endif
TEST(wchar, sizeof_wchar_t) {
EXPECT_EQ(4U, sizeof(wchar_t));
EXPECT_EQ(4U, sizeof(wint_t));
@ -45,7 +70,7 @@ TEST(wchar, sizeof_wchar_t) {
TEST(wchar, mbrlen) {
char bytes[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
EXPECT_EQ(0U, mbrlen(&bytes[0], 0, nullptr));
EXPECT_EQ(kExpectedResultForZeroLength, mbrlen(&bytes[0], 0, nullptr));
EXPECT_EQ(1U, mbrlen(&bytes[0], 1, nullptr));
EXPECT_EQ(1U, mbrlen(&bytes[4], 1, nullptr));
@ -264,63 +289,98 @@ TEST(wchar, wcsstr_80199) {
TEST(wchar, mbtowc) {
wchar_t out[8];
// bionic has the same misunderstanding of the result for a zero-length
// conversion for mbtowc as it does for all the other multibyte conversion
// functions but mbtowc returns different values than all the others:
//
// C23 7.24.7.2.4:
//
// If s is a null pointer, the mbtowc function returns a nonzero or zero
// value, if multibyte character encodings, respectively, do or do not have
// state-dependent encodings. If s is not a null pointer, the mbtowc function
// either returns 0 (if s points to the null character), or returns the number
// of bytes that are contained in the converted multibyte character (if the
// next n or fewer bytes form a valid multibyte character), or returns -1 (if
// they do not form a valid multibyte character).
#ifdef __BIONIC__
int expected_result_for_zero_length = 0;
#else
int expected_result_for_zero_length = -1;
#endif
out[0] = 'x';
ASSERT_EQ(0, mbtowc(out, "hello", 0));
ASSERT_EQ('x', out[0]);
EXPECT_EQ(expected_result_for_zero_length, mbtowc(out, "hello", 0));
EXPECT_EQ('x', out[0]);
ASSERT_EQ(0, mbtowc(out, "hello", 0));
ASSERT_EQ(0, mbtowc(out, "", 0));
ASSERT_EQ(1, mbtowc(out, "hello", 1));
ASSERT_EQ(L'h', out[0]);
EXPECT_EQ(expected_result_for_zero_length, mbtowc(out, "hello", 0));
EXPECT_EQ(0, mbtowc(out, "", 0));
EXPECT_EQ(1, mbtowc(out, "hello", 1));
EXPECT_EQ(L'h', out[0]);
ASSERT_EQ(0, mbtowc(nullptr, "hello", 0));
ASSERT_EQ(0, mbtowc(nullptr, "", 0));
ASSERT_EQ(1, mbtowc(nullptr, "hello", 1));
EXPECT_EQ(expected_result_for_zero_length, mbtowc(nullptr, "hello", 0));
EXPECT_EQ(0, mbtowc(nullptr, "", 0));
EXPECT_EQ(1, mbtowc(nullptr, "hello", 1));
ASSERT_EQ(0, mbtowc(nullptr, nullptr, 0));
EXPECT_EQ(0, mbtowc(nullptr, nullptr, 0));
}
TEST(wchar, mbrtowc) {
wchar_t out[8];
out[0] = 'x';
ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
ASSERT_EQ('x', out[0]);
EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "hello", 0, nullptr));
EXPECT_EQ('x', out[0]);
ASSERT_EQ(0U, mbrtowc(out, "hello", 0, nullptr));
ASSERT_EQ(0U, mbrtowc(out, "", 0, nullptr));
ASSERT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
ASSERT_EQ(L'h', out[0]);
EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "hello", 0, nullptr));
EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(out, "", 0, nullptr));
EXPECT_EQ(1U, mbrtowc(out, "hello", 1, nullptr));
EXPECT_EQ(L'h', out[0]);
ASSERT_EQ(0U, mbrtowc(nullptr, "hello", 0, nullptr));
ASSERT_EQ(0U, mbrtowc(nullptr, "", 0, nullptr));
ASSERT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(nullptr, "hello", 0, nullptr));
EXPECT_EQ(kExpectedResultForZeroLength, mbrtowc(nullptr, "", 0, nullptr));
EXPECT_EQ(1U, mbrtowc(nullptr, "hello", 1, nullptr));
ASSERT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
EXPECT_EQ(0U, mbrtowc(nullptr, nullptr, 0, nullptr));
ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
EXPECT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
uselocale(LC_GLOBAL_LOCALE);
// 1-byte UTF-8.
ASSERT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
ASSERT_EQ(L'a', out[0]);
EXPECT_EQ(1U, mbrtowc(out, "abcdef", 6, nullptr));
EXPECT_EQ(L'a', out[0]);
// 2-byte UTF-8.
ASSERT_EQ(2U, mbrtowc(out, "\xc2\xa2" "cdef", 6, nullptr));
ASSERT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
EXPECT_EQ(2U, mbrtowc(out,
"\xc2\xa2"
"cdef",
6, nullptr));
EXPECT_EQ(static_cast<wchar_t>(0x00a2), out[0]);
// 3-byte UTF-8.
ASSERT_EQ(3U, mbrtowc(out, "\xe2\x82\xac" "def", 6, nullptr));
ASSERT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
EXPECT_EQ(3U, mbrtowc(out,
"\xe2\x82\xac"
"def",
6, nullptr));
EXPECT_EQ(static_cast<wchar_t>(0x20ac), out[0]);
// 4-byte UTF-8.
ASSERT_EQ(4U, mbrtowc(out, "\xf0\xa4\xad\xa2" "ef", 6, nullptr));
ASSERT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
EXPECT_EQ(4U, mbrtowc(out,
"\xf0\xa4\xad\xa2"
"ef",
6, nullptr));
EXPECT_EQ(static_cast<wchar_t>(0x24b62), out[0]);
#if defined(__BIONIC__) // glibc allows this.
// Illegal 5-byte UTF-8.
ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf8\xa1\xa2\xa3\xa4" "f", 6, nullptr));
ASSERT_EQ(EILSEQ, errno);
EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
"\xf8\xa1\xa2\xa3\xa4"
"f",
6, nullptr));
EXPECT_EQ(EILSEQ, errno);
#endif
// Illegal over-long sequence.
ASSERT_EQ(static_cast<size_t>(-1), mbrtowc(out, "\xf0\x82\x82\xac" "ef", 6, nullptr));
ASSERT_EQ(EILSEQ, errno);
EXPECT_EQ(static_cast<size_t>(-1), mbrtowc(out,
"\xf0\x82\x82\xac"
"ef",
6, nullptr));
EXPECT_EQ(EILSEQ, errno);
}
TEST(wchar, mbrtowc_valid_non_characters) {