#include "base/include/buffer.h"
#include <cstdlib>
#include <cstring>
#include "base/include/path_utils.h"
#include "third_party/googletest/googletest/include/gtest/gtest.h"
#if OS_WIN
static const char kChars[] =
"0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char *mkdtemp(char *tmpl) {
int len = (int)strlen(tmpl);
if (len < 6 || strcmp(&tmpl[len - 6], "XXXXXX")) {
return NULL;
}
char *XXXXXX = &tmpl[len - 6];
unsigned long num = rand();
for (int i = 0; i < 1000; i++) {
unsigned long v = num;
for (int j = 0; j < 6; j++) {
XXXXXX[j] = kChars[v % 63];
v /= 63;
}
int fd = _mkdir(tmpl);
if (fd == 0) {
return tmpl;
}
if (errno != EEXIST) {
break;
}
num += 137;
}
return NULL;
}
#endif
namespace lynx {
namespace base {
namespace testing {
class BufferTest : public ::testing::Test {
public:
static void SetUpTestSuite() {
char *dir = mkdtemp(path.data());
ASSERT_NE(dir, nullptr);
}
static void TearDownTestSuite() {
#if OS_WIN
int ret = _rmdir(path.data());
#else
int ret = remove(path.data());
#endif
ASSERT_EQ(ret, 0);
}
static std::string path;
protected:
void SetUp() override {
file_path_ = PathUtils::JoinPaths(
{path,
::testing::UnitTest::GetInstance()->current_test_info()->name()});
}
void TearDown() override { remove(file_path_.c_str()); }
std::string file_path_;
};
std::string BufferTest::path = "BufferTestXXXXXX";
TEST_F(BufferTest, ReadWriteFile) {
StringBuffer write_data("FirstFirstFirstWriteData");
ASSERT_TRUE(write_data.WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_);
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), write_data.size());
ASSERT_EQ(memcmp(read_data->data(), write_data.data(), write_data.size()), 0);
ASSERT_EQ(read_data->data()[read_data->size()], 0);
}
TEST_F(BufferTest, ReadWriteBinaryFile) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < 256; ++i) {
bytes.push_back(static_cast<uint8_t>(i));
}
ByteBuffer write_data(
std::make_shared<const std::vector<uint8_t>>(std::move(bytes)));
ASSERT_TRUE(write_data.WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_);
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), write_data.size());
ASSERT_EQ(memcmp(read_data->data(), write_data.data(), write_data.size()), 0);
}
TEST_F(BufferTest, ReadWriteEmptyFile) {
ASSERT_TRUE(ByteRefBuffer(nullptr, 0).WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_, 0);
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), 0u);
}
TEST_F(BufferTest, WriteFileToExisted) {
ASSERT_TRUE(StringBuffer("FirstFirstFirstWriteData").WriteToFile(file_path_));
const std::string write_data = "AnotherWriteData";
ASSERT_TRUE(StringRefBuffer(write_data).WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_);
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), write_data.size());
ASSERT_EQ(memcmp(read_data->data(), write_data.data(), write_data.size()), 0);
}
TEST_F(BufferTest, WriteToNonExistedDir) {
auto file_path = PathUtils::JoinPaths({path, "not_existed", "ReadWriteFile"});
ASSERT_FALSE(StringBuffer("WriteData").WriteToFile(file_path));
}
TEST_F(BufferTest, ReadNonExistedFile) {
ASSERT_EQ(Buffer::ReadFromFile(file_path_), nullptr);
}
TEST_F(BufferTest, ReadFileTooLarge) {
StringBuffer write_data("FirstFirstFirstWriteData");
ASSERT_TRUE(write_data.WriteToFile(file_path_));
ASSERT_EQ(Buffer::ReadFromFile(file_path_, write_data.size() - 1), nullptr);
}
TEST_F(BufferTest, ReadFileAtSizeLimit) {
const uint8_t bytes[] = {0, 1, 127, 255};
ASSERT_TRUE(ByteRefBuffer(bytes, sizeof(bytes)).WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_, sizeof(bytes));
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), sizeof(bytes));
ASSERT_EQ(memcmp(read_data->data(), bytes, sizeof(bytes)), 0);
}
TEST_F(BufferTest, InvalidBufferDoesNotTruncateFile) {
StringBuffer write_data("WriteData");
ASSERT_TRUE(write_data.WriteToFile(file_path_));
ASSERT_FALSE(ByteRefBuffer(nullptr, 1).WriteToFile(file_path_));
auto read_data = Buffer::ReadFromFile(file_path_);
ASSERT_NE(read_data, nullptr);
ASSERT_EQ(read_data->size(), write_data.size());
ASSERT_EQ(memcmp(read_data->data(), write_data.data(), write_data.size()), 0);
}
}
}
}