#include "cx/buffer.h"
#include <gtest/gtest.h>
#include "util_allocator.h"
class BufferFixture : public ::testing::Test {
protected:
void SetUp() override {
cxBufferInit(&buf, nullptr,
16, cxDefaultAllocator,
CX_BUFFER_DEFAULT);
buf.size =
6;
buf.pos =
3;
}
void TearDown() override {
cxBufferDestroy(&buf);
}
CxBuffer buf{};
};
static void expect_default_flush_config(CxBuffer *buf) {
EXPECT_EQ(buf->flush_blkmax,
0);
EXPECT_EQ(buf->flush_blksize,
4096);
EXPECT_EQ(buf->flush_threshold,
SIZE_MAX);
EXPECT_EQ(buf->flush_func, nullptr);
EXPECT_EQ(buf->flush_target, nullptr);
}
TEST(BufferInit, WrapSpace) {
CxTestingAllocator alloc;
CxBuffer buf;
void *space = cxMalloc(&alloc,
16);
cxBufferInit(&buf, space,
16, &alloc,
CX_BUFFER_DEFAULT);
expect_default_flush_config(&buf);
EXPECT_EQ(buf.space, space);
EXPECT_EQ(buf.flags &
CX_BUFFER_AUTO_EXTEND,
0);
EXPECT_EQ(buf.flags &
CX_BUFFER_FREE_CONTENTS,
0);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.capacity,
16);
EXPECT_EQ(buf.allocator, &alloc);
cxBufferDestroy(&buf);
EXPECT_FALSE(alloc.verify());
cxFree(&alloc, space);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferInit, WrapSpaceAutoExtend) {
CxTestingAllocator alloc;
CxBuffer buf;
void *space = cxMalloc(&alloc,
16);
cxBufferInit(&buf, space,
16, &alloc,
CX_BUFFER_AUTO_EXTEND);
expect_default_flush_config(&buf);
EXPECT_EQ(buf.space, space);
EXPECT_EQ(buf.flags &
CX_BUFFER_AUTO_EXTEND,
CX_BUFFER_AUTO_EXTEND);
EXPECT_EQ(buf.flags &
CX_BUFFER_FREE_CONTENTS,
0);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.capacity,
16);
EXPECT_EQ(buf.allocator, &alloc);
cxBufferDestroy(&buf);
EXPECT_FALSE(alloc.verify());
cxFree(&alloc, space);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferInit, WrapSpaceAutoFree) {
CxTestingAllocator alloc;
CxBuffer buf;
void *space = cxMalloc(&alloc,
16);
cxBufferInit(&buf, space,
16, &alloc,
CX_BUFFER_FREE_CONTENTS);
expect_default_flush_config(&buf);
EXPECT_EQ(buf.space, space);
EXPECT_EQ(buf.flags &
CX_BUFFER_AUTO_EXTEND,
0);
EXPECT_EQ(buf.flags &
CX_BUFFER_FREE_CONTENTS,
CX_BUFFER_FREE_CONTENTS);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.capacity,
16);
EXPECT_EQ(buf.allocator, &alloc);
EXPECT_FALSE(alloc.verify());
cxBufferDestroy(&buf);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferInit, FreshSpace) {
CxTestingAllocator alloc;
CxBuffer buf;
cxBufferInit(&buf, nullptr,
8, &alloc,
CX_BUFFER_DEFAULT);
expect_default_flush_config(&buf);
EXPECT_NE(buf.space, nullptr);
EXPECT_EQ(buf.flags &
CX_BUFFER_AUTO_EXTEND,
0);
EXPECT_EQ(buf.flags &
CX_BUFFER_FREE_CONTENTS,
CX_BUFFER_FREE_CONTENTS);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(buf.allocator, &alloc);
EXPECT_FALSE(alloc.verify());
cxBufferDestroy(&buf);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferInit, OnHeap) {
CxTestingAllocator alloc;
CxBuffer *buf;
void *space = cxMalloc(&alloc,
16);
buf = cxBufferCreate(space,
16, &alloc,
CX_BUFFER_FREE_CONTENTS);
EXPECT_NE(buf, nullptr);
expect_default_flush_config(buf);
EXPECT_EQ(buf->space, space);
EXPECT_EQ(buf->flags &
CX_BUFFER_AUTO_EXTEND,
0);
EXPECT_EQ(buf->flags &
CX_BUFFER_FREE_CONTENTS,
CX_BUFFER_FREE_CONTENTS);
EXPECT_EQ(buf->pos,
0);
EXPECT_EQ(buf->size,
0);
EXPECT_EQ(buf->capacity,
16);
EXPECT_EQ(buf->allocator, &alloc);
cxBufferFree(buf);
EXPECT_TRUE(alloc.verify());
}
class BufferShiftFixture : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(alloc.verify());
cxBufferInit(&buf, nullptr,
16, &alloc,
CX_BUFFER_DEFAULT);
memcpy(buf.space,
"test____________",
16);
buf.capacity =
8;
buf.pos =
4;
buf.size =
4;
}
void TearDown() override {
cxBufferDestroy(&buf);
EXPECT_TRUE(alloc.verify());
}
CxTestingAllocator alloc;
CxBuffer buf{};
};
class BufferShiftLeft : public BufferShiftFixture {
};
TEST_F(BufferShiftLeft, Zero) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShiftLeft(&buf,
0);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftLeft, ZeroOffsetInterface) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShift(&buf, -
0);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftLeft, Standard) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShiftLeft(&buf,
2);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
2);
EXPECT_EQ(buf.size,
2);
EXPECT_TRUE(memcmp(buf.space,
"stst________",
8) ==
0);
}
TEST_F(BufferShiftLeft, Overshift) {
ASSERT_LT(buf.pos,
6);
ASSERT_LT(buf.size,
6);
int ret = cxBufferShiftLeft(&buf,
6);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftLeft, OvershiftPosOnly) {
buf.pos =
2;
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShiftLeft(&buf,
3);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
1);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftLeft, OffsetInterface) {
buf.pos =
3;
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShift(&buf, -
2);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
1);
EXPECT_EQ(buf.size,
2);
EXPECT_TRUE(memcmp(buf.space,
"stst________",
8) ==
0);
}
class BufferShiftRight : public BufferShiftFixture {
};
TEST_F(BufferShiftRight, Zero) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShiftRight(&buf,
0);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftRight, ZeroOffsetInterface) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShift(&buf, +
0);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_TRUE(memcmp(buf.space,
"test________",
8) ==
0);
}
TEST_F(BufferShiftRight, Standard) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShiftRight(&buf,
3);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
7);
EXPECT_EQ(buf.size,
7);
EXPECT_TRUE(memcmp(buf.space,
"testest_____",
8) ==
0);
}
TEST_F(BufferShiftRight, OvershiftDiscard) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
ASSERT_EQ(buf.capacity,
8);
int ret = cxBufferShiftRight(&buf,
6);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_TRUE(memcmp(buf.space,
"test__te____",
8) ==
0);
}
TEST_F(BufferShiftRight, OvershiftExtend) {
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
ASSERT_EQ(buf.capacity,
8);
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
int ret = cxBufferShiftRight(&buf,
6);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
10);
EXPECT_EQ(buf.size,
10);
EXPECT_GE(buf.capacity,
10);
EXPECT_TRUE(memcmp(buf.space,
"test__test__",
8) ==
0);
}
TEST_F(BufferShiftRight, OffsetInterface) {
buf.pos =
3;
ASSERT_EQ(buf.size,
4);
int ret = cxBufferShift(&buf,
2);
EXPECT_EQ(ret,
0);
EXPECT_EQ(buf.pos,
5);
EXPECT_EQ(buf.size,
6);
EXPECT_TRUE(memcmp(buf.space,
"tetest______",
8) ==
0);
}
TEST(BufferMinimumCapacity, Sufficient) {
CxTestingAllocator alloc;
auto space = cxMalloc(&alloc,
8);
CxBuffer buf;
cxBufferInit(&buf, space,
8, &alloc,
CX_BUFFER_FREE_CONTENTS);
memcpy(space,
"Testing",
8);
buf.size =
8;
cxBufferMinimumCapacity(&buf,
6);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(buf.size,
8);
EXPECT_TRUE(memcmp(buf.space,
"Testing",
8) ==
0);
cxBufferDestroy(&buf);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferMinimumCapacity, Extend) {
CxTestingAllocator alloc;
auto space = cxMalloc(&alloc,
8);
CxBuffer buf;
cxBufferInit(&buf, space,
8, &alloc,
CX_BUFFER_FREE_CONTENTS);
memcpy(space,
"Testing",
8);
buf.size =
8;
cxBufferMinimumCapacity(&buf,
16);
EXPECT_EQ(buf.capacity,
16);
EXPECT_EQ(buf.size,
8);
EXPECT_TRUE(memcmp(buf.space,
"Testing",
8) ==
0);
cxBufferDestroy(&buf);
EXPECT_TRUE(alloc.verify());
}
TEST(BufferClear, Test) {
char space[
16];
strcpy(space,
"clear test");
CxBuffer buf;
cxBufferInit(&buf, space,
16, cxDefaultAllocator,
CX_BUFFER_DEFAULT);
ASSERT_EQ(buf.size,
0);
cxBufferClear(&buf);
EXPECT_EQ(memcmp(space,
"clear test",
10),
0);
buf.size =
5;
buf.pos =
3;
cxBufferClear(&buf);
EXPECT_EQ(memcmp(space,
"\0\0\0\0\0 test",
10),
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.pos,
0);
cxBufferDestroy(&buf);
}
class BufferWrite : public ::testing::Test {
protected:
CxBuffer buf{}, target{};
void SetUp() override {
cxBufferInit(&target, nullptr,
16, cxDefaultAllocator,
CX_BUFFER_AUTO_EXTEND);
cxBufferInit(&buf, nullptr,
16, cxDefaultAllocator,
CX_BUFFER_DEFAULT);
buf.capacity =
8;
memset(buf.space,
0,
16);
memcpy(buf.space,
"prep",
4);
buf.size = buf.pos =
4;
}
void TearDown() override {
cxBufferDestroy(&buf);
cxBufferDestroy(&target);
}
void enableFlushing() {
buf.flush_target = ⌖
buf.flush_func = reinterpret_cast<cx_write_func>(cxBufferWrite);
buf.flush_blkmax =
1;
}
};
static size_t mock_write_limited_rate(
void const *ptr,
size_t size,
__attribute__((unused))
size_t nitems,
CxBuffer *buffer
) {
static bool full = false;
if (full) {
full = false;
return 0;
}
else {
full = true;
return cxBufferWrite(ptr, size, nitems >
2 ?
2 : nitems, buffer);
}
}
TEST_F(BufferWrite, SizeOneFit) {
const char *data =
"test";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
1,
4, &buf);
EXPECT_EQ(written,
4);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"preptest",
8),
0);
}
TEST_F(BufferWrite, SizeOneDiscard) {
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
1,
7, &buf);
EXPECT_EQ(written,
4);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"preptest\0",
9),
0);
}
TEST_F(BufferWrite, SizeOneExtend) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
1,
7, &buf);
EXPECT_EQ(written,
7);
EXPECT_EQ(buf.size,
11);
EXPECT_EQ(buf.pos,
11);
EXPECT_GE(buf.capacity,
11);
EXPECT_EQ(memcmp(buf.space,
"preptesting",
11),
0);
}
TEST_F(BufferWrite, MultibyteFit) {
const char *data =
"test";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
2,
2, &buf);
EXPECT_EQ(written,
2);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"preptest",
8),
0);
}
TEST_F(BufferWrite, MultibyteDiscard) {
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.size,
4);
buf.pos =
3;
size_t written = cxBufferWrite(data,
2,
4, &buf);
EXPECT_EQ(written,
2);
EXPECT_EQ(buf.size,
7);
EXPECT_EQ(buf.pos,
7);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"pretest\0",
8),
0);
}
TEST_F(BufferWrite, MultibyteExtend) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
const char *data =
"tester";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.size,
4);
buf.pos =
3;
size_t written = cxBufferWrite(data,
2,
3, &buf);
EXPECT_EQ(written,
3);
EXPECT_EQ(buf.size,
9);
EXPECT_EQ(buf.pos,
9);
EXPECT_GE(buf.capacity,
9);
EXPECT_EQ(memcmp(buf.space,
"pretester",
9),
0);
}
TEST_F(BufferWrite, PutcWrapperFit) {
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
int c = cxBufferPut(&buf, 0x200 |
'a');
EXPECT_EQ(c,
'a');
EXPECT_EQ(buf.size,
5);
EXPECT_EQ(buf.pos,
5);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"prepa\0",
6),
0);
}
TEST_F(BufferWrite, PutcWrapperDiscard) {
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.size,
4);
buf.pos =
8;
int c = cxBufferPut(&buf, 0x200 |
'a');
EXPECT_EQ(c,
EOF);
EXPECT_EQ(buf.size,
4);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"prep\0\0\0\0\0",
9),
0);
}
TEST_F(BufferWrite, PutcWrapperExtend) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.size,
4);
buf.pos =
8;
int c = cxBufferPut(&buf, 0x200 |
'a');
EXPECT_EQ(c,
'a');
EXPECT_EQ(buf.size,
9);
EXPECT_EQ(buf.pos,
9);
EXPECT_GE(buf.capacity,
9);
EXPECT_EQ(memcmp(buf.space,
"prep\0\0\0\0a",
9),
0);
}
TEST_F(BufferWrite, PutStringWrapperFit) {
const char *data =
"test";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferPutString(&buf, data);
EXPECT_EQ(written,
4);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"preptest",
8),
0);
}
TEST_F(BufferWrite, PutStringWrapperDiscard) {
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferPutString(&buf, data);
EXPECT_EQ(written,
4);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
8);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
"preptest\0",
9),
0);
}
TEST_F(BufferWrite, PutStringWrapperExtend) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferPutString(&buf, data);
EXPECT_EQ(written,
7);
EXPECT_EQ(buf.size,
11);
EXPECT_EQ(buf.pos,
11);
EXPECT_GE(buf.capacity,
11);
EXPECT_EQ(memcmp(buf.space,
"preptesting",
11),
0);
}
TEST_F(BufferWrite, MultOverflow) {
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
8,
SIZE_MAX /
4, &buf);
EXPECT_EQ(written,
0);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_EQ(memcmp(buf.space,
"prep\0",
5),
0);
}
TEST_F(BufferWrite, MaxCapaOverflow) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
const char *data =
"testing";
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
ASSERT_EQ(buf.size,
4);
size_t written = cxBufferWrite(data,
1,
SIZE_MAX -
2, &buf);
EXPECT_EQ(written,
0);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(buf.pos,
4);
EXPECT_EQ(buf.size,
4);
EXPECT_EQ(memcmp(buf.space,
"prep\0",
5),
0);
}
TEST_F(BufferWrite, OnlyOverwrite) {
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
ASSERT_EQ(buf.capacity,
8);
memcpy(buf.space,
"preptest",
8);
buf.pos =
3;
buf.size =
8;
size_t written = cxBufferWrite(
"XXX",
2,
2, &buf);
EXPECT_EQ(written,
2);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(buf.size,
8);
EXPECT_EQ(buf.pos,
7);
EXPECT_EQ(memcmp(buf.space,
"preXXX\0t",
8),
0);
}
TEST_F(BufferWrite, FlushAtCapacity) {
enableFlushing();
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
size_t written = cxBufferWrite(
"foo",
1,
3, &buf);
EXPECT_EQ(written,
3);
ASSERT_EQ(buf.pos,
7);
ASSERT_EQ(buf.size,
7);
ASSERT_EQ(target.pos,
0);
ASSERT_EQ(target.size,
0);
written = cxBufferWrite(
"hello",
1,
5, &buf);
EXPECT_EQ(written,
5);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(target.pos,
12);
ASSERT_EQ(target.size,
12);
EXPECT_EQ(memcmp(target.space,
"prepfoohello",
12),
0);
}
TEST_F(BufferWrite, FlushAtThreshold) {
enableFlushing();
buf.flush_threshold =
12;
buf.flags |=
CX_BUFFER_AUTO_EXTEND;
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
size_t written = cxBufferWrite(
"foobar",
1,
6, &buf);
EXPECT_EQ(written,
6);
ASSERT_EQ(buf.pos,
10);
ASSERT_EQ(buf.size,
10);
ASSERT_GE(buf.capacity,
10);
ASSERT_LE(buf.capacity,
12);
ASSERT_EQ(target.pos,
0);
ASSERT_EQ(target.size,
0);
written = cxBufferWrite(
"hello",
1,
5, &buf);
EXPECT_EQ(written,
5);
EXPECT_EQ(buf.pos,
0);
EXPECT_EQ(buf.size,
0);
EXPECT_LE(buf.capacity,
12);
EXPECT_EQ(target.pos,
15);
ASSERT_EQ(target.size,
15);
EXPECT_EQ(memcmp(target.space,
"prepfoobarhello",
15),
0);
}
TEST_F(BufferWrite, FlushRateLimited) {
enableFlushing();
target.capacity =
16;
target.flags &= ~
CX_BUFFER_AUTO_EXTEND;
buf.flush_func = (cx_write_func) mock_write_limited_rate;
ASSERT_EQ(buf.capacity,
8);
ASSERT_EQ(buf.pos,
4);
size_t written = cxBufferWrite(
"foo",
1,
3, &buf);
EXPECT_EQ(written,
3);
ASSERT_EQ(buf.pos,
7);
ASSERT_EQ(buf.size,
7);
ASSERT_EQ(target.pos,
0);
ASSERT_EQ(target.size,
0);
written = cxBufferWrite(
"hello, world!",
1,
13, &buf);
EXPECT_EQ(written,
13);
EXPECT_EQ(buf.pos,
7);
EXPECT_EQ(buf.size,
7);
EXPECT_EQ(buf.capacity,
8);
EXPECT_EQ(memcmp(buf.space,
" world!",
7),
0);
EXPECT_EQ(target.pos,
13);
ASSERT_EQ(target.size,
13);
EXPECT_EQ(target.capacity,
16);
EXPECT_EQ(memcmp(target.space,
"prepfoohello,",
13),
0);
}
class BufferSeek : public BufferFixture {
};
TEST_F(BufferSeek, SetZero) {
int result = cxBufferSeek(&buf,
0,
SEEK_SET);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
0);
}
TEST_F(BufferSeek, SetValid) {
int result = cxBufferSeek(&buf,
5,
SEEK_SET);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
5);
}
TEST_F(BufferSeek, SetInvalid) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf,
6,
SEEK_SET);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, CurZero) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf,
0,
SEEK_CUR);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, CurValidPositive) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf,
2,
SEEK_CUR);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
5);
}
TEST_F(BufferSeek, CurValidNegative) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf, -
3,
SEEK_CUR);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
0);
}
TEST_F(BufferSeek, CurInvalidPositive) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf,
3,
SEEK_CUR);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, CurInvalidNegative) {
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf, -
4,
SEEK_CUR);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, EndZero) {
ASSERT_EQ(buf.size,
6);
int result = cxBufferSeek(&buf,
0,
SEEK_END);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, EndValid) {
ASSERT_EQ(buf.size,
6);
int result = cxBufferSeek(&buf, -
6,
SEEK_END);
EXPECT_EQ(result,
0);
EXPECT_EQ(buf.pos,
0);
}
TEST_F(BufferSeek, EndInvalid) {
ASSERT_EQ(buf.size,
6);
int result = cxBufferSeek(&buf,
1,
SEEK_END);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.pos,
3);
}
TEST_F(BufferSeek, WhenceInvalid) {
ASSERT_EQ(buf.size,
6);
ASSERT_EQ(buf.pos,
3);
int result = cxBufferSeek(&buf,
2,
9000);
EXPECT_NE(result,
0);
EXPECT_EQ(buf.size,
6);
EXPECT_EQ(buf.pos,
3);
}
class BufferEof : public BufferFixture {
};
TEST_F(BufferEof, Reached) {
buf.pos = buf.size;
EXPECT_TRUE(cxBufferEof(&buf));
buf.pos = buf.size -
1;
ASSERT_FALSE(cxBufferEof(&buf));
cxBufferPut(&buf,
'a');
EXPECT_TRUE(cxBufferEof(&buf));
}
TEST_F(BufferEof, NotReached) {
buf.pos = buf.size -
1;
EXPECT_FALSE(cxBufferEof(&buf));
buf.pos =
0;
cxBufferWrite(
"test",
1,
5, &buf);
EXPECT_FALSE(cxBufferEof(&buf));
}
class BufferRead : public ::testing::Test {
protected:
CxBuffer buf{};
void SetUp() override {
cxBufferInit(&buf, nullptr,
16, cxDefaultAllocator,
CX_BUFFER_DEFAULT);
buf.capacity =
8;
memset(buf.space,
0,
16);
memcpy(buf.space,
"some data",
9);
buf.size =
9;
}
void TearDown() override {
cxBufferDestroy(&buf);
}
};
TEST_F(BufferRead, GetByte) {
buf.pos =
2;
EXPECT_EQ(cxBufferGet(&buf),
'm');
EXPECT_EQ(cxBufferGet(&buf),
'e');
EXPECT_EQ(cxBufferGet(&buf),
' ');
EXPECT_EQ(cxBufferGet(&buf),
'd');
EXPECT_EQ(buf.pos,
6);
}
TEST_F(BufferRead, GetEof) {
buf.pos = buf.size;
EXPECT_EQ(cxBufferGet(&buf),
EOF);
}
TEST_F(BufferRead, ReadWithinBounds) {
buf.pos =
2;
char target[
4];
auto read = cxBufferRead(&target,
1,
4, &buf);
ASSERT_EQ(read,
4);
EXPECT_EQ(memcmp(&target,
"me d",
4),
0);
EXPECT_EQ(buf.pos,
6);
}
TEST_F(BufferRead, ReadOutOfBounds) {
buf.pos =
6;
char target[
4];
auto read = cxBufferRead(&target,
1,
4, &buf);
ASSERT_EQ(read,
3);
EXPECT_EQ(memcmp(&target,
"ata",
3),
0);
EXPECT_EQ(buf.pos,
9);
}
TEST_F(BufferRead, ReadOutOfBoundsMultibyte) {
buf.pos =
6;
char target[
4];
target[
2] =
'\0';
auto read = cxBufferRead(&target,
2,
2, &buf);
ASSERT_EQ(read,
1);
EXPECT_EQ(memcmp(&target,
"at\0",
3),
0);
EXPECT_EQ(buf.pos,
8);
}
TEST_F(BufferRead, ReadEof) {
buf.pos =
9;
char target[
4];
auto read = cxBufferRead(&target,
1,
1, &buf);
ASSERT_EQ(read,
0);
EXPECT_EQ(buf.pos,
9);
}