| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/pickle.h" |
| #include "base/string16.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| const int testint = 2093847192; |
| const std::string teststr("Hello world"); // note non-aligned string length |
| const std::wstring testwstr(L"Hello, world"); |
| const char testdata[] = "AAA\0BBB\0"; |
| const int testdatalen = arraysize(testdata) - 1; |
| const bool testbool1 = false; |
| const bool testbool2 = true; |
| const uint16 testuint16 = 32123; |
| |
| // checks that the result |
| void VerifyResult(const Pickle& pickle) { |
| void* iter = NULL; |
| |
| int outint; |
| EXPECT_TRUE(pickle.ReadInt(&iter, &outint)); |
| EXPECT_EQ(testint, outint); |
| |
| std::string outstr; |
| EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); |
| EXPECT_EQ(teststr, outstr); |
| |
| std::wstring outwstr; |
| EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr)); |
| EXPECT_EQ(testwstr, outwstr); |
| |
| bool outbool; |
| EXPECT_TRUE(pickle.ReadBool(&iter, &outbool)); |
| EXPECT_EQ(testbool1, outbool); |
| EXPECT_TRUE(pickle.ReadBool(&iter, &outbool)); |
| EXPECT_EQ(testbool2, outbool); |
| |
| uint16 outuint16; |
| EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16)); |
| EXPECT_EQ(testuint16, outuint16); |
| |
| const char* outdata; |
| int outdatalen; |
| EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); |
| EXPECT_EQ(testdatalen, outdatalen); |
| EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); |
| |
| EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); |
| EXPECT_EQ(testdatalen, outdatalen); |
| EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0); |
| |
| // reads past the end should fail |
| EXPECT_FALSE(pickle.ReadInt(&iter, &outint)); |
| } |
| |
| } // namespace |
| |
| TEST(PickleTest, EncodeDecode) { |
| Pickle pickle; |
| |
| EXPECT_TRUE(pickle.WriteInt(testint)); |
| EXPECT_TRUE(pickle.WriteString(teststr)); |
| EXPECT_TRUE(pickle.WriteWString(testwstr)); |
| EXPECT_TRUE(pickle.WriteBool(testbool1)); |
| EXPECT_TRUE(pickle.WriteBool(testbool2)); |
| EXPECT_TRUE(pickle.WriteUInt16(testuint16)); |
| EXPECT_TRUE(pickle.WriteData(testdata, testdatalen)); |
| |
| // Over allocate BeginWriteData so we can test TrimWriteData. |
| char* dest = pickle.BeginWriteData(testdatalen + 100); |
| EXPECT_TRUE(dest); |
| memcpy(dest, testdata, testdatalen); |
| |
| pickle.TrimWriteData(testdatalen); |
| |
| VerifyResult(pickle); |
| |
| // test copy constructor |
| Pickle pickle2(pickle); |
| VerifyResult(pickle2); |
| |
| // test operator= |
| Pickle pickle3; |
| pickle3 = pickle; |
| VerifyResult(pickle3); |
| } |
| |
| // Tests that we can handle really small buffers. |
| TEST(PickleTest, SmallBuffer) { |
| scoped_array<char> buffer(new char[1]); |
| |
| // We should not touch the buffer. |
| Pickle pickle(buffer.get(), 1); |
| |
| void* iter = NULL; |
| int data; |
| EXPECT_FALSE(pickle.ReadInt(&iter, &data)); |
| } |
| |
| // Tests that we can handle improper headers. |
| TEST(PickleTest, BigSize) { |
| int buffer[] = { 0x56035200, 25, 40, 50 }; |
| |
| Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); |
| |
| void* iter = NULL; |
| int data; |
| EXPECT_FALSE(pickle.ReadInt(&iter, &data)); |
| } |
| |
| TEST(PickleTest, UnalignedSize) { |
| int buffer[] = { 10, 25, 40, 50 }; |
| |
| Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer)); |
| |
| void* iter = NULL; |
| int data; |
| EXPECT_FALSE(pickle.ReadInt(&iter, &data)); |
| } |
| |
| TEST(PickleTest, ZeroLenStr) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteString("")); |
| |
| void* iter = NULL; |
| std::string outstr; |
| EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); |
| EXPECT_EQ("", outstr); |
| } |
| |
| TEST(PickleTest, ZeroLenWStr) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteWString(L"")); |
| |
| void* iter = NULL; |
| std::string outstr; |
| EXPECT_TRUE(pickle.ReadString(&iter, &outstr)); |
| EXPECT_EQ("", outstr); |
| } |
| |
| TEST(PickleTest, BadLenStr) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteInt(-2)); |
| |
| void* iter = NULL; |
| std::string outstr; |
| EXPECT_FALSE(pickle.ReadString(&iter, &outstr)); |
| } |
| |
| TEST(PickleTest, BadLenWStr) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteInt(-1)); |
| |
| void* iter = NULL; |
| std::wstring woutstr; |
| EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr)); |
| } |
| |
| TEST(PickleTest, FindNext) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteInt(1)); |
| EXPECT_TRUE(pickle.WriteString("Domo")); |
| |
| const char* start = reinterpret_cast<const char*>(pickle.data()); |
| const char* end = start + pickle.size(); |
| |
| EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end)); |
| EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1)); |
| EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1)); |
| } |
| |
| TEST(PickleTest, FindNextWithIncompleteHeader) { |
| size_t header_size = sizeof(Pickle::Header); |
| scoped_array<char> buffer(new char[header_size - 1]); |
| memset(buffer.get(), 0x1, header_size - 1); |
| |
| const char* start = buffer.get(); |
| const char* end = start + header_size - 1; |
| |
| EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end)); |
| } |
| |
| TEST(PickleTest, IteratorHasRoom) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteInt(1)); |
| EXPECT_TRUE(pickle.WriteInt(2)); |
| |
| const void* iter = 0; |
| EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, 1)); |
| iter = pickle.payload(); |
| EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 0)); |
| EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 1)); |
| EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, -1)); |
| EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, sizeof(int) * 2)); |
| EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, (sizeof(int) * 2) + 1)); |
| } |
| |
| TEST(PickleTest, Resize) { |
| size_t unit = Pickle::kPayloadUnit; |
| scoped_array<char> data(new char[unit]); |
| char* data_ptr = data.get(); |
| for (size_t i = 0; i < unit; i++) |
| data_ptr[i] = 'G'; |
| |
| // construct a message that will be exactly the size of one payload unit, |
| // note that any data will have a 4-byte header indicating the size |
| const size_t payload_size_after_header = unit - sizeof(uint32); |
| Pickle pickle; |
| pickle.WriteData(data_ptr, |
| static_cast<int>(payload_size_after_header - sizeof(uint32))); |
| size_t cur_payload = payload_size_after_header; |
| |
| // note: we assume 'unit' is a power of 2 |
| EXPECT_EQ(unit, pickle.capacity()); |
| EXPECT_EQ(pickle.payload_size(), payload_size_after_header); |
| |
| // fill out a full page (noting data header) |
| pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32))); |
| cur_payload += unit; |
| EXPECT_EQ(unit * 2, pickle.capacity()); |
| EXPECT_EQ(cur_payload, pickle.payload_size()); |
| |
| // one more byte should double the capacity |
| pickle.WriteData(data_ptr, 1); |
| cur_payload += 5; |
| EXPECT_EQ(unit * 4, pickle.capacity()); |
| EXPECT_EQ(cur_payload, pickle.payload_size()); |
| } |
| |
| namespace { |
| |
| struct CustomHeader : Pickle::Header { |
| int blah; |
| }; |
| |
| } // namespace |
| |
| TEST(PickleTest, HeaderPadding) { |
| const uint32 kMagic = 0x12345678; |
| |
| Pickle pickle(sizeof(CustomHeader)); |
| pickle.WriteInt(kMagic); |
| |
| // this should not overwrite the 'int' payload |
| pickle.headerT<CustomHeader>()->blah = 10; |
| |
| void* iter = NULL; |
| int result; |
| ASSERT_TRUE(pickle.ReadInt(&iter, &result)); |
| |
| EXPECT_EQ(static_cast<uint32>(result), kMagic); |
| } |
| |
| TEST(PickleTest, EqualsOperator) { |
| Pickle source; |
| source.WriteInt(1); |
| |
| Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()), |
| source.size()); |
| Pickle copy; |
| copy = copy_refs_source_buffer; |
| ASSERT_EQ(source.size(), copy.size()); |
| } |
| |
| TEST(PickleTest, EvilLengths) { |
| Pickle source; |
| std::string str(100000, 'A'); |
| source.WriteData(str.c_str(), 100000); |
| // ReadString16 used to have its read buffer length calculation wrong leading |
| // to out-of-bounds reading. |
| void* iter = NULL; |
| string16 str16; |
| EXPECT_FALSE(source.ReadString16(&iter, &str16)); |
| |
| // And check we didn't break ReadString16. |
| str16 = (wchar_t) 'A'; |
| Pickle str16_pickle; |
| str16_pickle.WriteString16(str16); |
| iter = NULL; |
| EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16)); |
| EXPECT_EQ(1U, str16.length()); |
| |
| // Check we don't fail in a length check with large WStrings. |
| Pickle big_len; |
| big_len.WriteInt(1 << 30); |
| iter = NULL; |
| std::wstring wstr; |
| EXPECT_FALSE(big_len.ReadWString(&iter, &wstr)); |
| } |
| |
| // Check we can write zero bytes of data and 'data' can be NULL. |
| TEST(PickleTest, ZeroLength) { |
| Pickle pickle; |
| EXPECT_TRUE(pickle.WriteData(NULL, 0)); |
| |
| void* iter = NULL; |
| const char* outdata; |
| int outdatalen; |
| EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen)); |
| EXPECT_EQ(0, outdatalen); |
| // We can't assert that outdata is NULL. |
| } |
| |
| // Check that ReadBytes works properly with an iterator initialized to NULL. |
| TEST(PickleTest, ReadBytes) { |
| Pickle pickle; |
| int data = 0x7abcd; |
| EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data))); |
| |
| void* iter = NULL; |
| const char* outdata_char; |
| EXPECT_TRUE(pickle.ReadBytes(&iter, &outdata_char, sizeof(data))); |
| |
| int outdata; |
| memcpy(&outdata, outdata_char, sizeof(outdata)); |
| EXPECT_EQ(data, outdata); |
| } |