rocksdb/utilities/object_registry_test.cc
Peter Dillinger 449029f865 Remove deprecated ObjectLibrary::Register() (and Regex public API) (#9439)
Summary:
Regexes are considered potentially problematic for use in
registering RocksDB extensions, so we are removing
ObjectLibrary::Register() and the Regex public API it depended on (now
unused).

In reference to https://github.com/facebook/rocksdb/issues/9389

Why?
* The power of Regexes can make it hard to reason about which extension
will match what. (The replacement API isn't perfect, but we are at least
"holding the line" on patterns we have seen in practice.)
* It is easy to make regexes that don't quite mean what you think they
mean, such as forgetting that the `.` in `foo.bar` can match any character
or that matching is nondeterministic, as in `a🅱️42` matching `.*:[0-9]+`.
* Some regexes and implementations can have disastrously bad
performance. This might not be much practical concern for ObjectLibray
here, but we don't want to encourage potentially dangerous further use
in production code. (Testing code is fine. See TestRegex.)

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9439

Test Plan: CI

Reviewed By: mrambacher

Differential Revision: D33792342

Pulled By: pdillinger

fbshipit-source-id: 4f64dcb04764e639162c8977a5fa196f67754cec
2022-01-26 16:22:44 -08:00

697 lines
25 KiB
C++

// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#ifndef ROCKSDB_LITE
#include "rocksdb/utilities/object_registry.h"
#include "rocksdb/customizable.h"
#include "test_util/testharness.h"
namespace ROCKSDB_NAMESPACE {
class ObjRegistryTest : public testing::Test {
public:
static int num_a, num_b;
};
int ObjRegistryTest::num_a = 0;
int ObjRegistryTest::num_b = 0;
static FactoryFunc<Env> test_reg_a = ObjectLibrary::Default()->AddFactory<Env>(
ObjectLibrary::PatternEntry("a", false).AddSeparator("://"),
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*env_guard*/,
std::string* /* errmsg */) {
++ObjRegistryTest::num_a;
return Env::Default();
});
class WrappedEnv : public EnvWrapper {
private:
std::string id_;
public:
WrappedEnv(Env* t, const std::string& id) : EnvWrapper(t), id_(id) {}
const char* Name() const override { return id_.c_str(); }
std::string GetId() const override { return id_; }
};
static FactoryFunc<Env> test_reg_b = ObjectLibrary::Default()->AddFactory<Env>(
ObjectLibrary::PatternEntry("b", false).AddSeparator("://"),
[](const std::string& uri, std::unique_ptr<Env>* env_guard,
std::string* /* errmsg */) {
++ObjRegistryTest::num_b;
// Env::Default() is a singleton so we can't grant ownership directly to
// the caller - we must wrap it first.
env_guard->reset(new WrappedEnv(Env::Default(), uri));
return env_guard->get();
});
TEST_F(ObjRegistryTest, Basics) {
std::string msg;
std::unique_ptr<Env> env_guard;
auto registry = ObjectRegistry::NewInstance();
auto res = registry->NewObject<Env>("a://test", &env_guard, &msg);
ASSERT_NE(res, nullptr);
ASSERT_EQ(env_guard, nullptr);
ASSERT_EQ(1, num_a);
ASSERT_EQ(0, num_b);
res = registry->NewObject<Env>("b://test", &env_guard, &msg);
ASSERT_NE(res, nullptr);
ASSERT_NE(env_guard, nullptr);
ASSERT_EQ(1, num_a);
ASSERT_EQ(1, num_b);
res = registry->NewObject<Env>("c://test", &env_guard, &msg);
ASSERT_EQ(res, nullptr);
ASSERT_EQ(env_guard, nullptr);
ASSERT_EQ(1, num_a);
ASSERT_EQ(1, num_b);
}
TEST_F(ObjRegistryTest, LocalRegistry) {
std::string msg;
std::unique_ptr<Env> guard;
auto registry = ObjectRegistry::NewInstance();
std::shared_ptr<ObjectLibrary> library =
std::make_shared<ObjectLibrary>("local");
registry->AddLibrary(library);
library->AddFactory<Env>(
"test-local",
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return Env::Default(); });
ObjectLibrary::Default()->AddFactory<Env>(
"test-global",
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return Env::Default(); });
ASSERT_EQ(
ObjectRegistry::NewInstance()->NewObject<Env>("test-local", &guard, &msg),
nullptr);
ASSERT_NE(
ObjectRegistry::NewInstance()->NewObject("test-global", &guard, &msg),
nullptr);
ASSERT_NE(registry->NewObject<Env>("test-local", &guard, &msg), nullptr);
ASSERT_NE(registry->NewObject<Env>("test-global", &guard, &msg), nullptr);
}
TEST_F(ObjRegistryTest, CheckShared) {
std::shared_ptr<Env> shared;
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
std::shared_ptr<ObjectLibrary> library =
std::make_shared<ObjectLibrary>("shared");
registry->AddLibrary(library);
library->AddFactory<Env>(
"unguarded",
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return Env::Default(); });
library->AddFactory<Env>(
"guarded", [](const std::string& uri, std::unique_ptr<Env>* guard,
std::string* /* errmsg */) {
guard->reset(new WrappedEnv(Env::Default(), uri));
return guard->get();
});
ASSERT_OK(registry->NewSharedObject<Env>("guarded", &shared));
ASSERT_NE(shared, nullptr);
shared.reset();
ASSERT_NOK(registry->NewSharedObject<Env>("unguarded", &shared));
ASSERT_EQ(shared, nullptr);
}
TEST_F(ObjRegistryTest, CheckStatic) {
Env* env = nullptr;
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
std::shared_ptr<ObjectLibrary> library =
std::make_shared<ObjectLibrary>("static");
registry->AddLibrary(library);
library->AddFactory<Env>(
"unguarded",
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return Env::Default(); });
library->AddFactory<Env>(
"guarded", [](const std::string& uri, std::unique_ptr<Env>* guard,
std::string* /* errmsg */) {
guard->reset(new WrappedEnv(Env::Default(), uri));
return guard->get();
});
ASSERT_NOK(registry->NewStaticObject<Env>("guarded", &env));
ASSERT_EQ(env, nullptr);
env = nullptr;
ASSERT_OK(registry->NewStaticObject<Env>("unguarded", &env));
ASSERT_NE(env, nullptr);
}
TEST_F(ObjRegistryTest, CheckUnique) {
std::unique_ptr<Env> unique;
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
std::shared_ptr<ObjectLibrary> library =
std::make_shared<ObjectLibrary>("unique");
registry->AddLibrary(library);
library->AddFactory<Env>(
"unguarded",
[](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return Env::Default(); });
library->AddFactory<Env>(
"guarded", [](const std::string& uri, std::unique_ptr<Env>* guard,
std::string* /* errmsg */) {
guard->reset(new WrappedEnv(Env::Default(), uri));
return guard->get();
});
ASSERT_OK(registry->NewUniqueObject<Env>("guarded", &unique));
ASSERT_NE(unique, nullptr);
unique.reset();
ASSERT_NOK(registry->NewUniqueObject<Env>("unguarded", &unique));
ASSERT_EQ(unique, nullptr);
}
TEST_F(ObjRegistryTest, TestRegistryParents) {
auto grand = ObjectRegistry::Default();
auto parent = ObjectRegistry::NewInstance(); // parent with a grandparent
auto uncle = ObjectRegistry::NewInstance(grand);
auto child = ObjectRegistry::NewInstance(parent);
auto cousin = ObjectRegistry::NewInstance(uncle);
auto library = parent->AddLibrary("parent");
library->AddFactory<Env>(
"parent", [](const std::string& uri, std::unique_ptr<Env>* guard,
std::string* /* errmsg */) {
guard->reset(new WrappedEnv(Env::Default(), uri));
return guard->get();
});
library = cousin->AddLibrary("cousin");
library->AddFactory<Env>(
"cousin", [](const std::string& uri, std::unique_ptr<Env>* guard,
std::string* /* errmsg */) {
guard->reset(new WrappedEnv(Env::Default(), uri));
return guard->get();
});
std::unique_ptr<Env> guard;
std::string msg;
// a:://* is registered in Default, so they should all workd
ASSERT_NE(parent->NewObject<Env>("a://test", &guard, &msg), nullptr);
ASSERT_NE(child->NewObject<Env>("a://test", &guard, &msg), nullptr);
ASSERT_NE(uncle->NewObject<Env>("a://test", &guard, &msg), nullptr);
ASSERT_NE(cousin->NewObject<Env>("a://test", &guard, &msg), nullptr);
// The parent env is only registered for parent, not uncle,
// So parent and child should return success and uncle and cousin should fail
ASSERT_OK(parent->NewUniqueObject<Env>("parent", &guard));
ASSERT_OK(child->NewUniqueObject<Env>("parent", &guard));
ASSERT_NOK(uncle->NewUniqueObject<Env>("parent", &guard));
ASSERT_NOK(cousin->NewUniqueObject<Env>("parent", &guard));
// The cousin is only registered in the cousin, so all of the others should
// fail
ASSERT_OK(cousin->NewUniqueObject<Env>("cousin", &guard));
ASSERT_NOK(parent->NewUniqueObject<Env>("cousin", &guard));
ASSERT_NOK(child->NewUniqueObject<Env>("cousin", &guard));
ASSERT_NOK(uncle->NewUniqueObject<Env>("cousin", &guard));
}
class MyCustomizable : public Customizable {
public:
static const char* Type() { return "MyCustomizable"; }
MyCustomizable(const char* prefix, const std::string& id) : id_(id) {
name_ = id_.substr(0, strlen(prefix) - 1);
}
const char* Name() const override { return name_.c_str(); }
std::string GetId() const override { return id_; }
private:
std::string id_;
std::string name_;
};
TEST_F(ObjRegistryTest, TestManagedObjects) {
auto registry = ObjectRegistry::NewInstance();
auto m_a1 = std::make_shared<MyCustomizable>("", "A");
auto m_a2 = std::make_shared<MyCustomizable>("", "A");
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_OK(registry->SetManagedObject<MyCustomizable>(m_a1));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a1);
ASSERT_NOK(registry->SetManagedObject<MyCustomizable>(m_a2));
ASSERT_OK(registry->SetManagedObject<MyCustomizable>(m_a1));
m_a1.reset();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_OK(registry->SetManagedObject<MyCustomizable>(m_a2));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a2);
}
TEST_F(ObjRegistryTest, TestTwoManagedObjects) {
auto registry = ObjectRegistry::NewInstance();
auto m_a = std::make_shared<MyCustomizable>("", "A");
auto m_b = std::make_shared<MyCustomizable>("", "B");
std::vector<std::shared_ptr<MyCustomizable>> objects;
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 0U);
ASSERT_OK(registry->SetManagedObject(m_a));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_a);
ASSERT_OK(registry->SetManagedObject(m_b));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), m_b);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 2U);
ASSERT_OK(registry->ListManagedObjects("A", &objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_a);
ASSERT_OK(registry->ListManagedObjects("B", &objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_b);
ASSERT_OK(registry->ListManagedObjects("C", &objects));
ASSERT_EQ(objects.size(), 0U);
m_a.reset();
objects.clear();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), m_b);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_b);
m_b.reset();
objects.clear();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
}
TEST_F(ObjRegistryTest, TestAlternateNames) {
auto registry = ObjectRegistry::NewInstance();
auto m_a = std::make_shared<MyCustomizable>("", "A");
auto m_b = std::make_shared<MyCustomizable>("", "B");
std::vector<std::shared_ptr<MyCustomizable>> objects;
// Test no objects exist
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), nullptr);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 0U);
// Mark "TheOne" to be A
ASSERT_OK(registry->SetManagedObject("TheOne", m_a));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), m_a);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_a);
// Try to mark "TheOne" again.
ASSERT_NOK(registry->SetManagedObject("TheOne", m_b));
ASSERT_OK(registry->SetManagedObject("TheOne", m_a));
// Add "A" as a managed object. Registered 2x
ASSERT_OK(registry->SetManagedObject(m_a));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("B"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), m_a);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 2U);
// Delete "A".
m_a.reset();
objects.clear();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), nullptr);
ASSERT_OK(registry->SetManagedObject("TheOne", m_b));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), m_b);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 1U);
ASSERT_EQ(objects.front(), m_b);
m_b.reset();
objects.clear();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("TheOne"), nullptr);
ASSERT_OK(registry->ListManagedObjects(&objects));
ASSERT_EQ(objects.size(), 0U);
}
TEST_F(ObjRegistryTest, TestTwoManagedClasses) {
class MyCustomizable2 : public MyCustomizable {
public:
static const char* Type() { return "MyCustomizable2"; }
MyCustomizable2(const char* prefix, const std::string& id)
: MyCustomizable(prefix, id) {}
};
auto registry = ObjectRegistry::NewInstance();
auto m_a1 = std::make_shared<MyCustomizable>("", "A");
auto m_a2 = std::make_shared<MyCustomizable2>("", "A");
std::vector<std::shared_ptr<MyCustomizable>> obj1s;
std::vector<std::shared_ptr<MyCustomizable2>> obj2s;
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable2>("A"), nullptr);
ASSERT_OK(registry->SetManagedObject(m_a1));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a1);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable2>("A"), nullptr);
ASSERT_OK(registry->SetManagedObject(m_a2));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable2>("A"), m_a2);
ASSERT_OK(registry->ListManagedObjects(&obj1s));
ASSERT_OK(registry->ListManagedObjects(&obj2s));
ASSERT_EQ(obj1s.size(), 1U);
ASSERT_EQ(obj2s.size(), 1U);
ASSERT_EQ(obj1s.front(), m_a1);
ASSERT_EQ(obj2s.front(), m_a2);
m_a1.reset();
obj1s.clear();
obj2s.clear();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable2>("A"), m_a2);
m_a2.reset();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable2>("A"), nullptr);
}
TEST_F(ObjRegistryTest, TestManagedObjectsWithParent) {
auto base = ObjectRegistry::NewInstance();
auto registry = ObjectRegistry::NewInstance(base);
auto m_a = std::make_shared<MyCustomizable>("", "A");
auto m_b = std::make_shared<MyCustomizable>("", "A");
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_OK(base->SetManagedObject(m_a));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_a);
ASSERT_NOK(registry->SetManagedObject(m_b));
ASSERT_OK(registry->SetManagedObject(m_a));
m_a.reset();
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), nullptr);
ASSERT_OK(registry->SetManagedObject(m_b));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("A"), m_b);
}
TEST_F(ObjRegistryTest, TestGetOrCreateManagedObject) {
auto registry = ObjectRegistry::NewInstance();
registry->AddLibrary("test")->AddFactory<MyCustomizable>(
ObjectLibrary::PatternEntry::AsIndividualId("MC"),
[](const std::string& uri, std::unique_ptr<MyCustomizable>* guard,
std::string* /* errmsg */) {
guard->reset(new MyCustomizable("MC", uri));
return guard->get();
});
std::shared_ptr<MyCustomizable> m_a, m_b, obj;
std::vector<std::shared_ptr<MyCustomizable>> objs;
std::unordered_map<std::string, std::string> opt_map;
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("MC@A#1"), nullptr);
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("MC@B#1"), nullptr);
ASSERT_OK(registry->GetOrCreateManagedObject("MC@A#1", &m_a));
ASSERT_OK(registry->GetOrCreateManagedObject("MC@B#1", &m_b));
ASSERT_EQ(registry->GetManagedObject<MyCustomizable>("MC@A#1"), m_a);
ASSERT_OK(registry->GetOrCreateManagedObject("MC@A#1", &obj));
ASSERT_EQ(obj, m_a);
ASSERT_OK(registry->GetOrCreateManagedObject("MC@B#1", &obj));
ASSERT_EQ(obj, m_b);
ASSERT_OK(registry->ListManagedObjects(&objs));
ASSERT_EQ(objs.size(), 2U);
objs.clear();
m_a.reset();
obj.reset();
ASSERT_OK(registry->GetOrCreateManagedObject("MC@A#1", &m_a));
ASSERT_EQ(1, m_a.use_count());
ASSERT_OK(registry->GetOrCreateManagedObject("MC@B#1", &obj));
ASSERT_EQ(2, obj.use_count());
}
class PatternEntryTest : public testing::Test {};
TEST_F(PatternEntryTest, TestSimpleEntry) {
ObjectLibrary::PatternEntry entry("ABC", true);
ASSERT_TRUE(entry.Matches("ABC"));
ASSERT_FALSE(entry.Matches("AABC"));
ASSERT_FALSE(entry.Matches("ABCA"));
ASSERT_FALSE(entry.Matches("AABCA"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("BC"));
ASSERT_FALSE(entry.Matches("ABD"));
ASSERT_FALSE(entry.Matches("BCA"));
}
TEST_F(PatternEntryTest, TestPatternEntry) {
// Matches A:+
ObjectLibrary::PatternEntry entry("A", false);
entry.AddSeparator(":");
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("B"));
ASSERT_FALSE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA:B"));
ASSERT_FALSE(entry.Matches("AA:BB"));
ASSERT_TRUE(entry.Matches("A:B"));
ASSERT_TRUE(entry.Matches("A:BB"));
entry.SetOptional(true); // Now matches "A" or "A:+"
ASSERT_TRUE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("B"));
ASSERT_FALSE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA:B"));
ASSERT_FALSE(entry.Matches("AA:BB"));
ASSERT_TRUE(entry.Matches("A:B"));
ASSERT_TRUE(entry.Matches("A:BB"));
}
TEST_F(PatternEntryTest, MatchZeroOrMore) {
// Matches A:*
ObjectLibrary::PatternEntry entry("A", false);
entry.AddSeparator(":", false);
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("B"));
ASSERT_TRUE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("B:"));
ASSERT_FALSE(entry.Matches("B:A"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA:B"));
ASSERT_FALSE(entry.Matches("AA:BB"));
ASSERT_TRUE(entry.Matches("A:B"));
ASSERT_TRUE(entry.Matches("A:BB"));
entry.SetOptional(true); // Now matches "A" or "A:*"
ASSERT_TRUE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("B"));
ASSERT_TRUE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("B:"));
ASSERT_FALSE(entry.Matches("B:A"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA:B"));
ASSERT_FALSE(entry.Matches("AA:BB"));
ASSERT_TRUE(entry.Matches("A:B"));
ASSERT_TRUE(entry.Matches("A:BB"));
}
TEST_F(PatternEntryTest, TestSuffixEntry) {
ObjectLibrary::PatternEntry entry("AA", true);
entry.AddSuffix("BB");
ASSERT_TRUE(entry.Matches("AA"));
ASSERT_TRUE(entry.Matches("AABB"));
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AB"));
ASSERT_FALSE(entry.Matches("B"));
ASSERT_FALSE(entry.Matches("BB"));
ASSERT_FALSE(entry.Matches("ABA"));
ASSERT_FALSE(entry.Matches("BBAA"));
ASSERT_FALSE(entry.Matches("AABBA"));
ASSERT_FALSE(entry.Matches("AABBB"));
}
TEST_F(PatternEntryTest, TestNumericEntry) {
ObjectLibrary::PatternEntry entry("A", false);
entry.AddNumber(":");
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("A:"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_TRUE(entry.Matches("A:1"));
ASSERT_TRUE(entry.Matches("A:11"));
ASSERT_FALSE(entry.Matches("AA:1"));
ASSERT_FALSE(entry.Matches("AA:11"));
ASSERT_FALSE(entry.Matches("A:B"));
ASSERT_FALSE(entry.Matches("A:1B"));
ASSERT_FALSE(entry.Matches("A:B1"));
}
TEST_F(PatternEntryTest, TestIndividualIdEntry) {
auto entry = ObjectLibrary::PatternEntry::AsIndividualId("AA");
ASSERT_TRUE(entry.Matches("AA"));
ASSERT_TRUE(entry.Matches("AA@123#456"));
ASSERT_TRUE(entry.Matches("AA@deadbeef#id"));
ASSERT_FALSE(entry.Matches("A"));
ASSERT_FALSE(entry.Matches("AAA"));
ASSERT_FALSE(entry.Matches("AA@123"));
ASSERT_FALSE(entry.Matches("AA@123#"));
ASSERT_FALSE(entry.Matches("AA@#123"));
}
TEST_F(PatternEntryTest, TestTwoNameEntry) {
ObjectLibrary::PatternEntry entry("A");
entry.AnotherName("B");
ASSERT_TRUE(entry.Matches("A"));
ASSERT_TRUE(entry.Matches("B"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("BB"));
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("BA"));
ASSERT_FALSE(entry.Matches("AB"));
}
TEST_F(PatternEntryTest, TestTwoPatternEntry) {
ObjectLibrary::PatternEntry entry("AA", false);
entry.AddSeparator(":");
entry.AddSeparator(":");
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA::"));
ASSERT_FALSE(entry.Matches("AA::12"));
ASSERT_TRUE(entry.Matches("AA:1:2"));
ASSERT_TRUE(entry.Matches("AA:1:2:"));
ObjectLibrary::PatternEntry entry2("AA", false);
entry2.AddSeparator("::");
entry2.AddSeparator("##");
ASSERT_FALSE(entry2.Matches("AA"));
ASSERT_FALSE(entry2.Matches("AA:"));
ASSERT_FALSE(entry2.Matches("AA::"));
ASSERT_FALSE(entry2.Matches("AA::#"));
ASSERT_FALSE(entry2.Matches("AA::##"));
ASSERT_FALSE(entry2.Matches("AA##1::2"));
ASSERT_FALSE(entry2.Matches("AA::123##"));
ASSERT_TRUE(entry2.Matches("AA::1##2"));
ASSERT_TRUE(entry2.Matches("AA::12##34:"));
ASSERT_TRUE(entry2.Matches("AA::12::34##56"));
ASSERT_TRUE(entry2.Matches("AA::12##34::56"));
}
TEST_F(PatternEntryTest, TestTwoNumbersEntry) {
ObjectLibrary::PatternEntry entry("AA", false);
entry.AddNumber(":");
entry.AddNumber(":");
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AA:"));
ASSERT_FALSE(entry.Matches("AA::"));
ASSERT_FALSE(entry.Matches("AA::12"));
ASSERT_FALSE(entry.Matches("AA:1:2:"));
ASSERT_TRUE(entry.Matches("AA:1:2"));
ASSERT_TRUE(entry.Matches("AA:12:23456"));
ObjectLibrary::PatternEntry entry2("AA", false);
entry2.AddNumber(":");
entry2.AddNumber("#");
ASSERT_FALSE(entry2.Matches("AA"));
ASSERT_FALSE(entry2.Matches("AA:"));
ASSERT_FALSE(entry2.Matches("AA:#"));
ASSERT_FALSE(entry2.Matches("AA#:"));
ASSERT_FALSE(entry2.Matches("AA:123#"));
ASSERT_FALSE(entry2.Matches("AA:123#B"));
ASSERT_FALSE(entry2.Matches("AA:B#123"));
ASSERT_TRUE(entry2.Matches("AA:1#2"));
ASSERT_FALSE(entry2.Matches("AA:123#23:"));
ASSERT_FALSE(entry2.Matches("AA::12#234"));
}
TEST_F(PatternEntryTest, TestPatternAndSuffix) {
ObjectLibrary::PatternEntry entry("AA", false);
entry.AddSeparator("::");
entry.AddSuffix("##");
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("AA::"));
ASSERT_FALSE(entry.Matches("AA::##"));
ASSERT_FALSE(entry.Matches("AB::1##"));
ASSERT_FALSE(entry.Matches("AB::1##2"));
ASSERT_FALSE(entry.Matches("AA##1::"));
ASSERT_TRUE(entry.Matches("AA::1##"));
ASSERT_FALSE(entry.Matches("AA::1###"));
ObjectLibrary::PatternEntry entry2("AA", false);
entry2.AddSuffix("::");
entry2.AddSeparator("##");
ASSERT_FALSE(entry2.Matches("AA"));
ASSERT_FALSE(entry2.Matches("AA::"));
ASSERT_FALSE(entry2.Matches("AA::##"));
ASSERT_FALSE(entry2.Matches("AB::1##"));
ASSERT_FALSE(entry2.Matches("AB::1##2"));
ASSERT_TRUE(entry2.Matches("AA::##12"));
}
TEST_F(PatternEntryTest, TestTwoNamesAndPattern) {
ObjectLibrary::PatternEntry entry("AA", true);
entry.AddSeparator("::");
entry.AnotherName("BBB");
ASSERT_TRUE(entry.Matches("AA"));
ASSERT_TRUE(entry.Matches("AA::1"));
ASSERT_TRUE(entry.Matches("BBB"));
ASSERT_TRUE(entry.Matches("BBB::2"));
ASSERT_FALSE(entry.Matches("AA::"));
ASSERT_FALSE(entry.Matches("AAA::"));
ASSERT_FALSE(entry.Matches("BBB::"));
entry.SetOptional(false);
ASSERT_FALSE(entry.Matches("AA"));
ASSERT_FALSE(entry.Matches("BBB"));
ASSERT_FALSE(entry.Matches("AA::"));
ASSERT_FALSE(entry.Matches("AAA::"));
ASSERT_FALSE(entry.Matches("BBB::"));
ASSERT_TRUE(entry.Matches("AA::1"));
ASSERT_TRUE(entry.Matches("BBB::2"));
}
} // namespace ROCKSDB_NAMESPACE
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#else // ROCKSDB_LITE
#include <stdio.h>
int main(int /*argc*/, char** /*argv*/) {
fprintf(stderr, "SKIPPED as ObjRegistry is not supported in ROCKSDB_LITE\n");
return 0;
}
#endif // ROCKSDB_LITE