1 // Copyright (C) 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ICING_TESTING_COMMON_MATCHERS_H_ 16 #define ICING_TESTING_COMMON_MATCHERS_H_ 17 18 #include <algorithm> 19 #include <cinttypes> 20 #include <cmath> 21 #include <functional> 22 #include <string> 23 #include <vector> 24 25 #include "icing/text_classifier/lib3/utils/base/status.h" 26 #include "icing/text_classifier/lib3/utils/base/status_macros.h" 27 #include "gmock/gmock.h" 28 #include "gtest/gtest.h" 29 #include "icing/absl_ports/str_join.h" 30 #include "icing/index/hit/doc-hit-info.h" 31 #include "icing/index/hit/hit.h" 32 #include "icing/index/iterator/doc-hit-info-iterator-test-util.h" 33 #include "icing/index/iterator/doc-hit-info-iterator.h" 34 #include "icing/legacy/core/icing-string-util.h" 35 #include "icing/portable/equals-proto.h" 36 #include "icing/proto/search.pb.h" 37 #include "icing/proto/status.pb.h" 38 #include "icing/schema/joinable-property.h" 39 #include "icing/schema/schema-store.h" 40 #include "icing/schema/scorable_property_manager.h" 41 #include "icing/schema/section.h" 42 #include "icing/scoring/scored-document-hit.h" 43 44 namespace icing { 45 namespace lib { 46 47 // Used to match Token(Token::Type type, std::string_view text) 48 MATCHER_P2(EqualsToken, type, text, "") { 49 std::string arg_string(arg.text.data(), arg.text.length()); 50 if (arg.type != type || arg.text != text) { 51 *result_listener << IcingStringUtil::StringPrintf( 52 "(Expected: type=%d, text=\"%s\". Actual: type=%d, text=\"%s\")", type, 53 text, arg.type, arg_string.c_str()); 54 return false; 55 } 56 return true; 57 } 58 59 MATCHER_P(EqualsNormalizedTerm, text, "") { 60 std::string arg_string(arg.text.data(), arg.text.length()); 61 if (arg.text != text) { 62 *result_listener << IcingStringUtil::StringPrintf( 63 "(Expected: text=\"%s\". Actual: text=\"%s\")", text, 64 arg_string.c_str()); 65 return false; 66 } 67 return true; 68 } 69 70 // Used to match a DocHitInfo 71 MATCHER_P2(EqualsDocHitInfo, document_id, section_ids, "") { 72 const DocHitInfo& actual = arg; 73 SectionIdMask section_mask = kSectionIdMaskNone; 74 for (SectionId section_id : section_ids) { 75 section_mask |= UINT64_C(1) << section_id; 76 } 77 *result_listener << IcingStringUtil::StringPrintf( 78 "(actual is {document_id=%d, section_mask=%" PRIu64 79 "}, but expected was " 80 "{document_id=%d, section_mask=%" PRIu64 "}.)", 81 actual.document_id(), actual.hit_section_ids_mask(), document_id, 82 section_mask); 83 return actual.document_id() == document_id && 84 actual.hit_section_ids_mask() == section_mask; 85 } 86 87 // Used to match a DocHitInfoIterator::CallStats 88 MATCHER_P5(EqualsDocHitInfoIteratorCallStats, num_leaf_advance_calls_lite_index, 89 num_leaf_advance_calls_main_index, 90 num_leaf_advance_calls_integer_index, 91 num_leaf_advance_calls_no_index, num_blocks_inspected, "") { 92 const DocHitInfoIterator::CallStats& actual = arg; 93 *result_listener << IcingStringUtil::StringPrintf( 94 "(actual is {num_leaf_advance_calls_lite_index=%d, " 95 "num_leaf_advance_calls_main_index=%d, " 96 "num_leaf_advance_calls_integer_index=%d, " 97 "num_leaf_advance_calls_no_index=%d, num_blocks_inspected=%d}, but " 98 "expected was {num_leaf_advance_calls_lite_index=%d, " 99 "num_leaf_advance_calls_main_index=%d, " 100 "num_leaf_advance_calls_integer_index=%d, " 101 "num_leaf_advance_calls_no_index=%d, num_blocks_inspected=%d}.)", 102 actual.num_leaf_advance_calls_lite_index, 103 actual.num_leaf_advance_calls_main_index, 104 actual.num_leaf_advance_calls_integer_index, 105 actual.num_leaf_advance_calls_no_index, actual.num_blocks_inspected, 106 num_leaf_advance_calls_lite_index, num_leaf_advance_calls_main_index, 107 num_leaf_advance_calls_integer_index, num_leaf_advance_calls_no_index, 108 num_blocks_inspected); 109 return actual.num_leaf_advance_calls_lite_index == 110 num_leaf_advance_calls_lite_index && 111 actual.num_leaf_advance_calls_main_index == 112 num_leaf_advance_calls_main_index && 113 actual.num_leaf_advance_calls_integer_index == 114 num_leaf_advance_calls_integer_index && 115 actual.num_leaf_advance_calls_no_index == 116 num_leaf_advance_calls_no_index && 117 actual.num_blocks_inspected == num_blocks_inspected; 118 } 119 120 // Used to match a DocumentAssociatedScoreData 121 MATCHER_P5(EqualsDocumentAssociatedScoreData, corpus_id, document_score, 122 creation_timestamp_ms, length_in_tokens, 123 has_valid_scorable_property_cache_index, "") { 124 bool expected_has_valid_scorable_property_cache_index = 125 arg.scorable_property_cache_index() != -1; 126 return arg.corpus_id() == corpus_id && 127 arg.document_score() == document_score && 128 arg.creation_timestamp_ms() == creation_timestamp_ms && 129 arg.length_in_tokens() == length_in_tokens && 130 expected_has_valid_scorable_property_cache_index == 131 has_valid_scorable_property_cache_index; 132 } 133 134 // Used to match a ScorablePropertyManager::ScorablePropertyInfo 135 MATCHER_P2(EqualsScorablePropertyInfo, property_path, data_type, "") { 136 const ScorablePropertyManager::ScorablePropertyInfo& actual = arg; 137 return actual.property_path == property_path && actual.data_type == data_type; 138 } 139 140 struct ExtractTermFrequenciesResult { 141 std::array<Hit::TermFrequency, kTotalNumSections> term_frequencies = {0}; 142 SectionIdMask section_mask = kSectionIdMaskNone; 143 }; 144 // Extracts the term frequencies represented by the section_ids_tf_map. 145 // Returns: 146 // - a SectionIdMask representing all sections that appears as entries in the 147 // map, even if they have an entry with term_frequency==0 148 // - an array representing the term frequencies for each section. Sections not 149 // present in section_ids_tf_map have a term frequency of 0. 150 ExtractTermFrequenciesResult ExtractTermFrequencies( 151 const std::unordered_map<SectionId, Hit::TermFrequency>& 152 section_ids_tf_map); 153 154 struct CheckTermFrequencyResult { 155 std::string expected_term_frequencies_str; 156 std::string actual_term_frequencies_str; 157 bool term_frequencies_match = true; 158 }; 159 // Checks that the term frequencies in actual_term_frequencies match those 160 // specified in expected_section_ids_tf_map. If there is no entry in 161 // expected_section_ids_tf_map, then it is assumed that the term frequency for 162 // that section is 0. 163 // Returns: 164 // - a bool indicating if the term frequencies match 165 // - debug strings representing the contents of the actual and expected term 166 // term frequency arrays. 167 CheckTermFrequencyResult CheckTermFrequency( 168 const std::array<Hit::TermFrequency, kTotalNumSections>& 169 expected_term_frequencies, 170 const std::array<Hit::TermFrequency, kTotalNumSections>& 171 actual_term_frequencies); 172 173 // Used to match a DocHitInfo 174 MATCHER_P2(EqualsDocHitInfoWithTermFrequency, document_id, 175 section_ids_to_term_frequencies_map, "") { 176 const DocHitInfoTermFrequencyPair& actual = arg; 177 std::array<Hit::TermFrequency, kTotalNumSections> actual_tf_array; 178 for (SectionId section_id = 0; section_id < kTotalNumSections; ++section_id) { 179 actual_tf_array[section_id] = actual.hit_term_frequency(section_id); 180 } 181 ExtractTermFrequenciesResult expected = 182 ExtractTermFrequencies(section_ids_to_term_frequencies_map); 183 CheckTermFrequencyResult check_tf_result = 184 CheckTermFrequency(expected.term_frequencies, actual_tf_array); 185 186 *result_listener << IcingStringUtil::StringPrintf( 187 "(actual is {document_id=%d, section_mask=%" PRIu64 188 ", term_frequencies=%s}, but expected was " 189 "{document_id=%d, section_mask=%" PRIu64 ", term_frequencies=%s}.)", 190 actual.doc_hit_info().document_id(), 191 actual.doc_hit_info().hit_section_ids_mask(), 192 check_tf_result.actual_term_frequencies_str.c_str(), document_id, 193 expected.section_mask, 194 check_tf_result.expected_term_frequencies_str.c_str()); 195 return actual.doc_hit_info().document_id() == document_id && 196 actual.doc_hit_info().hit_section_ids_mask() == 197 expected.section_mask && 198 check_tf_result.term_frequencies_match; 199 } 200 201 MATCHER_P2(EqualsTermMatchInfo, term, section_ids_to_term_frequencies_map, "") { 202 const TermMatchInfo& actual = arg; 203 std::string term_str(term); 204 ExtractTermFrequenciesResult expected = 205 ExtractTermFrequencies(section_ids_to_term_frequencies_map); 206 CheckTermFrequencyResult check_tf_result = 207 CheckTermFrequency(expected.term_frequencies, actual.term_frequencies); 208 *result_listener << IcingStringUtil::StringPrintf( 209 "(actual is {term=%s, section_mask=%" PRIu64 210 ", term_frequencies=%s}, but expected was " 211 "{term=%s, section_mask=%" PRIu64 ", term_frequencies=%s}.)", 212 actual.term.data(), actual.section_ids_mask, 213 check_tf_result.actual_term_frequencies_str.c_str(), term_str.data(), 214 expected.section_mask, 215 check_tf_result.expected_term_frequencies_str.c_str()); 216 return actual.term == term && 217 actual.section_ids_mask == expected.section_mask && 218 check_tf_result.term_frequencies_match; 219 } 220 221 class ScoredDocumentHitFormatter { 222 public: operator()223 std::string operator()(const ScoredDocumentHit& scored_document_hit) { 224 return IcingStringUtil::StringPrintf( 225 "(document_id=%d, hit_section_id_mask=%" PRId64 ", score=%.2f)", 226 scored_document_hit.document_id(), 227 scored_document_hit.hit_section_id_mask(), scored_document_hit.score()); 228 } 229 }; 230 231 class ScoredDocumentHitEqualComparator { 232 public: operator()233 bool operator()(const ScoredDocumentHit& lhs, 234 const ScoredDocumentHit& rhs) const { 235 bool additional_scores_match = true; 236 if (lhs.additional_scores() != nullptr && 237 rhs.additional_scores() != nullptr) { 238 additional_scores_match = 239 *lhs.additional_scores() == *rhs.additional_scores(); 240 } else { 241 additional_scores_match = 242 lhs.additional_scores() == rhs.additional_scores(); 243 } 244 return lhs.document_id() == rhs.document_id() && 245 lhs.hit_section_id_mask() == rhs.hit_section_id_mask() && 246 std::fabs(lhs.score() - rhs.score()) < 1e-6 && 247 additional_scores_match; 248 } 249 }; 250 251 // Used to match a ScoredDocumentHit 252 MATCHER_P(EqualsScoredDocumentHit, expected_scored_document_hit, "") { 253 ScoredDocumentHitEqualComparator equal_comparator; 254 if (!equal_comparator(arg, expected_scored_document_hit)) { 255 ScoredDocumentHitFormatter formatter; 256 *result_listener << "Expected: " << formatter(expected_scored_document_hit) 257 << ". Actual: " << formatter(arg); 258 return false; 259 } 260 return true; 261 } 262 263 // Used to match a JoinedScoredDocumentHit 264 MATCHER_P(EqualsJoinedScoredDocumentHit, expected_joined_scored_document_hit, 265 "") { 266 ScoredDocumentHitEqualComparator equal_comparator; 267 if (std::fabs(arg.final_score() - 268 expected_joined_scored_document_hit.final_score()) > 1e-6 || 269 !equal_comparator( 270 arg.parent_scored_document_hit(), 271 expected_joined_scored_document_hit.parent_scored_document_hit()) || 272 arg.child_scored_document_hits().size() != 273 expected_joined_scored_document_hit.child_scored_document_hits() 274 .size() || 275 !std::equal( 276 arg.child_scored_document_hits().cbegin(), 277 arg.child_scored_document_hits().cend(), 278 expected_joined_scored_document_hit.child_scored_document_hits() 279 .cbegin(), 280 equal_comparator)) { 281 ScoredDocumentHitFormatter formatter; 282 283 *result_listener << IcingStringUtil::StringPrintf( 284 "Expected: final_score=%.2f, parent_scored_document_hit=%s, " 285 "child_scored_document_hits=[%s]. Actual: final_score=%.2f, " 286 "parent_scored_document_hit=%s, child_scored_document_hits=[%s]", 287 expected_joined_scored_document_hit.final_score(), 288 formatter( 289 expected_joined_scored_document_hit.parent_scored_document_hit()) 290 .c_str(), 291 absl_ports::StrJoin( 292 expected_joined_scored_document_hit.child_scored_document_hits(), 293 ",", formatter) 294 .c_str(), 295 arg.final_score(), formatter(arg.parent_scored_document_hit()).c_str(), 296 absl_ports::StrJoin(arg.child_scored_document_hits(), ",", formatter) 297 .c_str()); 298 return false; 299 } 300 return true; 301 } 302 303 MATCHER_P(EqualsSetSchemaResult, expected, "") { 304 const SchemaStore::SetSchemaResult& actual = arg; 305 306 if (actual.success == expected.success && 307 actual.old_schema_type_ids_changed == 308 expected.old_schema_type_ids_changed && 309 actual.schema_types_deleted_by_name == 310 expected.schema_types_deleted_by_name && 311 actual.schema_types_deleted_by_id == 312 expected.schema_types_deleted_by_id && 313 actual.schema_types_incompatible_by_name == 314 expected.schema_types_incompatible_by_name && 315 actual.schema_types_incompatible_by_id == 316 expected.schema_types_incompatible_by_id && 317 actual.schema_types_new_by_name == expected.schema_types_new_by_name && 318 actual.schema_types_changed_fully_compatible_by_name == 319 expected.schema_types_changed_fully_compatible_by_name && 320 actual.schema_types_index_incompatible_by_name == 321 expected.schema_types_index_incompatible_by_name && 322 actual.schema_types_join_incompatible_by_name == 323 expected.schema_types_join_incompatible_by_name && 324 actual.schema_types_scorable_property_inconsistent_by_id == 325 expected.schema_types_scorable_property_inconsistent_by_id) { 326 return true; 327 } 328 329 // Format schema_type_ids_changed 330 std::string actual_old_schema_type_ids_changed = absl_ports::StrCat( 331 "[", 332 absl_ports::StrJoin(actual.old_schema_type_ids_changed, ",", 333 absl_ports::NumberFormatter()), 334 "]"); 335 336 std::string expected_old_schema_type_ids_changed = absl_ports::StrCat( 337 "[", 338 absl_ports::StrJoin(expected.old_schema_type_ids_changed, ",", 339 absl_ports::NumberFormatter()), 340 "]"); 341 342 // Format schema_types_deleted_by_name 343 std::string actual_schema_types_deleted_by_name = absl_ports::StrCat( 344 "[", absl_ports::StrJoin(actual.schema_types_deleted_by_name, ","), "]"); 345 346 std::string expected_schema_types_deleted_by_name = absl_ports::StrCat( 347 "[", absl_ports::StrJoin(expected.schema_types_deleted_by_name, ","), 348 "]"); 349 350 // Format schema_types_deleted_by_id 351 std::string actual_schema_types_deleted_by_id = absl_ports::StrCat( 352 "[", 353 absl_ports::StrJoin(actual.schema_types_deleted_by_id, ",", 354 absl_ports::NumberFormatter()), 355 "]"); 356 357 std::string expected_schema_types_deleted_by_id = absl_ports::StrCat( 358 "[", 359 absl_ports::StrJoin(expected.schema_types_deleted_by_id, ",", 360 absl_ports::NumberFormatter()), 361 "]"); 362 363 // Format schema_types_incompatible_by_name 364 std::string actual_schema_types_incompatible_by_name = absl_ports::StrCat( 365 "[", absl_ports::StrJoin(actual.schema_types_incompatible_by_name, ","), 366 "]"); 367 368 std::string expected_schema_types_incompatible_by_name = absl_ports::StrCat( 369 "[", absl_ports::StrJoin(expected.schema_types_incompatible_by_name, ","), 370 "]"); 371 372 // Format schema_types_incompatible_by_id 373 std::string actual_schema_types_incompatible_by_id = absl_ports::StrCat( 374 "[", 375 absl_ports::StrJoin(actual.schema_types_incompatible_by_id, ",", 376 absl_ports::NumberFormatter()), 377 "]"); 378 379 std::string expected_schema_types_incompatible_by_id = absl_ports::StrCat( 380 "[", 381 absl_ports::StrJoin(expected.schema_types_incompatible_by_id, ",", 382 absl_ports::NumberFormatter()), 383 "]"); 384 385 // Format schema_types_new_by_name 386 std::string actual_schema_types_new_by_name = absl_ports::StrCat( 387 "[", absl_ports::StrJoin(actual.schema_types_new_by_name, ","), "]"); 388 389 std::string expected_schema_types_new_by_name = absl_ports::StrCat( 390 "[", absl_ports::StrJoin(expected.schema_types_new_by_name, ","), "]"); 391 392 // Format schema_types_changed_fully_compatible_by_name 393 std::string actual_schema_types_changed_fully_compatible_by_name = 394 absl_ports::StrCat( 395 "[", 396 absl_ports::StrJoin( 397 actual.schema_types_changed_fully_compatible_by_name, ","), 398 "]"); 399 400 std::string expected_schema_types_changed_fully_compatible_by_name = 401 absl_ports::StrCat( 402 "[", 403 absl_ports::StrJoin( 404 expected.schema_types_changed_fully_compatible_by_name, ","), 405 "]"); 406 407 // Format schema_types_deleted_by_id 408 std::string actual_schema_types_index_incompatible_by_name = 409 absl_ports::StrCat( 410 "[", 411 absl_ports::StrJoin(actual.schema_types_index_incompatible_by_name, 412 ","), 413 "]"); 414 415 std::string expected_schema_types_index_incompatible_by_name = 416 absl_ports::StrCat( 417 "[", 418 absl_ports::StrJoin(expected.schema_types_index_incompatible_by_name, 419 ","), 420 "]"); 421 422 // Format schema_types_join_incompatible_by_name 423 std::string actual_schema_types_join_incompatible_by_name = 424 absl_ports::StrCat( 425 "[", 426 absl_ports::StrJoin(actual.schema_types_join_incompatible_by_name, 427 ","), 428 "]"); 429 430 std::string expected_schema_types_join_incompatible_by_name = 431 absl_ports::StrCat( 432 "[", 433 absl_ports::StrJoin(expected.schema_types_join_incompatible_by_name, 434 ","), 435 "]"); 436 437 *result_listener << IcingStringUtil::StringPrintf( 438 "\nExpected {\n" 439 "\tsuccess=%d,\n" 440 "\told_schema_type_ids_changed=%s,\n" 441 "\tschema_types_deleted_by_name=%s,\n" 442 "\tschema_types_deleted_by_id=%s,\n" 443 "\tschema_types_incompatible_by_name=%s,\n" 444 "\tschema_types_incompatible_by_id=%s\n" 445 "\tschema_types_new_by_name=%s,\n" 446 "\tschema_types_changed_fully_compatible_by_name=%s\n" 447 "\tschema_types_index_incompatible_by_name=%s,\n" 448 "\tschema_types_join_incompatible_by_name=%s\n" 449 "}\n" 450 "Actual {\n" 451 "\tsuccess=%d,\n" 452 "\told_schema_type_ids_changed=%s,\n" 453 "\tschema_types_deleted_by_name=%s,\n" 454 "\tschema_types_deleted_by_id=%s,\n" 455 "\tschema_types_incompatible_by_name=%s,\n" 456 "\tschema_types_incompatible_by_id=%s\n" 457 "\tschema_types_new_by_name=%s,\n" 458 "\tschema_types_changed_fully_compatible_by_name=%s\n" 459 "\tschema_types_index_incompatible_by_name=%s,\n" 460 "\tschema_types_join_incompatible_by_name=%s\n" 461 "}\n", 462 expected.success, expected_old_schema_type_ids_changed.c_str(), 463 expected_schema_types_deleted_by_name.c_str(), 464 expected_schema_types_deleted_by_id.c_str(), 465 expected_schema_types_incompatible_by_name.c_str(), 466 expected_schema_types_incompatible_by_id.c_str(), 467 expected_schema_types_new_by_name.c_str(), 468 expected_schema_types_changed_fully_compatible_by_name.c_str(), 469 expected_schema_types_index_incompatible_by_name.c_str(), 470 expected_schema_types_join_incompatible_by_name.c_str(), actual.success, 471 actual_old_schema_type_ids_changed.c_str(), 472 actual_schema_types_deleted_by_name.c_str(), 473 actual_schema_types_deleted_by_id.c_str(), 474 actual_schema_types_incompatible_by_name.c_str(), 475 actual_schema_types_incompatible_by_id.c_str(), 476 actual_schema_types_new_by_name.c_str(), 477 actual_schema_types_changed_fully_compatible_by_name.c_str(), 478 actual_schema_types_index_incompatible_by_name.c_str(), 479 actual_schema_types_join_incompatible_by_name.c_str()); 480 return false; 481 } 482 483 MATCHER_P3(EqualsSectionMetadata, expected_id, expected_property_path, 484 expected_property_config_proto, "") { 485 const SectionMetadata& actual = arg; 486 return actual.id == expected_id && actual.path == expected_property_path && 487 actual.data_type == expected_property_config_proto.data_type() && 488 actual.tokenizer == 489 expected_property_config_proto.string_indexing_config() 490 .tokenizer_type() && 491 actual.term_match_type == 492 expected_property_config_proto.string_indexing_config() 493 .term_match_type() && 494 actual.numeric_match_type == 495 expected_property_config_proto.integer_indexing_config() 496 .numeric_match_type() && 497 actual.embedding_indexing_type == 498 expected_property_config_proto.embedding_indexing_config() 499 .embedding_indexing_type() && 500 actual.quantization_type == 501 expected_property_config_proto.embedding_indexing_config() 502 .quantization_type(); 503 } 504 505 MATCHER_P3(EqualsJoinablePropertyMetadata, expected_id, expected_property_path, 506 expected_property_config_proto, "") { 507 const JoinablePropertyMetadata& actual = arg; 508 return actual.id == expected_id && actual.path == expected_property_path && 509 actual.data_type == expected_property_config_proto.data_type() && 510 actual.value_type == 511 expected_property_config_proto.joinable_config().value_type() && 512 actual.delete_propagation_type == 513 expected_property_config_proto.joinable_config() 514 .delete_propagation_type(); 515 } 516 517 std::string StatusCodeToString(libtextclassifier3::StatusCode code); 518 519 std::string ProtoStatusCodeToString(StatusProto::Code code); 520 521 MATCHER(IsOk, "") { 522 libtextclassifier3::StatusAdapter adapter(arg); 523 if (adapter.status().ok()) { 524 return true; 525 } 526 *result_listener << IcingStringUtil::StringPrintf( 527 "Expected OK, actual was (%s:%s)", 528 StatusCodeToString(adapter.status().CanonicalCode()).c_str(), 529 adapter.status().error_message().c_str()); 530 return false; 531 } 532 533 MATCHER_P(IsOkAndHolds, matcher, "") { 534 if (!arg.ok()) { 535 *result_listener << IcingStringUtil::StringPrintf( 536 "Expected OK, actual was (%s:%s)", 537 StatusCodeToString(arg.status().CanonicalCode()).c_str(), 538 arg.status().error_message().c_str()); 539 return false; 540 } 541 return ExplainMatchResult(matcher, arg.ValueOrDie(), result_listener); 542 } 543 544 MATCHER_P(StatusIs, status_code, "") { 545 libtextclassifier3::StatusAdapter adapter(arg); 546 if (adapter.status().CanonicalCode() == status_code) { 547 return true; 548 } 549 *result_listener << IcingStringUtil::StringPrintf( 550 "Expected (%s:), actual was (%s:%s)", 551 StatusCodeToString(status_code).c_str(), 552 StatusCodeToString(adapter.status().CanonicalCode()).c_str(), 553 adapter.status().error_message().c_str()); 554 return false; 555 } 556 557 MATCHER_P2(StatusIs, status_code, error_matcher, "") { 558 libtextclassifier3::StatusAdapter adapter(arg); 559 if (adapter.status().CanonicalCode() != status_code) { 560 *result_listener << IcingStringUtil::StringPrintf( 561 "Expected (%s:), actual was (%s:%s)", 562 StatusCodeToString(status_code).c_str(), 563 StatusCodeToString(adapter.status().CanonicalCode()).c_str(), 564 adapter.status().error_message().c_str()); 565 return false; 566 } 567 return ExplainMatchResult(error_matcher, adapter.status().error_message(), 568 result_listener); 569 } 570 571 MATCHER(ProtoIsOk, "") { 572 if (arg.code() == StatusProto::OK) { 573 return true; 574 } 575 *result_listener << IcingStringUtil::StringPrintf( 576 "Expected OK, actual was (%s:%s)", 577 ProtoStatusCodeToString(arg.code()).c_str(), arg.message().c_str()); 578 return false; 579 } 580 581 MATCHER_P(ProtoStatusIs, status_code, "") { 582 if (arg.code() == status_code) { 583 return true; 584 } 585 *result_listener << IcingStringUtil::StringPrintf( 586 "Expected (%s:), actual was (%s:%s)", 587 ProtoStatusCodeToString(status_code).c_str(), 588 ProtoStatusCodeToString(arg.code()).c_str(), arg.message().c_str()); 589 return false; 590 } 591 592 MATCHER_P2(ProtoStatusIs, status_code, error_matcher, "") { 593 if (arg.code() != status_code) { 594 *result_listener << IcingStringUtil::StringPrintf( 595 "Expected (%s:), actual was (%s:%s)", 596 ProtoStatusCodeToString(status_code).c_str(), 597 ProtoStatusCodeToString(arg.code()).c_str(), arg.message().c_str()); 598 return false; 599 } 600 return ExplainMatchResult(error_matcher, arg.message(), result_listener); 601 } 602 603 MATCHER_P(EqualsSearchResultIgnoreStatsAndScores, expected, "") { 604 SearchResultProto actual_copy = arg; 605 actual_copy.clear_query_stats(); 606 actual_copy.clear_debug_info(); 607 for (SearchResultProto::ResultProto& result : 608 *actual_copy.mutable_results()) { 609 // Joined results 610 for (SearchResultProto::ResultProto& joined_result : 611 *result.mutable_joined_results()) { 612 joined_result.clear_score(); 613 } 614 result.clear_score(); 615 } 616 617 SearchResultProto expected_copy = expected; 618 expected_copy.clear_query_stats(); 619 expected_copy.clear_debug_info(); 620 for (SearchResultProto::ResultProto& result : 621 *expected_copy.mutable_results()) { 622 // Joined results 623 for (SearchResultProto::ResultProto& joined_result : 624 *result.mutable_joined_results()) { 625 joined_result.clear_score(); 626 } 627 result.clear_score(); 628 } 629 return ExplainMatchResult(portable_equals_proto::EqualsProto(expected_copy), 630 actual_copy, result_listener); 631 } 632 633 MATCHER_P(EqualsHit, expected_hit, "") { 634 const Hit& actual = arg; 635 return actual.value() == expected_hit.value() && 636 actual.flags() == expected_hit.flags() && 637 actual.term_frequency() == expected_hit.term_frequency(); 638 } 639 640 MATCHER(EqualsHit, "") { 641 return ExplainMatchResult(EqualsHit(std::get<1>(arg)), std::get<0>(arg), 642 result_listener); 643 } 644 645 // TODO(tjbarron) Remove this once icing has switched to depend on TC3 Status 646 #define ICING_STATUS_MACROS_CONCAT_NAME(x, y) \ 647 ICING_STATUS_MACROS_CONCAT_IMPL(x, y) 648 #define ICING_STATUS_MACROS_CONCAT_IMPL(x, y) x##y 649 650 #define ICING_EXPECT_OK(func) EXPECT_THAT(func, IsOk()) 651 #define ICING_ASSERT_OK(func) ASSERT_THAT(func, IsOk()) 652 #define ICING_ASSERT_OK_AND_ASSIGN(lhs, rexpr) \ 653 ICING_ASSERT_OK_AND_ASSIGN_IMPL( \ 654 ICING_STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, \ 655 rexpr) 656 #define ICING_ASSERT_OK_AND_ASSIGN_IMPL(statusor, lhs, rexpr) \ 657 auto statusor = (rexpr); \ 658 ICING_ASSERT_OK(statusor.status()); \ 659 lhs = std::move(statusor).ValueOrDie() 660 661 #define ICING_ASSERT_HAS_VALUE_AND_ASSIGN(lhs, rexpr) \ 662 ASSERT_TRUE(rexpr); \ 663 lhs = rexpr.value() 664 665 } // namespace lib 666 } // namespace icing 667 668 #endif // ICING_TESTING_COMMON_MATCHERS_H_ 669