| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 #include "minidump/minidump_string_writer.h" |
| 16 |
| 17 #include <windows.h> |
| 18 #include <dbghelp.h> |
| 19 #include <sys/types.h> |
| 20 |
| 21 #include <string> |
| 22 |
| 23 #include "base/basictypes.h" |
| 24 #include "base/compiler_specific.h" |
| 25 #include "base/format_macros.h" |
| 26 #include "base/strings/string16.h" |
| 27 #include "base/strings/stringprintf.h" |
| 28 #include "base/strings/utf_string_conversions.h" |
| 29 #include "gtest/gtest.h" |
| 30 #include "minidump/test/minidump_rva_list_test_util.h" |
| 31 #include "minidump/test/minidump_string_writer_test_util.h" |
| 32 #include "minidump/test/minidump_writable_test_util.h" |
| 33 #include "util/file/string_file.h" |
| 34 |
| 35 namespace crashpad { |
| 36 namespace test { |
| 37 namespace { |
| 38 |
| 39 TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { |
| 40 StringFile string_file; |
| 41 |
| 42 { |
| 43 SCOPED_TRACE("unset"); |
| 44 string_file.Reset(); |
| 45 crashpad::internal::MinidumpUTF16StringWriter string_writer; |
| 46 EXPECT_TRUE(string_writer.WriteEverything(&string_file)); |
| 47 ASSERT_EQ(6u, string_file.string().size()); |
| 48 |
| 49 const MINIDUMP_STRING* minidump_string = |
| 50 MinidumpStringAtRVA(string_file.string(), 0); |
| 51 EXPECT_TRUE(minidump_string); |
| 52 EXPECT_EQ(base::string16(), |
| 53 MinidumpStringAtRVAAsString(string_file.string(), 0)); |
| 54 } |
| 55 |
| 56 const struct { |
| 57 size_t input_length; |
| 58 const char* input_string; |
| 59 size_t output_length; |
| 60 base::char16 output_string[10]; |
| 61 } kTestData[] = { |
| 62 {0, "", 0, {}}, |
| 63 {1, "a", 1, {'a'}}, |
| 64 {2, "\0b", 2, {0, 'b'}}, |
| 65 {3, "cde", 3, {'c', 'd', 'e'}}, |
| 66 {9, "Hi world!", 9, {'H', 'i', ' ', 'w', 'o', 'r', 'l', 'd', '!'}}, |
| 67 {7, "ret\nurn", 7, {'r', 'e', 't', '\n', 'u', 'r', 'n'}}, |
| 68 {2, "\303\251", 1, {0x00e9}}, // é |
| 69 |
| 70 // oóöőo |
| 71 {8, "o\303\263\303\266\305\221o", 5, {'o', 0x00f3, 0x00f6, 0x151, 'o'}}, |
| 72 {4, "\360\220\204\202", 2, {0xd800, 0xdd02}}, // 𐄂 (non-BMP) |
| 73 }; |
| 74 |
| 75 for (size_t index = 0; index < arraysize(kTestData); ++index) { |
| 76 SCOPED_TRACE(base::StringPrintf( |
| 77 "index %" PRIuS ", input %s", index, kTestData[index].input_string)); |
| 78 |
| 79 // Make sure that the expected output string with its NUL terminator fits in |
| 80 // the space provided. |
| 81 ASSERT_EQ( |
| 82 0, |
| 83 kTestData[index] |
| 84 .output_string[arraysize(kTestData[index].output_string) - 1]); |
| 85 |
| 86 string_file.Reset(); |
| 87 crashpad::internal::MinidumpUTF16StringWriter string_writer; |
| 88 string_writer.SetUTF8(std::string(kTestData[index].input_string, |
| 89 kTestData[index].input_length)); |
| 90 EXPECT_TRUE(string_writer.WriteEverything(&string_file)); |
| 91 |
| 92 const size_t expected_utf16_units_with_nul = |
| 93 kTestData[index].output_length + 1; |
| 94 MINIDUMP_STRING tmp = {0}; |
| 95 ALLOW_UNUSED_LOCAL(tmp); |
| 96 const size_t expected_utf16_bytes = |
| 97 expected_utf16_units_with_nul * sizeof(tmp.Buffer[0]); |
| 98 ASSERT_EQ(sizeof(MINIDUMP_STRING) + expected_utf16_bytes, |
| 99 string_file.string().size()); |
| 100 |
| 101 const MINIDUMP_STRING* minidump_string = |
| 102 MinidumpStringAtRVA(string_file.string(), 0); |
| 103 EXPECT_TRUE(minidump_string); |
| 104 base::string16 expect_string = base::string16( |
| 105 kTestData[index].output_string, kTestData[index].output_length); |
| 106 EXPECT_EQ(expect_string, |
| 107 MinidumpStringAtRVAAsString(string_file.string(), 0)); |
| 108 } |
| 109 } |
| 110 |
| 111 TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { |
| 112 StringFile string_file; |
| 113 |
| 114 const char* kTestData[] = { |
| 115 "\200", // continuation byte |
| 116 "\300", // start byte followed by EOF |
| 117 "\310\177", // start byte without continuation |
| 118 "\340\200", // EOF in middle of 3-byte sequence |
| 119 "\340\200\115", // invalid 3-byte sequence |
| 120 "\303\0\251", // NUL in middle of valid sequence |
| 121 }; |
| 122 |
| 123 for (size_t index = 0; index < arraysize(kTestData); ++index) { |
| 124 SCOPED_TRACE(base::StringPrintf( |
| 125 "index %" PRIuS ", input %s", index, kTestData[index])); |
| 126 string_file.Reset(); |
| 127 crashpad::internal::MinidumpUTF16StringWriter string_writer; |
| 128 string_writer.SetUTF8(kTestData[index]); |
| 129 EXPECT_TRUE(string_writer.WriteEverything(&string_file)); |
| 130 |
| 131 // The requirements for conversion of invalid UTF-8 input are lax. Make sure |
| 132 // that at least enough data was written for a string that has one unit and |
| 133 // a NUL terminator, make sure that the length field matches the length of |
| 134 // data written, and make sure that at least one U+FFFD replacement |
| 135 // character was written. |
| 136 const MINIDUMP_STRING* minidump_string = |
| 137 MinidumpStringAtRVA(string_file.string(), 0); |
| 138 EXPECT_TRUE(minidump_string); |
| 139 MINIDUMP_STRING tmp = {0}; |
| 140 ALLOW_UNUSED_LOCAL(tmp); |
| 141 EXPECT_EQ(string_file.string().size() - sizeof(MINIDUMP_STRING) - |
| 142 sizeof(tmp.Buffer[0]), |
| 143 minidump_string->Length); |
| 144 base::string16 output_string = |
| 145 MinidumpStringAtRVAAsString(string_file.string(), 0); |
| 146 EXPECT_FALSE(output_string.empty()); |
| 147 EXPECT_NE(base::string16::npos, output_string.find(0xfffd)); |
| 148 } |
| 149 } |
| 150 |
| 151 TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { |
| 152 StringFile string_file; |
| 153 |
| 154 { |
| 155 SCOPED_TRACE("unset"); |
| 156 string_file.Reset(); |
| 157 crashpad::internal::MinidumpUTF8StringWriter string_writer; |
| 158 EXPECT_TRUE(string_writer.WriteEverything(&string_file)); |
| 159 ASSERT_EQ(5u, string_file.string().size()); |
| 160 |
| 161 const MinidumpUTF8String* minidump_string = |
| 162 MinidumpUTF8StringAtRVA(string_file.string(), 0); |
| 163 EXPECT_TRUE(minidump_string); |
| 164 EXPECT_EQ(std::string(), |
| 165 MinidumpUTF8StringAtRVAAsString(string_file.string(), 0)); |
| 166 } |
| 167 |
| 168 const struct { |
| 169 size_t length; |
| 170 const char* string; |
| 171 } kTestData[] = { |
| 172 {0, ""}, |
| 173 {1, "a"}, |
| 174 {2, "\0b"}, |
| 175 {3, "cde"}, |
| 176 {9, "Hi world!"}, |
| 177 {7, "ret\nurn"}, |
| 178 {2, "\303\251"}, // é |
| 179 |
| 180 // oóöőo |
| 181 {8, "o\303\263\303\266\305\221o"}, |
| 182 {4, "\360\220\204\202"}, // 𐄂 (non-BMP) |
| 183 }; |
| 184 |
| 185 for (size_t index = 0; index < arraysize(kTestData); ++index) { |
| 186 SCOPED_TRACE(base::StringPrintf( |
| 187 "index %" PRIuS ", input %s", index, kTestData[index].string)); |
| 188 |
| 189 string_file.Reset(); |
| 190 crashpad::internal::MinidumpUTF8StringWriter string_writer; |
| 191 std::string test_string(kTestData[index].string, kTestData[index].length); |
| 192 string_writer.SetUTF8(test_string); |
| 193 EXPECT_EQ(test_string, string_writer.UTF8()); |
| 194 EXPECT_TRUE(string_writer.WriteEverything(&string_file)); |
| 195 |
| 196 const size_t expected_utf8_bytes_with_nul = kTestData[index].length + 1; |
| 197 ASSERT_EQ(sizeof(MinidumpUTF8String) + expected_utf8_bytes_with_nul, |
| 198 string_file.string().size()); |
| 199 |
| 200 const MinidumpUTF8String* minidump_string = |
| 201 MinidumpUTF8StringAtRVA(string_file.string(), 0); |
| 202 EXPECT_TRUE(minidump_string); |
| 203 EXPECT_EQ(test_string, |
| 204 MinidumpUTF8StringAtRVAAsString(string_file.string(), 0)); |
| 205 } |
| 206 } |
| 207 |
| 208 struct MinidumpUTF16StringListWriterTraits { |
| 209 using MinidumpStringListWriterType = MinidumpUTF16StringListWriter; |
| 210 static base::string16 ExpectationForUTF8(const std::string& utf8) { |
| 211 return base::UTF8ToUTF16(utf8); |
| 212 } |
| 213 static base::string16 ObservationAtRVA(const std::string& file_contents, |
| 214 RVA rva) { |
| 215 return MinidumpStringAtRVAAsString(file_contents, rva); |
| 216 } |
| 217 }; |
| 218 |
| 219 struct MinidumpUTF8StringListWriterTraits { |
| 220 using MinidumpStringListWriterType = MinidumpUTF8StringListWriter; |
| 221 static std::string ExpectationForUTF8(const std::string& utf8) { |
| 222 return utf8; |
| 223 } |
| 224 static std::string ObservationAtRVA(const std::string& file_contents, |
| 225 RVA rva) { |
| 226 return MinidumpUTF8StringAtRVAAsString(file_contents, rva); |
| 227 } |
| 228 }; |
| 229 |
| 230 template <typename Traits> |
| 231 void MinidumpStringListTest() { |
| 232 std::vector<std::string> strings; |
| 233 strings.push_back(std::string("One")); |
| 234 strings.push_back(std::string()); |
| 235 strings.push_back(std::string("3")); |
| 236 strings.push_back(std::string("\360\237\222\251")); |
| 237 |
| 238 typename Traits::MinidumpStringListWriterType string_list_writer; |
| 239 EXPECT_FALSE(string_list_writer.IsUseful()); |
| 240 string_list_writer.InitializeFromVector(strings); |
| 241 EXPECT_TRUE(string_list_writer.IsUseful()); |
| 242 |
| 243 StringFile string_file; |
| 244 |
| 245 ASSERT_TRUE(string_list_writer.WriteEverything(&string_file)); |
| 246 |
| 247 const MinidumpRVAList* list = |
| 248 MinidumpRVAListAtStart(string_file.string(), strings.size()); |
| 249 ASSERT_TRUE(list); |
| 250 |
| 251 for (size_t index = 0; index < strings.size(); ++index) { |
| 252 EXPECT_EQ(Traits::ExpectationForUTF8(strings[index]), |
| 253 Traits::ObservationAtRVA(string_file.string(), |
| 254 list->children[index])); |
| 255 } |
| 256 } |
| 257 |
| 258 TEST(MinidumpStringWriter, MinidumpUTF16StringList) { |
| 259 MinidumpStringListTest<MinidumpUTF16StringListWriterTraits>(); |
| 260 } |
| 261 |
| 262 TEST(MinidumpStringWriter, MinidumpUTF8StringList) { |
| 263 MinidumpStringListTest<MinidumpUTF8StringListWriterTraits>(); |
| 264 } |
| 265 |
| 266 } // namespace |
| 267 } // namespace test |
| 268 } // namespace crashpad |
| OLD | NEW |