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