406 lines
12 KiB
C++
406 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2010 INRIA
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*
|
|
* Author: Mathieu Lacage <mathieu.lacage@cutebugs.net>
|
|
*/
|
|
|
|
#include "ns3/buffer.h"
|
|
#include "ns3/double.h"
|
|
#include "ns3/random-variable-stream.h"
|
|
#include "ns3/test.h"
|
|
|
|
using namespace ns3;
|
|
|
|
/**
|
|
* \ingroup network
|
|
* \defgroup network-test Network module unit tests
|
|
*/
|
|
|
|
/**
|
|
* \ingroup network-test
|
|
* \ingroup tests
|
|
*
|
|
* Buffer unit tests.
|
|
*/
|
|
class BufferTest : public TestCase
|
|
{
|
|
private:
|
|
/**
|
|
* Checks the buffer content
|
|
* \param b The buffer to check
|
|
* \param n The number of bytes to check
|
|
* \param array The array of bytes that should be in the buffer
|
|
*/
|
|
void EnsureWrittenBytes(Buffer b, uint32_t n, uint8_t array[]);
|
|
|
|
public:
|
|
void DoRun() override;
|
|
BufferTest();
|
|
};
|
|
|
|
BufferTest::BufferTest()
|
|
: TestCase("Buffer")
|
|
{
|
|
}
|
|
|
|
void
|
|
BufferTest::EnsureWrittenBytes(Buffer b, uint32_t n, uint8_t array[])
|
|
{
|
|
bool success = true;
|
|
uint8_t* expected = array;
|
|
const uint8_t* got;
|
|
got = b.PeekData();
|
|
for (uint32_t j = 0; j < n; j++)
|
|
{
|
|
if (got[j] != expected[j])
|
|
{
|
|
success = false;
|
|
}
|
|
}
|
|
if (!success)
|
|
{
|
|
std::ostringstream failure;
|
|
failure << "Buffer -- ";
|
|
failure << "expected: n=";
|
|
failure << n << ", ";
|
|
failure.setf(std::ios::hex, std::ios::basefield);
|
|
for (uint32_t j = 0; j < n; j++)
|
|
{
|
|
failure << (uint16_t)expected[j] << " ";
|
|
}
|
|
failure.setf(std::ios::dec, std::ios::basefield);
|
|
failure << "got: ";
|
|
failure.setf(std::ios::hex, std::ios::basefield);
|
|
for (uint32_t j = 0; j < n; j++)
|
|
{
|
|
failure << (uint16_t)got[j] << " ";
|
|
}
|
|
failure << std::endl;
|
|
NS_TEST_ASSERT_MSG_EQ(true, false, failure.str());
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Works only when variadic macros are
|
|
* available which is the case for gcc.
|
|
*/
|
|
#define ENSURE_WRITTEN_BYTES(buffer, n, ...) \
|
|
{ \
|
|
uint8_t bytes[] = {__VA_ARGS__}; \
|
|
EnsureWrittenBytes(buffer, n, bytes); \
|
|
}
|
|
|
|
void
|
|
BufferTest::DoRun()
|
|
{
|
|
Buffer buffer;
|
|
Buffer::Iterator i;
|
|
buffer.AddAtStart(6);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0x66);
|
|
ENSURE_WRITTEN_BYTES(buffer, 1, 0x66);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0x67);
|
|
ENSURE_WRITTEN_BYTES(buffer, 1, 0x67);
|
|
i.WriteHtonU16(0x6568);
|
|
i = buffer.Begin();
|
|
ENSURE_WRITTEN_BYTES(buffer, 3, 0x67, 0x65, 0x68);
|
|
i.WriteHtonU16(0x6369);
|
|
ENSURE_WRITTEN_BYTES(buffer, 3, 0x63, 0x69, 0x68);
|
|
i.WriteHtonU32(0xdeadbeaf);
|
|
ENSURE_WRITTEN_BYTES(buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
|
|
buffer.AddAtStart(2);
|
|
i = buffer.Begin();
|
|
i.WriteU16(0);
|
|
ENSURE_WRITTEN_BYTES(buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.Begin();
|
|
i.Next(8);
|
|
i.WriteU16(0);
|
|
ENSURE_WRITTEN_BYTES(buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
|
buffer.RemoveAtStart(3);
|
|
i = buffer.Begin();
|
|
ENSURE_WRITTEN_BYTES(buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
|
buffer.RemoveAtEnd(4);
|
|
i = buffer.Begin();
|
|
ENSURE_WRITTEN_BYTES(buffer, 3, 0x69, 0xde, 0xad);
|
|
buffer.AddAtStart(1);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0xff);
|
|
ENSURE_WRITTEN_BYTES(buffer, 4, 0xff, 0x69, 0xde, 0xad);
|
|
buffer.AddAtEnd(1);
|
|
i = buffer.Begin();
|
|
i.Next(4);
|
|
i.WriteU8(0xff);
|
|
i.Prev(2);
|
|
uint16_t saved = i.ReadU16();
|
|
i.Prev(2);
|
|
i.WriteHtonU16(0xff00);
|
|
i.Prev(2);
|
|
NS_TEST_ASSERT_MSG_EQ(i.ReadNtohU16(), 0xff00, "Could not read expected value");
|
|
i.Prev(2);
|
|
i.WriteU16(saved);
|
|
ENSURE_WRITTEN_BYTES(buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
|
|
Buffer o = buffer;
|
|
ENSURE_WRITTEN_BYTES(o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
|
|
o.AddAtStart(1);
|
|
i = o.Begin();
|
|
i.WriteU8(0xfe);
|
|
ENSURE_WRITTEN_BYTES(o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
|
|
buffer.AddAtStart(2);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0xfd);
|
|
i.WriteU8(0xfd);
|
|
ENSURE_WRITTEN_BYTES(o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
|
|
ENSURE_WRITTEN_BYTES(buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
|
|
|
|
// test 64-bit read/write
|
|
Buffer buff64;
|
|
buff64.AddAtStart(8);
|
|
i = buff64.Begin();
|
|
i.WriteU64(0x0123456789ABCDEFLLU);
|
|
i = buff64.Begin();
|
|
NS_TEST_ASSERT_MSG_EQ(i.ReadU64(), 0x0123456789abcdefLLU, "Could not read expected value");
|
|
i = buff64.Begin();
|
|
i.WriteHtolsbU64(0x0123456789ABCDEFLLU);
|
|
ENSURE_WRITTEN_BYTES(buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
|
|
i = buff64.Begin();
|
|
NS_TEST_ASSERT_MSG_EQ(i.ReadLsbtohU64(),
|
|
0x0123456789abcdefLLU,
|
|
"Could not read expected value");
|
|
i = buff64.Begin();
|
|
i.WriteHtonU64(0x0123456789ABCDEFLLU);
|
|
ENSURE_WRITTEN_BYTES(buff64, 8, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef);
|
|
i = buff64.Begin();
|
|
NS_TEST_ASSERT_MSG_EQ(i.ReadNtohU64(), 0x0123456789abcdefLLU, "could not read expected value");
|
|
|
|
// test self-assignment
|
|
{
|
|
Buffer a = o;
|
|
#if defined(__clang__)
|
|
#if __has_warning("-Wself-assign-overloaded")
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wself-assign-overloaded"
|
|
#endif
|
|
#endif
|
|
a = a;
|
|
#if defined(__clang__)
|
|
#if __has_warning("-Wself-assign-overloaded")
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
// test Remove start.
|
|
buffer = Buffer(5);
|
|
ENSURE_WRITTEN_BYTES(buffer, 5, 0, 0, 0, 0, 0);
|
|
buffer.RemoveAtStart(1);
|
|
ENSURE_WRITTEN_BYTES(buffer, 4, 0, 0, 0, 0);
|
|
buffer.AddAtStart(1);
|
|
buffer.Begin().WriteU8(0xff);
|
|
ENSURE_WRITTEN_BYTES(buffer, 5, 0xff, 0, 0, 0, 0);
|
|
buffer.RemoveAtStart(3);
|
|
ENSURE_WRITTEN_BYTES(buffer, 2, 0, 0);
|
|
buffer.AddAtStart(4);
|
|
buffer.Begin().WriteHtonU32(0xdeadbeaf);
|
|
ENSURE_WRITTEN_BYTES(buffer, 6, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
|
|
buffer.RemoveAtStart(2);
|
|
ENSURE_WRITTEN_BYTES(buffer, 4, 0xbe, 0xaf, 0, 0);
|
|
buffer.AddAtEnd(4);
|
|
i = buffer.Begin();
|
|
i.Next(4);
|
|
i.WriteHtonU32(0xdeadbeaf);
|
|
ENSURE_WRITTEN_BYTES(buffer, 8, 0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
|
|
buffer.RemoveAtStart(5);
|
|
ENSURE_WRITTEN_BYTES(buffer, 3, 0xad, 0xbe, 0xaf);
|
|
// test Remove end
|
|
buffer = Buffer(5);
|
|
ENSURE_WRITTEN_BYTES(buffer, 5, 0, 0, 0, 0, 0);
|
|
buffer.RemoveAtEnd(1);
|
|
ENSURE_WRITTEN_BYTES(buffer, 4, 0, 0, 0, 0);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.Begin();
|
|
i.Next(4);
|
|
i.WriteU8(0xab);
|
|
i.WriteU8(0xac);
|
|
ENSURE_WRITTEN_BYTES(buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
|
|
buffer.RemoveAtEnd(1);
|
|
ENSURE_WRITTEN_BYTES(buffer, 5, 0, 0, 0, 0, 0xab);
|
|
buffer.RemoveAtEnd(3);
|
|
ENSURE_WRITTEN_BYTES(buffer, 2, 0, 0);
|
|
buffer.AddAtEnd(6);
|
|
i = buffer.Begin();
|
|
i.Next(2);
|
|
i.WriteU8(0xac);
|
|
i.WriteU8(0xad);
|
|
i.WriteU8(0xae);
|
|
i.WriteU8(0xaf);
|
|
i.WriteU8(0xba);
|
|
i.WriteU8(0xbb);
|
|
ENSURE_WRITTEN_BYTES(buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
|
|
buffer.AddAtStart(3);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0x30);
|
|
i.WriteU8(0x31);
|
|
i.WriteU8(0x32);
|
|
ENSURE_WRITTEN_BYTES(buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
|
|
buffer.RemoveAtEnd(9);
|
|
ENSURE_WRITTEN_BYTES(buffer, 2, 0x30, 0x31);
|
|
buffer = Buffer(3);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.Begin();
|
|
i.Next(3);
|
|
i.WriteHtonU16(0xabcd);
|
|
buffer.AddAtStart(1);
|
|
buffer.Begin().WriteU8(0x21);
|
|
ENSURE_WRITTEN_BYTES(buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
|
|
buffer.RemoveAtEnd(8);
|
|
NS_TEST_ASSERT_MSG_EQ(buffer.GetSize(), 0, "Buffer size not zero");
|
|
|
|
buffer = Buffer(6);
|
|
buffer.AddAtStart(9);
|
|
buffer.AddAtEnd(3);
|
|
i = buffer.End();
|
|
i.Prev(1);
|
|
i.WriteU8(1, 1);
|
|
|
|
buffer = Buffer(6);
|
|
buffer.AddAtStart(3);
|
|
buffer.RemoveAtEnd(8);
|
|
buffer.AddAtEnd(4);
|
|
i = buffer.End();
|
|
i.Prev(4);
|
|
i.WriteU8(1, 4);
|
|
|
|
buffer = Buffer(1);
|
|
buffer.AddAtEnd(100);
|
|
i = buffer.End();
|
|
i.Prev(100);
|
|
i.WriteU8(1, 100);
|
|
|
|
// See \bugid{54}
|
|
{
|
|
const uint32_t actualSize = 72602;
|
|
const uint32_t chunkSize = 67624;
|
|
Ptr<UniformRandomVariable> bytesRng = CreateObject<UniformRandomVariable>();
|
|
bytesRng->SetAttribute("Min", DoubleValue(0));
|
|
bytesRng->SetAttribute("Max", DoubleValue(256));
|
|
|
|
Buffer inputBuffer;
|
|
Buffer outputBuffer;
|
|
|
|
inputBuffer.AddAtEnd(actualSize);
|
|
{
|
|
Buffer::Iterator iter = inputBuffer.Begin();
|
|
for (uint32_t i = 0; i < actualSize; i++)
|
|
{
|
|
iter.WriteU8(static_cast<uint8_t>(bytesRng->GetValue()));
|
|
}
|
|
}
|
|
|
|
outputBuffer.AddAtEnd(chunkSize);
|
|
Buffer::Iterator iter = outputBuffer.End();
|
|
iter.Prev(chunkSize);
|
|
iter.Write(inputBuffer.PeekData(), chunkSize);
|
|
|
|
NS_TEST_EXPECT_MSG_EQ(memcmp(inputBuffer.PeekData(), outputBuffer.PeekData(), chunkSize),
|
|
0,
|
|
"memcp works");
|
|
}
|
|
|
|
buffer = Buffer(5);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.End();
|
|
i.Prev(2);
|
|
i.WriteU8(0);
|
|
i.WriteU8(0x66);
|
|
ENSURE_WRITTEN_BYTES(buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
|
|
Buffer frag0 = buffer.CreateFragment(0, 2);
|
|
ENSURE_WRITTEN_BYTES(frag0, 2, 0x00, 0x00);
|
|
Buffer frag1 = buffer.CreateFragment(2, 5);
|
|
ENSURE_WRITTEN_BYTES(frag1, 5, 0x00, 0x00, 0x00, 0x00, 0x66);
|
|
frag0.AddAtEnd(frag1);
|
|
ENSURE_WRITTEN_BYTES(buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
|
|
ENSURE_WRITTEN_BYTES(frag0, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
|
|
|
|
buffer = Buffer(5);
|
|
buffer.AddAtStart(2);
|
|
i = buffer.Begin();
|
|
i.WriteU8(0x1);
|
|
i.WriteU8(0x2);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.End();
|
|
i.Prev(2);
|
|
i.WriteU8(0x3);
|
|
i.WriteU8(0x4);
|
|
ENSURE_WRITTEN_BYTES(buffer, 9, 0x1, 0x2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3, 0x4);
|
|
Buffer other;
|
|
other.AddAtStart(9);
|
|
i = other.Begin();
|
|
i.Write(buffer.Begin(), buffer.End());
|
|
ENSURE_WRITTEN_BYTES(other, 9, 0x1, 0x2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3, 0x4);
|
|
|
|
// See \bugid{1001}
|
|
std::string ct("This is the next content of the buffer.");
|
|
buffer = Buffer();
|
|
buffer.AddAtStart(ct.size());
|
|
i = buffer.Begin();
|
|
i.Write((const uint8_t*)ct.c_str(), ct.size());
|
|
uint32_t sizeBuffer = buffer.GetSize();
|
|
NS_TEST_ASSERT_MSG_EQ(sizeBuffer, ct.size(), "Buffer bad size");
|
|
const uint8_t* evilBuffer = buffer.PeekData();
|
|
NS_TEST_ASSERT_MSG_NE(evilBuffer, 0, "Buffer PeekData failed");
|
|
auto cBuf = (uint8_t*)malloc(sizeBuffer);
|
|
uint32_t copyLen = buffer.CopyData(cBuf, sizeBuffer);
|
|
NS_TEST_ASSERT_MSG_EQ(copyLen, sizeBuffer, "CopyData return bad size");
|
|
for (uint32_t i = 0; i < sizeBuffer; i++)
|
|
{
|
|
NS_TEST_ASSERT_MSG_EQ(cBuf[i],
|
|
*(((const uint8_t*)ct.c_str()) + i),
|
|
"Bad buffer copied data");
|
|
NS_TEST_ASSERT_MSG_EQ(evilBuffer[i], cBuf[i], "Bad buffer peeked");
|
|
}
|
|
free(cBuf);
|
|
|
|
// See \bugid{2044} Will not pass without bug2044 fix.
|
|
buffer = Buffer(1);
|
|
buffer.AddAtEnd(2);
|
|
i = buffer.Begin();
|
|
i.Next(1);
|
|
i.WriteU8(0x77);
|
|
i.WriteU8(0x66);
|
|
ENSURE_WRITTEN_BYTES(buffer, 3, 0x00, 0x77, 0x66);
|
|
i = buffer.Begin();
|
|
i.ReadU8();
|
|
uint16_t val1 = i.ReadNtohU16();
|
|
i = buffer.Begin();
|
|
i.ReadU8();
|
|
uint16_t val2 = 0;
|
|
val2 |= i.ReadU8();
|
|
val2 <<= 8;
|
|
val2 |= i.ReadU8();
|
|
NS_TEST_ASSERT_MSG_EQ(val1, val2, "Bad ReadNtohU16()");
|
|
}
|
|
|
|
/**
|
|
* \ingroup network-test
|
|
* \ingroup tests
|
|
*
|
|
* \brief Buffer TestSuite
|
|
*/
|
|
class BufferTestSuite : public TestSuite
|
|
{
|
|
public:
|
|
BufferTestSuite();
|
|
};
|
|
|
|
BufferTestSuite::BufferTestSuite()
|
|
: TestSuite("buffer", Type::UNIT)
|
|
{
|
|
AddTestCase(new BufferTest, TestCase::Duration::QUICK);
|
|
}
|
|
|
|
static BufferTestSuite g_bufferTestSuite; //!< Static variable for test initialization
|