blob: dd242146a39538948ad8285e1e2262bcdeb2a529 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 "shill/net/byte_string.h"
#include <arpa/inet.h>
#include <endian.h>
#include <gtest/gtest.h>
#include <string>
using testing::Test;
using std::string;
namespace shill {
namespace {
const unsigned char kTest1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const char kTest1HexString[] = "00010203040506070809";
const char kTest1HexSubstring[] = "0203040506070809";
const char kTest1HexSubstringReordered[] = "0504030209080706";
const unsigned char kTest2[] = { 1, 2, 3, 0xa };
const char kTest2HexString[] = "0102030A";
const unsigned int kTest2Uint32 = 0x0102030a;
const unsigned char kTest3[] = { 0, 0, 0, 0 };
const char kTest4[] = "Hello world";
const unsigned char kTest5[] = { 1, 2, 3 };
} // namespace
class ByteStringTest : public Test {
public:
bool IsCPUSameAsNetOrder() {
const uint32_t kTestValue = 0x12345678;
return htonl(kTestValue) == kTestValue;
}
void CalculateBitwiseAndResult(ByteString *bs,
ByteString *mask,
ByteString *expected_result,
size_t count) {
ASSERT_NE(nullptr, bs);
ASSERT_NE(nullptr, mask);
ASSERT_NE(nullptr, expected_result);
for (size_t i = 0; i < count; i++) {
EXPECT_FALSE(bs->BitwiseAnd(*mask));
unsigned char val = count - i;
mask->Append(ByteString(&val, 1));
val &= bs->GetConstData()[i];
expected_result->Append(ByteString(&val, 1));
}
}
void CalculateBitwiseOrResult(ByteString *bs,
ByteString *merge,
ByteString *expected_result,
size_t count) {
ASSERT_NE(nullptr, bs);
ASSERT_NE(nullptr, merge);
ASSERT_NE(nullptr, expected_result);
for (size_t i = 0; i < count; i++) {
EXPECT_FALSE(bs->BitwiseOr(*merge));
unsigned char val = sizeof(kTest1) - i;
merge->Append(ByteString(&val, 1));
val |= bs->GetConstData()[i];
expected_result->Append(ByteString(&val, 1));
}
}
};
TEST_F(ByteStringTest, Empty) {
uint32_t val;
ByteString bs1(0);
EXPECT_TRUE(bs1.IsEmpty());
EXPECT_EQ(0, bs1.GetLength());
EXPECT_EQ(nullptr, bs1.GetData());
EXPECT_FALSE(bs1.ConvertToNetUInt32(&val));
EXPECT_TRUE(bs1.IsZero());
}
TEST_F(ByteStringTest, NonEmpty) {
ByteString bs1(kTest1, sizeof(kTest1));
uint32_t val;
EXPECT_FALSE(bs1.IsEmpty());
ASSERT_NE(nullptr, bs1.GetData());
EXPECT_EQ(sizeof(kTest1), bs1.GetLength());
for (unsigned int i = 0; i < sizeof(kTest1); i++) {
EXPECT_EQ(bs1.GetData()[i], kTest1[i]);
}
EXPECT_FALSE(bs1.ConvertToNetUInt32(&val));
EXPECT_FALSE(bs1.IsZero());
// Build a ByteString (different to bs1), verify that the new ByteString
// looks as expected, verify that it's different to bs1.
ByteString bs2(kTest2, sizeof(kTest2));
ASSERT_NE(nullptr, bs2.GetData());
EXPECT_EQ(sizeof(kTest2), bs2.GetLength());
for (unsigned int i = 0; i < sizeof(kTest2); i++) {
EXPECT_EQ(bs2.GetData()[i], kTest2[i]);
}
EXPECT_FALSE(bs2.IsZero());
EXPECT_FALSE(bs2.Equals(bs1));
// Build _another_ ByteString (different to bs1 and bs2), verify that the
// new ByteString looks as expected, verify that it's different to bs1 and
// bs2.
ByteString bs3(kTest3, sizeof(kTest3));
ASSERT_NE(nullptr, bs3.GetData());
EXPECT_EQ(sizeof(kTest3), bs3.GetLength());
for (unsigned int i = 0; i < sizeof(kTest3); i++) {
EXPECT_EQ(bs3.GetData()[i], kTest3[i]);
}
EXPECT_TRUE(bs3.IsZero());
EXPECT_FALSE(bs2.Equals(bs1));
EXPECT_FALSE(bs3.Equals(bs1));
// Check two equal ByteStrings.
ByteString bs6(kTest1, sizeof(kTest1));
EXPECT_TRUE(bs6.Equals(bs1));
}
TEST_F(ByteStringTest, CopyTerminator) {
ByteString bs4(string(kTest4), false);
EXPECT_EQ(strlen(kTest4), bs4.GetLength());
EXPECT_EQ(0, memcmp(kTest4, bs4.GetData(), bs4.GetLength()));
ByteString bs5(string(kTest4), true);
EXPECT_EQ(strlen(kTest4) + 1, bs5.GetLength());
EXPECT_EQ(0, memcmp(kTest4, bs5.GetData(), bs5.GetLength()));
}
TEST_F(ByteStringTest, SubString) {
ByteString bs1(kTest1, sizeof(kTest1));
ByteString fragment(kTest1 + 3, 4);
EXPECT_TRUE(fragment.Equals(bs1.GetSubstring(3, 4)));
const int kMargin = sizeof(kTest1) - 3;
ByteString end_fragment(kTest1 + kMargin, sizeof(kTest1) - kMargin);
EXPECT_TRUE(end_fragment.Equals(bs1.GetSubstring(kMargin, sizeof(kTest1))));
// Verify that the ByteString correctly handles accessing a substring
// outside the range of the ByteString.
const size_t kBogusOffset = 10;
EXPECT_TRUE(bs1.GetSubstring(sizeof(kTest1), kBogusOffset).IsEmpty());
}
TEST_F(ByteStringTest, UInt32) {
ByteString bs1 = ByteString::CreateFromNetUInt32(kTest2Uint32);
uint32_t val;
EXPECT_EQ(4, bs1.GetLength());
ASSERT_NE(nullptr, bs1.GetData());
EXPECT_TRUE(bs1.ConvertToNetUInt32(&val));
EXPECT_EQ(kTest2Uint32, val);
EXPECT_FALSE(bs1.IsZero());
ByteString bs2(kTest2, sizeof(kTest2));
EXPECT_TRUE(bs1.Equals(bs2));
EXPECT_TRUE(bs2.ConvertToNetUInt32(&val));
EXPECT_EQ(kTest2Uint32, val);
ByteString bs3 = ByteString::CreateFromCPUUInt32(0x1020304);
EXPECT_EQ(4, bs1.GetLength());
ASSERT_NE(nullptr, bs3.GetData());
EXPECT_TRUE(bs3.ConvertToCPUUInt32(&val));
EXPECT_EQ(0x1020304, val);
EXPECT_FALSE(bs3.IsZero());
#if __BYTE_ORDER == __LITTLE_ENDIAN
EXPECT_FALSE(bs1.Equals(bs3));
#else
EXPECT_TRUE(bs1.Equals(bs3));
#endif
}
TEST_F(ByteStringTest, Resize) {
ByteString bs(kTest2, sizeof(kTest2));
const size_t kSizeExtension = 10;
bs.Resize(sizeof(kTest2) + kSizeExtension);
EXPECT_EQ(sizeof(kTest2) + kSizeExtension, bs.GetLength());
ASSERT_NE(nullptr, bs.GetData());
EXPECT_EQ(0, memcmp(bs.GetData(), kTest2, sizeof(kTest2)));
for (size_t i = sizeof(kTest2); i < sizeof(kTest2) + kSizeExtension; ++i) {
EXPECT_EQ(0, bs.GetData()[i]);
}
const size_t kSizeReduction = 2;
bs.Resize(sizeof(kTest2) - kSizeReduction);
EXPECT_EQ(sizeof(kTest2) - kSizeReduction, bs.GetLength());
EXPECT_EQ(0, memcmp(bs.GetData(), kTest2, sizeof(kTest2) - kSizeReduction));
}
TEST_F(ByteStringTest, HexEncode) {
ByteString bs(kTest2, sizeof(kTest2));
EXPECT_EQ(kTest2HexString, bs.HexEncode());
}
TEST_F(ByteStringTest, BitwiseAndWithAndWithoutOffsets) {
const size_t kOffset[] = {0, 2, 7};
for (size_t i = 0; i < arraysize(kOffset); ++i) {
ByteString bs(kTest1, sizeof(kTest1));
bs.RemovePrefix(kOffset[i]);
ByteString mask;
ByteString expected_result;
CalculateBitwiseAndResult(&bs, &mask, &expected_result,
sizeof(kTest1) - kOffset[i]);
EXPECT_TRUE(bs.BitwiseAnd(mask));
EXPECT_TRUE(bs.Equals(expected_result));
bs.Resize(sizeof(kTest1) - 1);
EXPECT_FALSE(bs.BitwiseAnd(mask));
}
}
TEST_F(ByteStringTest, BitwiseOrWithAndWithoutOffsets) {
const size_t kOffset[] = {0, 2, 7};
for (size_t i = 0; i < arraysize(kOffset); ++i) {
ByteString bs(kTest1, sizeof(kTest1));
bs.RemovePrefix(kOffset[i]);
ByteString merge;
ByteString expected_result;
CalculateBitwiseOrResult(&bs, &merge, &expected_result,
sizeof(kTest1) - kOffset[i]);
EXPECT_TRUE(bs.BitwiseOr(merge));
EXPECT_TRUE(bs.Equals(expected_result));
bs.Resize(sizeof(kTest1) - 1);
EXPECT_FALSE(bs.BitwiseOr(merge));
}
}
TEST_F(ByteStringTest, BitwiseInvertWithAndWithoutOffsets) {
const size_t kOffset[] = {0, 2, 7};
for (size_t i = 0; i < arraysize(kOffset); ++i) {
ByteString bs(kTest1, sizeof(kTest1));
bs.RemovePrefix(kOffset[i]);
ByteString invert;
for (size_t j = kOffset[i]; j < sizeof(kTest1); j++) {
unsigned char val = kTest1[j] ^ 0xff;
invert.Append(ByteString(&val, 1));
}
bs.BitwiseInvert();
EXPECT_TRUE(bs.Equals(invert));
}
}
// The tests, below, test various ByteString operations where some bytes have
// been removed from the beginning of one or more of the ByteStrings in the
// test.
TEST_F(ByteStringTest, EmptyOffset) {
uint32_t val;
ByteString bs1(kTest1, sizeof(kTest1));
bs1.RemovePrefix(sizeof(kTest1));
EXPECT_TRUE(bs1.IsEmpty());
EXPECT_EQ(0, bs1.GetLength());
EXPECT_EQ(nullptr, bs1.GetData());
EXPECT_FALSE(bs1.ConvertToNetUInt32(&val));
EXPECT_TRUE(bs1.IsZero());
}
TEST_F(ByteStringTest, NonEmptyOffset) {
ByteString bs1(kTest1, sizeof(kTest1));
const size_t kNewLength1 = 2;
const size_t kOffset1 = sizeof(kTest1) - kNewLength1;
{
bs1.RemovePrefix(kOffset1);
ASSERT_NE(nullptr, bs1.GetData());
EXPECT_FALSE(bs1.IsEmpty());
EXPECT_EQ(kNewLength1, bs1.GetLength());
for (unsigned int i = kOffset1; i < sizeof(kTest1); i++) {
EXPECT_EQ(bs1.GetData()[i - kOffset1], kTest1[i]);
}
uint32_t val;
EXPECT_FALSE(bs1.ConvertToNetUInt32(&val));
EXPECT_FALSE(bs1.IsZero());
}
// Check a non-equal ByteString.
{
const size_t kNewLength2 = 3;
const size_t kOffset2 = sizeof(kTest2) - kNewLength2;
ByteString bs2(kTest2, sizeof(kTest2));
bs2.RemovePrefix(kOffset2);
ASSERT_NE(nullptr, bs2.GetData());
EXPECT_EQ(kNewLength2, bs2.GetLength());
for (unsigned int i = kOffset2; i < sizeof(kTest2); i++) {
EXPECT_EQ(bs2.GetData()[i - kOffset2], kTest2[i]);
}
EXPECT_FALSE(bs2.IsZero());
EXPECT_FALSE(bs2.Equals(bs1));
}
// Check whether two equal ByteStrings are, in fact, equal.
{
ByteString bs6(kTest1, sizeof(kTest1));
bs6.RemovePrefix(kOffset1);
EXPECT_TRUE(bs6.Equals(bs1));
}
}
TEST_F(ByteStringTest, CopyTerminatorOffset) {
{
ByteString bs4(string(kTest4), false);
const size_t kOffset4 = 1;
bs4.RemovePrefix(kOffset4);
EXPECT_EQ(strlen(kTest4) - kOffset4, bs4.GetLength());
EXPECT_EQ(0, memcmp(kTest4 + kOffset4, bs4.GetData(), bs4.GetLength()));
}
{
ByteString bs5(string(kTest4), true);
const size_t kOffset5 = 1;
bs5.RemovePrefix(kOffset5);
EXPECT_EQ(strlen(kTest4) + 1 - kOffset5, bs5.GetLength());
EXPECT_EQ(0, memcmp(kTest4 + kOffset5, bs5.GetData(), bs5.GetLength()));
}
}
TEST_F(ByteStringTest, SubStringOffset) {
const size_t kFramgmetOffset = 3;
const size_t kFragmentLength = 4;
ByteString bs1(kTest1, sizeof(kTest1));
ByteString fragment(kTest1, kFramgmetOffset + kFragmentLength);
fragment.RemovePrefix(kFramgmetOffset);
EXPECT_TRUE(fragment.Equals(bs1.GetSubstring(kFramgmetOffset,
kFragmentLength)));
const int kMargin = sizeof(kTest1) - kFramgmetOffset;
ByteString end_fragment(kTest1 + kMargin, sizeof(kTest1) - kMargin);
EXPECT_TRUE(end_fragment.Equals(bs1.GetSubstring(kMargin, sizeof(kTest1))));
// Verify that the ByteString correctly handles accessing a substring
// outside the range of the ByteString.
const size_t kBogusOffset = 10;
EXPECT_TRUE(bs1.GetSubstring(sizeof(kTest1), kBogusOffset).IsEmpty());
}
TEST_F(ByteStringTest, ResizeOffset) {
ByteString bs(kTest2, sizeof(kTest2));
const size_t kOffset = 1;
bs.RemovePrefix(kOffset);
const size_t kSizeExtension = 10;
bs.Resize(sizeof(kTest2) + kSizeExtension);
EXPECT_EQ(sizeof(kTest2) + kSizeExtension, bs.GetLength());
ASSERT_NE(nullptr, bs.GetData());
EXPECT_EQ(0, memcmp(bs.GetData(),
kTest2 + kOffset,
sizeof(kTest2) - kOffset));
for (size_t i = sizeof(kTest2) - kOffset;
i < sizeof(kTest2) + kSizeExtension; ++i) {
EXPECT_EQ(0, bs.GetData()[i]);
}
const size_t kSizeReduction = 2;
bs.Resize(sizeof(kTest2) - kSizeReduction);
EXPECT_EQ(sizeof(kTest2) - kSizeReduction, bs.GetLength());
EXPECT_EQ(0, memcmp(bs.GetData(), kTest2 + kOffset,
sizeof(kTest2) - kSizeReduction));
}
TEST_F(ByteStringTest, HexEncodeWithOffset) {
ByteString bs(kTest2, sizeof(kTest2));
const size_t kOffset = 2;
const size_t kBytesPerHexDigit = 2;
bs.RemovePrefix(kOffset);
EXPECT_EQ(kTest2HexString + kOffset * kBytesPerHexDigit, bs.HexEncode());
}
TEST_F(ByteStringTest, ChopByteClear) {
ByteString bs(kTest1, sizeof(kTest1));
ByteString expected_result(kTest2, sizeof(kTest2));
bs.RemovePrefix(5);
bs.Clear();
bs.Append(ByteString(kTest2, sizeof(kTest2)));
EXPECT_TRUE(bs.Equals(expected_result));
}
TEST_F(ByteStringTest, CreateFromHexString) {
ByteString bs = ByteString::CreateFromHexString("");
EXPECT_TRUE(bs.IsEmpty());
ByteString bs1 = ByteString::CreateFromHexString("0");
EXPECT_TRUE(bs1.IsEmpty());
ByteString bs2 = ByteString::CreateFromHexString("0y");
EXPECT_TRUE(bs2.IsEmpty());
ByteString bs3 = ByteString::CreateFromHexString("ab");
EXPECT_EQ(1, bs3.GetLength());
EXPECT_EQ(0xab, bs3.GetData()[0]);
ByteString bs4 = ByteString::CreateFromHexString(kTest1HexString);
EXPECT_EQ(kTest1HexString, bs4.HexEncode());
}
TEST_F(ByteStringTest, ConvertFromNetToCPUUInt32Array) {
ByteString bs1;
EXPECT_TRUE(bs1.ConvertFromNetToCPUUInt32Array());
EXPECT_TRUE(bs1.IsEmpty());
// Conversion should fail when the length of ByteString is not a
// multiple of 4.
ByteString bs2(kTest1, sizeof(kTest1));
EXPECT_EQ(kTest1HexString, bs2.HexEncode());
EXPECT_FALSE(bs2.ConvertFromNetToCPUUInt32Array());
EXPECT_EQ(kTest1HexString, bs2.HexEncode());
// Conversion should succeed when the length of ByteString is a
// multiple of 4. Also test the case when bytes stored in ByteString
// is not word-aligned after calling RemovePrefix().
bs2.RemovePrefix(2);
EXPECT_EQ(kTest1HexSubstring, bs2.HexEncode());
EXPECT_TRUE(bs2.ConvertFromNetToCPUUInt32Array());
if (IsCPUSameAsNetOrder()) {
EXPECT_EQ(kTest1HexSubstring, bs2.HexEncode());
} else {
EXPECT_EQ(kTest1HexSubstringReordered, bs2.HexEncode());
}
}
TEST_F(ByteStringTest, ConvertFromCPUToNetUInt32Array) {
ByteString bs1;
EXPECT_TRUE(bs1.ConvertFromCPUToNetUInt32Array());
EXPECT_TRUE(bs1.IsEmpty());
// Conversion should fail when the length of ByteString is not a
// multiple of 4.
ByteString bs2(kTest1, sizeof(kTest1));
EXPECT_EQ(kTest1HexString, bs2.HexEncode());
EXPECT_FALSE(bs2.ConvertFromCPUToNetUInt32Array());
EXPECT_EQ(kTest1HexString, bs2.HexEncode());
// Conversion should succeed when the length of ByteString is a
// multiple of 4. Also test the case when bytes stored in ByteString
// is not word-aligned after calling RemovePrefix().
bs2.RemovePrefix(2);
EXPECT_EQ(kTest1HexSubstring, bs2.HexEncode());
EXPECT_TRUE(bs2.ConvertFromCPUToNetUInt32Array());
if (IsCPUSameAsNetOrder()) {
EXPECT_EQ(kTest1HexSubstring, bs2.HexEncode());
} else {
EXPECT_EQ(kTest1HexSubstringReordered, bs2.HexEncode());
}
}
TEST_F(ByteStringTest, LessThan) {
ByteString bs1(kTest1, sizeof(kTest1));
ByteString bs2(kTest2, sizeof(kTest2));
ByteString bs3(kTest3, sizeof(kTest3));
ByteString bs5(kTest5, sizeof(kTest5));
// bs2 is shorter, but the first four bytes of bs1 are less than those in bs2.
EXPECT_TRUE(ByteString::IsLessThan(bs1, bs2));
// bs2 and bs3 are the same length, but bs3 has less byte values.
EXPECT_TRUE(ByteString::IsLessThan(bs3, bs2));
// bs3 is shorter than bs1 and the first four bytes of bs3 are less than
// the first four bytes of bs1.
EXPECT_TRUE(ByteString::IsLessThan(bs3, bs1));
// The first three bytes of bs5 are equal to the first three bytes of bs2,
// but bs5 is shorter than bs2.
EXPECT_TRUE(ByteString::IsLessThan(bs5, bs2));
// A Bytestring is not less than another identical one.
EXPECT_FALSE(ByteString::IsLessThan(bs5, bs5));
}
} // namespace shill