From a21a1cc28e26ba086b85232948c015517221740d Mon Sep 17 00:00:00 2001 From: GUJIEJASON <1776127334@qq.com> Date: Tue, 10 Dec 2024 01:25:00 +0800 Subject: [PATCH] update value_field_test --- db/fields.cpp | 18 +-- db/fields.h | 9 ++ test/value_field_test.cc | 290 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 278 insertions(+), 39 deletions(-) diff --git a/db/fields.cpp b/db/fields.cpp index 2d76a6c..cfa4828 100644 --- a/db/fields.cpp +++ b/db/fields.cpp @@ -163,27 +163,27 @@ std::string& Fields::operator[](const std::string& field_name) { } /* 通过若干个字段查询 Key */ -//std::vector Fields::FindKeysByFields(leveldb::DB* db, const FieldArray& fields) { +// std::vector Fields::FindKeysByFields(leveldb::DB* db, const FieldArray& fields) { // Fields to_fields = Fields(fields); // to_fields.Fields::SortFields(); // FieldArray search_fields_ = to_fields.fields_; -// + // std::vector find_keys; -// + // Iterator* it = db->NewIterator(leveldb::ReadOptions()); // for (it->SeekToFirst(); it->Valid(); it->Next()) { -// + // Slice iter_key_slice = it->key(); // Slice iter_key_for_parse; // if (!GetLengthPrefixedSlice(&iter_key_slice, &iter_key_for_parse)) { // continue; // } -// + // std::string iter_key = iter_key_for_parse.ToString(); // if (std::find(find_keys.begin(), find_keys.end(), iter_key) != find_keys.end()){ // continue; // } -// + // FieldArray iter_fields_ = Fields::ParseValue(it->value().ToString()).fields_; // if (iter_fields_ == search_fields_ || // std::includes(iter_fields_.begin(), iter_fields_.end(), @@ -191,12 +191,12 @@ std::string& Fields::operator[](const std::string& field_name) { // find_keys.emplace_back(iter_key); // } // } -// + // assert(it->status().ok()); // delete it; -// + // return find_keys; -//} +// } std::vector Fields::FindKeysByFields(leveldb::DB* db, const FieldArray& fields) { Fields to_fields = Fields(fields); diff --git a/db/fields.h b/db/fields.h index c7fd728..e7412da 100644 --- a/db/fields.h +++ b/db/fields.h @@ -59,6 +59,15 @@ class Fields { /* 通过若干个字段查询 Key */ static std::vector FindKeysByFields(leveldb::DB* db, const FieldArray& fields); + + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + + iterator begin() { return fields_.begin(); } + const_iterator begin() const { return fields_.cbegin(); } + iterator end() { return fields_.end(); } + const_iterator end() const { return fields_.cend(); } + size_t size() const { return fields_.size(); } }; } // namespace leveldb diff --git a/test/value_field_test.cc b/test/value_field_test.cc index 0945325..8ea72be 100644 --- a/test/value_field_test.cc +++ b/test/value_field_test.cc @@ -1,55 +1,285 @@ #include "gtest/gtest.h" #include "leveldb/db.h" #include "db/fields.h" - +#include "leveldb/write_batch.h" using namespace leveldb; +Status OpenDB(const std::string& dbName, DB** db) { + // 如果数据库已经存在,则删除它。 + std::string rm_command = "rm -rf " + dbName; + system(rm_command.c_str()); + + Options options; + options.create_if_missing = true; + return DB::Open(options, dbName, db); +} + +class FieldsTest : public ::testing::Test { +protected: + void SetUp() override { + Status s = OpenDB("testdb", &db_); + EXPECT_TRUE(s.ok()) << "Failed to open database: " << s.ToString(); + } + + void TearDown() override { + delete db_; + db_ = nullptr; + } + + DB* db_ = nullptr; // 数据库实例指针。 +}; + +// 测试批量插入和验证 +TEST_F(FieldsTest, TestBulkInsertAndValidation) { + const size_t num_fields = 1000; + FieldArray fields; + + // 准备大量字段数据(逆序添加以测试排序) + for (size_t i = num_fields; i > 0; --i) { + fields.emplace_back(std::to_string(i), "value_" + std::to_string(i)); + } + + // 创建 Fields 对象并添加所有字段 + Fields f(fields); + + // 验证所有字段都被正确添加 + EXPECT_EQ(f.size(), num_fields); + + // 排序字段 + f.SortFields(); -constexpr int value_size = 2048; -constexpr int data_size = 128 << 20; + // 验证每个字段的存在性和值(现在应该按顺序排列) + for (size_t i = 1; i <= num_fields; ++i) { + auto field_name = std::to_string(i); + EXPECT_TRUE(f.HasField(field_name)) << "Missing field: " << field_name; + EXPECT_EQ(f.GetField(field_name).second, "value_" + std::to_string(i)) << "Incorrect value for field: " << field_name; + } + // 序列化字段,并将结果插入数据库 + std::string serialized_value = f.SerializeValue(); + const std::string key = "bulk_data_key"; + Status status = db_->Put(WriteOptions(), key, serialized_value); + EXPECT_TRUE(status.ok()) << "Failed to put data into database: " << status.ToString(); + + // 从数据库中读取并反序列化字段 + std::string retrieved_value; + status = db_->Get(ReadOptions(), key, &retrieved_value); + EXPECT_TRUE(status.ok()) << "Failed to get data from database: " << status.ToString(); + Fields deserialized_fields = Fields::ParseValue(retrieved_value); + + // 验证反序列化的字段是否与原始字段匹配 + EXPECT_EQ(deserialized_fields.size(), num_fields); + for (size_t i = 1; i <= num_fields; ++i) { + auto field_name = std::to_string(i); + EXPECT_TRUE(deserialized_fields.HasField(field_name)) << "Deserialized field missing: " << field_name; + EXPECT_EQ(deserialized_fields.GetField(field_name).second, "value_" + std::to_string(i)) << "Incorrect deserialized value for field: " << field_name; + } -Status OpenDB(std::string dbName, DB **db) { - Options options; - options.create_if_missing = true; - return DB::Open(options, dbName, db); } +// 测试批量删除功能 +TEST_F(FieldsTest, TestBulkDelete) { + const size_t num_fields = 1000; + FieldArray fields; + + // 准备大量字段数据 + for (size_t i = 0; i < num_fields; ++i) { + fields.emplace_back(std::to_string(i), "value_" + std::to_string(i)); + } -TEST(TestValueField, ReadValueField) { - DB *db; + // 创建 Fields 对象并添加所有字段 + Fields f(fields); - if(OpenDB("testdb", &db).ok() == false) { - std::cerr << "open db failed" << std::endl; - abort(); - } + // 批量删除一半的字段 + std::vector delete_field_names; + for (size_t i = 0; i < num_fields / 2; ++i) { + delete_field_names.push_back(std::to_string(i)); + } + f.DeleteFields(delete_field_names); - std::string key = "k_1"; + // 验证删除后的字段数量和内容 + EXPECT_EQ(f.size(), num_fields / 2); + for (size_t i = 0; i < num_fields; ++i) { + auto field_name = std::to_string(i); + if (i < num_fields / 2) { + EXPECT_FALSE(f.HasField(field_name)) << "Deleted field still exists: " << field_name; + } else { + EXPECT_TRUE(f.HasField(field_name)) << "Missing non-deleted field: " << field_name; + EXPECT_EQ(f.GetField(field_name).second, "value_" + std::to_string(i)) << "Incorrect value for non-deleted field: " << field_name; + } + } +} + +// 测试单个更新操作 +TEST_F(FieldsTest, TestSingleUpdate) { + FieldArray fields = {{"field1", "old_value"}, {"field2", "value2"}}; + Fields f(fields); + f.UpdateField("field1", "new_value"); - FieldArray fields = { - {"name", "Customer#000000001"}, - {"address", "IVhzIApeRb"}, - {"phone", "25-989-741-2988"} - }; + EXPECT_EQ(f.GetField("field1").second, "new_value"); + EXPECT_EQ(f.GetField("field2").second, "value2"); - // 序列化并插入 - std::string value = SerializeValue(fields); - db->Put(WriteOptions(), key, value); + // 检查排序是否正确 + EXPECT_TRUE(std::is_sorted(f.begin(), f.end(), + [](const Field& lhs, const Field& rhs) { + return lhs.first < rhs.first; + })) << "Fields are not sorted after single update."; +} - // 读取并反序列化 - std::string value_ret; - db->Get(ReadOptions(), key, &value_ret); - auto fields_ret = ParseValue(value_ret); +// 测试批量更新操作 +TEST_F(FieldsTest, TestBulkUpdate) { + const size_t num_fields = 500; + FieldArray fields; + // 准备大量字段数据 + for (size_t i = 0; i < num_fields; ++i) { + fields.emplace_back(std::to_string(i), "old_value_" + std::to_string(i)); + } + // 创建 Fields 对象并添加所有字段 + Fields f(fields); + // 批量更新一半的字段 + FieldArray update_fields; + for (size_t i = 0; i < num_fields / 2; ++i) { + update_fields.emplace_back(std::to_string(i), "new_value_" + std::to_string(i)); + } + f.UpdateFields(update_fields); + // 验证更新后的字段值 + for (size_t i = 0; i < num_fields; ++i) { + auto field_name = std::to_string(i); + auto expected_value = (i < num_fields / 2) ? ("new_value_" + std::to_string(i)) : ("old_value_" + std::to_string(i)); + EXPECT_EQ(f.GetField(field_name).second, expected_value) << "Incorrect value for updated field: " << field_name; + } + + // 检查排序是否正确 + EXPECT_TRUE(std::is_sorted(f.begin(), f.end(), + [](const Field& lhs, const Field& rhs) { + return lhs.first < rhs.first; + })) << "Fields are not sorted after bulk update."; } +// 测试各种构造函数 +TEST_F(FieldsTest, TestConstructors) { + // 单个 Field 构造 + Fields f_single(Field("single", "value")); + EXPECT_EQ(f_single.size(), 1); + EXPECT_TRUE(f_single.HasField("single")); -int main(int argc, char** argv) { - // All tests currently run with the same read-only file limits. - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + // FieldArray 构造 + FieldArray fields = {{"array1", "value1"}, {"array2", "value2"}}; + Fields f_array(fields); + EXPECT_EQ(f_array.size(), 2); + EXPECT_TRUE(f_array.HasField("array1")); + EXPECT_TRUE(f_array.HasField("array2")); + + // field_names 数组构造 + std::vector field_names = {"name1", "name2"}; + Fields f_names(field_names); + EXPECT_EQ(f_names.size(), 2); +} + +// 测试 operator[] 访问功能 +TEST_F(FieldsTest, TestOperatorBracketAccess) { + // 创建一个 Fields 对象并添加一些字段 + FieldArray fields = {{"field1", "value1"}, {"field2", "value2"}}; + Fields f(fields); + + // 使用 operator[] 来获取字段值 + EXPECT_EQ(f["field1"], "value1"); + EXPECT_EQ(f["field2"], "value2"); + + // 尝试获取不存在的字段,应该返回空字符串并打印错误信息 + testing::internal::CaptureStderr(); + EXPECT_EQ(f["nonexistent_field"], ""); +} + +// 测试 operator[] 更新功能 +TEST_F(FieldsTest, TestOperatorBracketUpdate) { + // 创建一个 Fields 对象并添加一些字段 + Fields f; + + // 使用 operator[] 来设置字段值(字段不存在时应插入) + f["field1"] = "value1"; + EXPECT_EQ(f["field1"], "value1"); + + // 更新已存在的字段值 + f["field1"] = "new_value1"; + EXPECT_EQ(f["field1"], "new_value1"); + + // 插入多个新字段 + f["field2"] = "value2"; + f["field3"] = "value3"; + + // 验证所有字段都已正确插入 + EXPECT_EQ(f.size(), 3); + EXPECT_EQ(f["field1"], "new_value1"); + EXPECT_EQ(f["field2"], "value2"); + EXPECT_EQ(f["field3"], "value3"); + + // 检查排序是否正确 + EXPECT_TRUE(std::is_sorted(f.begin(), f.end(), + [](const Field& lhs, const Field& rhs) { + return lhs.first < rhs.first; + })) << "Fields are not sorted after updates."; +} + +// 测试批量插入、排序、序列化/反序列化以及 FindKeysByFields 功能 +TEST_F(FieldsTest, TestBulkInsertSortSerializeAndFindKeys) { + const size_t num_entries = 500; + leveldb::WriteBatch batch; + + // 准备大量键值对数据(逆序添加以测试排序) + std::map data_to_insert; + for (size_t i = num_entries; i > 0; --i) { + std::string key = "key_" + std::to_string(i); + FieldArray fields = {{"field1", "value1_" + std::to_string(i)}, {"field2", "value2_" + std::to_string(i)}}; + data_to_insert[key] = Fields(fields); + + // 将序列化后的字段添加到 WriteBatch 中 + batch.Put(key, data_to_insert[key].SerializeValue()); + } + + // 提交批量写入操作 + Status status = db_->Write(WriteOptions(), &batch); + EXPECT_TRUE(status.ok()) << "Failed to write batch: " << status.ToString(); + + // 验证插入的数据是否正确 + for (size_t i = 1; i <= num_entries; ++i) { + std::string key = "key_" + std::to_string(i); + std::string value; + status = db_->Get(ReadOptions(), key, &value); + EXPECT_TRUE(status.ok()) << "Failed to read key: " << key << ", error: " << status.ToString(); + + // 反序列化并验证字段值 + Fields f = Fields::ParseValue(value); + EXPECT_EQ(f["field1"], "value1_" + std::to_string(i)) << "Incorrect value for field1 in key: " << key; + EXPECT_EQ(f["field2"], "value2_" + std::to_string(i)) << "Incorrect value for field2 in key: " << key; + } + + // 使用 FindKeysByFields 查找包含特定字段的键 + FieldArray fields_to_find = {{"field1", ""}, {"field2", ""}}; + std::vector found_keys = Fields::FindKeysByFields(db_, fields_to_find); + + // 验证找到的键是否正确 + EXPECT_EQ(found_keys.size(), num_entries) << "Expected " << num_entries << " keys but found " << found_keys.size(); + for (size_t i = 1; i <= num_entries; ++i) { + std::string expected_key = "key_" + std::to_string(i); + EXPECT_TRUE(std::find(found_keys.begin(), found_keys.end(), expected_key) != found_keys.end()) + << "Key not found: " << expected_key; + } + + // 再次查找,这次没有符合条件的字段 + FieldArray no_match_fields = {{"nonexistent_field", ""}}; + found_keys = Fields::FindKeysByFields(db_, no_match_fields); + EXPECT_TRUE(found_keys.empty()) << "Expected an empty result for non-matching fields."; + + } + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file