Files
unison/src/network/test/buffer-test.cc
2024-09-06 19:32:31 +00:00

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