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