Files
alibaba--zvec/tests/db/index/common/db_proto_converter_test.cc
2026-07-13 12:47:42 +08:00

550 lines
22 KiB
C++

// Copyright 2025-present the zvec project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include "db/index/common/proto_converter.h"
#include "db/index/common/type_helper.h"
using namespace zvec;
TEST(ConverterTest, InvertIndexParamsConversion) {
// Test conversion from protobuf to C++ InvertIndexParams
proto::InvertIndexParams invert_pb;
invert_pb.set_enable_range_optimization(true);
auto invert_params = ProtoConverter::FromPb(invert_pb);
ASSERT_NE(invert_params, nullptr);
EXPECT_TRUE(invert_params->enable_range_optimization());
EXPECT_EQ(invert_params->type(), IndexType::INVERT);
// Test with false value
proto::InvertIndexParams invert_pb2;
invert_pb2.set_enable_range_optimization(false);
auto invert_params2 = ProtoConverter::FromPb(invert_pb2);
ASSERT_NE(invert_params2, nullptr);
EXPECT_FALSE(invert_params2->enable_range_optimization());
// Test conversion from C++ to protobuf
InvertIndexParams original_params(true);
auto pb_result = ProtoConverter::ToPb(&original_params);
EXPECT_TRUE(pb_result.enable_range_optimization());
}
TEST(ConverterTest, HnswIndexParamsConversion) {
// Test conversion from protobuf to C++ HnswIndexParams
proto::HnswIndexParams hnsw_pb;
auto *base_params = hnsw_pb.mutable_base();
base_params->set_metric_type(proto::MT_L2);
base_params->set_quantize_type(proto::QT_FP16);
hnsw_pb.set_m(16);
hnsw_pb.set_ef_construction(100);
auto hnsw_params = ProtoConverter::FromPb(hnsw_pb);
ASSERT_NE(hnsw_params, nullptr);
EXPECT_EQ(hnsw_params->metric_type(), MetricType::L2);
EXPECT_EQ(hnsw_params->m(), 16);
EXPECT_EQ(hnsw_params->ef_construction(), 100);
EXPECT_EQ(hnsw_params->quantize_type(), QuantizeType::FP16);
EXPECT_EQ(hnsw_params->type(), IndexType::HNSW);
// Test conversion from C++ to protobuf
HnswIndexParams original_params(MetricType::IP, 32, 200, QuantizeType::INT8);
auto pb_result = ProtoConverter::ToPb(&original_params);
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_IP);
EXPECT_EQ(pb_result.m(), 32);
EXPECT_EQ(pb_result.ef_construction(), 200);
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_INT8);
}
TEST(ConverterTest, FlatIndexParamsConversion) {
// Test conversion from protobuf to C++ FlatIndexParams
proto::FlatIndexParams flat_pb;
auto *base_params = flat_pb.mutable_base();
base_params->set_metric_type(proto::MT_COSINE);
base_params->set_quantize_type(proto::QT_INT4);
auto flat_params = ProtoConverter::FromPb(flat_pb);
ASSERT_NE(flat_params, nullptr);
EXPECT_EQ(flat_params->metric_type(), MetricType::COSINE);
EXPECT_EQ(flat_params->quantize_type(), QuantizeType::INT4);
EXPECT_EQ(flat_params->type(), IndexType::FLAT);
// Test conversion from C++ to protobuf
FlatIndexParams original_params(MetricType::L2, QuantizeType::FP16);
auto pb_result = ProtoConverter::ToPb(&original_params);
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_L2);
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_FP16);
}
TEST(ConverterTest, IVFIndexParamsConversion) {
// Test conversion from protobuf to C++ IVFIndexParams
proto::IVFIndexParams ivf_pb;
auto *base_params = ivf_pb.mutable_base();
base_params->set_metric_type(proto::MT_IP);
base_params->set_quantize_type(proto::QT_INT8);
ivf_pb.set_n_list(128);
auto ivf_params = ProtoConverter::FromPb(ivf_pb);
ASSERT_NE(ivf_params, nullptr);
EXPECT_EQ(ivf_params->metric_type(), MetricType::IP);
EXPECT_EQ(ivf_params->n_list(), 128);
EXPECT_EQ(ivf_params->quantize_type(), QuantizeType::INT8);
EXPECT_EQ(ivf_params->type(), IndexType::IVF);
// Test conversion from C++ to protobuf
IVFIndexParams original_params(MetricType::COSINE, 256, 10, false,
QuantizeType::INT4);
auto pb_result = ProtoConverter::ToPb(&original_params);
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_COSINE);
EXPECT_EQ(pb_result.n_list(), 256);
EXPECT_EQ(pb_result.n_iters(), 10);
EXPECT_FALSE(pb_result.use_soar());
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_INT4);
}
TEST(ConverterTest, IndexParamsConversion) {
// Test conversion from protobuf to C++ IndexParams for HNSW
proto::IndexParams index_pb;
auto *hnsw_pb = index_pb.mutable_hnsw();
auto *base_params = hnsw_pb->mutable_base();
base_params->set_metric_type(proto::MT_L2);
base_params->set_quantize_type(proto::QT_FP16);
hnsw_pb->set_m(16);
hnsw_pb->set_ef_construction(100);
auto index_params = ProtoConverter::FromPb(index_pb);
ASSERT_NE(index_params, nullptr);
EXPECT_EQ(index_params->type(), IndexType::HNSW);
auto hnsw_cast = std::dynamic_pointer_cast<HnswIndexParams>(index_params);
ASSERT_NE(hnsw_cast, nullptr);
EXPECT_EQ(hnsw_cast->metric_type(), MetricType::L2);
EXPECT_EQ(hnsw_cast->m(), 16);
EXPECT_EQ(hnsw_cast->ef_construction(), 100);
EXPECT_EQ(hnsw_cast->quantize_type(), QuantizeType::FP16);
// Test conversion from C++ HnswIndexParams to protobuf IndexParams
HnswIndexParams hnsw_original(MetricType::IP, 32, 200);
auto pb_result = ProtoConverter::ToPb(&hnsw_original);
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_IP);
EXPECT_EQ(pb_result.m(), 32);
EXPECT_EQ(pb_result.ef_construction(), 200);
// Test conversion from protobuf to C++ IndexParams for FLAT
proto::IndexParams index_pb2;
auto *flat_pb = index_pb2.mutable_flat();
auto *base_params2 = flat_pb->mutable_base();
base_params2->set_metric_type(proto::MT_COSINE);
base_params2->set_quantize_type(proto::QT_INT8);
auto index_params2 = ProtoConverter::FromPb(index_pb2);
ASSERT_NE(index_params2, nullptr);
EXPECT_EQ(index_params2->type(), IndexType::FLAT);
auto flat_cast = std::dynamic_pointer_cast<FlatIndexParams>(index_params2);
ASSERT_NE(flat_cast, nullptr);
EXPECT_EQ(flat_cast->metric_type(), MetricType::COSINE);
EXPECT_EQ(flat_cast->quantize_type(), QuantizeType::INT8);
// Test conversion from C++ FlatIndexParams to protobuf IndexParams
FlatIndexParams flat_original(MetricType::L2);
auto pb_result2 = ProtoConverter::ToPb(&flat_original);
EXPECT_EQ(pb_result2.base().metric_type(), proto::MT_L2);
// Test conversion from protobuf to C++ IndexParams for IVF
proto::IndexParams index_pb3;
auto *ivf_pb = index_pb3.mutable_ivf();
auto *base_params3 = ivf_pb->mutable_base();
base_params3->set_metric_type(proto::MT_IP);
base_params3->set_quantize_type(proto::QT_INT4);
ivf_pb->set_n_list(128);
auto index_params3 = ProtoConverter::FromPb(index_pb3);
ASSERT_NE(index_params3, nullptr);
EXPECT_EQ(index_params3->type(), IndexType::IVF);
auto ivf_cast = std::dynamic_pointer_cast<IVFIndexParams>(index_params3);
ASSERT_NE(ivf_cast, nullptr);
EXPECT_EQ(ivf_cast->metric_type(), MetricType::IP);
EXPECT_EQ(ivf_cast->n_list(), 128);
EXPECT_EQ(ivf_cast->quantize_type(), QuantizeType::INT4);
// Test conversion from C++ IVFIndexParams to protobuf IndexParams
IVFIndexParams ivf_original(MetricType::COSINE, 256);
auto pb_result3 = ProtoConverter::ToPb(&ivf_original);
EXPECT_EQ(pb_result3.base().metric_type(), proto::MT_COSINE);
EXPECT_EQ(pb_result3.n_list(), 256);
// Test conversion from protobuf to C++ IndexParams for INVERT
proto::IndexParams index_pb4;
auto *invert_pb = index_pb4.mutable_invert();
invert_pb->set_enable_range_optimization(true);
auto index_params4 = ProtoConverter::FromPb(index_pb4);
ASSERT_NE(index_params4, nullptr);
EXPECT_EQ(index_params4->type(), IndexType::INVERT);
auto invert_cast =
std::dynamic_pointer_cast<InvertIndexParams>(index_params4);
ASSERT_NE(invert_cast, nullptr);
EXPECT_TRUE(invert_cast->enable_range_optimization());
// Test conversion from C++ InvertIndexParams to protobuf IndexParams
InvertIndexParams invert_original(false);
auto pb_result4 = ProtoConverter::ToPb(&invert_original);
EXPECT_FALSE(pb_result4.enable_range_optimization());
}
TEST(ConverterTest, FieldSchemaConversion) {
// Test conversion from protobuf to C++ FieldSchema
proto::FieldSchema field_pb;
field_pb.set_name("test_field");
field_pb.set_data_type(proto::DT_VECTOR_FP32);
field_pb.set_dimension(128);
field_pb.set_nullable(true);
// Add index params
auto *index_params_pb = field_pb.mutable_index_params();
auto *hnsw_pb = index_params_pb->mutable_hnsw();
auto *base_params = hnsw_pb->mutable_base();
base_params->set_metric_type(proto::MT_L2);
base_params->set_quantize_type(proto::QT_FP16);
hnsw_pb->set_m(16);
hnsw_pb->set_ef_construction(100);
auto field_schema = ProtoConverter::FromPb(field_pb);
ASSERT_NE(field_schema, nullptr);
EXPECT_EQ(field_schema->name(), "test_field");
EXPECT_EQ(field_schema->data_type(), DataType::VECTOR_FP32);
EXPECT_TRUE(field_schema->nullable());
EXPECT_EQ(field_schema->dimension(), 128u);
ASSERT_NE(field_schema->index_params(), nullptr);
EXPECT_EQ(field_schema->index_params()->type(), IndexType::HNSW);
// Test conversion from C++ to protobuf
FieldSchema original_field("another_field", DataType::ARRAY_INT32, 64, false,
nullptr);
auto pb_result = ProtoConverter::ToPb(original_field);
EXPECT_EQ(pb_result.name(), "another_field");
EXPECT_EQ(pb_result.data_type(), proto::DT_ARRAY_INT32);
EXPECT_FALSE(pb_result.nullable());
EXPECT_EQ(pb_result.dimension(), 64u);
}
TEST(ConverterTest, CollectionSchemaConversion) {
// Test conversion from protobuf to C++ CollectionSchema
proto::CollectionSchema schema_pb;
schema_pb.set_name("test_collection");
schema_pb.set_max_doc_count_per_segment(1000000);
auto *field1_pb = schema_pb.add_fields();
field1_pb->set_name("field1");
field1_pb->set_data_type(proto::DT_STRING);
auto *field2_pb = schema_pb.add_fields();
field2_pb->set_name("field2");
field2_pb->set_data_type(proto::DT_VECTOR_FP32);
field2_pb->set_dimension(128);
auto collection_schema = ProtoConverter::FromPb(schema_pb);
ASSERT_NE(collection_schema, nullptr);
EXPECT_EQ(collection_schema->name(), "test_collection");
EXPECT_EQ(collection_schema->fields().size(), 2);
EXPECT_EQ(collection_schema->max_doc_count_per_segment(), 1000000u);
// Test conversion from C++ to protobuf
CollectionSchema original_schema;
original_schema.set_name("original_collection");
auto pb_result = ProtoConverter::ToPb(original_schema);
EXPECT_EQ(pb_result.name(), "original_collection");
}
TEST(ConverterTest, BlockMetaConversion) {
// Test conversion from protobuf to C++ BlockMeta
proto::BlockMeta meta_pb;
meta_pb.set_block_id(1);
meta_pb.set_block_type(proto::BT_SCALAR);
meta_pb.set_min_doc_id(100);
meta_pb.set_max_doc_id(200);
meta_pb.set_doc_count(50);
meta_pb.add_columns("col1");
meta_pb.add_columns("col2");
auto block_meta = ProtoConverter::FromPb(meta_pb);
ASSERT_NE(block_meta, nullptr);
EXPECT_EQ(block_meta->id(), 1u);
EXPECT_EQ(block_meta->type(), BlockType::SCALAR);
EXPECT_EQ(block_meta->min_doc_id(), 100u);
EXPECT_EQ(block_meta->max_doc_id(), 200u);
EXPECT_EQ(block_meta->doc_count(), 50u);
EXPECT_EQ(block_meta->columns().size(), 2);
EXPECT_EQ(block_meta->columns()[0], "col1");
EXPECT_EQ(block_meta->columns()[1], "col2");
// Test conversion from C++ to protobuf
BlockMeta original_meta(2, BlockType::VECTOR_INDEX, 300, 400);
original_meta.set_doc_count(75);
original_meta.add_column("col3");
original_meta.add_column("col4");
auto pb_result = ProtoConverter::ToPb(original_meta);
EXPECT_EQ(pb_result.block_id(), 2u);
EXPECT_EQ(pb_result.block_type(), proto::BT_VECTOR_INDEX);
EXPECT_EQ(pb_result.min_doc_id(), 300u);
EXPECT_EQ(pb_result.max_doc_id(), 400u);
EXPECT_EQ(pb_result.doc_count(), 75u);
EXPECT_EQ(pb_result.columns_size(), 2);
EXPECT_EQ(pb_result.columns(0), "col3");
EXPECT_EQ(pb_result.columns(1), "col4");
}
TEST(ConverterTest, SegmentMetaConversion) {
// Test conversion from protobuf to C++ SegmentMeta
proto::SegmentMeta segment_pb;
segment_pb.set_segment_id(10);
// Add persisted blocks
auto *block1_pb = segment_pb.add_persisted_blocks();
block1_pb->set_block_id(1);
block1_pb->set_block_type(proto::BT_SCALAR);
block1_pb->set_min_doc_id(0);
block1_pb->set_max_doc_id(100);
block1_pb->set_doc_count(50);
block1_pb->add_columns("col1");
block1_pb->add_columns("col2");
auto *block2_pb = segment_pb.add_persisted_blocks();
block2_pb->set_block_id(2);
block2_pb->set_block_type(proto::BT_VECTOR_INDEX);
block2_pb->set_min_doc_id(101);
block2_pb->set_max_doc_id(200);
block2_pb->set_doc_count(75);
block2_pb->add_columns("vec_col");
// Add writing forward block
auto *writing_block_pb = segment_pb.mutable_writing_forward_block();
writing_block_pb->set_block_id(3);
writing_block_pb->set_block_type(proto::BT_SCALAR);
writing_block_pb->set_min_doc_id(201);
writing_block_pb->set_max_doc_id(300);
writing_block_pb->set_doc_count(25);
writing_block_pb->add_columns("col3");
// Add indexed vector fields
segment_pb.add_indexed_vector_fields("vec_col1");
segment_pb.add_indexed_vector_fields("vec_col2");
auto segment_meta = ProtoConverter::FromPb(segment_pb);
ASSERT_NE(segment_meta, nullptr);
EXPECT_EQ(segment_meta->id(), 10u);
EXPECT_EQ(segment_meta->persisted_blocks().size(), 2);
EXPECT_TRUE(segment_meta->has_writing_forward_block());
// Check first persisted block
const auto &block1 = segment_meta->persisted_blocks()[0];
EXPECT_EQ(block1.id(), 1u);
EXPECT_EQ(block1.type(), BlockType::SCALAR);
EXPECT_EQ(block1.min_doc_id(), 0u);
EXPECT_EQ(block1.max_doc_id(), 100u);
EXPECT_EQ(block1.doc_count(), 50u);
EXPECT_EQ(block1.columns().size(), 2);
EXPECT_EQ(block1.columns()[0], "col1");
EXPECT_EQ(block1.columns()[1], "col2");
// Check second persisted block
const auto &block2 = segment_meta->persisted_blocks()[1];
EXPECT_EQ(block2.id(), 2u);
EXPECT_EQ(block2.type(), BlockType::VECTOR_INDEX);
EXPECT_EQ(block2.min_doc_id(), 101u);
EXPECT_EQ(block2.max_doc_id(), 200u);
EXPECT_EQ(block2.doc_count(), 75u);
EXPECT_EQ(block2.columns().size(), 1);
EXPECT_EQ(block2.columns()[0], "vec_col");
// Check writing forward block
const auto &writing_block = segment_meta->writing_forward_block();
EXPECT_EQ(writing_block.value().id(), 3u);
EXPECT_EQ(writing_block.value().type(), BlockType::SCALAR);
EXPECT_EQ(writing_block.value().min_doc_id(), 201u);
EXPECT_EQ(writing_block.value().max_doc_id(), 300u);
EXPECT_EQ(writing_block.value().doc_count(), 25u);
EXPECT_EQ(writing_block.value().columns().size(), 1);
EXPECT_EQ(writing_block.value().columns()[0], "col3");
// Check indexed vector fields
EXPECT_TRUE(segment_meta->vector_indexed("vec_col1"));
EXPECT_TRUE(segment_meta->vector_indexed("vec_col2"));
EXPECT_FALSE(segment_meta->vector_indexed("non_existent_field"));
// Test conversion from C++ to protobuf
SegmentMeta original_meta(20);
// Add persisted blocks
BlockMeta block1_meta(1, BlockType::SCALAR_INDEX, 0, 50);
block1_meta.set_doc_count(25);
block1_meta.add_column("col3");
block1_meta.add_column("col4");
original_meta.add_persisted_block(block1_meta);
BlockMeta block2_meta(2, BlockType::VECTOR_INDEX_QUANTIZE, 51, 100);
block2_meta.set_doc_count(30);
block2_meta.add_column("vec_col2");
original_meta.add_persisted_block(block2_meta);
// Set writing forward block
BlockMeta writing_block_meta(3, BlockType::SCALAR, 101, 150);
writing_block_meta.set_doc_count(40);
writing_block_meta.add_column("col5");
original_meta.set_writing_forward_block(writing_block_meta);
// Add indexed vector fields
original_meta.add_indexed_vector_field("vec_field1");
original_meta.add_indexed_vector_field("vec_field2");
auto pb_result = ProtoConverter::ToPb(original_meta);
EXPECT_EQ(pb_result.segment_id(), 20u);
EXPECT_EQ(pb_result.persisted_blocks_size(), 2);
// Check first persisted block
const auto &pb_block1 = pb_result.persisted_blocks(0);
EXPECT_EQ(pb_block1.block_id(), 1u);
EXPECT_EQ(pb_block1.block_type(), proto::BT_SCALAR_INDEX);
EXPECT_EQ(pb_block1.min_doc_id(), 0u);
EXPECT_EQ(pb_block1.max_doc_id(), 50u);
EXPECT_EQ(pb_block1.doc_count(), 25u);
EXPECT_EQ(pb_block1.columns_size(), 2);
EXPECT_EQ(pb_block1.columns(0), "col3");
EXPECT_EQ(pb_block1.columns(1), "col4");
// Check second persisted block
const auto &pb_block2 = pb_result.persisted_blocks(1);
EXPECT_EQ(pb_block2.block_id(), 2u);
EXPECT_EQ(pb_block2.block_type(), proto::BT_VECTOR_INDEX_QUANTIZE);
EXPECT_EQ(pb_block2.min_doc_id(), 51u);
EXPECT_EQ(pb_block2.max_doc_id(), 100u);
EXPECT_EQ(pb_block2.doc_count(), 30u);
EXPECT_EQ(pb_block2.columns_size(), 1);
EXPECT_EQ(pb_block2.columns(0), "vec_col2");
// Check writing forward block
const auto &pb_writing_block = pb_result.writing_forward_block();
EXPECT_EQ(pb_writing_block.block_id(), 3u);
EXPECT_EQ(pb_writing_block.block_type(), proto::BT_SCALAR);
EXPECT_EQ(pb_writing_block.min_doc_id(), 101u);
EXPECT_EQ(pb_writing_block.max_doc_id(), 150u);
EXPECT_EQ(pb_writing_block.doc_count(), 40u);
EXPECT_EQ(pb_writing_block.columns_size(), 1);
EXPECT_EQ(pb_writing_block.columns(0), "col5");
// Check indexed vector fields
EXPECT_EQ(pb_result.indexed_vector_fields_size(), 2);
EXPECT_EQ(pb_result.indexed_vector_fields(0), "vec_field1");
EXPECT_EQ(pb_result.indexed_vector_fields(1), "vec_field2");
}
TEST(ConverterTest, SegmentMetaWithEmptyFields) {
// Test conversion with minimal data
proto::SegmentMeta segment_pb;
segment_pb.set_segment_id(1);
auto segment_meta = ProtoConverter::FromPb(segment_pb);
ASSERT_NE(segment_meta, nullptr);
EXPECT_EQ(segment_meta->id(), 1u);
EXPECT_EQ(segment_meta->persisted_blocks().size(), 0);
EXPECT_FALSE(segment_meta->has_writing_forward_block());
EXPECT_EQ(segment_meta->indexed_vector_fields().size(), 0);
// Test conversion from C++ to protobuf with minimal data
SegmentMeta original_meta(5);
auto pb_result = ProtoConverter::ToPb(original_meta);
EXPECT_EQ(pb_result.segment_id(), 5u);
EXPECT_EQ(pb_result.persisted_blocks_size(), 0);
EXPECT_FALSE(pb_result.has_writing_forward_block());
EXPECT_EQ(pb_result.indexed_vector_fields_size(), 0);
}
// ==================== enable_rotate roundtrip tests ====================
TEST(ConverterTest, HnswIndexParamsWithEnableRotate) {
// C++ -> PB -> C++ roundtrip with enable_rotate = true
HnswIndexParams original(MetricType::COSINE, 16, 200, QuantizeType::INT8,
false, QuantizerParam(true));
EXPECT_TRUE(original.quantizer_param().enable_rotate());
auto pb = ProtoConverter::ToPb(&original);
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
auto restored = ProtoConverter::FromPb(pb);
ASSERT_NE(restored, nullptr);
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
EXPECT_TRUE(restored->enable_rotate()); // convenience getter
EXPECT_EQ(restored->metric_type(), MetricType::COSINE);
EXPECT_EQ(restored->m(), 16);
EXPECT_EQ(restored->ef_construction(), 200);
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
// C++ -> PB -> C++ roundtrip with enable_rotate = false
HnswIndexParams original_no_rot(MetricType::L2, 32, 100, QuantizeType::FP16);
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
auto restored2 = ProtoConverter::FromPb(pb2);
ASSERT_NE(restored2, nullptr);
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
}
TEST(ConverterTest, FlatIndexParamsWithEnableRotate) {
FlatIndexParams original(MetricType::IP, QuantizeType::INT8,
QuantizerParam(true));
EXPECT_TRUE(original.quantizer_param().enable_rotate());
auto pb = ProtoConverter::ToPb(&original);
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
auto restored = ProtoConverter::FromPb(pb);
ASSERT_NE(restored, nullptr);
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
EXPECT_EQ(restored->metric_type(), MetricType::IP);
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
// enable_rotate = false
FlatIndexParams original_no_rot(MetricType::L2, QuantizeType::FP16);
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
auto restored2 = ProtoConverter::FromPb(pb2);
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
}
TEST(ConverterTest, IVFIndexParamsWithEnableRotate) {
IVFIndexParams original(MetricType::COSINE, 256, 20, true, QuantizeType::INT8,
QuantizerParam(true));
EXPECT_TRUE(original.quantizer_param().enable_rotate());
auto pb = ProtoConverter::ToPb(&original);
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
auto restored = ProtoConverter::FromPb(pb);
ASSERT_NE(restored, nullptr);
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
EXPECT_EQ(restored->metric_type(), MetricType::COSINE);
EXPECT_EQ(restored->n_list(), 256);
EXPECT_EQ(restored->n_iters(), 20);
EXPECT_TRUE(restored->use_soar());
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
// enable_rotate = false
IVFIndexParams original_no_rot(MetricType::L2, 128, 10, false,
QuantizeType::FP16);
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
auto restored2 = ProtoConverter::FromPb(pb2);
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
}