diff options
author | Grace Zhao <gracezrx@google.com> | 2023-07-07 15:31:32 -0700 |
---|---|---|
committer | Grace Zhao <gracezrx@google.com> | 2023-07-07 15:31:32 -0700 |
commit | 3094e6cc63609d1fff7b57f6d8548853b4840924 (patch) | |
tree | c37f32245d3655235cfc55bbb42ec66b94adc4c0 | |
parent | 4ac48569941d4f48b1a9bffdaf4abb2a3e8e9269 (diff) | |
download | icing-3094e6cc63609d1fff7b57f6d8548853b4840924.tar.gz |
Update Icing from upstream.
Descriptions:
========================================================================
Fix MainIndex::TransferAndAddHits by adding a safety check
========================================================================
[Indexable_nested_properties_list 4.5/5] Modify sectionId assignment so that all property paths in the indexable_nested_properties_list consume sectionIds.
========================================================================
Bug: 288934779
Bug: 289150947
NO_IFTTT="Path is only valid in G3."
Change-Id: Ibad4a09d2026ad038f6b64391497e4248fb891ed
-rw-r--r-- | icing/icing-search-engine_schema_test.cc | 278 | ||||
-rw-r--r-- | icing/index/main/main-index.cc | 7 | ||||
-rw-r--r-- | icing/schema/schema-property-iterator.cc | 36 | ||||
-rw-r--r-- | icing/schema/schema-property-iterator.h | 18 | ||||
-rw-r--r-- | icing/schema/schema-property-iterator_test.cc | 708 | ||||
-rw-r--r-- | icing/schema/schema-type-manager.cc | 29 | ||||
-rw-r--r-- | icing/schema/section-manager-builder_test.cc | 4 | ||||
-rw-r--r-- | icing/schema/section-manager.cc | 33 | ||||
-rw-r--r-- | icing/schema/section-manager_test.cc | 244 | ||||
-rw-r--r-- | synced_AOSP_CL_number.txt | 2 |
10 files changed, 1296 insertions, 63 deletions
diff --git a/icing/icing-search-engine_schema_test.cc b/icing/icing-search-engine_schema_test.cc index 1987afe..af9d0e2 100644 --- a/icing/icing-search-engine_schema_test.cc +++ b/icing/icing-search-engine_schema_test.cc @@ -18,7 +18,6 @@ #include <string> #include <utility> -#include "icing/text_classifier/lib3/utils/base/status.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "icing/document-builder.h" @@ -27,14 +26,12 @@ #include "icing/icing-search-engine.h" #include "icing/jni/jni-cache.h" #include "icing/join/join-processor.h" -#include "icing/portable/endian.h" #include "icing/portable/equals-proto.h" #include "icing/portable/platform.h" #include "icing/proto/debug.pb.h" #include "icing/proto/document.pb.h" #include "icing/proto/document_wrapper.pb.h" #include "icing/proto/initialize.pb.h" -#include "icing/proto/logging.pb.h" #include "icing/proto/optimize.pb.h" #include "icing/proto/persist.pb.h" #include "icing/proto/reset.pb.h" @@ -1081,6 +1078,281 @@ TEST_F(IcingSearchEngineSchemaTest, EqualsSearchResultIgnoreStatsAndScores(empty_result)); } +TEST_F( + IcingSearchEngineSchemaTest, + SetSchemaChangeNestedPropertiesListTriggersIndexRestorationAndReturnsOk) { + IcingSearchEngine icing(GetDefaultIcingOptions(), GetTestJniCache()); + ASSERT_THAT(icing.Initialize().status(), ProtoIsOk()); + + SchemaTypeConfigProto person_proto = + SchemaTypeConfigBuilder() + .SetType("Person") + .AddProperty( + PropertyConfigBuilder() + .SetName("name") + .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty( + PropertyConfigBuilder() + .SetName("lastName") + .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty( + PropertyConfigBuilder() + .SetName("address") + .SetDataTypeString(TERM_MATCH_UNKNOWN, TOKENIZER_NONE) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("age") + .SetDataTypeInt64(NUMERIC_MATCH_RANGE) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("birthday") + .SetDataTypeInt64(NUMERIC_MATCH_UNKNOWN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .Build(); + // Create a schema with nested properties: + // - "sender.address": string type, (nested) non-indexable. Section id = 0. + // - "sender.age": int64 type, (nested) indexed. Section id = 1. + // - "sender.birthday": int64 type, (nested) non-indexable. Section id = 2. + // - "sender.lastName": int64 type, (nested) indexed. Section id = 3. + // - "sender.name": string type, (nested) indexed. Section id = 4. + // - "subject": string type, indexed. Section id = 5. + // - "timestamp": int64 type, indexed. Section id = 6. + // - "sender.foo": unknown type, (nested) non-indexable. Section id = 7. + // + // "sender.address" and "sender.birthday" are assigned a section id because + // they are listed in the indexable_nested_properties_list for 'Email.sender'. + // They are assigned a sectionId but are not indexed since their indexing + // configs are non-indexable. + // + // "sender.foo" is also assigned a section id, but is also not undefined by + // the schema definition. Trying to index a document with this nested property + // should fail. + SchemaProto nested_schema = + SchemaBuilder() + .AddType(person_proto) + .AddType( + SchemaTypeConfigBuilder() + .SetType("Email") + .AddProperty( + PropertyConfigBuilder() + .SetName("sender") + .SetDataTypeDocument( + "Person", /*indexable_nested_properties_list=*/ + {"age", "lastName", "address", "name", "birthday", + "foo"}) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty( + PropertyConfigBuilder() + .SetName("subject") + .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("timestamp") + .SetDataTypeInt64(NUMERIC_MATCH_RANGE) + .SetCardinality(CARDINALITY_OPTIONAL))) + .Build(); + + SetSchemaResultProto set_schema_result = icing.SetSchema(nested_schema); + // Ignore latency numbers. They're covered elsewhere. + set_schema_result.clear_latency_ms(); + SetSchemaResultProto expected_set_schema_result; + expected_set_schema_result.mutable_status()->set_code(StatusProto::OK); + expected_set_schema_result.mutable_new_schema_types()->Add("Email"); + expected_set_schema_result.mutable_new_schema_types()->Add("Person"); + EXPECT_THAT(set_schema_result, EqualsProto(expected_set_schema_result)); + + DocumentProto document = + DocumentBuilder() + .SetKey("namespace1", "uri1") + .SetSchema("Email") + .SetCreationTimestampMs(1000) + .AddStringProperty("subject", + "Did you get the memo about TPS reports?") + .AddDocumentProperty( + "sender", + DocumentBuilder() + .SetKey("namespace1", "uri1") + .SetSchema("Person") + .AddStringProperty("name", "Bill") + .AddStringProperty("lastName", "Lundbergh") + .AddStringProperty("address", "1600 Amphitheatre Pkwy") + .AddInt64Property("age", 20) + .AddInt64Property("birthday", 20) + .Build()) + .AddInt64Property("timestamp", 1234) + .Build(); + + // Indexing this doc should fail, since the 'sender.foo' property is not found + DocumentProto invalid_document = + DocumentBuilder() + .SetKey("namespace2", "uri1") + .SetSchema("Email") + .SetCreationTimestampMs(1000) + .AddStringProperty("subject", + "Did you get the memo about TPS reports?") + .AddDocumentProperty( + "sender", + DocumentBuilder() + .SetKey("namespace1", "uri1") + .SetSchema("Person") + .AddStringProperty("name", "Bill") + .AddStringProperty("lastName", "Lundbergh") + .AddStringProperty("address", "1600 Amphitheatre Pkwy") + .AddInt64Property("age", 20) + .AddInt64Property("birthday", 20) + .AddBytesProperty("foo", "bar bytes") + .Build()) + .AddInt64Property("timestamp", 1234) + .Build(); + + EXPECT_THAT(icing.Put(document).status(), ProtoIsOk()); + EXPECT_THAT(icing.Put(invalid_document).status(), + ProtoStatusIs(StatusProto::NOT_FOUND)); + + SearchResultProto expected_search_result_proto; + expected_search_result_proto.mutable_status()->set_code(StatusProto::OK); + *expected_search_result_proto.mutable_results()->Add()->mutable_document() = + document; + + SearchResultProto empty_result; + empty_result.mutable_status()->set_code(StatusProto::OK); + + // Verify term search + // document should match a query for 'Bill' in 'sender.name', but not in + // 'sender.lastName' + SearchSpecProto search_spec1; + search_spec1.set_query("sender.name:Bill"); + search_spec1.set_term_match_type(TermMatchType::EXACT_ONLY); + + SearchResultProto actual_results = + icing.Search(search_spec1, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, EqualsSearchResultIgnoreStatsAndScores( + expected_search_result_proto)); + + search_spec1.set_query("sender.lastName:Bill"); + actual_results = icing.Search(search_spec1, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + // document should match a query for 'Lundber' in 'sender.lastName', but not + // in 'sender.name'. + SearchSpecProto search_spec2; + search_spec2.set_query("sender.lastName:Lundber"); + search_spec2.set_term_match_type(TermMatchType::PREFIX); + + actual_results = icing.Search(search_spec2, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, EqualsSearchResultIgnoreStatsAndScores( + expected_search_result_proto)); + + search_spec2.set_query("sender.name:Lundber"); + actual_results = icing.Search(search_spec2, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + // document should not match a query for 'Amphitheatre' because the + // 'sender.address' field is not indexed. + search_spec2.set_query("Amphitheatre"); + search_spec2.set_term_match_type(TermMatchType::PREFIX); + + actual_results = icing.Search(search_spec2, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + // Verify numeric (integer) search + // document should match a query for 20 in 'sender.age', but not in + // 'timestamp' or 'sender.birthday' + SearchSpecProto search_spec3; + search_spec3.set_query("sender.age == 20"); + search_spec3.set_search_type( + SearchSpecProto::SearchType::EXPERIMENTAL_ICING_ADVANCED_QUERY); + search_spec3.add_enabled_features(std::string(kNumericSearchFeature)); + + actual_results = icing.Search(search_spec3, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, EqualsSearchResultIgnoreStatsAndScores( + expected_search_result_proto)); + + search_spec3.set_query("timestamp == 20"); + actual_results = icing.Search(search_spec3, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + search_spec3.set_query("birthday == 20"); + actual_results = icing.Search(search_spec3, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + // Now update the schema and don't index "sender.name", "sender.birthday" and + // "sender.foo". + // This should reassign section ids, lead to an index rebuild and ensure that + // nothing match a query for "Bill". + // + // Section id assignment: + // - "sender.address": string type, (nested) non-indexable. Section id = 0. + // - "sender.age": int64 type, (nested) indexed. Section id = 1. + // - "sender.birthday": int64 type, (nested) unindexed. No section id. + // - "sender.lastName": int64 type, (nested) indexed. Section id = 2. + // - "sender.name": string type, (nested) unindexed. No section id. + // - "subject": string type, indexed. Section id = 3. + // - "timestamp": int64 type, indexed. Section id = 4. + // - "sender.foo": unknown type, invalid. No section id. + SchemaProto nested_schema_with_less_props = + SchemaBuilder() + .AddType(person_proto) + .AddType(SchemaTypeConfigBuilder() + .SetType("Email") + .AddProperty( + PropertyConfigBuilder() + .SetName("sender") + .SetDataTypeDocument( + "Person", /*indexable_nested_properties=*/ + {"age", "lastName", "address"}) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("subject") + .SetDataTypeString(TERM_MATCH_PREFIX, + TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("timestamp") + .SetDataTypeInt64(NUMERIC_MATCH_RANGE) + .SetCardinality(CARDINALITY_OPTIONAL))) + .Build(); + + set_schema_result = icing.SetSchema(nested_schema_with_less_props); + // Ignore latency numbers. They're covered elsewhere. + set_schema_result.clear_latency_ms(); + expected_set_schema_result = SetSchemaResultProto(); + expected_set_schema_result.mutable_status()->set_code(StatusProto::OK); + expected_set_schema_result.mutable_index_incompatible_changed_schema_types() + ->Add("Email"); + EXPECT_THAT(set_schema_result, EqualsProto(expected_set_schema_result)); + + // Verify term search + // document shouldn't match a query for 'Bill' in either 'sender.name' or + // 'subject' + search_spec1.set_query("sender.name:Bill"); + actual_results = icing.Search(search_spec1, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); + + search_spec1.set_query("subject:Bill"); + actual_results = icing.Search(search_spec1, GetDefaultScoringSpec(), + ResultSpecProto::default_instance()); + EXPECT_THAT(actual_results, + EqualsSearchResultIgnoreStatsAndScores(empty_result)); +} + TEST_F(IcingSearchEngineSchemaTest, SetSchemaNewJoinablePropertyTriggersIndexRestorationAndReturnsOk) { IcingSearchEngine icing(GetDefaultIcingOptions(), GetTestJniCache()); diff --git a/icing/index/main/main-index.cc b/icing/index/main/main-index.cc index d5e9d57..aae60c6 100644 --- a/icing/index/main/main-index.cc +++ b/icing/index/main/main-index.cc @@ -751,6 +751,13 @@ libtextclassifier3::StatusOr<DocumentId> MainIndex::TransferAndAddHits( old_pl_accessor.GetNextHitsBatch()); while (!tmp.empty()) { for (const Hit& hit : tmp) { + // A safety check to add robustness to the codebase, so to make sure that + // we never access invalid memory, in case that hit from the posting list + // is corrupted. + if (hit.document_id() < 0 || + hit.document_id() >= document_id_old_to_new.size()) { + continue; + } DocumentId new_document_id = document_id_old_to_new[hit.document_id()]; // Transfer the document id of the hit, if the document is not deleted // or outdated. diff --git a/icing/schema/schema-property-iterator.cc b/icing/schema/schema-property-iterator.cc index 2d1ca7e..8fc245c 100644 --- a/icing/schema/schema-property-iterator.cc +++ b/icing/schema/schema-property-iterator.cc @@ -55,8 +55,12 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() { // If an element in sorted_top_level_indexable_nested_properties_ < the // current property path, it means that we've already iterated past the // possible position for it without seeing it. - // It's not a valid property path in our schema definition. Ignore it and - // advance current_top_level_indexable_nested_properties_idx_. + // It's not a valid property path in our schema definition. Add it to + // unknown_indexable_nested_properties_ and advance + // current_top_level_indexable_nested_properties_idx_. + unknown_indexable_nested_property_paths_.push_back( + sorted_top_level_indexable_nested_properties_.at( + current_top_level_indexable_nested_properties_idx_)); ++current_top_level_indexable_nested_properties_idx_; } @@ -75,13 +79,16 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() { : nullptr; if (current_indexable_nested_prop == nullptr || *current_indexable_nested_prop > curr_property_path) { - // Current property is not in the indexable list. Set its indexable - // config according to the current level's indexable config. - levels_.back().SetCurrentPropertyIndexable( - levels_.back().GetLevelNestedIndexable()); + // Current property is not in the indexable list. Set it as indexable if + // its schema level is indexable AND it is an indexable property. + bool is_property_indexable = + levels_.back().GetLevelNestedIndexable() && + SchemaUtil::IsIndexedProperty(curr_property_config); + levels_.back().SetCurrentPropertyIndexable(is_property_indexable); } else if (*current_indexable_nested_prop == curr_property_path) { // Current property is in the indexable list. Set its indexable config - // to true. + // to true. This property will consume a sectionId regardless of whether + // or not it is actually indexable. levels_.back().SetCurrentPropertyIndexable(true); ++current_top_level_indexable_nested_properties_idx_; } @@ -134,8 +141,14 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() { property)); } current_top_level_indexable_nested_properties_idx_ = 0; + // Sort elements and dedupe std::sort(sorted_top_level_indexable_nested_properties_.begin(), sorted_top_level_indexable_nested_properties_.end()); + auto last = + std::unique(sorted_top_level_indexable_nested_properties_.begin(), + sorted_top_level_indexable_nested_properties_.end()); + sorted_top_level_indexable_nested_properties_.erase( + last, sorted_top_level_indexable_nested_properties_.end()); } bool is_cycle = @@ -169,6 +182,15 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() { all_nested_properties_indexable)); parent_type_config_names_.insert(nested_type_config.schema_type()); } + + // Before returning, move all remaining uniterated properties from + // sorted_top_level_indexable_nested_properties_ into + // unknown_indexable_nested_properties_. + std::move(sorted_top_level_indexable_nested_properties_.begin() + + current_top_level_indexable_nested_properties_idx_, + sorted_top_level_indexable_nested_properties_.end(), + std::back_inserter(unknown_indexable_nested_property_paths_)); + return absl_ports::OutOfRangeError("End of iterator"); } diff --git a/icing/schema/schema-property-iterator.h b/icing/schema/schema-property-iterator.h index 3babf9e..66b8f32 100644 --- a/icing/schema/schema-property-iterator.h +++ b/icing/schema/schema-property-iterator.h @@ -83,6 +83,15 @@ class SchemaPropertyIterator { return levels_.back().GetLevelNestedIndexable(); } + // The set of indexable nested properties that are defined in the + // indexable_nested_properties_list but are not found in the schema + // definition. These properties still consume sectionIds, but will not be + // indexed. + const std::vector<std::string>& unknown_indexable_nested_property_paths() + const { + return unknown_indexable_nested_property_paths_; + } + // Advances to the next leaf property. // // Returns: @@ -196,6 +205,15 @@ class SchemaPropertyIterator { // Current iteration index in the sorted_top_level_indexable_nested_properties // list. int current_top_level_indexable_nested_properties_idx_ = 0; + + // Vector of indexable nested properties defined in the + // indexable_nested_properties_list, but not found in the schema definition. + // These properties still consume sectionIds, but will not be indexed. + // Properties are inserted into this vector in sorted order. + // + // TODO(b/289152024): Implement support for indexing these properties if they + // are in the child types of polymorphic nested properties. + std::vector<std::string> unknown_indexable_nested_property_paths_; }; } // namespace lib diff --git a/icing/schema/schema-property-iterator_test.cc b/icing/schema/schema-property-iterator_test.cc index ed71134..2b0226d 100644 --- a/icing/schema/schema-property-iterator_test.cc +++ b/icing/schema/schema-property-iterator_test.cc @@ -31,7 +31,9 @@ namespace lib { namespace { using portable_equals_proto::EqualsProto; +using ::testing::ElementsAre; using ::testing::Eq; +using ::testing::IsEmpty; using ::testing::IsFalse; using ::testing::IsTrue; @@ -42,13 +44,14 @@ TEST(SchemaPropertyIteratorTest, SchemaTypeConfigProto schema_type_config = SchemaTypeConfigBuilder() .SetType(schema_type_name) - .AddProperty(PropertyConfigBuilder().SetName("Google").SetDataType( - TYPE_STRING)) + .AddProperty( + PropertyConfigBuilder().SetName("Google").SetDataTypeString( + TERM_MATCH_EXACT, TOKENIZER_PLAIN)) .AddProperty(PropertyConfigBuilder().SetName("Youtube").SetDataType( TYPE_BYTES)) .AddProperty(PropertyConfigBuilder() .SetName("Alphabet") - .SetDataType(TYPE_INT64)) + .SetDataTypeInt64(NUMERIC_MATCH_UNKNOWN)) .Build(); SchemaUtil::TypeConfigMap type_config_map = { {schema_type_name, schema_type_config}}; @@ -58,7 +61,7 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Alphabet")); EXPECT_THAT(iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config.properties(2))); - EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(iterator.Advance(), IsOk()); EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Google")); @@ -70,10 +73,12 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Youtube")); EXPECT_THAT(iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config.properties(1))); - EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(iterator.unknown_indexable_nested_property_paths(), IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -85,19 +90,20 @@ TEST(SchemaPropertyIteratorTest, SchemaTypeConfigProto schema_type_config1 = SchemaTypeConfigBuilder() .SetType(schema_type_name1) - .AddProperty(PropertyConfigBuilder().SetName("Google").SetDataType( - TYPE_STRING)) + .AddProperty( + PropertyConfigBuilder().SetName("Google").SetDataTypeString( + TERM_MATCH_EXACT, TOKENIZER_PLAIN)) .AddProperty(PropertyConfigBuilder().SetName("Youtube").SetDataType( TYPE_BYTES)) .AddProperty(PropertyConfigBuilder() .SetName("Alphabet") - .SetDataType(TYPE_INT64)) + .SetDataTypeInt64(NUMERIC_MATCH_RANGE)) .Build(); SchemaTypeConfigProto schema_type_config2 = SchemaTypeConfigBuilder() .SetType(schema_type_name2) - .AddProperty( - PropertyConfigBuilder().SetName("Foo").SetDataType(TYPE_STRING)) + .AddProperty(PropertyConfigBuilder().SetName("Foo").SetDataTypeString( + TERM_MATCH_UNKNOWN, TOKENIZER_NONE)) .AddProperty( PropertyConfigBuilder().SetName("Bar").SetDataTypeDocument( schema_type_name1, /*index_nested_properties=*/true)) @@ -106,7 +112,8 @@ TEST(SchemaPropertyIteratorTest, SchemaTypeConfigBuilder() .SetType(schema_type_name3) .AddProperty( - PropertyConfigBuilder().SetName("Hello").SetDataType(TYPE_STRING)) + PropertyConfigBuilder().SetName("Hello").SetDataTypeString( + TERM_MATCH_EXACT, TOKENIZER_PLAIN)) .AddProperty( PropertyConfigBuilder().SetName("World").SetDataTypeDocument( schema_type_name1, /*index_nested_properties=*/true)) @@ -158,13 +165,13 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Bar.Youtube")); EXPECT_THAT(iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config1.properties(1))); - EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(iterator.Advance(), IsOk()); EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Foo")); EXPECT_THAT(iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config2.properties(0))); - EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(iterator.Advance(), IsOk()); EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World.Alphabet")); @@ -182,10 +189,12 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World.Youtube")); EXPECT_THAT(iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config1.properties(1))); - EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(iterator.unknown_indexable_nested_property_paths(), IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -235,6 +244,7 @@ TEST(SchemaPropertyIteratorTest, SchemaPropertyIterator iterator(schema_type_config, type_config_map); EXPECT_THAT(iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(iterator.unknown_indexable_nested_property_paths(), IsEmpty()); } TEST(SchemaPropertyIteratorTest, NestedIndexable) { @@ -413,6 +423,8 @@ TEST(SchemaPropertyIteratorTest, NestedIndexable) { EXPECT_THAT(iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(iterator.unknown_indexable_nested_property_paths(), IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -426,7 +438,7 @@ TEST(SchemaPropertyIteratorTest, .AddProperty( PropertyConfigBuilder() .SetName("schema1prop1") - .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)) + .SetDataTypeString(TERM_MATCH_UNKNOWN, TOKENIZER_NONE)) .AddProperty( PropertyConfigBuilder() .SetName("schema1prop2") @@ -435,6 +447,12 @@ TEST(SchemaPropertyIteratorTest, PropertyConfigBuilder() .SetName("schema1prop3") .SetDataTypeString(TERM_MATCH_UNKNOWN, TOKENIZER_NONE)) + .AddProperty(PropertyConfigBuilder() + .SetName("schema1prop4") + .SetDataTypeInt64(NUMERIC_MATCH_RANGE)) + .AddProperty(PropertyConfigBuilder() + .SetName("schema1prop5") + .SetDataType(TYPE_BOOLEAN)) .Build(); SchemaTypeConfigProto schema_type_config2 = SchemaTypeConfigBuilder() @@ -445,15 +463,15 @@ TEST(SchemaPropertyIteratorTest, .SetDataTypeDocument( schema_type_name1, /*indexable_nested_properties_list=*/{"schema1prop2", - "schema1prop3"})) + "schema1prop3", + "schema1prop5"})) .AddProperty( PropertyConfigBuilder() .SetName("schema2prop2") .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)) - .AddProperty( - PropertyConfigBuilder() - .SetName("schema2prop3") - .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)) + .AddProperty(PropertyConfigBuilder() + .SetName("schema2prop3") + .SetDataTypeInt64(NUMERIC_MATCH_UNKNOWN)) .Build(); SchemaUtil::TypeConfigMap type_config_map = { {schema_type_name1, schema_type_config1}, @@ -461,11 +479,22 @@ TEST(SchemaPropertyIteratorTest, // Order of iteration for Schema2: // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2", - // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"} + // "schema2prop1.schema1prop3", "schema2prop1.schema1prop4", + // "schema2prop1.schema1prop5", "schema2prop2", "schema2prop3"} // // Indexable properties: - // {"schema2prop1.schema1prop2", "schema2prop1.schema1prop3", "schema2prop2", - // "schema2prop3"} + // {"schema2prop1.schema1prop2", "schema2prop1.schema1prop3", + // "schema2prop1.schema1prop5", "schema2prop2"}. + // + // "schema2prop1.schema1prop4" is indexable by its indexing-config, but is not + // considered indexable for Schema2 because Schema2 sets its + // index_nested_properties config to false, and "schema1prop4" is not + // in the indexable_nested_properties_list for schema2prop1. + // + // "schema2prop1.schema1prop1", "schema2prop1.schema1prop3" and + // "schema2prop1.schema1prop5" are non-indexable by its indexing-config. + // However "schema2prop1.schema1prop3" and "schema2prop1.schema1prop5" are + // indexed as it appears in the indexable_list. SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map); EXPECT_THAT(schema2_iterator.Advance(), IsOk()); @@ -490,6 +519,20 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop4")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(3))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop5")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(4))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop2")); EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config2.properties(1))); @@ -499,10 +542,54 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop3")); EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), EqualsProto(schema_type_config2.properties(2))); - EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse()); EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + + // Iterate through schema1 properties. Schema1 only has non-document type leaf + // properties, so its properties will be assigned indexable or not according + // to their indexing configs. + SchemaPropertyIterator schema1_iterator(schema_type_config1, type_config_map); + + EXPECT_THAT(schema1_iterator.Advance(), IsOk()); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyPath(), Eq("schema1prop1")); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema1_iterator.Advance(), IsOk()); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyPath(), Eq("schema1prop2")); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema1_iterator.Advance(), IsOk()); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyPath(), Eq("schema1prop3")); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(2))); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema1_iterator.Advance(), IsOk()); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyPath(), Eq("schema1prop4")); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(3))); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema1_iterator.Advance(), IsOk()); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyPath(), Eq("schema1prop5")); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(4))); + EXPECT_THAT(schema1_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema1_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema1_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -654,6 +741,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema3_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema2: // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2", // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"} @@ -702,6 +792,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -774,6 +867,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema3_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema2: // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2"} // @@ -798,6 +894,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, @@ -951,6 +1050,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema3_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema2: // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2", // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"} @@ -997,6 +1099,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST( @@ -1084,6 +1189,9 @@ TEST( EXPECT_THAT(schema4_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema4_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema3: // {"schema3prop1.schema2prop1.schema1prop1", // "schema3prop1.schema2prop1.schema1prop2"}. @@ -1108,6 +1216,9 @@ TEST( EXPECT_THAT(schema3_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema2: // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2"} // @@ -1133,6 +1244,443 @@ TEST( EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); +} + +TEST(SchemaPropertyIteratorTest, + IndexableNestedPropertiesList_unknownPropPaths) { + std::string schema_type_name1 = "SchemaOne"; + std::string schema_type_name2 = "SchemaTwo"; + std::string schema_type_name3 = "SchemaThree"; + std::string schema_type_name4 = "SchemaFour"; + + SchemaTypeConfigProto schema_type_config1 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name1) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema1prop1") + .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema1prop2") + .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN)) + .Build(); + SchemaTypeConfigProto schema_type_config2 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name2) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema2prop1") + .SetDataTypeDocument(schema_type_name1, + /*indexable_nested_properties_list=*/ + {"schema1prop2", "schema1prop2.foo", + "foo.bar", "zzz", "aaa.zzz"})) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema2prop2") + .SetDataTypeDocument( + schema_type_name1, + /*indexable_nested_properties_list=*/ + {"schema1prop1", "schema1prop2", "unknown.path"})) + .Build(); + SchemaTypeConfigProto schema_type_config3 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name3) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema3prop1") + .SetDataTypeDocument( + schema_type_name2, + /*indexable_nested_properties_list=*/ + {"schema3prop1", "schema2prop1", "schema1prop2", + "schema2prop1.schema1prop2", "schema2prop1.zzz", "zzz"})) + .Build(); + SchemaTypeConfigProto schema_type_config4 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name4) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema4prop1") + .SetDataTypeDocument(schema_type_name3, + /*index_nested_properties=*/true)) + .Build(); + SchemaUtil::TypeConfigMap type_config_map = { + {schema_type_name1, schema_type_config1}, + {schema_type_name2, schema_type_config2}, + {schema_type_name3, schema_type_config3}, + {schema_type_name4, schema_type_config4}}; + + // Order of iteration for Schema4: + // "schema4prop1.schema3prop1.schema2prop1.schema1prop1", + // "schema4prop1.schema3prop1.schema2prop1.schema1prop2" (indexable), + // "schema4prop1.schema3prop1.schema2prop2.schema1prop1", + // "schema4prop1.schema3prop1.schema2prop2.schema1prop2" + // + // Unknown property paths from schema3 will also be included for schema4, + // since schema4 sets index_nested_properties=true. + // This includes everything in schema3prop1's list except + // "schema2prop1.schema1prop2". + SchemaPropertyIterator schema4_iterator(schema_type_config4, type_config_map); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop1")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop2")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop2.schema1prop1")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop2.schema1prop2")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema4_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre("schema4prop1.schema3prop1.schema1prop2", + "schema4prop1.schema3prop1.schema2prop1", + "schema4prop1.schema3prop1.schema2prop1.zzz", + "schema4prop1.schema3prop1.schema3prop1", + "schema4prop1.schema3prop1.zzz")); + + // Order of iteration for Schema3: + // "schema3prop1.schema2prop1.schema1prop1", + // "schema3prop1.schema2prop1.schema1prop2" (indexable), + // "schema3prop1.schema2prop2.schema1prop1", + // "schema3prop1.schema2prop2.schema1prop2" + // + // Unknown properties (in order): + // "schema3prop1.schema1prop2", "schema3prop1.schema2prop1" (not a leaf prop), + // "schema3prop1.schema2prop1.zzz", "schema3prop1.schema3prop1", + // "schema3prop1.zzz" + SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop1.schema1prop1")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop1.schema1prop2")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop2.schema1prop1")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop2.schema1prop2")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre( + "schema3prop1.schema1prop2", "schema3prop1.schema2prop1", + "schema3prop1.schema2prop1.zzz", "schema3prop1.schema3prop1", + "schema3prop1.zzz")); + + // Order of iteration for Schema2: + // "schema2prop1.schema1prop1", + // "schema2prop1.schema1prop2" (indexable), + // "schema2prop2.schema1prop1" (indexable), + // "schema2prop2.schema1prop2" (indexable) + // + // Unknown properties (in order): + // "schema2prop1.aaa.zzz", "schema2prop1.foo.bar", + // "schema2prop1.schema1prop2.foo", "schema2prop1.zzz", + // "schema2prop2.unknown.path" + SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop1")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop2")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop2.schema1prop1")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop2.schema1prop2")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT( + schema2_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre("schema2prop1.aaa.zzz", "schema2prop1.foo.bar", + "schema2prop1.schema1prop2.foo", "schema2prop1.zzz", + "schema2prop2.unknown.path")); +} + +TEST(SchemaPropertyIteratorTest, + IndexableNestedPropertiesListDuplicateElements) { + std::string schema_type_name1 = "SchemaOne"; + std::string schema_type_name2 = "SchemaTwo"; + std::string schema_type_name3 = "SchemaThree"; + std::string schema_type_name4 = "SchemaFour"; + + SchemaTypeConfigProto schema_type_config1 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name1) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema1prop1") + .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema1prop2") + .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN)) + .Build(); + SchemaTypeConfigProto schema_type_config2 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name2) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema2prop1") + .SetDataTypeDocument( + schema_type_name1, + /*indexable_nested_properties_list=*/ + {"schema1prop2", "schema1prop2", "schema1prop2.foo", + "schema1prop2.foo", "foo.bar", "foo.bar", "foo.bar", + "zzz", "zzz", "aaa.zzz", "schema1prop2"})) + .AddProperty(PropertyConfigBuilder() + .SetName("schema2prop2") + .SetDataTypeDocument( + schema_type_name1, + /*indexable_nested_properties_list=*/ + {"schema1prop1", "schema1prop2", "unknown.path", + "unknown.path", "unknown.path", "unknown.path", + "schema1prop1"})) + .Build(); + SchemaTypeConfigProto schema_type_config3 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name3) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema3prop1") + .SetDataTypeDocument( + schema_type_name2, + /*indexable_nested_properties_list=*/ + {"schema3prop1", "schema3prop1", "schema2prop1", + "schema2prop1", "schema1prop2", "schema1prop2", + "schema2prop1.schema1prop2", "schema2prop1.schema1prop2", + "schema2prop1.zzz", "zzz", "zzz"})) + .Build(); + SchemaTypeConfigProto schema_type_config4 = + SchemaTypeConfigBuilder() + .SetType(schema_type_name4) + .AddProperty( + PropertyConfigBuilder() + .SetName("schema4prop1") + .SetDataTypeDocument(schema_type_name3, + /*index_nested_properties=*/true)) + .Build(); + SchemaUtil::TypeConfigMap type_config_map = { + {schema_type_name1, schema_type_config1}, + {schema_type_name2, schema_type_config2}, + {schema_type_name3, schema_type_config3}, + {schema_type_name4, schema_type_config4}}; + + // The results of this test case is the same as the previous test case. This + // is to test that the indexable-list is deduped correctly. + + // Order of iteration for Schema4: + // "schema4prop1.schema3prop1.schema2prop1.schema1prop1", + // "schema4prop1.schema3prop1.schema2prop1.schema1prop2" (indexable), + // "schema4prop1.schema3prop1.schema2prop2.schema1prop1", + // "schema4prop1.schema3prop1.schema2prop2.schema1prop2" + // + // Unknown property paths from schema3 will also be included for schema4, + // since schema4 sets index_nested_properties=true. + // This includes everything in schema3prop1's list except + // "schema2prop1.schema1prop2". + SchemaPropertyIterator schema4_iterator(schema_type_config4, type_config_map); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop1")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop2")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop2.schema1prop1")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), IsOk()); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(), + Eq("schema4prop1.schema3prop1.schema2prop2.schema1prop2")); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema4_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema4_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre("schema4prop1.schema3prop1.schema1prop2", + "schema4prop1.schema3prop1.schema2prop1", + "schema4prop1.schema3prop1.schema2prop1.zzz", + "schema4prop1.schema3prop1.schema3prop1", + "schema4prop1.schema3prop1.zzz")); + + // Order of iteration for Schema3: + // "schema3prop1.schema2prop1.schema1prop1", + // "schema3prop1.schema2prop1.schema1prop2" (indexable), + // "schema3prop1.schema2prop2.schema1prop1", + // "schema3prop1.schema2prop2.schema1prop2" + // + // Unknown properties (in order): + // "schema2prop1.aaa.zzz", "schema2prop1.foo.bar", + // "schema2prop1.schema1prop2.foo", "schema2prop1.zzz", + // "schema2prop2.unknown.path" + SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop1.schema1prop1")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop1.schema1prop2")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop2.schema1prop1")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), IsOk()); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), + Eq("schema3prop1.schema2prop2.schema1prop2")); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema3_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre( + "schema3prop1.schema1prop2", "schema3prop1.schema2prop1", + "schema3prop1.schema2prop1.zzz", "schema3prop1.schema3prop1", + "schema3prop1.zzz")); + + // Order of iteration for Schema2: + // "schema2prop1.schema1prop1", + // "schema2prop1.schema1prop2" (indexable), + // "schema2prop2.schema1prop1" (indexable), + // "schema2prop2.schema1prop2" (indexable) + // + // Unknown properties (in order): + // "schema2prop1.aaa.zzz", "schema2prop1.foo.bar", + // "schema2prop1.schema1prop2.foo", "schema2prop1.zzz", + // "schema2prop2.unknown.path" + SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop1")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop1.schema1prop2")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop2.schema1prop1")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(0))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), IsOk()); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), + Eq("schema2prop2.schema1prop2")); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(), + EqualsProto(schema_type_config1.properties(1))); + EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue()); + + EXPECT_THAT(schema2_iterator.Advance(), + StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT( + schema2_iterator.unknown_indexable_nested_property_paths(), + testing::ElementsAre("schema2prop1.aaa.zzz", "schema2prop1.foo.bar", + "schema2prop1.schema1prop2.foo", "schema2prop1.zzz", + "schema2prop2.unknown.path")); } TEST(SchemaPropertyIteratorTest, @@ -1288,6 +1836,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema3_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema3_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for Schema2: // {"prop1.prop1", "prop1.prop2", // "prop1.prop3", "prop2", "prop3"} @@ -1331,6 +1882,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema2_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema2_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, SingleLevelCycle) { std::string schema_a = "A"; @@ -1386,6 +1940,9 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycle) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema B: // {"schemaBprop2"}, indexable. SchemaPropertyIterator schema_b_iterator(schema_type_config_b, @@ -1399,6 +1956,9 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycle) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) { @@ -1478,6 +2038,9 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema B: // {"schemaBprop1.schemaCprop1.schemaAprop2", "schemaBprop1.schemaCprop2", // "schemaBprop2"} @@ -1509,6 +2072,9 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema C: // {"schemaCprop1.schemaAprop1.schemaBprop2", "schemaCprop1.schemaAprop2", // "schemaCprop2"} @@ -1539,6 +2105,9 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) { EXPECT_THAT(schema_c_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_c_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, SingleLevelCycleWithIndexableList) { @@ -1661,6 +2230,9 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycleWithIndexableList) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema B: // {"schemaBprop1" (true), // "schemaBprop2.schemaBprop1" (true), @@ -1729,6 +2301,9 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycleWithIndexableList) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, MultipleCycles) { @@ -1838,6 +2413,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema B: // {"schemaBprop1.schemaCprop1.schemaAprop2", // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2", @@ -1877,6 +2455,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema C: // {"schemaCprop1.schemaAprop1.schemaBprop2", "schemaCprop1.schemaAprop2", // "schemaCprop1.schemaAprop3.schemaDprop2", "schemaCprop2"} @@ -1915,6 +2496,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) { EXPECT_THAT(schema_c_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_c_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema D: // {"schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2", // "schemaDprop1.schemaAprop1.schemaBprop2", "schemaDprop1.schemaAprop2", @@ -1953,6 +2537,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) { EXPECT_THAT(schema_d_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_d_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) { @@ -2143,6 +2730,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration and whether each property is indexable for schema B: // "schemaBprop1.schemaCprop1.schemaAprop2" (false), // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" (false), @@ -2181,6 +2771,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema C: // "schemaCprop1.schemaAprop1.schemaBprop2" (false), // "schemaCprop1.schemaAprop2" (false), @@ -2219,6 +2812,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) { EXPECT_THAT(schema_c_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_c_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema D: // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false), // "schemaDprop1.schemaAprop1.schemaBprop2" (false), @@ -2256,6 +2852,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) { EXPECT_THAT(schema_d_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_d_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) { @@ -2446,6 +3045,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration and whether each property is indexable for schema B: // "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" // (true), @@ -2579,6 +3181,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) { EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration and whether each property is indexable for schema C: // "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" // (true), "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" @@ -2700,6 +3305,9 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) { EXPECT_THAT(schema_c_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_c_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration and whether each property is indexable for schema D: // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" // (true), "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" @@ -2818,10 +3426,13 @@ TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) { EXPECT_THAT(schema_d_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_d_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, - MultipleCyclesWithIndexableList_nonExistentPropPaths) { + MultipleCyclesWithIndexableList_unknownPropPaths) { std::string schema_a = "A"; std::string schema_b = "B"; std::string schema_c = "C"; @@ -2910,7 +3521,7 @@ TEST(SchemaPropertyIteratorTest, {schema_d, schema_type_config_d}}; // Order of iteration and whether each property is indexable for schema A: - // {"schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true), + // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true), // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" (true), // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2" // (true), "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" @@ -2924,14 +3535,20 @@ TEST(SchemaPropertyIteratorTest, // "schemaAprop3.schemaDprop2" (true) // // The following properties listed in the indexable_list are not defined - // in the schema and should not be seen during iteration: - // - From schemaAprop1's list: - // "schemaBprop1.schemaCprop1", "schemaBprop1.schemaCprop1.schemaAprop3", - // "schemaAprop2", "schemaBprop2.schemaCprop2", "schemaBprop1.foo.bar", - // "foo", "bar" - // - From schemaAprop3's list: - // "schemaBprop2", "bar", "schemaDprop2.foo", "schemaDprop1", - // "schemaAprop3.schemaDprop2" + // in the schema and should not be seen during iteration. These should appear + // in the unknown_indexable_nested_properties_ set. + // "schemaAprop1.bar", + // "schemaAprop1.foo", + // "schemaAprop1.schemaAprop2", + // "schemaAprop1.schemaBprop1.foo.bar", + // "schemaAprop1.schemaBprop1.schemaCprop1", + // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3", + // "schemaAprop1.schemaBprop2.schemaCprop2", + // "schemaAprop3.bar", + // "schemaAprop3.schemaAprop3.schemaDprop2", + // "schemaAprop3.schemaBprop2", + // "schemaAprop3.schemaDprop1", + // "schemaAprop3.schemaDprop2.foo" SchemaPropertyIterator schema_a_iterator(schema_type_config_a, type_config_map); @@ -3025,6 +3642,17 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT( + schema_a_iterator.unknown_indexable_nested_property_paths(), + ElementsAre( + "schemaAprop1.bar", "schemaAprop1.foo", "schemaAprop1.schemaAprop2", + "schemaAprop1.schemaBprop1.foo.bar", + "schemaAprop1.schemaBprop1.schemaCprop1", + "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3", + "schemaAprop1.schemaBprop2.schemaCprop2", "schemaAprop3.bar", + "schemaAprop3.schemaAprop3.schemaDprop2", "schemaAprop3.schemaBprop2", + "schemaAprop3.schemaDprop1", "schemaAprop3.schemaDprop2.foo")); + // Order of iteration and whether each property is indexable for schema B: // "schemaBprop1.schemaCprop1.schemaAprop2" (false), // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" (false), @@ -3063,6 +3691,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema_b_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_b_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema C: // "schemaCprop1.schemaAprop1.schemaBprop2" (false), // "schemaCprop1.schemaAprop2" (false), @@ -3101,6 +3732,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema_c_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + EXPECT_THAT(schema_c_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); + // Order of iteration for schema D: // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false), // "schemaDprop1.schemaAprop1.schemaBprop2" (false), @@ -3138,6 +3772,9 @@ TEST(SchemaPropertyIteratorTest, EXPECT_THAT(schema_d_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_d_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } TEST(SchemaPropertyIteratorTest, TopLevelCycleWithMultipleIndexableLists) { @@ -3257,6 +3894,9 @@ TEST(SchemaPropertyIteratorTest, TopLevelCycleWithMultipleIndexableLists) { EXPECT_THAT(schema_a_iterator.Advance(), StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE)); + + EXPECT_THAT(schema_a_iterator.unknown_indexable_nested_property_paths(), + IsEmpty()); } } // namespace diff --git a/icing/schema/schema-type-manager.cc b/icing/schema/schema-type-manager.cc index ca2f45c..4a6b7f2 100644 --- a/icing/schema/schema-type-manager.cc +++ b/icing/schema/schema-type-manager.cc @@ -20,6 +20,7 @@ #include "icing/text_classifier/lib3/utils/base/statusor.h" #include "icing/absl_ports/canonical_errors.h" #include "icing/schema/joinable-property-manager.h" +#include "icing/schema/property-util.h" #include "icing/schema/schema-property-iterator.h" #include "icing/schema/schema-util.h" #include "icing/schema/section-manager.h" @@ -68,6 +69,34 @@ SchemaTypeManager::Create(const SchemaUtil::TypeConfigMap& type_config_map, schema_type_id, iterator.GetCurrentPropertyConfig(), iterator.GetCurrentPropertyPath())); } + + // Process unknown property paths in the indexable_nested_properties_list. + // These property paths should consume sectionIds but are currently + // not indexed. + // + // SectionId assignment order: + // - We assign section ids to known (existing) properties first in alphabet + // order. + // - After handling all known properties, we assign section ids to all + // unknown (non-existent) properties that are specified in the + // indexable_nested_properties_list. + // - As a result, assignment of the entire section set is not done + // alphabetically, but assignment is still deterministic and alphabetical + // order is preserved inside the known properties and unknown properties + // sets individually. + for (const auto& property_path : + iterator.unknown_indexable_nested_property_paths()) { + PropertyConfigProto unknown_property_config; + unknown_property_config.set_property_name(std::string( + property_util::SplitPropertyPathExpr(property_path).back())); + unknown_property_config.set_data_type( + PropertyConfigProto::DataType::UNKNOWN); + + ICING_RETURN_IF_ERROR( + section_manager_builder.ProcessSchemaTypePropertyConfig( + schema_type_id, unknown_property_config, + std::string(property_path))); + } } return std::unique_ptr<SchemaTypeManager>(new SchemaTypeManager( diff --git a/icing/schema/section-manager-builder_test.cc b/icing/schema/section-manager-builder_test.cc index 60dd507..1d452d5 100644 --- a/icing/schema/section-manager-builder_test.cc +++ b/icing/schema/section-manager-builder_test.cc @@ -270,9 +270,11 @@ TEST_P(NonIndexableSectionManagerBuilderTest, Build) { ICING_ASSERT_OK(builder.ProcessSchemaTypePropertyConfig( /*schema_type_id=*/0, property_config, std::string(kPropertyPath))); + // NonIndexable sections will still consume a sectionId. std::unique_ptr<SectionManager> section_manager = std::move(builder).Build(); EXPECT_THAT(section_manager->GetMetadataList(std::string(kSchemaType)), - IsOkAndHolds(Pointee(IsEmpty()))); + IsOkAndHolds(Pointee(ElementsAre(EqualsSectionMetadata( + /*expected_id=*/0, kPropertyPath, property_config))))); } // The following types are considered non-indexable: diff --git a/icing/schema/section-manager.cc b/icing/schema/section-manager.cc index 38042d0..3d540d6 100644 --- a/icing/schema/section-manager.cc +++ b/icing/schema/section-manager.cc @@ -15,15 +15,9 @@ #include "icing/schema/section-manager.h" #include <algorithm> -#include <cinttypes> -#include <cstddef> #include <cstdint> -#include <iterator> -#include <memory> #include <string> #include <string_view> -#include <unordered_map> -#include <unordered_set> #include <utility> #include <vector> @@ -35,7 +29,6 @@ #include "icing/proto/schema.pb.h" #include "icing/proto/term.pb.h" #include "icing/schema/property-util.h" -#include "icing/schema/schema-util.h" #include "icing/schema/section.h" #include "icing/store/document-filter-data.h" #include "icing/store/key-mapper.h" @@ -99,12 +92,14 @@ SectionManager::Builder::ProcessSchemaTypePropertyConfig( return absl_ports::InvalidArgumentError("Invalid schema type id"); } - if (SchemaUtil::IsIndexedProperty(property_config)) { - ICING_RETURN_IF_ERROR( - AppendNewSectionMetadata(§ion_metadata_cache_[schema_type_id], - std::move(property_path), property_config)); - } - + // We don't need to check if the property is indexable. This method will + // only be called properties that should consume sectionIds, even if the + // property's indexing configuration itself is not indexable. + // This would be the case for unknown and non-indexable property paths that + // are defined in the indexable_nested_properties_list. + ICING_RETURN_IF_ERROR( + AppendNewSectionMetadata(§ion_metadata_cache_[schema_type_id], + std::move(property_path), property_config)); return libtextclassifier3::Status::OK; } @@ -141,6 +136,13 @@ libtextclassifier3::StatusOr<SectionGroup> SectionManager::ExtractSections( for (const SectionMetadata& section_metadata : *metadata_list) { switch (section_metadata.data_type) { case PropertyConfigProto::DataType::STRING: { + if (section_metadata.term_match_type == TermMatchType::UNKNOWN || + section_metadata.tokenizer == + StringIndexingConfig::TokenizerType::NONE) { + // Skip if term-match type is UNKNOWN, or if the tokenizer-type is + // NONE. + break; + } AppendSection( section_metadata, property_util::ExtractPropertyValuesFromDocument<std::string_view>( @@ -149,6 +151,11 @@ libtextclassifier3::StatusOr<SectionGroup> SectionManager::ExtractSections( break; } case PropertyConfigProto::DataType::INT64: { + if (section_metadata.numeric_match_type == + IntegerIndexingConfig::NumericMatchType::UNKNOWN) { + // Skip if numeric-match type is UNKNOWN. + break; + } AppendSection(section_metadata, property_util::ExtractPropertyValuesFromDocument<int64_t>( document, section_metadata.path), diff --git a/icing/schema/section-manager_test.cc b/icing/schema/section-manager_test.cc index db2be6b..eee78e9 100644 --- a/icing/schema/section-manager_test.cc +++ b/icing/schema/section-manager_test.cc @@ -14,7 +14,6 @@ #include "icing/schema/section-manager.h" -#include <limits> #include <memory> #include <string> #include <string_view> @@ -25,7 +24,6 @@ #include "icing/file/filesystem.h" #include "icing/proto/document.pb.h" #include "icing/proto/schema.pb.h" -#include "icing/proto/term.pb.h" #include "icing/schema-builder.h" #include "icing/schema/schema-type-manager.h" #include "icing/schema/schema-util.h" @@ -63,6 +61,28 @@ static constexpr std::string_view kTypeConversation = "Conversation"; static constexpr std::string_view kPropertyEmails = "emails"; static constexpr std::string_view kPropertyName = "name"; +// type and property names of Group +static constexpr std::string_view kTypeGroup = "Group"; +// indexable +static constexpr std::string_view kPropertyConversation = "conversation"; +static constexpr std::string_view kPropertyGroupName = "groupName"; +// nested indexable +static constexpr std::string_view kPropertyNestedConversationName = "name"; +static constexpr std::string_view kPropertyNestedConversationEmailRecipientIds = + "emails.recipientIds"; +static constexpr std::string_view kPropertyNestedConversationEmailRecipient = + "emails.recipients"; +static constexpr std::string_view kPropertyNestedConversationEmailSubject = + "emails.subject"; +// nested non-indexable +static constexpr std::string_view kPropertyNestedConversationEmailAttachment = + "emails.attachment"; +// non-existent property path +static constexpr std::string_view kPropertyNestedNonExistent = + "emails.nonExistentNestedProperty"; +static constexpr std::string_view kPropertyNestedNonExistent2 = + "emails.nonExistentNestedProperty2"; + constexpr int64_t kDefaultTimestamp = 1663274901; PropertyConfigProto CreateRecipientIdsPropertyConfig() { @@ -105,6 +125,22 @@ PropertyConfigProto CreateNamePropertyConfig() { .Build(); } +PropertyConfigProto CreateAttachmentPropertyConfig() { + return PropertyConfigBuilder() + .SetName(kPropertyAttachment) + .SetDataType(TYPE_BYTES) + .SetCardinality(CARDINALITY_OPTIONAL) + .Build(); +} + +PropertyConfigProto CreateGroupNamePropertyConfig() { + return PropertyConfigBuilder() + .SetName(kPropertyGroupName) + .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL) + .Build(); +} + SchemaTypeConfigProto CreateEmailTypeConfig() { return SchemaTypeConfigBuilder() .SetType(kTypeEmail) @@ -139,6 +175,28 @@ SchemaTypeConfigProto CreateConversationTypeConfig() { .Build(); } +SchemaTypeConfigProto CreateGroupTypeConfig() { + return SchemaTypeConfigBuilder() + .SetType(kTypeGroup) + .AddProperty(CreateGroupNamePropertyConfig()) + .AddProperty( + PropertyConfigBuilder() + .SetName(kPropertyConversation) + .SetDataTypeDocument( + kTypeConversation, + /*indexable_nested_properties_list=*/ + {std::string(kPropertyNestedConversationName), + std::string(kPropertyNestedConversationEmailRecipientIds), + std::string(kPropertyNestedConversationEmailSubject), + std::string(kPropertyNestedConversationEmailRecipient), + std::string(kPropertyNestedConversationEmailAttachment), + std::string(kPropertyNestedNonExistent2), + std::string(kPropertyNestedNonExistent), + std::string(kPropertyNestedNonExistent)}) + .SetCardinality(CARDINALITY_REPEATED)) + .Build(); +} + class SectionManagerTest : public ::testing::Test { protected: void SetUp() override { @@ -146,9 +204,11 @@ class SectionManagerTest : public ::testing::Test { auto email_type = CreateEmailTypeConfig(); auto conversation_type = CreateConversationTypeConfig(); + auto group_type = CreateGroupTypeConfig(); type_config_map_.emplace(email_type.schema_type(), email_type); type_config_map_.emplace(conversation_type.schema_type(), conversation_type); + type_config_map_.emplace(group_type.schema_type(), group_type); // DynamicTrieKeyMapper uses 3 internal arrays for bookkeeping. Give each // one 128KiB so the total DynamicTrieKeyMapper should get 384KiB @@ -158,6 +218,7 @@ class SectionManagerTest : public ::testing::Test { filesystem_, test_dir_, key_mapper_size)); ICING_ASSERT_OK(schema_type_mapper_->Put(kTypeEmail, 0)); ICING_ASSERT_OK(schema_type_mapper_->Put(kTypeConversation, 1)); + ICING_ASSERT_OK(schema_type_mapper_->Put(kTypeGroup, 2)); email_document_ = DocumentBuilder() @@ -183,6 +244,15 @@ class SectionManagerTest : public ::testing::Test { DocumentProto(email_document_), DocumentProto(email_document_)) .Build(); + + group_document_ = + DocumentBuilder() + .SetKey("icing", "group/1") + .SetSchema(std::string(kTypeGroup)) + .AddDocumentProperty(std::string(kPropertyConversation), + DocumentProto(conversation_document_)) + .AddStringProperty(std::string(kPropertyGroupName), "group_name_1") + .Build(); } void TearDown() override { @@ -197,6 +267,7 @@ class SectionManagerTest : public ::testing::Test { DocumentProto email_document_; DocumentProto conversation_document_; + DocumentProto group_document_; }; TEST_F(SectionManagerTest, ExtractSections) { @@ -295,6 +366,91 @@ TEST_F(SectionManagerTest, ExtractSectionsNested) { ElementsAre(kDefaultTimestamp, kDefaultTimestamp)); } +TEST_F(SectionManagerTest, ExtractSectionsIndexableNestedPropertiesList) { + // Use SchemaTypeManager factory method to instantiate SectionManager. + ICING_ASSERT_OK_AND_ASSIGN( + std::unique_ptr<SchemaTypeManager> schema_type_manager, + SchemaTypeManager::Create(type_config_map_, schema_type_mapper_.get())); + + // Extracts all sections from 'Group' document + ICING_ASSERT_OK_AND_ASSIGN( + SectionGroup section_group, + schema_type_manager->section_manager().ExtractSections(group_document_)); + + // SectionId assignments: + // 0 -> conversation.emails.attachment (bytes, non-indexable) + // 1 -> conversation.emails.recipientIds (int64) + // 2 -> conversation.emails.recipients (string) + // 3 -> conversation.emails.subject (string) + // 4 -> conversation.name + // (string, but no entry for this in conversation_document_) + // 5 -> groupName (string) + // 6 -> conversation.emails.nonExistentNestedProperty + // (unknown, non-indexable) + // 7 -> conversation.emails.nonExistentNestedProperty2 + // (unknown, non-indexable) + // + // SectionId assignment order: + // - We assign section ids to known (existing) properties first in alphabet + // order. + // - After handling all known properties, we assign section ids to all unknown + // (non-existent) properties that are specified in the + // indexable_nested_properties_list. + // - As a result, assignment of the entire section set is not done + // alphabetically, but assignment is still deterministic and alphabetical + // order is preserved inside the known properties and unknown properties + // sets individually. + // + // 'conversation.emails.attachment', + // 'conversation.emails.nonExistentNestedProperty' and + // 'conversation.emails.nonExistentNestedProperty2' are assigned sectionIds + // even though they are non-indexable because they appear in 'Group' schema + // type's indexable_nested_props_list. + // However 'conversation.emails.attachment' does not exist in section_group + // (even though the property exists and has a sectionId assignment) as + // SectionManager::ExtractSections only extracts indexable string and integer + // section data from a document. + + // String sections + EXPECT_THAT(section_group.string_sections, SizeIs(3)); + + EXPECT_THAT(section_group.string_sections[0].metadata, + EqualsSectionMetadata( + /*expected_id=*/2, + /*expected_property_path=*/"conversation.emails.recipients", + CreateRecipientsPropertyConfig())); + EXPECT_THAT(section_group.string_sections[0].content, + ElementsAre("recipient1", "recipient2", "recipient3", + "recipient1", "recipient2", "recipient3")); + + EXPECT_THAT(section_group.string_sections[1].metadata, + EqualsSectionMetadata( + /*expected_id=*/3, + /*expected_property_path=*/"conversation.emails.subject", + CreateSubjectPropertyConfig())); + EXPECT_THAT(section_group.string_sections[1].content, + ElementsAre("the subject", "the subject")); + + EXPECT_THAT(section_group.string_sections[2].metadata, + EqualsSectionMetadata( + /*expected_id=*/5, + /*expected_property_path=*/"groupName", + CreateGroupNamePropertyConfig())); + EXPECT_THAT(section_group.string_sections[2].content, + ElementsAre("group_name_1")); + + // Integer sections + EXPECT_THAT(section_group.integer_sections, SizeIs(1)); + + EXPECT_THAT(section_group.integer_sections[0].metadata, + EqualsSectionMetadata( + /*expected_id=*/1, + /*expected_property_path=*/"conversation.emails.recipientIds", + CreateRecipientIdsPropertyConfig())); + EXPECT_THAT(section_group.integer_sections[0].content, + ElementsAre(1, 2, 3, 1, 2, 3)); +} + TEST_F(SectionManagerTest, GetSectionMetadata) { // Use SchemaTypeManager factory method to instantiate SectionManager. ICING_ASSERT_OK_AND_ASSIGN( @@ -352,6 +508,86 @@ TEST_F(SectionManagerTest, GetSectionMetadata) { IsOkAndHolds(Pointee(EqualsSectionMetadata( /*expected_id=*/4, /*expected_property_path=*/"name", CreateNamePropertyConfig())))); + + // Group (section id -> section property path): + // 0 -> conversation.emails.attachment (non-indexable) + // 1 -> conversation.emails.recipientIds + // 2 -> conversation.emails.recipients + // 3 -> conversation.emails.subject + // 4 -> conversation.name + // 5 -> groupName + // 6 -> conversation.emails.nonExistentNestedProperty (non-indexable) + // 7 -> conversation.emails.nonExistentNestedProperty2 (non-indexable) + // + // SectionId assignment order: + // - We assign section ids to known (existing) properties first in alphabet + // order. + // - After handling all known properties, we assign section ids to all unknown + // (non-existent) properties that are specified in the + // indexable_nested_properties_list. + // - As a result, assignment of the entire section set is not done + // alphabetically, but assignment is still deterministic and alphabetical + // order is preserved inside the known properties and unknown properties + // sets individually. + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/0), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/0, + /*expected_property_path=*/"conversation.emails.attachment", + CreateAttachmentPropertyConfig())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/1), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/1, + /*expected_property_path=*/"conversation.emails.recipientIds", + CreateRecipientIdsPropertyConfig())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/2), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/2, + /*expected_property_path=*/"conversation.emails.recipients", + CreateRecipientsPropertyConfig())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/3), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/3, + /*expected_property_path=*/"conversation.emails.subject", + CreateSubjectPropertyConfig())))); + EXPECT_THAT( + schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/4), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/4, /*expected_property_path=*/"conversation.name", + CreateNamePropertyConfig())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/5), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/5, /*expected_property_path=*/"groupName", + CreateGroupNamePropertyConfig())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/6), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/6, + /*expected_property_path=*/ + "conversation.emails.nonExistentNestedProperty", + PropertyConfigBuilder() + .SetName("nonExistentNestedProperty") + .SetDataType(TYPE_UNKNOWN) + .Build())))); + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/7), + IsOkAndHolds(Pointee(EqualsSectionMetadata( + /*expected_id=*/7, + /*expected_property_path=*/ + "conversation.emails.nonExistentNestedProperty2", + PropertyConfigBuilder() + .SetName("nonExistentNestedProperty2") + .SetDataType(TYPE_UNKNOWN) + .Build())))); + // Check that no more properties are indexed + EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( + /*schema_type_id=*/2, /*section_id=*/8), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); } TEST_F(SectionManagerTest, GetSectionMetadataInvalidSchemaTypeId) { @@ -359,13 +595,13 @@ TEST_F(SectionManagerTest, GetSectionMetadataInvalidSchemaTypeId) { ICING_ASSERT_OK_AND_ASSIGN( std::unique_ptr<SchemaTypeManager> schema_type_manager, SchemaTypeManager::Create(type_config_map_, schema_type_mapper_.get())); - ASSERT_THAT(type_config_map_, SizeIs(2)); + ASSERT_THAT(type_config_map_, SizeIs(3)); EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( /*schema_type_id=*/-1, /*section_id=*/0), StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); EXPECT_THAT(schema_type_manager->section_manager().GetSectionMetadata( - /*schema_type_id=*/2, /*section_id=*/0), + /*schema_type_id=*/3, /*section_id=*/0), StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); } diff --git a/synced_AOSP_CL_number.txt b/synced_AOSP_CL_number.txt index 9a7bd49..09c1edd 100644 --- a/synced_AOSP_CL_number.txt +++ b/synced_AOSP_CL_number.txt @@ -1 +1 @@ -set(synced_AOSP_CL_number=546080947) +set(synced_AOSP_CL_number=546391919) |