|
1 // Copyright (c) 2011 Google Inc. |
|
2 // All rights reserved. |
|
3 // |
|
4 // Redistribution and use in source and binary forms, with or without |
|
5 // modification, are permitted provided that the following conditions are |
|
6 // met: |
|
7 // |
|
8 // * Redistributions of source code must retain the above copyright |
|
9 // notice, this list of conditions and the following disclaimer. |
|
10 // * Redistributions in binary form must reproduce the above |
|
11 // copyright notice, this list of conditions and the following disclaimer |
|
12 // in the documentation and/or other materials provided with the |
|
13 // distribution. |
|
14 // * Neither the name of Google Inc. nor the names of its |
|
15 // contributors may be used to endorse or promote products derived from |
|
16 // this software without specific prior written permission. |
|
17 // |
|
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 |
|
30 // Original author: Ted Mielczarek <ted.mielczarek@gmail.com> |
|
31 |
|
32 // synth_elf_unittest.cc: |
|
33 // Unittests for google_breakpad::synth_elf::ELF |
|
34 |
|
35 #include <elf.h> |
|
36 |
|
37 #include "breakpad_googletest_includes.h" |
|
38 #include "common/linux/elfutils.h" |
|
39 #include "common/linux/synth_elf.h" |
|
40 #include "common/using_std_string.h" |
|
41 |
|
42 using google_breakpad::ElfClass32; |
|
43 using google_breakpad::ElfClass64; |
|
44 using google_breakpad::synth_elf::ELF; |
|
45 using google_breakpad::synth_elf::Notes; |
|
46 using google_breakpad::synth_elf::Section; |
|
47 using google_breakpad::synth_elf::StringTable; |
|
48 using google_breakpad::synth_elf::SymbolTable; |
|
49 using google_breakpad::test_assembler::Endianness; |
|
50 using google_breakpad::test_assembler::kBigEndian; |
|
51 using google_breakpad::test_assembler::kLittleEndian; |
|
52 using google_breakpad::test_assembler::Label; |
|
53 using ::testing::Test; |
|
54 using ::testing::Types; |
|
55 |
|
56 class StringTableTest : public Test { |
|
57 public: |
|
58 StringTableTest() : table(kLittleEndian) {} |
|
59 |
|
60 StringTable table; |
|
61 }; |
|
62 |
|
63 TEST_F(StringTableTest, Empty) { |
|
64 EXPECT_EQ(1U, table.Size()); |
|
65 string contents; |
|
66 ASSERT_TRUE(table.GetContents(&contents)); |
|
67 const char* kExpectedContents = "\0"; |
|
68 EXPECT_EQ(0, memcmp(kExpectedContents, |
|
69 contents.c_str(), |
|
70 contents.size())); |
|
71 ASSERT_TRUE(table.empty_string.IsKnownConstant()); |
|
72 EXPECT_EQ(0U, table.empty_string.Value()); |
|
73 } |
|
74 |
|
75 TEST_F(StringTableTest, Basic) { |
|
76 const string s1("table fills with strings"); |
|
77 const string s2("offsets preserved as labels"); |
|
78 const string s3("verified with tests"); |
|
79 const char* kExpectedContents = |
|
80 "\0table fills with strings\0" |
|
81 "offsets preserved as labels\0" |
|
82 "verified with tests\0"; |
|
83 Label l1(table.Add(s1)); |
|
84 Label l2(table.Add(s2)); |
|
85 Label l3(table.Add(s3)); |
|
86 string contents; |
|
87 ASSERT_TRUE(table.GetContents(&contents)); |
|
88 EXPECT_EQ(0, memcmp(kExpectedContents, |
|
89 contents.c_str(), |
|
90 contents.size())); |
|
91 // empty_string is at zero, other strings start at 1. |
|
92 ASSERT_TRUE(l1.IsKnownConstant()); |
|
93 EXPECT_EQ(1U, l1.Value()); |
|
94 // Each string has an extra byte for a trailing null. |
|
95 EXPECT_EQ(1 + s1.length() + 1, l2.Value()); |
|
96 EXPECT_EQ(1 + s1.length() + 1 + s2.length() + 1, l3.Value()); |
|
97 } |
|
98 |
|
99 TEST_F(StringTableTest, Duplicates) { |
|
100 const string s1("string 1"); |
|
101 const string s2("string 2"); |
|
102 const string s3(""); |
|
103 const char* kExpectedContents = "\0string 1\0string 2\0"; |
|
104 Label l1(table.Add(s1)); |
|
105 Label l2(table.Add(s2)); |
|
106 // Adding strings twice should return the same Label. |
|
107 Label l3(table.Add(s3)); |
|
108 Label l4(table.Add(s2)); |
|
109 string contents; |
|
110 ASSERT_TRUE(table.GetContents(&contents)); |
|
111 EXPECT_EQ(0, memcmp(kExpectedContents, |
|
112 contents.c_str(), |
|
113 contents.size())); |
|
114 EXPECT_EQ(0U, table.empty_string.Value()); |
|
115 EXPECT_EQ(table.empty_string.Value(), l3.Value()); |
|
116 EXPECT_EQ(l2.Value(), l4.Value()); |
|
117 } |
|
118 |
|
119 class SymbolTableTest : public Test {}; |
|
120 |
|
121 TEST_F(SymbolTableTest, Simple32) { |
|
122 StringTable table(kLittleEndian); |
|
123 SymbolTable syms(kLittleEndian, 4, table); |
|
124 |
|
125 const string kFuncName1 = "superfunc"; |
|
126 const uint32_t kFuncAddr1 = 0x10001000; |
|
127 const uint32_t kFuncSize1 = 0x10; |
|
128 const string kFuncName2 = "awesomefunc"; |
|
129 const uint32_t kFuncAddr2 = 0x20002000; |
|
130 const uint32_t kFuncSize2 = 0x2f; |
|
131 const string kFuncName3 = "megafunc"; |
|
132 const uint32_t kFuncAddr3 = 0x30003000; |
|
133 const uint32_t kFuncSize3 = 0x3c; |
|
134 |
|
135 syms.AddSymbol(kFuncName1, kFuncAddr1, kFuncSize1, |
|
136 ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), |
|
137 SHN_UNDEF + 1); |
|
138 syms.AddSymbol(kFuncName2, kFuncAddr2, kFuncSize2, |
|
139 ELF32_ST_INFO(STB_LOCAL, STT_FUNC), |
|
140 SHN_UNDEF + 2); |
|
141 syms.AddSymbol(kFuncName3, kFuncAddr3, kFuncSize3, |
|
142 ELF32_ST_INFO(STB_LOCAL, STT_FUNC), |
|
143 SHN_UNDEF + 3); |
|
144 |
|
145 const char kExpectedStringTable[] = "\0superfunc\0awesomefunc\0megafunc"; |
|
146 const size_t kExpectedStringTableSize = sizeof(kExpectedStringTable); |
|
147 EXPECT_EQ(kExpectedStringTableSize, table.Size()); |
|
148 string table_contents; |
|
149 table.GetContents(&table_contents); |
|
150 EXPECT_EQ(0, memcmp(kExpectedStringTable, |
|
151 table_contents.c_str(), |
|
152 table_contents.size())); |
|
153 |
|
154 const uint8_t kExpectedSymbolContents[] = { |
|
155 // Symbol 1 |
|
156 0x01, 0x00, 0x00, 0x00, // name |
|
157 0x00, 0x10, 0x00, 0x10, // value |
|
158 0x10, 0x00, 0x00, 0x00, // size |
|
159 ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), // info |
|
160 0x00, // other |
|
161 0x01, 0x00, // shndx |
|
162 // Symbol 2 |
|
163 0x0B, 0x00, 0x00, 0x00, // name |
|
164 0x00, 0x20, 0x00, 0x20, // value |
|
165 0x2f, 0x00, 0x00, 0x00, // size |
|
166 ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info |
|
167 0x00, // other |
|
168 0x02, 0x00, // shndx |
|
169 // Symbol 3 |
|
170 0x17, 0x00, 0x00, 0x00, // name |
|
171 0x00, 0x30, 0x00, 0x30, // value |
|
172 0x3c, 0x00, 0x00, 0x00, // size |
|
173 ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info |
|
174 0x00, // other |
|
175 0x03, 0x00, // shndx |
|
176 }; |
|
177 const size_t kExpectedSymbolSize = sizeof(kExpectedSymbolContents); |
|
178 EXPECT_EQ(kExpectedSymbolSize, syms.Size()); |
|
179 |
|
180 string symbol_contents; |
|
181 syms.GetContents(&symbol_contents); |
|
182 EXPECT_EQ(0, memcmp(kExpectedSymbolContents, |
|
183 symbol_contents.c_str(), |
|
184 symbol_contents.size())); |
|
185 } |
|
186 |
|
187 template<typename ElfClass> |
|
188 class BasicElf : public Test {}; |
|
189 |
|
190 // Doesn't seem worthwhile writing the tests to be endian-independent |
|
191 // when they're unlikely to ever be run on big-endian systems. |
|
192 #if defined(__i386__) || defined(__x86_64__) |
|
193 |
|
194 typedef Types<ElfClass32, ElfClass64> ElfClasses; |
|
195 |
|
196 TYPED_TEST_CASE(BasicElf, ElfClasses); |
|
197 |
|
198 TYPED_TEST(BasicElf, EmptyLE) { |
|
199 typedef typename TypeParam::Ehdr Ehdr; |
|
200 typedef typename TypeParam::Phdr Phdr; |
|
201 typedef typename TypeParam::Shdr Shdr; |
|
202 const size_t kStringTableSize = sizeof("\0.shstrtab"); |
|
203 const size_t kStringTableAlign = 4 - kStringTableSize % 4; |
|
204 const size_t kExpectedSize = sizeof(Ehdr) + |
|
205 // Two sections, SHT_NULL + the section header string table. |
|
206 2 * sizeof(Shdr) + |
|
207 kStringTableSize + kStringTableAlign; |
|
208 |
|
209 // It doesn't really matter that the machine type is right for the class. |
|
210 ELF elf(EM_386, TypeParam::kClass, kLittleEndian); |
|
211 elf.Finish(); |
|
212 EXPECT_EQ(kExpectedSize, elf.Size()); |
|
213 |
|
214 string contents; |
|
215 ASSERT_TRUE(elf.GetContents(&contents)); |
|
216 ASSERT_EQ(kExpectedSize, contents.size()); |
|
217 const Ehdr* header = |
|
218 reinterpret_cast<const Ehdr*>(contents.data()); |
|
219 const uint8_t kIdent[] = { |
|
220 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, |
|
221 TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, |
|
222 0, 0, 0, 0, 0, 0, 0, 0 |
|
223 }; |
|
224 EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); |
|
225 EXPECT_EQ(ET_EXEC, header->e_type); |
|
226 EXPECT_EQ(EM_386, header->e_machine); |
|
227 EXPECT_EQ(static_cast<unsigned int>(EV_CURRENT), header->e_version); |
|
228 EXPECT_EQ(0U, header->e_entry); |
|
229 EXPECT_EQ(0U, header->e_phoff); |
|
230 EXPECT_EQ(sizeof(Ehdr) + kStringTableSize + kStringTableAlign, |
|
231 header->e_shoff); |
|
232 EXPECT_EQ(0U, header->e_flags); |
|
233 EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); |
|
234 EXPECT_EQ(sizeof(Phdr), header->e_phentsize); |
|
235 EXPECT_EQ(0, header->e_phnum); |
|
236 EXPECT_EQ(sizeof(Shdr), header->e_shentsize); |
|
237 EXPECT_EQ(2, header->e_shnum); |
|
238 EXPECT_EQ(1, header->e_shstrndx); |
|
239 |
|
240 const Shdr* shdr = |
|
241 reinterpret_cast<const Shdr*>(contents.data() + header->e_shoff); |
|
242 EXPECT_EQ(0U, shdr[0].sh_name); |
|
243 EXPECT_EQ(static_cast<unsigned int>(SHT_NULL), shdr[0].sh_type); |
|
244 EXPECT_EQ(0U, shdr[0].sh_flags); |
|
245 EXPECT_EQ(0U, shdr[0].sh_addr); |
|
246 EXPECT_EQ(0U, shdr[0].sh_offset); |
|
247 EXPECT_EQ(0U, shdr[0].sh_size); |
|
248 EXPECT_EQ(0U, shdr[0].sh_link); |
|
249 EXPECT_EQ(0U, shdr[0].sh_info); |
|
250 EXPECT_EQ(0U, shdr[0].sh_addralign); |
|
251 EXPECT_EQ(0U, shdr[0].sh_entsize); |
|
252 |
|
253 EXPECT_EQ(1U, shdr[1].sh_name); |
|
254 EXPECT_EQ(static_cast<unsigned int>(SHT_STRTAB), shdr[1].sh_type); |
|
255 EXPECT_EQ(0U, shdr[1].sh_flags); |
|
256 EXPECT_EQ(0U, shdr[1].sh_addr); |
|
257 EXPECT_EQ(sizeof(Ehdr), shdr[1].sh_offset); |
|
258 EXPECT_EQ(kStringTableSize, shdr[1].sh_size); |
|
259 EXPECT_EQ(0U, shdr[1].sh_link); |
|
260 EXPECT_EQ(0U, shdr[1].sh_info); |
|
261 EXPECT_EQ(0U, shdr[1].sh_addralign); |
|
262 EXPECT_EQ(0U, shdr[1].sh_entsize); |
|
263 } |
|
264 |
|
265 TYPED_TEST(BasicElf, BasicLE) { |
|
266 typedef typename TypeParam::Ehdr Ehdr; |
|
267 typedef typename TypeParam::Phdr Phdr; |
|
268 typedef typename TypeParam::Shdr Shdr; |
|
269 const size_t kStringTableSize = sizeof("\0.text\0.bss\0.shstrtab"); |
|
270 const size_t kStringTableAlign = 4 - kStringTableSize % 4; |
|
271 const size_t kExpectedSize = sizeof(Ehdr) + |
|
272 // Four sections, SHT_NULL + the section header string table + |
|
273 // 4096 bytes of the size-aligned .text section + one program header. |
|
274 sizeof(Phdr) + 4 * sizeof(Shdr) + 4096 + |
|
275 kStringTableSize + kStringTableAlign; |
|
276 |
|
277 // It doesn't really matter that the machine type is right for the class. |
|
278 ELF elf(EM_386, TypeParam::kClass, kLittleEndian); |
|
279 Section text(kLittleEndian); |
|
280 text.Append(4094, 0); |
|
281 int text_idx = elf.AddSection(".text", text, SHT_PROGBITS); |
|
282 Section bss(kLittleEndian); |
|
283 bss.Append(16, 0); |
|
284 int bss_idx = elf.AddSection(".bss", bss, SHT_NOBITS); |
|
285 elf.AddSegment(text_idx, bss_idx, PT_LOAD); |
|
286 elf.Finish(); |
|
287 EXPECT_EQ(kExpectedSize, elf.Size()); |
|
288 |
|
289 string contents; |
|
290 ASSERT_TRUE(elf.GetContents(&contents)); |
|
291 ASSERT_EQ(kExpectedSize, contents.size()); |
|
292 const Ehdr* header = |
|
293 reinterpret_cast<const Ehdr*>(contents.data()); |
|
294 const uint8_t kIdent[] = { |
|
295 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, |
|
296 TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, |
|
297 0, 0, 0, 0, 0, 0, 0, 0 |
|
298 }; |
|
299 EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); |
|
300 EXPECT_EQ(ET_EXEC, header->e_type); |
|
301 EXPECT_EQ(EM_386, header->e_machine); |
|
302 EXPECT_EQ(static_cast<unsigned int>(EV_CURRENT), header->e_version); |
|
303 EXPECT_EQ(0U, header->e_entry); |
|
304 EXPECT_EQ(sizeof(Ehdr), header->e_phoff); |
|
305 EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096 + kStringTableSize + |
|
306 kStringTableAlign, header->e_shoff); |
|
307 EXPECT_EQ(0U, header->e_flags); |
|
308 EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); |
|
309 EXPECT_EQ(sizeof(Phdr), header->e_phentsize); |
|
310 EXPECT_EQ(1, header->e_phnum); |
|
311 EXPECT_EQ(sizeof(Shdr), header->e_shentsize); |
|
312 EXPECT_EQ(4, header->e_shnum); |
|
313 EXPECT_EQ(3, header->e_shstrndx); |
|
314 |
|
315 const Shdr* shdr = |
|
316 reinterpret_cast<const Shdr*>(contents.data() + header->e_shoff); |
|
317 EXPECT_EQ(0U, shdr[0].sh_name); |
|
318 EXPECT_EQ(static_cast<unsigned int>(SHT_NULL), shdr[0].sh_type); |
|
319 EXPECT_EQ(0U, shdr[0].sh_flags); |
|
320 EXPECT_EQ(0U, shdr[0].sh_addr); |
|
321 EXPECT_EQ(0U, shdr[0].sh_offset); |
|
322 EXPECT_EQ(0U, shdr[0].sh_size); |
|
323 EXPECT_EQ(0U, shdr[0].sh_link); |
|
324 EXPECT_EQ(0U, shdr[0].sh_info); |
|
325 EXPECT_EQ(0U, shdr[0].sh_addralign); |
|
326 EXPECT_EQ(0U, shdr[0].sh_entsize); |
|
327 |
|
328 EXPECT_EQ(1U, shdr[1].sh_name); |
|
329 EXPECT_EQ(static_cast<unsigned int>(SHT_PROGBITS), shdr[1].sh_type); |
|
330 EXPECT_EQ(0U, shdr[1].sh_flags); |
|
331 EXPECT_EQ(0U, shdr[1].sh_addr); |
|
332 EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), shdr[1].sh_offset); |
|
333 EXPECT_EQ(4094U, shdr[1].sh_size); |
|
334 EXPECT_EQ(0U, shdr[1].sh_link); |
|
335 EXPECT_EQ(0U, shdr[1].sh_info); |
|
336 EXPECT_EQ(0U, shdr[1].sh_addralign); |
|
337 EXPECT_EQ(0U, shdr[1].sh_entsize); |
|
338 |
|
339 EXPECT_EQ(sizeof("\0.text"), shdr[2].sh_name); |
|
340 EXPECT_EQ(static_cast<unsigned int>(SHT_NOBITS), shdr[2].sh_type); |
|
341 EXPECT_EQ(0U, shdr[2].sh_flags); |
|
342 EXPECT_EQ(0U, shdr[2].sh_addr); |
|
343 EXPECT_EQ(0U, shdr[2].sh_offset); |
|
344 EXPECT_EQ(16U, shdr[2].sh_size); |
|
345 EXPECT_EQ(0U, shdr[2].sh_link); |
|
346 EXPECT_EQ(0U, shdr[2].sh_info); |
|
347 EXPECT_EQ(0U, shdr[2].sh_addralign); |
|
348 EXPECT_EQ(0U, shdr[2].sh_entsize); |
|
349 |
|
350 EXPECT_EQ(sizeof("\0.text\0.bss"), shdr[3].sh_name); |
|
351 EXPECT_EQ(static_cast<unsigned int>(SHT_STRTAB), shdr[3].sh_type); |
|
352 EXPECT_EQ(0U, shdr[3].sh_flags); |
|
353 EXPECT_EQ(0U, shdr[3].sh_addr); |
|
354 EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096, shdr[3].sh_offset); |
|
355 EXPECT_EQ(kStringTableSize, shdr[3].sh_size); |
|
356 EXPECT_EQ(0U, shdr[3].sh_link); |
|
357 EXPECT_EQ(0U, shdr[3].sh_info); |
|
358 EXPECT_EQ(0U, shdr[3].sh_addralign); |
|
359 EXPECT_EQ(0U, shdr[3].sh_entsize); |
|
360 |
|
361 const Phdr* phdr = |
|
362 reinterpret_cast<const Phdr*>(contents.data() + header->e_phoff); |
|
363 EXPECT_EQ(static_cast<unsigned int>(PT_LOAD), phdr->p_type); |
|
364 EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), phdr->p_offset); |
|
365 EXPECT_EQ(0U, phdr->p_vaddr); |
|
366 EXPECT_EQ(0U, phdr->p_paddr); |
|
367 EXPECT_EQ(4096U, phdr->p_filesz); |
|
368 EXPECT_EQ(4096U + 16U, phdr->p_memsz); |
|
369 EXPECT_EQ(0U, phdr->p_flags); |
|
370 EXPECT_EQ(0U, phdr->p_align); |
|
371 } |
|
372 |
|
373 class ElfNotesTest : public Test {}; |
|
374 |
|
375 TEST_F(ElfNotesTest, Empty) { |
|
376 Notes notes(kLittleEndian); |
|
377 string contents; |
|
378 ASSERT_TRUE(notes.GetContents(&contents)); |
|
379 EXPECT_EQ(0U, contents.size()); |
|
380 } |
|
381 |
|
382 TEST_F(ElfNotesTest, Notes) { |
|
383 Notes notes(kLittleEndian); |
|
384 notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t *>("\x42\x02\0\0"), |
|
385 4); |
|
386 notes.AddNote(2, "a", reinterpret_cast<const uint8_t *>("foobar"), |
|
387 sizeof("foobar") - 1); |
|
388 |
|
389 const uint8_t kExpectedNotesContents[] = { |
|
390 // Note 1 |
|
391 0x06, 0x00, 0x00, 0x00, // name size, including terminating zero |
|
392 0x04, 0x00, 0x00, 0x00, // desc size |
|
393 0x01, 0x00, 0x00, 0x00, // type |
|
394 'L', 'i', 'n', 'u', 'x', 0x00, 0x00, 0x00, // padded "Linux" |
|
395 0x42, 0x02, 0x00, 0x00, // desc |
|
396 // Note 2 |
|
397 0x02, 0x00, 0x00, 0x00, // name size |
|
398 0x06, 0x00, 0x00, 0x00, // desc size |
|
399 0x02, 0x00, 0x00, 0x00, // type |
|
400 'a', 0x00, 0x00, 0x00, // padded "a" |
|
401 'f', 'o', 'o', 'b', 'a', 'r', 0x00, 0x00, // padded "foobar" |
|
402 }; |
|
403 const size_t kExpectedNotesSize = sizeof(kExpectedNotesContents); |
|
404 EXPECT_EQ(kExpectedNotesSize, notes.Size()); |
|
405 |
|
406 string notes_contents; |
|
407 ASSERT_TRUE(notes.GetContents(¬es_contents)); |
|
408 EXPECT_EQ(0, memcmp(kExpectedNotesContents, |
|
409 notes_contents.data(), |
|
410 notes_contents.size())); |
|
411 } |
|
412 |
|
413 #endif // defined(__i386__) || defined(__x86_64__) |