| // Copyright 2012 Google Inc. All Rights Reserved. |
| // Author: charliehotel@google.com (Christopher Hoover) |
| // |
| // Modified by FRC Team 971. |
| // |
| // Tests for Buffer. |
| |
| #include "gbuffer.h" |
| |
| #include <stdint.h> |
| #include <limits> |
| #include <memory> |
| |
| #include <gtest/gtest.h> |
| |
| #include "aos/common/queue_testutils.h" |
| |
| #define GG_LONGLONG(x) x##LL |
| #define GG_ULONGLONG(x) x##ULL |
| #define ARRAYSIZE(x) (static_cast<int>(sizeof(x)/sizeof(x[0]))) |
| |
| namespace glibusb { |
| namespace { |
| |
| typedef ::testing::Types<int8_t, int16_t, int32_t, int64_t, |
| uint8_t, uint16_t, uint32_t, uint64_t> AllIntegerTypes; |
| |
| class BufferTest : public ::testing::Test { |
| public: |
| BufferTest() { |
| ::aos::common::testing::EnableTestLogging(); |
| } |
| }; |
| typedef BufferTest BufferDeathTest; |
| |
| // Tests that a newly constructed buffer is empty. |
| TEST_F(BufferTest, EmptyBufferLength) { |
| Buffer buffer; |
| EXPECT_EQ(0u, buffer.Length()); |
| } |
| |
| // Tests clearing. |
| TEST_F(BufferTest, EmptyBufferClear) { |
| Buffer buffer; |
| buffer.Append(uint8_t(1)); |
| buffer.Clear(); |
| EXPECT_EQ(0u, buffer.Length()); |
| } |
| |
| // Tests resizing. |
| TEST_F(BufferTest, EmptyBufferResize) { |
| Buffer buffer; |
| const Buffer::size_type kSize = 100; |
| buffer.Resize(kSize); |
| EXPECT_EQ(kSize, buffer.Length()); |
| } |
| |
| // Tests getting a pointer on an empty buffer. |
| TEST_F(BufferTest, EmptyBufferGetPointer) { |
| Buffer buffer; |
| void *p; |
| const void *cp; |
| p = buffer.GetBufferPointer(0); |
| EXPECT_EQ(NULL, p); |
| cp = buffer.GetBufferPointer(0); |
| EXPECT_EQ(NULL, cp); |
| p = buffer.GetBufferPointer(0, 0); |
| EXPECT_EQ(NULL, p); |
| cp = buffer.GetBufferPointer(0, 0); |
| EXPECT_EQ(NULL, cp); |
| } |
| |
| // Tests getting a pointer on an empty buffer. |
| TEST_F(BufferTest, ConstEmptyBufferGetPointer) { |
| const Buffer buffer; |
| const void *cp; |
| cp = buffer.GetBufferPointer(0); |
| EXPECT_EQ(NULL, cp); |
| cp = buffer.GetBufferPointer(0, 0); |
| EXPECT_EQ(NULL, cp); |
| } |
| |
| |
| // Tests Get on an empty buffer. |
| template <typename T> |
| class EmptyBufferGetDeathTest : public BufferTest { |
| public: |
| void Check() { |
| Buffer buffer; |
| T value; |
| EXPECT_DEATH(buffer.Get(0, &value), "CHECK(.*) failed"); |
| } |
| }; |
| |
| // Tests Get for all types on an empty bufer. |
| TYPED_TEST_CASE(EmptyBufferGetDeathTest, AllIntegerTypes); |
| TYPED_TEST(EmptyBufferGetDeathTest, Check) { |
| this->Check(); |
| } |
| |
| |
| // Tests Put on an empty buffer. |
| template <typename T> |
| class EmptyBufferPutDeathTest : public BufferTest { |
| public: |
| void Check() { |
| Buffer buffer; |
| T value(0); |
| EXPECT_DEATH(buffer.Put(0, value), "CHECK(.*) failed"); |
| } |
| }; |
| |
| // Tests Put for all types on an empty bufer. |
| TYPED_TEST_CASE(EmptyBufferPutDeathTest, AllIntegerTypes); |
| TYPED_TEST(EmptyBufferPutDeathTest, Check) { |
| this->Check(); |
| } |
| |
| |
| // Tests getting a string on an empty buffer. |
| TEST_F(BufferDeathTest, EmptyBufferGetString) { |
| Buffer buffer; |
| std::string s; |
| EXPECT_DEATH(buffer.Get(0, &s), "CHECK(.*) failed"); |
| } |
| |
| |
| // Tests removing the header from an empty buffer. |
| TEST_F(BufferDeathTest, EmptyBufferRemoveHeader) { |
| Buffer buffer; |
| buffer.RemoveHeader(0); |
| EXPECT_EQ(0u, buffer.Length()); |
| EXPECT_DEATH(buffer.RemoveHeader(1), "CHECK(.*) failed"); |
| } |
| |
| |
| // Tests adding a header of size 0. |
| TEST_F(BufferTest, EmptyBufferAddHeader) { |
| Buffer buffer; |
| buffer.AddHeader(0); |
| EXPECT_EQ(0u, buffer.Length()); |
| } |
| |
| |
| // Tests adding a header of size > 0. |
| TEST_F(BufferTest, EmptyBufferAddHeader2) { |
| Buffer buffer; |
| const Buffer::size_type kSize = 100; |
| buffer.AddHeader(kSize); |
| EXPECT_EQ(kSize, buffer.Length()); |
| } |
| |
| |
| // Tests copying an empty buffer. |
| TEST_F(BufferTest, EmptyBufferCopy) { |
| Buffer buffer; |
| Buffer buffer2; |
| buffer2.Append(uint8_t(1)); |
| buffer2.Copy(buffer); |
| EXPECT_EQ(0u, buffer2.Length()); |
| } |
| |
| // Tests dumping an empty buffer. |
| TEST_F(BufferTest, EmptyBufferDump) { |
| Buffer buffer; |
| std::string s = buffer.Dump(); |
| EXPECT_EQ("", s); |
| } |
| |
| |
| // Tests slicing an empty buffer. |
| TEST_F(BufferTest, EmptyBufferSlice) { |
| Buffer buffer; |
| ::std::unique_ptr<Buffer> slice(buffer.MakeSlice(0, 0)); |
| EXPECT_EQ(0u, slice->Length()); |
| } |
| |
| |
| // Tests Get, Put and Append for signed and unsigned integers. |
| template <typename T> |
| class PutGetAppendIntegerTest : public BufferTest { |
| public: |
| void Check() { |
| static const T kValues[] = { |
| std::numeric_limits<T>::max(), |
| T(0), |
| std::numeric_limits<T>::min() |
| }; |
| |
| for (int i = 0; i < ARRAYSIZE(kValues); ++i) { |
| const T kValue = kValues[i]; |
| |
| // Tests Put - Get |
| { |
| Buffer buffer; |
| buffer.Resize(sizeof(T)); |
| buffer.Put(0, kValue); |
| T check; |
| buffer.Get(0, &check); |
| EXPECT_EQ(kValue, check); |
| } |
| |
| // Tests Append - Get |
| { |
| Buffer buffer; |
| buffer.Append(kValue); |
| T check; |
| buffer.Get(0, &check); |
| EXPECT_EQ(kValue, check); |
| } |
| } |
| } |
| }; |
| |
| // Tests Get, Put and Append for all signed integers. |
| TYPED_TEST_CASE(PutGetAppendIntegerTest, AllIntegerTypes); |
| TYPED_TEST(PutGetAppendIntegerTest, Check) { |
| this->Check(); |
| } |
| |
| const uint8_t kDeadBeef[] = { |
| 0xef, 0xbe, 0xad, 0xde |
| }; |
| |
| // Test harness for a buffer construct from "C" data. |
| class ConstructedFromDataBufferTest : public testing::Test { |
| protected: |
| void SetUp() { |
| buffer.reset(new Buffer(kDeadBeef, sizeof(kDeadBeef))); |
| } |
| |
| ::std::unique_ptr<Buffer> buffer; |
| }; |
| |
| typedef ConstructedFromDataBufferTest ConstructedFromDataBufferDeathTest; |
| |
| // Tests constructing a buffer from "C" data. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataBufferLength) { |
| EXPECT_EQ(sizeof(kDeadBeef), buffer->Length()); |
| } |
| |
| // Tests that a buffer constructed from "C" data contains the right |
| // data. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataByteAccess) { |
| for (int i = 0; i < ARRAYSIZE(kDeadBeef); ++i) { |
| uint8_t u8; |
| buffer->Get(i, &u8); |
| EXPECT_EQ(kDeadBeef[i], u8); |
| } |
| } |
| |
| // Tests clearing. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataClear) { |
| buffer->Clear(); |
| EXPECT_EQ(0u, buffer->Length()); |
| } |
| |
| // Tests resizing. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataResize) { |
| const Buffer::size_type kSize = 100; |
| buffer->Resize(kSize); |
| EXPECT_EQ(kSize, buffer->Length()); |
| } |
| |
| // Tests that getting a pointer works. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataGetPointer) { |
| void *p; |
| const void *cp; |
| p = buffer->GetBufferPointer(0); |
| EXPECT_EQ(NULL, p); |
| cp = buffer->GetBufferPointer(0); |
| EXPECT_EQ(NULL, cp); |
| p = buffer->GetBufferPointer(0, 0); |
| EXPECT_EQ(NULL, p); |
| cp = buffer->GetBufferPointer(0, 0); |
| EXPECT_EQ(NULL, cp); |
| |
| p = buffer->GetBufferPointer(2); |
| EXPECT_TRUE(p != NULL); |
| EXPECT_EQ(kDeadBeef[0], *static_cast<uint8_t *>(p)); |
| EXPECT_EQ(kDeadBeef[1], *(static_cast<uint8_t *>(p) + 1)); |
| cp = buffer->GetBufferPointer(2); |
| EXPECT_TRUE(p != NULL); |
| EXPECT_EQ(kDeadBeef[0], *static_cast<uint8_t *>(p)); |
| EXPECT_EQ(kDeadBeef[1], *(static_cast<uint8_t *>(p) + 1)); |
| |
| p = buffer->GetBufferPointer(1, 2); |
| EXPECT_TRUE(p != NULL); |
| EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p)); |
| EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1)); |
| cp = buffer->GetBufferPointer(1, 2); |
| EXPECT_TRUE(p != NULL); |
| EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p)); |
| EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1)); |
| |
| const Buffer &const_buffer(*buffer); |
| cp = const_buffer.GetBufferPointer(1, 2); |
| EXPECT_TRUE(p != NULL); |
| EXPECT_EQ(kDeadBeef[1], *static_cast<uint8_t *>(p)); |
| EXPECT_EQ(kDeadBeef[2], *(static_cast<uint8_t *>(p) + 1)); |
| } |
| |
| // Tests that Get{S,U}{8,16,32,64} work on zero. |
| TEST_F(BufferTest, GetZero) { |
| ::std::unique_ptr<Buffer> buffer(new Buffer()); |
| for (int i = 0; i < 8; ++i) { |
| buffer->Append(uint8_t(0)); |
| } |
| int8_t s8; |
| uint8_t u8; |
| int16_t s16; |
| uint16_t u16; |
| int32_t s32; |
| uint32_t u32; |
| int64_t s64; |
| uint64_t u64; |
| buffer->Get(0, &s8); |
| EXPECT_EQ(0, s8); |
| buffer->Get(0, &u8); |
| EXPECT_EQ(0u, u8); |
| buffer->Get(0, &s16); |
| EXPECT_EQ(0, s16); |
| buffer->Get(0, &u16); |
| EXPECT_EQ(0u, u16); |
| buffer->Get(0, &s32); |
| EXPECT_EQ(0, s32); |
| buffer->Get(0, &u32); |
| EXPECT_EQ(0u, u32); |
| buffer->Get(0, &s64); |
| EXPECT_EQ(0, s64); |
| buffer->Get(0, &u64); |
| EXPECT_EQ(0u, u64); |
| } |
| |
| // Tests that GetU{8,16,32,64} work. |
| TEST_F(BufferTest, GetUXX) { |
| ::std::unique_ptr<Buffer> buffer(new Buffer()); |
| buffer->Append(uint8_t(0x88)); |
| buffer->Append(uint8_t(0x77)); |
| buffer->Append(uint8_t(0x66)); |
| buffer->Append(uint8_t(0x55)); |
| buffer->Append(uint8_t(0x44)); |
| buffer->Append(uint8_t(0x33)); |
| buffer->Append(uint8_t(0x22)); |
| buffer->Append(uint8_t(0x11)); |
| uint8_t u8; |
| uint16_t u16; |
| uint32_t u32; |
| uint64_t u64; |
| buffer->Get(0, &u8); |
| EXPECT_EQ(0x88u, u8); |
| buffer->Get(0, &u16); |
| EXPECT_EQ(0x7788u, u16); |
| buffer->Get(0, &u32); |
| EXPECT_EQ(0x55667788u, u32); |
| buffer->Get(0, &u64); |
| EXPECT_EQ(GG_ULONGLONG(0x1122334455667788), u64); |
| } |
| |
| // Tests that GetS{8,16,32,64} work for positive values. |
| TEST_F(BufferTest, GetSXXPositive) { |
| ::std::unique_ptr<Buffer> buffer(new Buffer()); |
| buffer->Append(uint8_t(0x08)); |
| buffer->Append(uint8_t(0x07)); |
| buffer->Append(uint8_t(0x06)); |
| buffer->Append(uint8_t(0x05)); |
| buffer->Append(uint8_t(0x04)); |
| buffer->Append(uint8_t(0x03)); |
| buffer->Append(uint8_t(0x02)); |
| buffer->Append(uint8_t(0x01)); |
| int8_t s8; |
| int16_t s16; |
| int32_t s32; |
| int64_t s64; |
| buffer->Get(0, &s8); |
| EXPECT_EQ(0x08, s8); |
| buffer->Get(0, &s16); |
| EXPECT_EQ(0x0708, s16); |
| buffer->Get(0, &s32); |
| EXPECT_EQ(0x05060708, s32); |
| buffer->Get(0, &s64); |
| EXPECT_EQ(GG_LONGLONG(0x0102030405060708), s64); |
| } |
| |
| // Tests that GetS{8,16,32,64} work for negative values. |
| TEST_F(BufferTest, GetSXXNegative) { |
| ::std::unique_ptr<Buffer> buffer(new Buffer()); |
| buffer->Append(uint8_t(0xF8)); |
| buffer->Append(uint8_t(0xF7)); |
| buffer->Append(uint8_t(0x06)); |
| buffer->Append(uint8_t(0xF5)); |
| buffer->Append(uint8_t(0x04)); |
| buffer->Append(uint8_t(0x03)); |
| buffer->Append(uint8_t(0x02)); |
| buffer->Append(uint8_t(0xF1)); |
| |
| // Calculate directly the the signed (2's complement) value that we |
| // should expect. |
| const int8_t kExpected8 = 0xF8 - 0xFF - 1; |
| int8_t s8; |
| buffer->Get(0, &s8); |
| EXPECT_EQ(kExpected8, s8); |
| |
| const int16_t kExpected16 = 0xF7F8 - 0xFFFF - 1; |
| int16_t s16; |
| buffer->Get(0, &s16); |
| EXPECT_EQ(kExpected16, s16); |
| |
| const int32_t kExpected32 = 0xF506F7F8 - 0xFFFFFFFF - 1; |
| int32_t s32; |
| buffer->Get(0, &s32); |
| EXPECT_EQ(kExpected32, s32); |
| |
| const int64_t kExpected64 = (GG_LONGLONG(0xF1020304F506F7F8) - |
| GG_LONGLONG(0xFFFFFFFFFFFFFFFF) - |
| GG_LONGLONG(1)); |
| int64_t s64; |
| buffer->Get(0, &s64); |
| EXPECT_EQ(kExpected64, s64); |
| } |
| |
| // Tests that getting a string works. |
| TEST_F(ConstructedFromDataBufferDeathTest, ConstructedFromDataGetString) { |
| std::string s; |
| EXPECT_DEATH(buffer->Get(0, &s), "CHECK(.*) failed"); |
| buffer->Append(uint8_t(0)); |
| Buffer::size_type n = buffer->Get(0, &s); |
| EXPECT_STREQ("\xEF\xBE\xAD\xDE", s.c_str()); |
| EXPECT_EQ(4u, n); |
| n = buffer->Get(1, &s); |
| EXPECT_STREQ("\xBE\xAD\xDE", s.c_str()); |
| EXPECT_EQ(4u, n); |
| } |
| |
| // Tests removing a header. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataRemoveHeader) { |
| buffer->RemoveHeader(0); |
| EXPECT_EQ(sizeof(kDeadBeef), buffer->Length()); |
| buffer->RemoveHeader(2); |
| EXPECT_EQ(sizeof(kDeadBeef) - 2, buffer->Length()); |
| uint16_t u16; |
| buffer->Get(0, &u16); |
| EXPECT_EQ(0xdeadu, u16); |
| } |
| |
| // Tests adding a zero-length header. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataAddHeader) { |
| buffer->AddHeader(0); |
| EXPECT_EQ(sizeof(kDeadBeef), buffer->Length()); |
| } |
| |
| // Tests adding a header of size > 0. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataAddHeader2) { |
| const int kSize = 100; |
| buffer->AddHeader(kSize); |
| EXPECT_EQ(sizeof(kDeadBeef) + kSize, buffer->Length()); |
| uint32_t u32; |
| buffer->Get(kSize, &u32); |
| EXPECT_EQ(0xdeadbeefu, u32); |
| } |
| |
| // Tests copying. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataCopy) { |
| buffer->Append(uint8_t(0)); |
| std::string s; |
| buffer->Get(0, &s); |
| |
| Buffer buffer2; |
| buffer2.Copy(*buffer); |
| std::string s2; |
| buffer2.Get(0, &s2); |
| |
| EXPECT_STREQ(s.c_str(), s2.c_str()); |
| } |
| |
| // Tests dumping. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataDump) { |
| const char kExpected[] = |
| "0x00000000: ef be ad de | ....\n"; |
| std::string s = buffer->Dump(); |
| EXPECT_STREQ(kExpected, s.c_str()); |
| } |
| |
| // Tests emtpy slicing. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataSlice) { |
| ::std::unique_ptr<Buffer> slice(buffer->MakeSlice(0, 0)); |
| EXPECT_EQ(0u, slice->Length()); |
| } |
| |
| // Tests slicing. |
| TEST_F(ConstructedFromDataBufferTest, ConstructedFromDataSlice2) { |
| ::std::unique_ptr<Buffer> slice(buffer->MakeSlice(0, 2)); |
| EXPECT_EQ(2u, slice->Length()); |
| uint16_t u16; |
| slice->Get(0, &u16); |
| EXPECT_EQ(0xbeefu, u16); |
| } |
| |
| // Tests dumping. |
| TEST_F(BufferTest, DumpTest) { |
| const char kData[] = "Hello"; |
| const char kExpected[] = |
| "0x00000000: 48 65 6c 6c 6f 00 " |
| " | Hello.\n"; |
| Buffer buffer(kData, sizeof(kData)); |
| std::string s = buffer.Dump(); |
| EXPECT_STREQ(kExpected, s.c_str()); |
| } |
| |
| #if 0 |
| // Tests writing to a file. |
| TEST_F(BufferTest, FileTest) { |
| const char kData[] = "Hello"; |
| Buffer buffer(kData, sizeof(kData)); |
| string out; |
| FileCloser file(MutableStringFile("file", &out, |
| DO_NOT_TAKE_OWNERSHIP, |
| DO_NOT_ALLOW_MMAP)); |
| buffer.WriteOrDie(file.get()); |
| EXPECT_STREQ(kData, out.c_str()); |
| } |
| |
| TEST_F(BufferTest, WritePathOrDieTest) { |
| const char kData[] = "Hello"; |
| Buffer buffer(kData, sizeof(kData)); |
| buffer.WriteToPathOrDie("/dev/null"); |
| } |
| #endif |
| |
| // Tests appending. |
| TEST_F(BufferTest, AppendBuffer) { |
| const char kData1[] = "Hello "; |
| const char kData2[] = "World"; |
| Buffer buffer1(kData1, sizeof(kData1) - 1); |
| EXPECT_EQ(sizeof(kData1) - 1, buffer1.Length()); |
| Buffer buffer2(kData2, sizeof(kData2)); |
| EXPECT_EQ(sizeof(kData2), buffer2.Length()); |
| Buffer buffer; |
| EXPECT_EQ(0u, buffer.Length()); |
| buffer.Append(Buffer()); |
| buffer.Append(buffer1); |
| buffer.Append(buffer2); |
| std::string s; |
| buffer.Get(0, &s); |
| EXPECT_STREQ("Hello World", s.c_str()); |
| } |
| |
| // Tests operator== |
| TEST_F(BufferTest, OpEqualTrue) { |
| Buffer b1; |
| Buffer b2; |
| EXPECT_EQ(b1, b2); |
| b1.Append(uint8_t(1)); |
| b2.Append(uint8_t(1)); |
| EXPECT_EQ(b1, b2); |
| } |
| |
| // Tests operator== |
| TEST_F(BufferTest, OpEqualFalse) { |
| Buffer empty; |
| Buffer b1; |
| Buffer b2; |
| Buffer b12; |
| b1.Append(uint8_t(1)); |
| b2.Append(uint8_t(2)); |
| b12.Append(uint8_t(1)); |
| b12.Append(uint8_t(2)); |
| EXPECT_NE(empty, b1); |
| EXPECT_NE(b1, empty); |
| EXPECT_NE(b1, b2); |
| EXPECT_NE(b1, b12); |
| EXPECT_NE(b12, b1); |
| } |
| |
| TEST_F(BufferTest, Dump) { |
| Buffer b; |
| b.Append(uint8_t(1)); |
| std::string s = b.Dump(); |
| } |
| |
| } // namespace |
| } // namespace glibusb |