Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
8.2 KiB
263 lines
8.2 KiB
// Protocol Buffers - Google's data interchange format |
|
// Copyright 2023 Google LLC. All rights reserved. |
|
// https://developers.google.com/protocol-buffers/ |
|
// |
|
// Redistribution and use in source and binary forms, with or without |
|
// modification, are permitted provided that the following conditions are |
|
// met: |
|
// |
|
// * Redistributions of source code must retain the above copyright |
|
// notice, this list of conditions and the following disclaimer. |
|
// * Redistributions in binary form must reproduce the above |
|
// copyright notice, this list of conditions and the following disclaimer |
|
// in the documentation and/or other materials provided with the |
|
// distribution. |
|
// * Neither the name of Google LLC nor the names of its |
|
// contributors may be used to endorse or promote products derived from |
|
// this software without specific prior written permission. |
|
// |
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
|
// Tests for upb_table. |
|
|
|
#include <limits.h> |
|
#include <string.h> |
|
|
|
#include <iostream> |
|
#include <map> |
|
#include <set> |
|
#include <string> |
|
#include <unordered_map> |
|
#include <vector> |
|
|
|
#include "gtest/gtest.h" |
|
#include "upb/hash/int_table.h" |
|
#include "upb/hash/str_table.h" |
|
#include "upb/upb.hpp" |
|
|
|
// Must be last. |
|
#include "upb/port/def.inc" |
|
|
|
using std::vector; |
|
|
|
TEST(Table, StringTable) { |
|
vector<std::string> keys; |
|
keys.push_back("google.protobuf.FileDescriptorSet"); |
|
keys.push_back("google.protobuf.FileDescriptorProto"); |
|
keys.push_back("google.protobuf.DescriptorProto"); |
|
keys.push_back("google.protobuf.DescriptorProto.ExtensionRange"); |
|
keys.push_back("google.protobuf.FieldDescriptorProto"); |
|
keys.push_back("google.protobuf.EnumDescriptorProto"); |
|
keys.push_back("google.protobuf.EnumValueDescriptorProto"); |
|
keys.push_back("google.protobuf.ServiceDescriptorProto"); |
|
keys.push_back("google.protobuf.MethodDescriptorProto"); |
|
keys.push_back("google.protobuf.FileOptions"); |
|
keys.push_back("google.protobuf.MessageOptions"); |
|
keys.push_back("google.protobuf.FieldOptions"); |
|
keys.push_back("google.protobuf.EnumOptions"); |
|
keys.push_back("google.protobuf.EnumValueOptions"); |
|
keys.push_back("google.protobuf.ServiceOptions"); |
|
keys.push_back("google.protobuf.MethodOptions"); |
|
keys.push_back("google.protobuf.UninterpretedOption"); |
|
keys.push_back("google.protobuf.UninterpretedOption.NamePart"); |
|
|
|
/* Initialize structures. */ |
|
upb::Arena arena; |
|
upb_strtable t; |
|
upb_strtable_init(&t, keys.size(), arena.ptr()); |
|
std::map<std::string, int32_t> m; |
|
std::set<std::string> all; |
|
for (const auto& key : keys) { |
|
all.insert(key); |
|
upb_value val = {uint64_t(key[0])}; |
|
upb_strtable_insert(&t, key.data(), key.size(), val, arena.ptr()); |
|
m[key] = key[0]; |
|
} |
|
|
|
/* Test correctness. */ |
|
for (const auto& key : keys) { |
|
upb_value val; |
|
bool ok = upb_strtable_lookup2(&t, key.data(), key.size(), &val); |
|
EXPECT_TRUE(ok); |
|
EXPECT_EQ(val.val, uint64_t(key[0])); |
|
EXPECT_EQ(m[key], key[0]); |
|
} |
|
|
|
intptr_t iter = UPB_STRTABLE_BEGIN; |
|
upb_StringView key; |
|
upb_value val; |
|
while (upb_strtable_next2(&t, &key, &val, &iter)) { |
|
std::set<std::string>::iterator i = all.find(key.data); |
|
EXPECT_NE(i, all.end()); |
|
all.erase(i); |
|
} |
|
EXPECT_TRUE(all.empty()); |
|
|
|
// Test iteration with resizes. |
|
|
|
for (int i = 0; i < 10; i++) { |
|
intptr_t iter = UPB_STRTABLE_BEGIN; |
|
while (upb_strtable_next2(&t, &key, &val, &iter)) { |
|
// Even if we invalidate the iterator it should only return real elements. |
|
EXPECT_EQ(val.val, m[key.data]); |
|
|
|
// Force a resize even though the size isn't changing. |
|
// Also forces the table size to grow so some new buckets end up empty. |
|
bool ok = upb_strtable_resize(&t, 5 + i, arena.ptr()); |
|
EXPECT_TRUE(ok); |
|
} |
|
} |
|
} |
|
|
|
class IntTableTest : public testing::TestWithParam<int> { |
|
void SetUp() override { |
|
if (GetParam() > 0) { |
|
for (int i = 0; i < GetParam(); i++) { |
|
keys_.push_back(i + 1); |
|
} |
|
} else { |
|
for (int32_t i = 0; i < 64; i++) { |
|
if (i < 32) |
|
keys_.push_back(i + 1); |
|
else |
|
keys_.push_back(10101 + i); |
|
} |
|
} |
|
} |
|
|
|
protected: |
|
std::vector<int32_t> keys_; |
|
}; |
|
|
|
TEST_P(IntTableTest, TestIntTable) { |
|
/* Initialize structures. */ |
|
upb::Arena arena; |
|
upb_inttable t; |
|
upb_inttable_init(&t, arena.ptr()); |
|
uint32_t largest_key = 0; |
|
std::map<uint32_t, uint32_t> m; |
|
std::unordered_map<uint32_t, uint32_t> hm; |
|
for (const auto& key : keys_) { |
|
largest_key = UPB_MAX((int32_t)largest_key, key); |
|
upb_value val = upb_value_uint32(key * 2); |
|
bool ok = upb_inttable_insert(&t, key, val, arena.ptr()); |
|
EXPECT_TRUE(ok); |
|
m[key] = key * 2; |
|
hm[key] = key * 2; |
|
} |
|
EXPECT_EQ(upb_inttable_count(&t), keys_.size()); |
|
|
|
/* Test correctness. */ |
|
int count = 0; |
|
for (uint32_t i = 0; i <= largest_key; i++) { |
|
upb_value val; |
|
bool ok = upb_inttable_lookup(&t, i, &val); |
|
if (ok) { /* Assume map implementation is correct. */ |
|
EXPECT_EQ(val.val, i * 2); |
|
EXPECT_EQ(m[i], i * 2); |
|
EXPECT_EQ(hm[i], i * 2); |
|
count++; |
|
} |
|
} |
|
EXPECT_EQ(count, keys_.size()); |
|
EXPECT_EQ(count, upb_inttable_count(&t)); |
|
|
|
// Test replace. |
|
count = 0; |
|
for (uint32_t i = 0; i <= largest_key; i++) { |
|
upb_value val = upb_value_uint32(i * 3); |
|
bool ok = upb_inttable_replace(&t, i, val); |
|
if (ok) { /* Assume map implementation is correct. */ |
|
m[i] = i * 3; |
|
hm[i] = i * 3; |
|
count++; |
|
} |
|
} |
|
EXPECT_EQ(count, keys_.size()); |
|
EXPECT_EQ(count, upb_inttable_count(&t)); |
|
|
|
// Compact and test correctness again. |
|
upb_inttable_compact(&t, arena.ptr()); |
|
count = 0; |
|
for (uint32_t i = 0; i <= largest_key; i++) { |
|
upb_value val; |
|
bool ok = upb_inttable_lookup(&t, i, &val); |
|
if (ok) { /* Assume map implementation is correct. */ |
|
EXPECT_EQ(val.val, i * 3); |
|
EXPECT_EQ(m[i], i * 3); |
|
EXPECT_EQ(hm[i], i * 3); |
|
count++; |
|
} |
|
} |
|
EXPECT_EQ(count, keys_.size()); |
|
EXPECT_EQ(count, upb_inttable_count(&t)); |
|
|
|
for (const auto& key : keys_) { |
|
upb_value val; |
|
bool ok = upb_inttable_remove(&t, key, &val); |
|
EXPECT_TRUE(ok); |
|
EXPECT_EQ(val.val, (uint32_t)key * 3); |
|
count--; |
|
EXPECT_EQ(count, upb_inttable_count(&t)); |
|
} |
|
EXPECT_EQ(0, upb_inttable_count(&t)); |
|
} |
|
|
|
INSTANTIATE_TEST_SUITE_P(IntTableParams, IntTableTest, |
|
testing::Values(8, 64, 512, -32)); |
|
|
|
/* |
|
* This test can't pass right now because the table can't store a value of |
|
* (uint64_t)-1. |
|
*/ |
|
TEST(Table, MaxValue) { |
|
/* |
|
typedef upb::TypedIntTable<uint64_t> Table; |
|
Table table; |
|
uintptr_t uint64_max = (uint64_t)-1; |
|
table.Insert(1, uint64_max); |
|
std::pair<bool, uint64_t> found = table.Lookup(1); |
|
ASSERT(found.first); |
|
ASSERT(found.second == uint64_max); |
|
*/ |
|
} |
|
|
|
TEST(Table, Delete) { |
|
upb::Arena arena; |
|
upb_inttable t; |
|
upb_inttable_init(&t, arena.ptr()); |
|
upb_inttable_insert(&t, 0, upb_value_bool(true), arena.ptr()); |
|
upb_inttable_insert(&t, 2, upb_value_bool(true), arena.ptr()); |
|
upb_inttable_insert(&t, 4, upb_value_bool(true), arena.ptr()); |
|
upb_inttable_compact(&t, arena.ptr()); |
|
upb_inttable_remove(&t, 0, NULL); |
|
upb_inttable_remove(&t, 2, NULL); |
|
upb_inttable_remove(&t, 4, NULL); |
|
|
|
intptr_t iter = UPB_INTTABLE_BEGIN; |
|
uintptr_t key; |
|
upb_value val; |
|
while (upb_inttable_next(&t, &key, &val, &iter)) { |
|
ASSERT_TRUE(false); |
|
} |
|
} |
|
|
|
TEST(Table, Init) { |
|
for (int i = 0; i < 2048; i++) { |
|
/* Tests that the size calculations in init() (lg2 size for target load) |
|
* work for all expected sizes. */ |
|
upb::Arena arena; |
|
upb_strtable t; |
|
upb_strtable_init(&t, i, arena.ptr()); |
|
} |
|
}
|
|
|