Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Elliott Hughes | 4f71319 | 2015-12-04 22:00:26 -0800 | [diff] [blame] | 17 | #include "android-base/utf8.h" |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 18 | |
| 19 | #include <gtest/gtest.h> |
| 20 | |
Renaud Paquay | e3e7813 | 2017-05-22 15:24:35 -0700 | [diff] [blame] | 21 | #include <fcntl.h> |
| 22 | #include <stdlib.h> |
| 23 | |
Mark Salyzyn | 9f1cf25 | 2018-11-12 12:45:59 -0800 | [diff] [blame] | 24 | #include "android-base/file.h" |
Elliott Hughes | 4f71319 | 2015-12-04 22:00:26 -0800 | [diff] [blame] | 25 | #include "android-base/macros.h" |
Renaud Paquay | e3e7813 | 2017-05-22 15:24:35 -0700 | [diff] [blame] | 26 | #include "android-base/unique_fd.h" |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 27 | |
| 28 | namespace android { |
| 29 | namespace base { |
| 30 | |
| 31 | TEST(UTFStringConversionsTest, ConvertInvalidUTF8) { |
| 32 | std::wstring wide; |
| 33 | |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 34 | errno = 0; |
| 35 | |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 36 | // Standalone \xa2 is an invalid UTF-8 sequence, so this should return an |
| 37 | // error. Concatenate two C/C++ literal string constants to prevent the |
| 38 | // compiler from giving an error about "\xa2af" containing a "hex escape |
| 39 | // sequence out of range". |
| 40 | EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide)); |
| 41 | |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 42 | EXPECT_EQ(EILSEQ, errno); |
| 43 | |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 44 | // Even if an invalid character is encountered, UTF8ToWide() should still do |
| 45 | // its best to convert the rest of the string. sysdeps_win32.cpp: |
| 46 | // _console_write_utf8() depends on this behavior. |
| 47 | // |
| 48 | // Thus, we verify that the valid characters are converted, but we ignore the |
| 49 | // specific replacement character that UTF8ToWide() may replace the invalid |
| 50 | // UTF-8 characters with because we want to allow that to change if the |
| 51 | // implementation changes. |
Dan Albert | bac7bb5 | 2016-01-15 12:14:24 -0800 | [diff] [blame] | 52 | EXPECT_EQ(0U, wide.find(L"before")); |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 53 | const wchar_t after_wide[] = L"after"; |
| 54 | EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide)); |
| 55 | } |
| 56 | |
| 57 | // Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc |
| 58 | |
| 59 | // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 60 | // Use of this source code is governed by a BSD-style license that can be |
| 61 | // found in the LICENSE file. |
| 62 | |
| 63 | // The tests below from utf_string_conversions_unittest.cc check for this |
| 64 | // preprocessor symbol, so define it, as it is appropriate for Windows. |
| 65 | #define WCHAR_T_IS_UTF16 |
| 66 | static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes"); |
| 67 | |
| 68 | // The tests below from utf_string_conversions_unittest.cc call versions of |
| 69 | // UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are |
| 70 | // stub implementations with that signature. These are just for testing and |
| 71 | // should not be moved to base because they assert/expect no errors which is |
| 72 | // probably not a good idea (or at least it is something that should be left |
| 73 | // up to the caller, not a base library). |
| 74 | |
| 75 | static std::wstring UTF8ToWide(const std::string& utf8) { |
| 76 | std::wstring utf16; |
| 77 | EXPECT_TRUE(UTF8ToWide(utf8, &utf16)); |
| 78 | return utf16; |
| 79 | } |
| 80 | |
| 81 | static std::string WideToUTF8(const std::wstring& utf16) { |
| 82 | std::string utf8; |
| 83 | EXPECT_TRUE(WideToUTF8(utf16, &utf8)); |
| 84 | return utf8; |
| 85 | } |
| 86 | |
| 87 | namespace { |
| 88 | |
| 89 | const wchar_t* const kConvertRoundtripCases[] = { |
| 90 | L"Google Video", |
| 91 | // "网页 图片 资讯更多 »" |
| 92 | L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb", |
| 93 | // "Παγκόσμιος Ιστός" |
| 94 | L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9" |
| 95 | L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2", |
| 96 | // "Поиск страниц на русском" |
| 97 | L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442" |
| 98 | L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430" |
| 99 | L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c", |
| 100 | // "전체서비스" |
| 101 | L"\xc804\xccb4\xc11c\xbe44\xc2a4", |
| 102 | |
| 103 | // Test characters that take more than 16 bits. This will depend on whether |
| 104 | // wchar_t is 16 or 32 bits. |
| 105 | #if defined(WCHAR_T_IS_UTF16) |
| 106 | L"\xd800\xdf00", |
| 107 | // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) |
| 108 | L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44", |
| 109 | #elif defined(WCHAR_T_IS_UTF32) |
| 110 | L"\x10300", |
| 111 | // ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E) |
| 112 | L"\x11d40\x11d41\x11d42\x11d43\x11d44", |
| 113 | #endif |
| 114 | }; |
| 115 | |
| 116 | } // namespace |
| 117 | |
| 118 | TEST(UTFStringConversionsTest, ConvertUTF8AndWide) { |
| 119 | // we round-trip all the wide strings through UTF-8 to make sure everything |
| 120 | // agrees on the conversion. This uses the stream operators to test them |
| 121 | // simultaneously. |
| 122 | for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) { |
| 123 | std::ostringstream utf8; |
| 124 | utf8 << WideToUTF8(kConvertRoundtripCases[i]); |
| 125 | std::wostringstream wide; |
| 126 | wide << UTF8ToWide(utf8.str()); |
| 127 | |
| 128 | EXPECT_EQ(kConvertRoundtripCases[i], wide.str()); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) { |
| 133 | // An empty std::wstring should be converted to an empty std::string, |
| 134 | // and vice versa. |
| 135 | std::wstring wempty; |
| 136 | std::string empty; |
| 137 | EXPECT_EQ(empty, WideToUTF8(wempty)); |
| 138 | EXPECT_EQ(wempty, UTF8ToWide(empty)); |
| 139 | } |
| 140 | |
| 141 | TEST(UTFStringConversionsTest, ConvertUTF8ToWide) { |
| 142 | struct UTF8ToWideCase { |
| 143 | const char* utf8; |
| 144 | const wchar_t* wide; |
| 145 | bool success; |
| 146 | } convert_cases[] = { |
| 147 | // Regular UTF-8 input. |
| 148 | {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true}, |
| 149 | // Non-character is passed through. |
| 150 | {"\xef\xbf\xbfHello", L"\xffffHello", true}, |
| 151 | // Truncated UTF-8 sequence. |
| 152 | {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, |
| 153 | // Truncated off the end. |
| 154 | {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false}, |
| 155 | // Non-shortest-form UTF-8. |
| 156 | {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false}, |
| 157 | // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal. |
| 158 | // Note that for whatever reason, this test fails on Windows XP. |
| 159 | {"\xed\xb0\x80", L"\xfffd", false}, |
| 160 | // Non-BMP characters. The second is a non-character regarded as valid. |
| 161 | // The result will either be in UTF-16 or UTF-32. |
| 162 | #if defined(WCHAR_T_IS_UTF16) |
| 163 | {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true}, |
| 164 | {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true}, |
| 165 | #elif defined(WCHAR_T_IS_UTF32) |
| 166 | {"A\xF0\x90\x8C\x80z", L"A\x10300z", true}, |
| 167 | {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true}, |
| 168 | #endif |
| 169 | }; |
| 170 | |
| 171 | for (size_t i = 0; i < arraysize(convert_cases); i++) { |
| 172 | std::wstring converted; |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 173 | errno = 0; |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 174 | const bool success = UTF8ToWide(convert_cases[i].utf8, |
| 175 | strlen(convert_cases[i].utf8), |
| 176 | &converted); |
| 177 | EXPECT_EQ(convert_cases[i].success, success); |
| 178 | // The original test always compared expected and converted, but don't do |
| 179 | // that because our implementation of UTF8ToWide() does not guarantee to |
| 180 | // produce the same output in error situations. |
| 181 | if (success) { |
| 182 | std::wstring expected(convert_cases[i].wide); |
| 183 | EXPECT_EQ(expected, converted); |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 184 | } else { |
| 185 | EXPECT_EQ(EILSEQ, errno); |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 186 | } |
| 187 | } |
| 188 | |
| 189 | // Manually test an embedded NULL. |
| 190 | std::wstring converted; |
| 191 | EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted)); |
| 192 | ASSERT_EQ(3U, converted.length()); |
| 193 | EXPECT_EQ(static_cast<wchar_t>(0), converted[0]); |
| 194 | EXPECT_EQ('Z', converted[1]); |
| 195 | EXPECT_EQ('\t', converted[2]); |
| 196 | |
| 197 | // Make sure that conversion replaces, not appends. |
| 198 | EXPECT_TRUE(UTF8ToWide("B", 1, &converted)); |
| 199 | ASSERT_EQ(1U, converted.length()); |
| 200 | EXPECT_EQ('B', converted[0]); |
| 201 | } |
| 202 | |
| 203 | #if defined(WCHAR_T_IS_UTF16) |
| 204 | // This test is only valid when wchar_t == UTF-16. |
| 205 | TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) { |
| 206 | struct WideToUTF8Case { |
| 207 | const wchar_t* utf16; |
| 208 | const char* utf8; |
| 209 | bool success; |
| 210 | } convert_cases[] = { |
| 211 | // Regular UTF-16 input. |
| 212 | {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, |
| 213 | // Test a non-BMP character. |
| 214 | {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true}, |
| 215 | // Non-characters are passed through. |
| 216 | {L"\xffffHello", "\xEF\xBF\xBFHello", true}, |
| 217 | {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true}, |
| 218 | // The first character is a truncated UTF-16 character. |
| 219 | // Note that for whatever reason, this test fails on Windows XP. |
| 220 | {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", |
| 221 | #if (WINVER >= 0x0600) |
| 222 | // Only Vista and later has a new API/flag that correctly returns false. |
| 223 | false |
| 224 | #else |
| 225 | true |
| 226 | #endif |
| 227 | }, |
| 228 | // Truncated at the end. |
| 229 | // Note that for whatever reason, this test fails on Windows XP. |
| 230 | {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", |
| 231 | #if (WINVER >= 0x0600) |
| 232 | // Only Vista and later has a new API/flag that correctly returns false. |
| 233 | false |
| 234 | #else |
| 235 | true |
| 236 | #endif |
| 237 | }, |
| 238 | }; |
| 239 | |
| 240 | for (size_t i = 0; i < arraysize(convert_cases); i++) { |
| 241 | std::string converted; |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 242 | errno = 0; |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 243 | const bool success = WideToUTF8(convert_cases[i].utf16, |
| 244 | wcslen(convert_cases[i].utf16), |
| 245 | &converted); |
| 246 | EXPECT_EQ(convert_cases[i].success, success); |
| 247 | // The original test always compared expected and converted, but don't do |
| 248 | // that because our implementation of WideToUTF8() does not guarantee to |
| 249 | // produce the same output in error situations. |
| 250 | if (success) { |
| 251 | std::string expected(convert_cases[i].utf8); |
| 252 | EXPECT_EQ(expected, converted); |
Spencer Low | d21dc82 | 2015-11-12 15:20:15 -0800 | [diff] [blame] | 253 | } else { |
| 254 | EXPECT_EQ(EILSEQ, errno); |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 255 | } |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | #elif defined(WCHAR_T_IS_UTF32) |
| 260 | // This test is only valid when wchar_t == UTF-32. |
| 261 | TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) { |
| 262 | struct WideToUTF8Case { |
| 263 | const wchar_t* utf32; |
| 264 | const char* utf8; |
| 265 | bool success; |
| 266 | } convert_cases[] = { |
| 267 | // Regular 16-bit input. |
| 268 | {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true}, |
| 269 | // Test a non-BMP character. |
| 270 | {L"A\x10300z", "A\xF0\x90\x8C\x80z", true}, |
| 271 | // Non-characters are passed through. |
| 272 | {L"\xffffHello", "\xEF\xBF\xBFHello", true}, |
| 273 | {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true}, |
| 274 | // Invalid Unicode code points. |
| 275 | {L"\xfffffffHello", "\xEF\xBF\xBDHello", false}, |
| 276 | // The first character is a truncated UTF-16 character. |
| 277 | {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false}, |
| 278 | {L"\xdc01Hello", "\xef\xbf\xbdHello", false}, |
| 279 | }; |
| 280 | |
| 281 | for (size_t i = 0; i < arraysize(convert_cases); i++) { |
| 282 | std::string converted; |
| 283 | EXPECT_EQ(convert_cases[i].success, |
| 284 | WideToUTF8(convert_cases[i].utf32, |
| 285 | wcslen(convert_cases[i].utf32), |
| 286 | &converted)); |
| 287 | std::string expected(convert_cases[i].utf8); |
| 288 | EXPECT_EQ(expected, converted); |
| 289 | } |
| 290 | } |
| 291 | #endif // defined(WCHAR_T_IS_UTF32) |
| 292 | |
| 293 | // The test below uses these types and functions, so just do enough to get the |
| 294 | // test running. |
| 295 | typedef wchar_t char16; |
| 296 | typedef std::wstring string16; |
| 297 | |
| 298 | template<typename T> |
| 299 | static void* WriteInto(T* t, size_t size) { |
| 300 | // std::(w)string::resize() already includes space for a NULL terminator. |
| 301 | t->resize(size - 1); |
| 302 | return &(*t)[0]; |
| 303 | } |
| 304 | |
| 305 | // A stub implementation that calls a helper from above, just to get the test |
| 306 | // below working. This is just for testing and should not be moved to base |
| 307 | // because this ignores errors which is probably not a good idea, plus it takes |
| 308 | // a string16 type which we don't really have. |
| 309 | static std::string UTF16ToUTF8(const string16& utf16) { |
| 310 | return WideToUTF8(utf16); |
| 311 | } |
| 312 | |
| 313 | TEST(UTFStringConversionsTest, ConvertMultiString) { |
| 314 | static char16 multi16[] = { |
| 315 | 'f', 'o', 'o', '\0', |
| 316 | 'b', 'a', 'r', '\0', |
| 317 | 'b', 'a', 'z', '\0', |
| 318 | '\0' |
| 319 | }; |
| 320 | static char multi[] = { |
| 321 | 'f', 'o', 'o', '\0', |
| 322 | 'b', 'a', 'r', '\0', |
| 323 | 'b', 'a', 'z', '\0', |
| 324 | '\0' |
| 325 | }; |
| 326 | string16 multistring16; |
| 327 | memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16, |
| 328 | sizeof(multi16)); |
| 329 | EXPECT_EQ(arraysize(multi16) - 1, multistring16.length()); |
| 330 | std::string expected; |
| 331 | memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi)); |
| 332 | EXPECT_EQ(arraysize(multi) - 1, expected.length()); |
| 333 | const std::string& converted = UTF16ToUTF8(multistring16); |
| 334 | EXPECT_EQ(arraysize(multi) - 1, converted.length()); |
| 335 | EXPECT_EQ(expected, converted); |
| 336 | } |
| 337 | |
| 338 | // The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8() |
| 339 | // and SysUTF8ToWide(), so these are stub implementations that call the helpers |
| 340 | // above. These are just for testing and should not be moved to base because |
| 341 | // they ignore errors which is probably not a good idea. |
| 342 | |
| 343 | static std::string SysWideToUTF8(const std::wstring& utf16) { |
| 344 | return WideToUTF8(utf16); |
| 345 | } |
| 346 | |
| 347 | static std::wstring SysUTF8ToWide(const std::string& utf8) { |
| 348 | return UTF8ToWide(utf8); |
| 349 | } |
| 350 | |
| 351 | // Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc |
| 352 | |
| 353 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 354 | // Use of this source code is governed by a BSD-style license that can be |
| 355 | // found in the LICENSE file. |
| 356 | |
| 357 | #ifdef WCHAR_T_IS_UTF32 |
| 358 | static const std::wstring kSysWideOldItalicLetterA = L"\x10300"; |
| 359 | #else |
| 360 | static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00"; |
| 361 | #endif |
| 362 | |
| 363 | TEST(SysStrings, SysWideToUTF8) { |
| 364 | EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world")); |
| 365 | EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d")); |
| 366 | |
| 367 | // >16 bits |
| 368 | EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA)); |
| 369 | |
| 370 | // Error case. When Windows finds a UTF-16 character going off the end of |
| 371 | // a string, it just converts that literal value to UTF-8, even though this |
| 372 | // is invalid. |
| 373 | // |
| 374 | // This is what XP does, but Vista has different behavior, so we don't bother |
| 375 | // verifying it: |
| 376 | // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw", |
| 377 | // SysWideToUTF8(L"\x4f60\xd800zyxw")); |
| 378 | |
| 379 | // Test embedded NULLs. |
| 380 | std::wstring wide_null(L"a"); |
| 381 | wide_null.push_back(0); |
| 382 | wide_null.push_back('b'); |
| 383 | |
| 384 | std::string expected_null("a"); |
| 385 | expected_null.push_back(0); |
| 386 | expected_null.push_back('b'); |
| 387 | |
| 388 | EXPECT_EQ(expected_null, SysWideToUTF8(wide_null)); |
| 389 | } |
| 390 | |
| 391 | TEST(SysStrings, SysUTF8ToWide) { |
| 392 | EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world")); |
| 393 | EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd")); |
| 394 | // >16 bits |
| 395 | EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80")); |
| 396 | |
| 397 | // Error case. When Windows finds an invalid UTF-8 character, it just skips |
| 398 | // it. This seems weird because it's inconsistent with the reverse conversion. |
| 399 | // |
| 400 | // This is what XP does, but Vista has different behavior, so we don't bother |
| 401 | // verifying it: |
| 402 | // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw")); |
| 403 | |
| 404 | // Test embedded NULLs. |
| 405 | std::string utf8_null("a"); |
| 406 | utf8_null.push_back(0); |
| 407 | utf8_null.push_back('b'); |
| 408 | |
| 409 | std::wstring expected_null(L"a"); |
| 410 | expected_null.push_back(0); |
| 411 | expected_null.push_back('b'); |
| 412 | |
| 413 | EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null)); |
| 414 | } |
| 415 | |
Renaud Paquay | e3e7813 | 2017-05-22 15:24:35 -0700 | [diff] [blame] | 416 | TEST(UTF8PathToWindowsLongPathTest, DontAddPrefixIfShorterThanMaxPath) { |
| 417 | std::string utf8 = "c:\\mypath\\myfile.txt"; |
| 418 | |
| 419 | std::wstring wide; |
| 420 | EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); |
| 421 | |
| 422 | EXPECT_EQ(std::string::npos, wide.find(LR"(\\?\)")); |
| 423 | } |
| 424 | |
| 425 | TEST(UTF8PathToWindowsLongPathTest, AddPrefixIfLongerThanMaxPath) { |
| 426 | std::string utf8 = "c:\\mypath"; |
| 427 | while (utf8.length() < 300 /* MAX_PATH is 260 */) { |
| 428 | utf8 += "\\mypathsegment"; |
| 429 | } |
| 430 | |
| 431 | std::wstring wide; |
| 432 | EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); |
| 433 | |
| 434 | EXPECT_EQ(0U, wide.find(LR"(\\?\)")); |
| 435 | EXPECT_EQ(std::string::npos, wide.find(L"/")); |
| 436 | } |
| 437 | |
| 438 | TEST(UTF8PathToWindowsLongPathTest, AddPrefixAndFixSeparatorsIfLongerThanMaxPath) { |
| 439 | std::string utf8 = "c:/mypath"; |
| 440 | while (utf8.length() < 300 /* MAX_PATH is 260 */) { |
| 441 | utf8 += "/mypathsegment"; |
| 442 | } |
| 443 | |
| 444 | std::wstring wide; |
| 445 | EXPECT_TRUE(UTF8PathToWindowsLongPath(utf8.c_str(), &wide)); |
| 446 | |
| 447 | EXPECT_EQ(0U, wide.find(LR"(\\?\)")); |
| 448 | EXPECT_EQ(std::string::npos, wide.find(L"/")); |
| 449 | } |
| 450 | |
| 451 | namespace utf8 { |
| 452 | |
| 453 | TEST(Utf8FilesTest, CanCreateOpenAndDeleteFileWithLongPath) { |
| 454 | TemporaryDir td; |
| 455 | |
| 456 | // Create long directory path |
| 457 | std::string utf8 = td.path; |
| 458 | while (utf8.length() < 300 /* MAX_PATH is 260 */) { |
| 459 | utf8 += "\\mypathsegment"; |
| 460 | EXPECT_EQ(0, mkdir(utf8.c_str(), 0)); |
| 461 | } |
| 462 | |
| 463 | // Create file |
| 464 | utf8 += "\\test-file.bin"; |
| 465 | int flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; |
| 466 | int mode = 0666; |
| 467 | android::base::unique_fd fd(open(utf8.c_str(), flags, mode)); |
| 468 | EXPECT_NE(-1, fd.get()); |
| 469 | |
| 470 | // Close file |
| 471 | fd.reset(); |
| 472 | EXPECT_EQ(-1, fd.get()); |
| 473 | |
| 474 | // Open file with fopen |
| 475 | FILE* file = fopen(utf8.c_str(), "rb"); |
| 476 | EXPECT_NE(nullptr, file); |
| 477 | |
| 478 | if (file) { |
| 479 | fclose(file); |
| 480 | } |
| 481 | |
| 482 | // Delete file |
| 483 | EXPECT_EQ(0, unlink(utf8.c_str())); |
| 484 | } |
| 485 | |
| 486 | } // namespace utf8 |
Elliott Hughes | c1fd492 | 2015-11-11 18:02:29 +0000 | [diff] [blame] | 487 | } // namespace base |
| 488 | } // namespace android |