• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 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 #include "icing/scoring/advanced_scoring/advanced-scorer.h"
16 
17 #include <cmath>
18 #include <memory>
19 #include <string>
20 #include <string_view>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "icing/document-builder.h"
25 #include "icing/file/filesystem.h"
26 #include "icing/index/hit/doc-hit-info.h"
27 #include "icing/join/join-children-fetcher.h"
28 #include "icing/proto/document.pb.h"
29 #include "icing/proto/schema.pb.h"
30 #include "icing/proto/scoring.pb.h"
31 #include "icing/proto/usage.pb.h"
32 #include "icing/schema-builder.h"
33 #include "icing/schema/schema-store.h"
34 #include "icing/scoring/scorer-factory.h"
35 #include "icing/scoring/scorer.h"
36 #include "icing/store/document-id.h"
37 #include "icing/store/document-store.h"
38 #include "icing/testing/common-matchers.h"
39 #include "icing/testing/fake-clock.h"
40 #include "icing/testing/tmp-directory.h"
41 
42 namespace icing {
43 namespace lib {
44 
45 namespace {
46 using ::testing::DoubleNear;
47 using ::testing::Eq;
48 
49 class AdvancedScorerTest : public testing::Test {
50  protected:
AdvancedScorerTest()51   AdvancedScorerTest()
52       : test_dir_(GetTestTempDir() + "/icing"),
53         doc_store_dir_(test_dir_ + "/doc_store"),
54         schema_store_dir_(test_dir_ + "/schema_store") {}
55 
SetUp()56   void SetUp() override {
57     filesystem_.DeleteDirectoryRecursively(test_dir_.c_str());
58     filesystem_.CreateDirectoryRecursively(doc_store_dir_.c_str());
59     filesystem_.CreateDirectoryRecursively(schema_store_dir_.c_str());
60 
61     ICING_ASSERT_OK_AND_ASSIGN(
62         schema_store_,
63         SchemaStore::Create(&filesystem_, schema_store_dir_, &fake_clock_));
64 
65     ICING_ASSERT_OK_AND_ASSIGN(
66         DocumentStore::CreateResult create_result,
67         DocumentStore::Create(&filesystem_, doc_store_dir_, &fake_clock_,
68                               schema_store_.get(),
69                               /*force_recovery_and_revalidate_documents=*/false,
70                               /*namespace_id_fingerprint=*/false,
71                               PortableFileBackedProtoLog<
72                                   DocumentWrapper>::kDeflateCompressionLevel,
73                               /*initialize_stats=*/nullptr));
74     document_store_ = std::move(create_result.document_store);
75 
76     // Creates a simple email schema
77     SchemaProto test_email_schema =
78         SchemaBuilder()
79             .AddType(SchemaTypeConfigBuilder().SetType("email").AddProperty(
80                 PropertyConfigBuilder()
81                     .SetName("subject")
82                     .SetDataTypeString(
83                         TermMatchType::PREFIX,
84                         StringIndexingConfig::TokenizerType::PLAIN)
85                     .SetCardinality(CARDINALITY_OPTIONAL)))
86             .AddType(SchemaTypeConfigBuilder()
87                          .SetType("person")
88                          .AddProperty(
89                              PropertyConfigBuilder()
90                                  .SetName("emailAddress")
91                                  .SetDataTypeString(
92                                      TermMatchType::PREFIX,
93                                      StringIndexingConfig::TokenizerType::PLAIN)
94                                  .SetCardinality(CARDINALITY_OPTIONAL))
95                          .AddProperty(
96                              PropertyConfigBuilder()
97                                  .SetName("name")
98                                  .SetDataTypeString(
99                                      TermMatchType::PREFIX,
100                                      StringIndexingConfig::TokenizerType::PLAIN)
101                                  .SetCardinality(CARDINALITY_OPTIONAL))
102 
103                          .AddProperty(
104                              PropertyConfigBuilder()
105                                  .SetName("phoneNumber")
106                                  .SetDataTypeString(
107                                      TermMatchType::PREFIX,
108                                      StringIndexingConfig::TokenizerType::PLAIN)
109                                  .SetCardinality(CARDINALITY_OPTIONAL)))
110             .Build();
111 
112     ICING_ASSERT_OK(schema_store_->SetSchema(
113         test_email_schema, /*ignore_errors_and_delete_documents=*/false,
114         /*allow_circular_schema_definitions=*/false));
115   }
116 
TearDown()117   void TearDown() override {
118     document_store_.reset();
119     schema_store_.reset();
120     filesystem_.DeleteDirectoryRecursively(test_dir_.c_str());
121   }
122 
123   const std::string test_dir_;
124   const std::string doc_store_dir_;
125   const std::string schema_store_dir_;
126   Filesystem filesystem_;
127   std::unique_ptr<SchemaStore> schema_store_;
128   std::unique_ptr<DocumentStore> document_store_;
129   FakeClock fake_clock_;
130 };
131 
132 constexpr double kEps = 0.0000000001;
133 constexpr int kDefaultScore = 0;
134 constexpr int64_t kDefaultCreationTimestampMs = 1571100001111;
135 
CreateDocument(const std::string & name_space,const std::string & uri,int score=kDefaultScore,int64_t creation_timestamp_ms=kDefaultCreationTimestampMs)136 DocumentProto CreateDocument(
137     const std::string& name_space, const std::string& uri,
138     int score = kDefaultScore,
139     int64_t creation_timestamp_ms = kDefaultCreationTimestampMs) {
140   return DocumentBuilder()
141       .SetKey(name_space, uri)
142       .SetSchema("email")
143       .SetScore(score)
144       .SetCreationTimestampMs(creation_timestamp_ms)
145       .Build();
146 }
147 
CreateUsageReport(std::string name_space,std::string uri,int64_t timestamp_ms,UsageReport::UsageType usage_type)148 UsageReport CreateUsageReport(std::string name_space, std::string uri,
149                               int64_t timestamp_ms,
150                               UsageReport::UsageType usage_type) {
151   UsageReport usage_report;
152   usage_report.set_document_namespace(name_space);
153   usage_report.set_document_uri(uri);
154   usage_report.set_usage_timestamp_ms(timestamp_ms);
155   usage_report.set_usage_type(usage_type);
156   return usage_report;
157 }
158 
CreateAdvancedScoringSpec(const std::string & advanced_scoring_expression)159 ScoringSpecProto CreateAdvancedScoringSpec(
160     const std::string& advanced_scoring_expression) {
161   ScoringSpecProto scoring_spec;
162   scoring_spec.set_rank_by(
163       ScoringSpecProto::RankingStrategy::ADVANCED_SCORING_EXPRESSION);
164   scoring_spec.set_advanced_scoring_expression(advanced_scoring_expression);
165   return scoring_spec;
166 }
167 
CreatePropertyWeight(std::string path,double weight)168 PropertyWeight CreatePropertyWeight(std::string path, double weight) {
169   PropertyWeight property_weight;
170   property_weight.set_path(std::move(path));
171   property_weight.set_weight(weight);
172   return property_weight;
173 }
174 
CreateTypePropertyWeights(std::string schema_type,std::vector<PropertyWeight> && property_weights)175 TypePropertyWeights CreateTypePropertyWeights(
176     std::string schema_type, std::vector<PropertyWeight>&& property_weights) {
177   TypePropertyWeights type_property_weights;
178   type_property_weights.set_schema_type(std::move(schema_type));
179   type_property_weights.mutable_property_weights()->Reserve(
180       property_weights.size());
181 
182   for (PropertyWeight& property_weight : property_weights) {
183     *type_property_weights.add_property_weights() = std::move(property_weight);
184   }
185 
186   return type_property_weights;
187 }
188 
TEST_F(AdvancedScorerTest,InvalidAdvancedScoringSpec)189 TEST_F(AdvancedScorerTest, InvalidAdvancedScoringSpec) {
190   // Empty scoring expression for advanced scoring
191   ScoringSpecProto scoring_spec;
192   scoring_spec.set_rank_by(
193       ScoringSpecProto::RankingStrategy::ADVANCED_SCORING_EXPRESSION);
194   EXPECT_THAT(scorer_factory::Create(scoring_spec, /*default_score=*/10,
195                                      document_store_.get(), schema_store_.get(),
196                                      fake_clock_.GetSystemTimeMilliseconds()),
197               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
198 
199   // Non-empty scoring expression for normal scoring
200   scoring_spec = ScoringSpecProto::default_instance();
201   scoring_spec.set_rank_by(ScoringSpecProto::RankingStrategy::DOCUMENT_SCORE);
202   scoring_spec.set_advanced_scoring_expression("1");
203   EXPECT_THAT(scorer_factory::Create(scoring_spec, /*default_score=*/10,
204                                      document_store_.get(), schema_store_.get(),
205                                      fake_clock_.GetSystemTimeMilliseconds()),
206               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
207 }
208 
TEST_F(AdvancedScorerTest,SimpleExpression)209 TEST_F(AdvancedScorerTest, SimpleExpression) {
210   ICING_ASSERT_OK_AND_ASSIGN(
211       DocumentId document_id,
212       document_store_->Put(CreateDocument("namespace", "uri")));
213 
214   ICING_ASSERT_OK_AND_ASSIGN(
215       std::unique_ptr<Scorer> scorer,
216       AdvancedScorer::Create(CreateAdvancedScoringSpec("123"),
217                              /*default_score=*/10, document_store_.get(),
218                              schema_store_.get(),
219                              fake_clock_.GetSystemTimeMilliseconds()));
220 
221   DocHitInfo docHitInfo = DocHitInfo(document_id);
222 
223   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(123));
224 }
225 
TEST_F(AdvancedScorerTest,BasicPureArithmeticExpression)226 TEST_F(AdvancedScorerTest, BasicPureArithmeticExpression) {
227   ICING_ASSERT_OK_AND_ASSIGN(
228       DocumentId document_id,
229       document_store_->Put(CreateDocument("namespace", "uri")));
230   DocHitInfo docHitInfo = DocHitInfo(document_id);
231 
232   ICING_ASSERT_OK_AND_ASSIGN(
233       std::unique_ptr<Scorer> scorer,
234       AdvancedScorer::Create(CreateAdvancedScoringSpec("1 + 2"),
235                              /*default_score=*/10, document_store_.get(),
236                              schema_store_.get(),
237                              fake_clock_.GetSystemTimeMilliseconds()));
238   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(3));
239 
240   ICING_ASSERT_OK_AND_ASSIGN(
241       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("-1 + 2"),
242                                      /*default_score=*/10,
243                                      document_store_.get(), schema_store_.get(),
244                                      fake_clock_.GetSystemTimeMilliseconds()));
245   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(1));
246 
247   ICING_ASSERT_OK_AND_ASSIGN(
248       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("1 + -2"),
249                                      /*default_score=*/10,
250                                      document_store_.get(), schema_store_.get(),
251                                      fake_clock_.GetSystemTimeMilliseconds()));
252   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(-1));
253 
254   ICING_ASSERT_OK_AND_ASSIGN(
255       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("1 - 2"),
256                                      /*default_score=*/10,
257                                      document_store_.get(), schema_store_.get(),
258                                      fake_clock_.GetSystemTimeMilliseconds()));
259   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(-1));
260 
261   ICING_ASSERT_OK_AND_ASSIGN(
262       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("1 * 2"),
263                                      /*default_score=*/10,
264                                      document_store_.get(), schema_store_.get(),
265                                      fake_clock_.GetSystemTimeMilliseconds()));
266   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(2));
267 
268   ICING_ASSERT_OK_AND_ASSIGN(
269       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("1 / 2"),
270                                      /*default_score=*/10,
271                                      document_store_.get(), schema_store_.get(),
272                                      fake_clock_.GetSystemTimeMilliseconds()));
273   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(0.5));
274 }
275 
TEST_F(AdvancedScorerTest,BasicMathFunctionExpression)276 TEST_F(AdvancedScorerTest, BasicMathFunctionExpression) {
277   ICING_ASSERT_OK_AND_ASSIGN(
278       DocumentId document_id,
279       document_store_->Put(CreateDocument("namespace", "uri")));
280   DocHitInfo docHitInfo = DocHitInfo(document_id);
281 
282   ICING_ASSERT_OK_AND_ASSIGN(
283       std::unique_ptr<Scorer> scorer,
284       AdvancedScorer::Create(CreateAdvancedScoringSpec("log(10, 1000)"),
285                              /*default_score=*/10, document_store_.get(),
286                              schema_store_.get(),
287                              fake_clock_.GetSystemTimeMilliseconds()));
288   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(3, kEps));
289 
290   ICING_ASSERT_OK_AND_ASSIGN(
291       scorer,
292       AdvancedScorer::Create(
293           CreateAdvancedScoringSpec("log(2.718281828459045)"),
294           /*default_score=*/10, document_store_.get(), schema_store_.get(),
295           fake_clock_.GetSystemTimeMilliseconds()));
296   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(1, kEps));
297 
298   ICING_ASSERT_OK_AND_ASSIGN(
299       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("pow(2, 10)"),
300                                      /*default_score=*/10,
301                                      document_store_.get(), schema_store_.get(),
302                                      fake_clock_.GetSystemTimeMilliseconds()));
303   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(1024));
304 
305   ICING_ASSERT_OK_AND_ASSIGN(
306       scorer,
307       AdvancedScorer::Create(
308           CreateAdvancedScoringSpec("max(10, 11, 12, 13, 14)"),
309           /*default_score=*/10, document_store_.get(), schema_store_.get(),
310           fake_clock_.GetSystemTimeMilliseconds()));
311   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(14));
312 
313   ICING_ASSERT_OK_AND_ASSIGN(
314       scorer,
315       AdvancedScorer::Create(
316           CreateAdvancedScoringSpec("min(10, 11, 12, 13, 14)"),
317           /*default_score=*/10, document_store_.get(), schema_store_.get(),
318           fake_clock_.GetSystemTimeMilliseconds()));
319   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(10));
320 
321   ICING_ASSERT_OK_AND_ASSIGN(
322       scorer,
323       AdvancedScorer::Create(
324           CreateAdvancedScoringSpec("len(10, 11, 12, 13, 14)"),
325           /*default_score=*/10, document_store_.get(), schema_store_.get(),
326           fake_clock_.GetSystemTimeMilliseconds()));
327   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(5));
328 
329   ICING_ASSERT_OK_AND_ASSIGN(
330       scorer,
331       AdvancedScorer::Create(
332           CreateAdvancedScoringSpec("sum(10, 11, 12, 13, 14)"),
333           /*default_score=*/10, document_store_.get(), schema_store_.get(),
334           fake_clock_.GetSystemTimeMilliseconds()));
335   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(10 + 11 + 12 + 13 + 14));
336 
337   ICING_ASSERT_OK_AND_ASSIGN(
338       scorer,
339       AdvancedScorer::Create(
340           CreateAdvancedScoringSpec("avg(10, 11, 12, 13, 14)"),
341           /*default_score=*/10, document_store_.get(), schema_store_.get(),
342           fake_clock_.GetSystemTimeMilliseconds()));
343   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq((10 + 11 + 12 + 13 + 14) / 5.));
344 
345   ICING_ASSERT_OK_AND_ASSIGN(
346       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("sqrt(2)"),
347                                      /*default_score=*/10,
348                                      document_store_.get(), schema_store_.get(),
349                                      fake_clock_.GetSystemTimeMilliseconds()));
350   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(sqrt(2), kEps));
351 
352   ICING_ASSERT_OK_AND_ASSIGN(
353       scorer,
354       AdvancedScorer::Create(CreateAdvancedScoringSpec("abs(-2) + abs(2)"),
355                              /*default_score=*/10, document_store_.get(),
356                              schema_store_.get(),
357                              fake_clock_.GetSystemTimeMilliseconds()));
358   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(4));
359 
360   ICING_ASSERT_OK_AND_ASSIGN(
361       scorer,
362       AdvancedScorer::Create(
363           CreateAdvancedScoringSpec("sin(3.141592653589793)"),
364           /*default_score=*/10, document_store_.get(), schema_store_.get(),
365           fake_clock_.GetSystemTimeMilliseconds()));
366   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(0, kEps));
367 
368   ICING_ASSERT_OK_AND_ASSIGN(
369       scorer,
370       AdvancedScorer::Create(
371           CreateAdvancedScoringSpec("cos(3.141592653589793)"),
372           /*default_score=*/10, document_store_.get(), schema_store_.get(),
373           fake_clock_.GetSystemTimeMilliseconds()));
374   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(-1, kEps));
375 
376   ICING_ASSERT_OK_AND_ASSIGN(
377       scorer,
378       AdvancedScorer::Create(
379           CreateAdvancedScoringSpec("tan(3.141592653589793 / 4)"),
380           /*default_score=*/10, document_store_.get(), schema_store_.get(),
381           fake_clock_.GetSystemTimeMilliseconds()));
382   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(1, kEps));
383 }
384 
TEST_F(AdvancedScorerTest,DocumentScoreCreationTimestampFunctionExpression)385 TEST_F(AdvancedScorerTest, DocumentScoreCreationTimestampFunctionExpression) {
386   ICING_ASSERT_OK_AND_ASSIGN(
387       DocumentId document_id,
388       document_store_->Put(CreateDocument(
389           "namespace", "uri", /*score=*/123,
390           /*creation_timestamp_ms=*/kDefaultCreationTimestampMs)));
391   DocHitInfo docHitInfo = DocHitInfo(document_id);
392 
393   ICING_ASSERT_OK_AND_ASSIGN(
394       std::unique_ptr<Scorer> scorer,
395       AdvancedScorer::Create(CreateAdvancedScoringSpec("this.documentScore()"),
396                              /*default_score=*/10, document_store_.get(),
397                              schema_store_.get(),
398                              fake_clock_.GetSystemTimeMilliseconds()));
399   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(123));
400 
401   ICING_ASSERT_OK_AND_ASSIGN(
402       scorer,
403       AdvancedScorer::Create(
404           CreateAdvancedScoringSpec("this.creationTimestamp()"),
405           /*default_score=*/10, document_store_.get(), schema_store_.get(),
406           fake_clock_.GetSystemTimeMilliseconds()));
407   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(kDefaultCreationTimestampMs));
408 
409   ICING_ASSERT_OK_AND_ASSIGN(
410       scorer,
411       AdvancedScorer::Create(
412           CreateAdvancedScoringSpec(
413               "this.documentScore() + this.creationTimestamp()"),
414           /*default_score=*/10, document_store_.get(), schema_store_.get(),
415           fake_clock_.GetSystemTimeMilliseconds()));
416   EXPECT_THAT(scorer->GetScore(docHitInfo),
417               Eq(123 + kDefaultCreationTimestampMs));
418 }
419 
TEST_F(AdvancedScorerTest,DocumentUsageFunctionExpression)420 TEST_F(AdvancedScorerTest, DocumentUsageFunctionExpression) {
421   ICING_ASSERT_OK_AND_ASSIGN(
422       DocumentId document_id,
423       document_store_->Put(CreateDocument("namespace", "uri")));
424   DocHitInfo docHitInfo = DocHitInfo(document_id);
425 
426   ICING_ASSERT_OK_AND_ASSIGN(
427       std::unique_ptr<Scorer> scorer,
428       AdvancedScorer::Create(
429           CreateAdvancedScoringSpec("this.usageCount(1) + this.usageCount(2) "
430                                     "+ this.usageLastUsedTimestamp(3)"),
431           /*default_score=*/10, document_store_.get(), schema_store_.get(),
432           fake_clock_.GetSystemTimeMilliseconds()));
433   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(0));
434   ICING_ASSERT_OK(document_store_->ReportUsage(
435       CreateUsageReport("namespace", "uri", 100000, UsageReport::USAGE_TYPE1)));
436   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(1));
437   ICING_ASSERT_OK(document_store_->ReportUsage(
438       CreateUsageReport("namespace", "uri", 200000, UsageReport::USAGE_TYPE2)));
439   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(2));
440   ICING_ASSERT_OK(document_store_->ReportUsage(
441       CreateUsageReport("namespace", "uri", 300000, UsageReport::USAGE_TYPE3)));
442   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(300002));
443 
444   ICING_ASSERT_OK_AND_ASSIGN(
445       scorer,
446       AdvancedScorer::Create(
447           CreateAdvancedScoringSpec("this.usageLastUsedTimestamp(1)"),
448           /*default_score=*/10, document_store_.get(), schema_store_.get(),
449           fake_clock_.GetSystemTimeMilliseconds()));
450   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(100000));
451   ICING_ASSERT_OK_AND_ASSIGN(
452       scorer,
453       AdvancedScorer::Create(
454           CreateAdvancedScoringSpec("this.usageLastUsedTimestamp(2)"),
455           /*default_score=*/10, document_store_.get(), schema_store_.get(),
456           fake_clock_.GetSystemTimeMilliseconds()));
457   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(200000));
458   ICING_ASSERT_OK_AND_ASSIGN(
459       scorer,
460       AdvancedScorer::Create(
461           CreateAdvancedScoringSpec("this.usageLastUsedTimestamp(3)"),
462           /*default_score=*/10, document_store_.get(), schema_store_.get(),
463           fake_clock_.GetSystemTimeMilliseconds()));
464   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(300000));
465 }
466 
TEST_F(AdvancedScorerTest,DocumentUsageFunctionOutOfRange)467 TEST_F(AdvancedScorerTest, DocumentUsageFunctionOutOfRange) {
468   ICING_ASSERT_OK_AND_ASSIGN(
469       DocumentId document_id,
470       document_store_->Put(CreateDocument("namespace", "uri")));
471   DocHitInfo docHitInfo = DocHitInfo(document_id);
472 
473   const double default_score = 123;
474 
475   // Should get default score for the following expressions that cause "runtime"
476   // errors.
477 
478   ICING_ASSERT_OK_AND_ASSIGN(
479       std::unique_ptr<Scorer> scorer,
480       AdvancedScorer::Create(CreateAdvancedScoringSpec("this.usageCount(4)"),
481                              default_score, document_store_.get(),
482                              schema_store_.get(),
483                              fake_clock_.GetSystemTimeMilliseconds()));
484   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(default_score));
485 
486   ICING_ASSERT_OK_AND_ASSIGN(
487       scorer, AdvancedScorer::Create(
488                   CreateAdvancedScoringSpec("this.usageCount(0)"),
489                   default_score, document_store_.get(), schema_store_.get(),
490                   fake_clock_.GetSystemTimeMilliseconds()));
491   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(default_score));
492 
493   ICING_ASSERT_OK_AND_ASSIGN(
494       scorer, AdvancedScorer::Create(
495                   CreateAdvancedScoringSpec("this.usageCount(1.5)"),
496                   default_score, document_store_.get(), schema_store_.get(),
497                   fake_clock_.GetSystemTimeMilliseconds()));
498   EXPECT_THAT(scorer->GetScore(docHitInfo), Eq(default_score));
499 }
500 
501 // scoring-processor_test.cc will help to get better test coverage for relevance
502 // score.
TEST_F(AdvancedScorerTest,RelevanceScoreFunctionScoreExpression)503 TEST_F(AdvancedScorerTest, RelevanceScoreFunctionScoreExpression) {
504   DocumentProto test_document =
505       DocumentBuilder()
506           .SetScore(5)
507           .SetKey("namespace", "uri")
508           .SetSchema("email")
509           .AddStringProperty("subject", "subject foo")
510           .SetCreationTimestampMs(kDefaultCreationTimestampMs)
511           .Build();
512 
513   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id,
514                              document_store_->Put(test_document));
515   ICING_ASSERT_OK_AND_ASSIGN(
516       std::unique_ptr<AdvancedScorer> scorer,
517       AdvancedScorer::Create(CreateAdvancedScoringSpec("this.relevanceScore()"),
518                              /*default_score=*/10, document_store_.get(),
519                              schema_store_.get(),
520                              fake_clock_.GetSystemTimeMilliseconds()));
521   scorer->PrepareToScore(/*query_term_iterators=*/{});
522 
523   // Should get the default score.
524   DocHitInfo docHitInfo = DocHitInfo(document_id);
525   EXPECT_THAT(scorer->GetScore(docHitInfo, /*query_it=*/nullptr), Eq(10));
526 }
527 
TEST_F(AdvancedScorerTest,ChildrenScoresFunctionScoreExpression)528 TEST_F(AdvancedScorerTest, ChildrenScoresFunctionScoreExpression) {
529   const double default_score = 123;
530 
531   ICING_ASSERT_OK_AND_ASSIGN(
532       DocumentId document_id_1,
533       document_store_->Put(CreateDocument("namespace", "uri1")));
534   DocHitInfo docHitInfo1 = DocHitInfo(document_id_1);
535   ICING_ASSERT_OK_AND_ASSIGN(
536       DocumentId document_id_2,
537       document_store_->Put(CreateDocument("namespace", "uri2")));
538   DocHitInfo docHitInfo2 = DocHitInfo(document_id_2);
539   ICING_ASSERT_OK_AND_ASSIGN(
540       DocumentId document_id_3,
541       document_store_->Put(CreateDocument("namespace", "uri3")));
542   DocHitInfo docHitInfo3 = DocHitInfo(document_id_3);
543 
544   // Create a JoinChildrenFetcher that matches:
545   //   document_id_1 to fake_child1 with score 1 and fake_child2 with score 2.
546   //   document_id_2 to fake_child3 with score 4.
547   //   document_id_3 has no child.
548   JoinSpecProto join_spec;
549   join_spec.set_parent_property_expression("this.qualifiedId()");
550   join_spec.set_child_property_expression("sender");
551   std::unordered_map<DocumentId, std::vector<ScoredDocumentHit>>
552       map_joinable_qualified_id;
553   ScoredDocumentHit fake_child1(/*document_id=*/10, kSectionIdMaskNone,
554                                 /*score=*/1.0);
555   ScoredDocumentHit fake_child2(/*document_id=*/11, kSectionIdMaskNone,
556                                 /*score=*/2.0);
557   ScoredDocumentHit fake_child3(/*document_id=*/12, kSectionIdMaskNone,
558                                 /*score=*/4.0);
559   map_joinable_qualified_id[document_id_1].push_back(fake_child1);
560   map_joinable_qualified_id[document_id_1].push_back(fake_child2);
561   map_joinable_qualified_id[document_id_2].push_back(fake_child3);
562   JoinChildrenFetcher fetcher(join_spec, std::move(map_joinable_qualified_id));
563 
564   ICING_ASSERT_OK_AND_ASSIGN(
565       std::unique_ptr<AdvancedScorer> scorer,
566       AdvancedScorer::Create(
567           CreateAdvancedScoringSpec("len(this.childrenRankingSignals())"),
568           default_score, document_store_.get(), schema_store_.get(),
569           fake_clock_.GetSystemTimeMilliseconds(), &fetcher));
570   // document_id_1 has two children.
571   EXPECT_THAT(scorer->GetScore(docHitInfo1, /*query_it=*/nullptr), Eq(2));
572   // document_id_2 has one child.
573   EXPECT_THAT(scorer->GetScore(docHitInfo2, /*query_it=*/nullptr), Eq(1));
574   // document_id_3 has no child.
575   EXPECT_THAT(scorer->GetScore(docHitInfo3, /*query_it=*/nullptr), Eq(0));
576 
577   ICING_ASSERT_OK_AND_ASSIGN(
578       scorer,
579       AdvancedScorer::Create(
580           CreateAdvancedScoringSpec("sum(this.childrenRankingSignals())"),
581           default_score, document_store_.get(), schema_store_.get(),
582           fake_clock_.GetSystemTimeMilliseconds(), &fetcher));
583   // document_id_1 has two children with scores 1 and 2.
584   EXPECT_THAT(scorer->GetScore(docHitInfo1, /*query_it=*/nullptr), Eq(3));
585   // document_id_2 has one child with score 4.
586   EXPECT_THAT(scorer->GetScore(docHitInfo2, /*query_it=*/nullptr), Eq(4));
587   // document_id_3 has no child.
588   EXPECT_THAT(scorer->GetScore(docHitInfo3, /*query_it=*/nullptr), Eq(0));
589 
590   ICING_ASSERT_OK_AND_ASSIGN(
591       scorer,
592       AdvancedScorer::Create(
593           CreateAdvancedScoringSpec("avg(this.childrenRankingSignals())"),
594           default_score, document_store_.get(), schema_store_.get(),
595           fake_clock_.GetSystemTimeMilliseconds(), &fetcher));
596   // document_id_1 has two children with scores 1 and 2.
597   EXPECT_THAT(scorer->GetScore(docHitInfo1, /*query_it=*/nullptr), Eq(3 / 2.));
598   // document_id_2 has one child with score 4.
599   EXPECT_THAT(scorer->GetScore(docHitInfo2, /*query_it=*/nullptr), Eq(4 / 1.));
600   // document_id_3 has no child.
601   // This is an evaluation error, so default_score will be returned.
602   EXPECT_THAT(scorer->GetScore(docHitInfo3, /*query_it=*/nullptr),
603               Eq(default_score));
604 
605   ICING_ASSERT_OK_AND_ASSIGN(
606       scorer, AdvancedScorer::Create(
607                   CreateAdvancedScoringSpec(
608                       // Equivalent to "avg(this.childrenRankingSignals())"
609                       "sum(this.childrenRankingSignals()) / "
610                       "len(this.childrenRankingSignals())"),
611                   default_score, document_store_.get(), schema_store_.get(),
612                   fake_clock_.GetSystemTimeMilliseconds(), &fetcher));
613   // document_id_1 has two children with scores 1 and 2.
614   EXPECT_THAT(scorer->GetScore(docHitInfo1, /*query_it=*/nullptr), Eq(3 / 2.));
615   // document_id_2 has one child with score 4.
616   EXPECT_THAT(scorer->GetScore(docHitInfo2, /*query_it=*/nullptr), Eq(4 / 1.));
617   // document_id_3 has no child.
618   // This is an evaluation error, so default_score will be returned.
619   EXPECT_THAT(scorer->GetScore(docHitInfo3, /*query_it=*/nullptr),
620               Eq(default_score));
621 }
622 
TEST_F(AdvancedScorerTest,PropertyWeightsFunctionScoreExpression)623 TEST_F(AdvancedScorerTest, PropertyWeightsFunctionScoreExpression) {
624   DocumentProto test_document_1 =
625       DocumentBuilder().SetKey("namespace", "uri1").SetSchema("email").Build();
626   DocumentProto test_document_2 =
627       DocumentBuilder().SetKey("namespace", "uri2").SetSchema("person").Build();
628   DocumentProto test_document_3 =
629       DocumentBuilder().SetKey("namespace", "uri3").SetSchema("person").Build();
630 
631   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id_1,
632                              document_store_->Put(test_document_1));
633   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id_2,
634                              document_store_->Put(test_document_2));
635   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id_3,
636                              document_store_->Put(test_document_3));
637 
638   ScoringSpecProto spec_proto = CreateAdvancedScoringSpec("");
639 
640   *spec_proto.add_type_property_weights() = CreateTypePropertyWeights(
641       /*schema_type=*/"email",
642       {CreatePropertyWeight(/*path=*/"subject", /*weight=*/1.0)});
643   *spec_proto.add_type_property_weights() = CreateTypePropertyWeights(
644       /*schema_type=*/"person",
645       {CreatePropertyWeight(/*path=*/"emailAddress", /*weight=*/0.5),
646        CreatePropertyWeight(/*path=*/"name", /*weight=*/0.8),
647        CreatePropertyWeight(/*path=*/"phoneNumber", /*weight=*/1.0)});
648 
649   // Let the hit for test_document_1 match property "subject".
650   // So this.propertyWeights() for test_document_1 will return [1].
651   DocHitInfo doc_hit_info_1 = DocHitInfo(document_id_1);
652   doc_hit_info_1.UpdateSection(0);
653 
654   // Let the hit for test_document_2 match properties "emailAddress" and "name".
655   // So this.propertyWeights() for test_document_2 will return [0.5, 0.8].
656   DocHitInfo doc_hit_info_2 = DocHitInfo(document_id_2);
657   doc_hit_info_2.UpdateSection(0);
658   doc_hit_info_2.UpdateSection(1);
659 
660   // Let the hit for test_document_3 match properties "emailAddress", "name" and
661   // "phoneNumber". So this.propertyWeights() for test_document_3 will return
662   // [0.5, 0.8, 1].
663   DocHitInfo doc_hit_info_3 = DocHitInfo(document_id_3);
664   doc_hit_info_3.UpdateSection(0);
665   doc_hit_info_3.UpdateSection(1);
666   doc_hit_info_3.UpdateSection(2);
667 
668   spec_proto.set_advanced_scoring_expression("min(this.propertyWeights())");
669   ICING_ASSERT_OK_AND_ASSIGN(
670       std::unique_ptr<AdvancedScorer> scorer,
671       AdvancedScorer::Create(spec_proto,
672                              /*default_score=*/10, document_store_.get(),
673                              schema_store_.get(),
674                              fake_clock_.GetSystemTimeMilliseconds()));
675   // min([1]) = 1
676   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
677   // min([0.5, 0.8]) = 0.5
678   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(0.5));
679   // min([0.5, 0.8, 1.0]) = 0.5
680   EXPECT_THAT(scorer->GetScore(doc_hit_info_3, /*query_it=*/nullptr), Eq(0.5));
681 
682   spec_proto.set_advanced_scoring_expression("max(this.propertyWeights())");
683   ICING_ASSERT_OK_AND_ASSIGN(
684       scorer, AdvancedScorer::Create(spec_proto,
685                                      /*default_score=*/10,
686                                      document_store_.get(), schema_store_.get(),
687                                      fake_clock_.GetSystemTimeMilliseconds()));
688   // max([1]) = 1
689   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
690   // max([0.5, 0.8]) = 0.8
691   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(0.8));
692   // max([0.5, 0.8, 1.0]) = 1
693   EXPECT_THAT(scorer->GetScore(doc_hit_info_3, /*query_it=*/nullptr), Eq(1));
694 
695   spec_proto.set_advanced_scoring_expression("sum(this.propertyWeights())");
696   ICING_ASSERT_OK_AND_ASSIGN(
697       scorer, AdvancedScorer::Create(spec_proto,
698                                      /*default_score=*/10,
699                                      document_store_.get(), schema_store_.get(),
700                                      fake_clock_.GetSystemTimeMilliseconds()));
701   // sum([1]) = 1
702   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
703   // sum([0.5, 0.8]) = 1.3
704   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(1.3));
705   // sum([0.5, 0.8, 1.0]) = 2.3
706   EXPECT_THAT(scorer->GetScore(doc_hit_info_3, /*query_it=*/nullptr), Eq(2.3));
707 }
708 
TEST_F(AdvancedScorerTest,PropertyWeightsFunctionScoreExpressionUnspecifiedWeights)709 TEST_F(AdvancedScorerTest,
710        PropertyWeightsFunctionScoreExpressionUnspecifiedWeights) {
711   DocumentProto test_document_1 =
712       DocumentBuilder().SetKey("namespace", "uri1").SetSchema("email").Build();
713   DocumentProto test_document_2 =
714       DocumentBuilder().SetKey("namespace", "uri2").SetSchema("person").Build();
715 
716   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id_1,
717                              document_store_->Put(test_document_1));
718   ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id_2,
719                              document_store_->Put(test_document_2));
720 
721   ScoringSpecProto spec_proto = CreateAdvancedScoringSpec("");
722 
723   // The entry for type "email" is missing, so every properties in "email"
724   // should get weight 1.0.
725   // The weight of "phoneNumber" in "person" type is unspecified, which should
726   // default to 1/2 = 0.5
727   *spec_proto.add_type_property_weights() = CreateTypePropertyWeights(
728       /*schema_type=*/"person",
729       {CreatePropertyWeight(/*path=*/"emailAddress", /*weight=*/1.0),
730        CreatePropertyWeight(/*path=*/"name", /*weight=*/2)});
731 
732   // Let the hit for test_document_1 match property "subject".
733   // So this.propertyWeights() for test_document_1 will return [1].
734   DocHitInfo doc_hit_info_1 = DocHitInfo(document_id_1);
735   doc_hit_info_1.UpdateSection(0);
736 
737   // Let the hit for test_document_2 match properties "emailAddress", "name" and
738   // "phoneNumber". So this.propertyWeights() for test_document_3 will return
739   // [0.5, 1, 0.5].
740   DocHitInfo doc_hit_info_2 = DocHitInfo(document_id_2);
741   doc_hit_info_2.UpdateSection(0);
742   doc_hit_info_2.UpdateSection(1);
743   doc_hit_info_2.UpdateSection(2);
744 
745   spec_proto.set_advanced_scoring_expression("min(this.propertyWeights())");
746   ICING_ASSERT_OK_AND_ASSIGN(
747       std::unique_ptr<AdvancedScorer> scorer,
748       AdvancedScorer::Create(spec_proto,
749                              /*default_score=*/10, document_store_.get(),
750                              schema_store_.get(),
751                              fake_clock_.GetSystemTimeMilliseconds()));
752   // min([1]) = 1
753   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
754   // min([0.5, 1, 0.5]) = 0.5
755   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(0.5));
756 
757   spec_proto.set_advanced_scoring_expression("max(this.propertyWeights())");
758   ICING_ASSERT_OK_AND_ASSIGN(
759       scorer, AdvancedScorer::Create(spec_proto,
760                                      /*default_score=*/10,
761                                      document_store_.get(), schema_store_.get(),
762                                      fake_clock_.GetSystemTimeMilliseconds()));
763   // max([1]) = 1
764   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
765   // max([0.5, 1, 0.5]) = 1
766   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(1));
767 
768   spec_proto.set_advanced_scoring_expression("sum(this.propertyWeights())");
769   ICING_ASSERT_OK_AND_ASSIGN(
770       scorer, AdvancedScorer::Create(spec_proto,
771                                      /*default_score=*/10,
772                                      document_store_.get(), schema_store_.get(),
773                                      fake_clock_.GetSystemTimeMilliseconds()));
774   // sum([1]) = 1
775   EXPECT_THAT(scorer->GetScore(doc_hit_info_1, /*query_it=*/nullptr), Eq(1));
776   // sum([0.5, 1, 0.5]) = 2
777   EXPECT_THAT(scorer->GetScore(doc_hit_info_2, /*query_it=*/nullptr), Eq(2));
778 }
779 
TEST_F(AdvancedScorerTest,InvalidChildrenScoresFunctionScoreExpression)780 TEST_F(AdvancedScorerTest, InvalidChildrenScoresFunctionScoreExpression) {
781   const double default_score = 123;
782 
783   // Without join_children_fetcher provided,
784   // "len(this.childrenRankingSignals())" cannot be created.
785   EXPECT_THAT(
786       AdvancedScorer::Create(
787           CreateAdvancedScoringSpec("len(this.childrenRankingSignals())"),
788           default_score, document_store_.get(), schema_store_.get(),
789           fake_clock_.GetSystemTimeMilliseconds(),
790           /*join_children_fetcher=*/nullptr),
791       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
792 
793   // The root expression can only be of double type, but here it is of list
794   // type.
795   JoinChildrenFetcher fake_fetcher(JoinSpecProto::default_instance(),
796                                    /*map_joinable_qualified_id=*/{});
797   EXPECT_THAT(AdvancedScorer::Create(
798                   CreateAdvancedScoringSpec("this.childrenRankingSignals()"),
799                   default_score, document_store_.get(), schema_store_.get(),
800                   fake_clock_.GetSystemTimeMilliseconds(), &fake_fetcher),
801               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
802 }
803 
TEST_F(AdvancedScorerTest,ComplexExpression)804 TEST_F(AdvancedScorerTest, ComplexExpression) {
805   const int64_t creation_timestamp_ms = 123;
806   ICING_ASSERT_OK_AND_ASSIGN(
807       DocumentId document_id,
808       document_store_->Put(CreateDocument("namespace", "uri", /*score=*/123,
809                                           creation_timestamp_ms)));
810   DocHitInfo docHitInfo = DocHitInfo(document_id);
811 
812   ICING_ASSERT_OK_AND_ASSIGN(
813       std::unique_ptr<AdvancedScorer> scorer,
814       AdvancedScorer::Create(CreateAdvancedScoringSpec(
815                                  "pow(sin(2), 2)"
816                                  // This is this.usageCount(1)
817                                  "+ this.usageCount(this.documentScore() - 122)"
818                                  "/ 12.34"
819                                  "* (10 * pow(2 * 1, sin(2))"
820                                  "+ 10 * (2 + 10 + this.creationTimestamp()))"
821                                  // This should evaluate to default score.
822                                  "+ this.relevanceScore()"),
823                              /*default_score=*/10, document_store_.get(),
824                              schema_store_.get(),
825                              fake_clock_.GetSystemTimeMilliseconds()));
826   EXPECT_FALSE(scorer->is_constant());
827   scorer->PrepareToScore(/*query_term_iterators=*/{});
828 
829   ICING_ASSERT_OK(document_store_->ReportUsage(
830       CreateUsageReport("namespace", "uri", 0, UsageReport::USAGE_TYPE1)));
831   ICING_ASSERT_OK(document_store_->ReportUsage(
832       CreateUsageReport("namespace", "uri", 0, UsageReport::USAGE_TYPE1)));
833   EXPECT_THAT(scorer->GetScore(docHitInfo, /*query_it=*/nullptr),
834               DoubleNear(pow(sin(2), 2) +
835                              2 / 12.34 *
836                                  (10 * pow(2 * 1, sin(2)) +
837                                   10 * (2 + 10 + creation_timestamp_ms)) +
838                              10,
839                          kEps));
840 }
841 
TEST_F(AdvancedScorerTest,ConstantExpression)842 TEST_F(AdvancedScorerTest, ConstantExpression) {
843   ICING_ASSERT_OK_AND_ASSIGN(
844       std::unique_ptr<AdvancedScorer> scorer,
845       AdvancedScorer::Create(CreateAdvancedScoringSpec(
846                                  "pow(sin(2), 2)"
847                                  "+ log(2, 122) / 12.34"
848                                  "* (10 * pow(2 * 1, sin(2)) + 10 * (2 + 10))"),
849                              /*default_score=*/10, document_store_.get(),
850                              schema_store_.get(),
851                              fake_clock_.GetSystemTimeMilliseconds()));
852   EXPECT_TRUE(scorer->is_constant());
853 }
854 
855 // Should be a parsing Error
TEST_F(AdvancedScorerTest,EmptyExpression)856 TEST_F(AdvancedScorerTest, EmptyExpression) {
857   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec(""),
858                                      /*default_score=*/10,
859                                      document_store_.get(), schema_store_.get(),
860                                      fake_clock_.GetSystemTimeMilliseconds()),
861               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
862 }
863 
TEST_F(AdvancedScorerTest,EvaluationErrorShouldReturnDefaultScore)864 TEST_F(AdvancedScorerTest, EvaluationErrorShouldReturnDefaultScore) {
865   const double default_score = 123;
866 
867   ICING_ASSERT_OK_AND_ASSIGN(
868       DocumentId document_id,
869       document_store_->Put(CreateDocument("namespace", "uri")));
870   DocHitInfo docHitInfo = DocHitInfo(document_id);
871 
872   ICING_ASSERT_OK_AND_ASSIGN(
873       std::unique_ptr<Scorer> scorer,
874       AdvancedScorer::Create(CreateAdvancedScoringSpec("log(0)"), default_score,
875                              document_store_.get(), schema_store_.get(),
876                              fake_clock_.GetSystemTimeMilliseconds()));
877   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(default_score, kEps));
878 
879   ICING_ASSERT_OK_AND_ASSIGN(
880       scorer,
881       AdvancedScorer::Create(CreateAdvancedScoringSpec("1 / 0"), default_score,
882                              document_store_.get(), schema_store_.get(),
883                              fake_clock_.GetSystemTimeMilliseconds()));
884   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(default_score, kEps));
885 
886   ICING_ASSERT_OK_AND_ASSIGN(
887       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("sqrt(-1)"),
888                                      default_score, document_store_.get(),
889                                      schema_store_.get(),
890                                      fake_clock_.GetSystemTimeMilliseconds()));
891   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(default_score, kEps));
892 
893   ICING_ASSERT_OK_AND_ASSIGN(
894       scorer, AdvancedScorer::Create(CreateAdvancedScoringSpec("pow(-1, 0.5)"),
895                                      default_score, document_store_.get(),
896                                      schema_store_.get(),
897                                      fake_clock_.GetSystemTimeMilliseconds()));
898   EXPECT_THAT(scorer->GetScore(docHitInfo), DoubleNear(default_score, kEps));
899 }
900 
901 // The following tests should trigger a type error while the visitor tries to
902 // build a ScoreExpression object.
TEST_F(AdvancedScorerTest,MathTypeError)903 TEST_F(AdvancedScorerTest, MathTypeError) {
904   const double default_score = 0;
905 
906   EXPECT_THAT(
907       AdvancedScorer::Create(CreateAdvancedScoringSpec("test"), default_score,
908                              document_store_.get(), schema_store_.get(),
909                              fake_clock_.GetSystemTimeMilliseconds()),
910       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
911 
912   EXPECT_THAT(
913       AdvancedScorer::Create(CreateAdvancedScoringSpec("log()"), default_score,
914                              document_store_.get(), schema_store_.get(),
915                              fake_clock_.GetSystemTimeMilliseconds()),
916       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
917 
918   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("log(1, 2, 3)"),
919                                      default_score, document_store_.get(),
920                                      schema_store_.get(),
921                                      fake_clock_.GetSystemTimeMilliseconds()),
922               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
923 
924   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("log(1, this)"),
925                                      default_score, document_store_.get(),
926                                      schema_store_.get(),
927                                      fake_clock_.GetSystemTimeMilliseconds()),
928               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
929 
930   EXPECT_THAT(
931       AdvancedScorer::Create(CreateAdvancedScoringSpec("pow(1)"), default_score,
932                              document_store_.get(), schema_store_.get(),
933                              fake_clock_.GetSystemTimeMilliseconds()),
934       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
935 
936   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("sqrt(1, 2)"),
937                                      default_score, document_store_.get(),
938                                      schema_store_.get(),
939                                      fake_clock_.GetSystemTimeMilliseconds()),
940               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
941 
942   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("abs(1, 2)"),
943                                      default_score, document_store_.get(),
944                                      schema_store_.get(),
945                                      fake_clock_.GetSystemTimeMilliseconds()),
946               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
947 
948   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("sin(1, 2)"),
949                                      default_score, document_store_.get(),
950                                      schema_store_.get(),
951                                      fake_clock_.GetSystemTimeMilliseconds()),
952               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
953 
954   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("cos(1, 2)"),
955                                      default_score, document_store_.get(),
956                                      schema_store_.get(),
957                                      fake_clock_.GetSystemTimeMilliseconds()),
958               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
959 
960   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("tan(1, 2)"),
961                                      default_score, document_store_.get(),
962                                      schema_store_.get(),
963                                      fake_clock_.GetSystemTimeMilliseconds()),
964               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
965 
966   EXPECT_THAT(
967       AdvancedScorer::Create(CreateAdvancedScoringSpec("this"), default_score,
968                              document_store_.get(), schema_store_.get(),
969                              fake_clock_.GetSystemTimeMilliseconds()),
970       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
971 
972   EXPECT_THAT(
973       AdvancedScorer::Create(CreateAdvancedScoringSpec("-this"), default_score,
974                              document_store_.get(), schema_store_.get(),
975                              fake_clock_.GetSystemTimeMilliseconds()),
976       StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
977 
978   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("1 + this"),
979                                      default_score, document_store_.get(),
980                                      schema_store_.get(),
981                                      fake_clock_.GetSystemTimeMilliseconds()),
982               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
983 }
984 
TEST_F(AdvancedScorerTest,DocumentFunctionTypeError)985 TEST_F(AdvancedScorerTest, DocumentFunctionTypeError) {
986   const double default_score = 0;
987 
988   EXPECT_THAT(AdvancedScorer::Create(
989                   CreateAdvancedScoringSpec("documentScore(1)"), default_score,
990                   document_store_.get(), schema_store_.get(),
991                   fake_clock_.GetSystemTimeMilliseconds()),
992               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
993   EXPECT_THAT(AdvancedScorer::Create(
994                   CreateAdvancedScoringSpec("this.creationTimestamp(1)"),
995                   default_score, document_store_.get(), schema_store_.get(),
996                   fake_clock_.GetSystemTimeMilliseconds()),
997               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
998   EXPECT_THAT(AdvancedScorer::Create(
999                   CreateAdvancedScoringSpec("this.usageCount()"), default_score,
1000                   document_store_.get(), schema_store_.get(),
1001                   fake_clock_.GetSystemTimeMilliseconds()),
1002               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1003   EXPECT_THAT(AdvancedScorer::Create(
1004                   CreateAdvancedScoringSpec("usageLastUsedTimestamp(1, 1)"),
1005                   default_score, document_store_.get(), schema_store_.get(),
1006                   fake_clock_.GetSystemTimeMilliseconds()),
1007               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1008   EXPECT_THAT(AdvancedScorer::Create(
1009                   CreateAdvancedScoringSpec("relevanceScore(1)"), default_score,
1010                   document_store_.get(), schema_store_.get(),
1011                   fake_clock_.GetSystemTimeMilliseconds()),
1012               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1013   EXPECT_THAT(AdvancedScorer::Create(
1014                   CreateAdvancedScoringSpec("documentScore(this)"),
1015                   default_score, document_store_.get(), schema_store_.get(),
1016                   fake_clock_.GetSystemTimeMilliseconds()),
1017               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1018   EXPECT_THAT(AdvancedScorer::Create(
1019                   CreateAdvancedScoringSpec("that.documentScore()"),
1020                   default_score, document_store_.get(), schema_store_.get(),
1021                   fake_clock_.GetSystemTimeMilliseconds()),
1022               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1023   EXPECT_THAT(AdvancedScorer::Create(
1024                   CreateAdvancedScoringSpec("this.this.creationTimestamp()"),
1025                   default_score, document_store_.get(), schema_store_.get(),
1026                   fake_clock_.GetSystemTimeMilliseconds()),
1027               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1028   EXPECT_THAT(AdvancedScorer::Create(CreateAdvancedScoringSpec("this.log(2)"),
1029                                      default_score, document_store_.get(),
1030                                      schema_store_.get(),
1031                                      fake_clock_.GetSystemTimeMilliseconds()),
1032               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
1033 }
1034 
1035 }  // namespace
1036 
1037 }  // namespace lib
1038 }  // namespace icing
1039