1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "utils/grammar/semantics/evaluators/compose-eval.h"
18 
19 #include <vector>
20 
21 #include "utils/base/statusor.h"
22 #include "utils/flatbuffers/flatbuffers.h"
23 #include "utils/flatbuffers/reflection.h"
24 #include "utils/flatbuffers/test-utils.h"
25 #include "utils/grammar/semantics/evaluator.h"
26 #include "utils/grammar/semantics/evaluators/const-eval.h"
27 #include "utils/grammar/semantics/expression_generated.h"
28 #include "utils/grammar/testing/utils.h"
29 #include "utils/grammar/testing/value_generated.h"
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
32 #include "flatbuffers/flatbuffers.h"
33 
34 namespace libtextclassifier3::grammar {
35 namespace {
36 
37 class ComposeEvaluatorTest : public GrammarTest {
38  protected:
ComposeEvaluatorTest()39   explicit ComposeEvaluatorTest()
40       : const_eval_(semantic_values_schema_.get()) {}
41 
42   // Evaluator that just returns a constant value.
43   ConstEvaluator const_eval_;
44 };
45 
TEST_F(ComposeEvaluatorTest,SetsSingleField)46 TEST_F(ComposeEvaluatorTest, SetsSingleField) {
47   TestDateT date;
48   date.day = 1;
49   date.month = 2;
50   date.year = 2020;
51   ComposeExpressionT compose_expression;
52   compose_expression.type =
53       TypeIdForName(semantic_values_schema_.get(),
54                     "libtextclassifier3.grammar.TestValue")
55           .value();
56   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
57   compose_expression.fields.back()->path = CreateUnpackedFieldPath({"date"});
58   compose_expression.fields.back()->value = CreateConstDateExpression(date);
59   OwnedFlatbuffer<SemanticExpression> expression =
60       CreateExpression(std::move(compose_expression));
61 
62   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
63 
64   StatusOr<const SemanticValue*> result =
65       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
66 
67   EXPECT_TRUE(result.ok());
68   const SemanticValue* result_value = result.ValueOrDie();
69   ASSERT_NE(result_value, nullptr);
70   EXPECT_EQ(result_value->type()->name()->str(),
71             "libtextclassifier3.grammar.TestValue");
72   const TestValue* result_test_value = result_value->Table<TestValue>();
73   EXPECT_EQ(result_test_value->date()->day(), 1);
74   EXPECT_EQ(result_test_value->date()->month(), 2);
75   EXPECT_EQ(result_test_value->date()->year(), 2020);
76 }
77 
TEST_F(ComposeEvaluatorTest,SetsStringField)78 TEST_F(ComposeEvaluatorTest, SetsStringField) {
79   ComposeExpressionT compose_expression;
80   compose_expression.type =
81       TypeIdForName(semantic_values_schema_.get(),
82                     "libtextclassifier3.grammar.TestValue")
83           .value();
84   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
85   compose_expression.fields.back()->path =
86       CreateUnpackedFieldPath({"test_string"});
87   compose_expression.fields.back()->value =
88       CreatePrimitiveConstExpression<StringPiece>("this is a test");
89   OwnedFlatbuffer<SemanticExpression> expression =
90       CreateExpression(std::move(compose_expression));
91 
92   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
93 
94   StatusOr<const SemanticValue*> result =
95       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
96 
97   EXPECT_TRUE(result.ok());
98   const SemanticValue* result_value = result.ValueOrDie();
99   ASSERT_NE(result_value, nullptr);
100   EXPECT_EQ(result_value->type()->name()->str(),
101             "libtextclassifier3.grammar.TestValue");
102   const TestValue* result_test_value = result_value->Table<TestValue>();
103   EXPECT_EQ(result_test_value->test_string()->str(), "this is a test");
104 }
105 
TEST_F(ComposeEvaluatorTest,SetsPrimitiveField)106 TEST_F(ComposeEvaluatorTest, SetsPrimitiveField) {
107   ComposeExpressionT compose_expression;
108   compose_expression.type = TypeIdForName(semantic_values_schema_.get(),
109                                           "libtextclassifier3.grammar.TestDate")
110                                 .value();
111   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
112   compose_expression.fields.back()->path = CreateUnpackedFieldPath({"day"});
113   compose_expression.fields.back()->value =
114       CreatePrimitiveConstExpression<int>(1);
115 
116   OwnedFlatbuffer<SemanticExpression> expression =
117       CreateExpression(std::move(compose_expression));
118 
119   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
120 
121   StatusOr<const SemanticValue*> result =
122       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
123 
124   EXPECT_TRUE(result.ok());
125   const SemanticValue* result_value = result.ValueOrDie();
126   ASSERT_NE(result_value, nullptr);
127   EXPECT_EQ(result_value->type()->name()->str(),
128             "libtextclassifier3.grammar.TestDate");
129   const TestDate* result_date = result_value->Table<TestDate>();
130   EXPECT_EQ(result_date->day(), 1);
131 }
132 
TEST_F(ComposeEvaluatorTest,MergesMultipleField)133 TEST_F(ComposeEvaluatorTest, MergesMultipleField) {
134   TestDateT day;
135   day.day = 1;
136 
137   TestDateT month;
138   month.month = 2;
139 
140   TestDateT year;
141   year.year = 2020;
142 
143   ComposeExpressionT compose_expression;
144   compose_expression.type =
145       TypeIdForName(semantic_values_schema_.get(),
146                     "libtextclassifier3.grammar.TestValue")
147           .value();
148   for (const TestDateT& component : std::vector<TestDateT>{day, month, year}) {
149     compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
150     compose_expression.fields.back()->path = CreateUnpackedFieldPath({"date"});
151     compose_expression.fields.back()->value =
152         CreateConstDateExpression(component);
153   }
154   OwnedFlatbuffer<SemanticExpression> expression =
155       CreateExpression(std::move(compose_expression));
156 
157   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
158 
159   StatusOr<const SemanticValue*> result =
160       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
161 
162   EXPECT_TRUE(result.ok());
163   const SemanticValue* result_value = result.ValueOrDie();
164   ASSERT_NE(result_value, nullptr);
165   EXPECT_EQ(result_value->type()->name()->str(),
166             "libtextclassifier3.grammar.TestValue");
167   const TestValue* result_test_value = result_value->Table<TestValue>();
168   EXPECT_EQ(result_test_value->date()->day(), 1);
169   EXPECT_EQ(result_test_value->date()->month(), 2);
170   EXPECT_EQ(result_test_value->date()->year(), 2020);
171 }
172 
TEST_F(ComposeEvaluatorTest,SucceedsEvenWhenEmpty)173 TEST_F(ComposeEvaluatorTest, SucceedsEvenWhenEmpty) {
174   ComposeExpressionT compose_expression;
175   compose_expression.type =
176       TypeIdForName(semantic_values_schema_.get(),
177                     "libtextclassifier3.grammar.TestValue")
178           .value();
179   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
180   compose_expression.fields.back()->path = CreateUnpackedFieldPath({"date"});
181   compose_expression.fields.back()->value.reset(new SemanticExpressionT);
182   OwnedFlatbuffer<SemanticExpression> expression =
183       CreateExpression(std::move(compose_expression));
184 
185   // Just return null value.
186   struct : public SemanticExpressionEvaluator {
187     StatusOr<const SemanticValue*> Apply(const EvalContext&,
188                                          const SemanticExpression*,
189                                          UnsafeArena*) const override {
190       return nullptr;
191     }
192   } null_eval;
193 
194   ComposeEvaluator compose_eval(&null_eval, semantic_values_schema_.get());
195 
196   StatusOr<const SemanticValue*> result =
197       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
198 
199   EXPECT_TRUE(result.ok());
200 }
201 
TEST_F(ComposeEvaluatorTest,AddsRepeatedPrimitiveField)202 TEST_F(ComposeEvaluatorTest, AddsRepeatedPrimitiveField) {
203   ComposeExpressionT compose_expression;
204   compose_expression.type =
205       TypeIdForName(semantic_values_schema_.get(),
206                     "libtextclassifier3.grammar.TestValue")
207           .value();
208   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
209   compose_expression.fields.back()->path =
210       CreateUnpackedFieldPath({"repeated_enum"});
211   compose_expression.fields.back()->value =
212       CreatePrimitiveConstExpression<int>(TestEnum_ENUM_1);
213   compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
214   compose_expression.fields.back()->path =
215       CreateUnpackedFieldPath({"repeated_enum"});
216   compose_expression.fields.back()->value =
217       CreatePrimitiveConstExpression<int>(TestEnum_ENUM_2);
218   OwnedFlatbuffer<SemanticExpression> expression =
219       CreateExpression(std::move(compose_expression));
220 
221   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
222 
223   StatusOr<const SemanticValue*> result =
224       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
225 
226   EXPECT_TRUE(result.ok());
227   const SemanticValue* result_value = result.ValueOrDie();
228   ASSERT_NE(result_value, nullptr);
229   EXPECT_EQ(result_value->type()->name()->str(),
230             "libtextclassifier3.grammar.TestValue");
231   const TestValue* result_test_value = result_value->Table<TestValue>();
232   EXPECT_EQ(result_test_value->repeated_enum()->size(), 2);
233   EXPECT_EQ(result_test_value->repeated_enum()->Get(0), TestEnum_ENUM_1);
234   EXPECT_EQ(result_test_value->repeated_enum()->Get(1), TestEnum_ENUM_2);
235 }
236 
TEST_F(ComposeEvaluatorTest,AddsRepeatedSubmessage)237 TEST_F(ComposeEvaluatorTest, AddsRepeatedSubmessage) {
238   ComposeExpressionT compose_expression;
239   compose_expression.type =
240       TypeIdForName(semantic_values_schema_.get(),
241                     "libtextclassifier3.grammar.TestValue")
242           .value();
243   {
244     compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
245     compose_expression.fields.back()->path =
246         CreateUnpackedFieldPath({"repeated_date"});
247     TestDateT date;
248     date.day = 1;
249     date.month = 2;
250     date.year = 2020;
251     compose_expression.fields.back()->value = CreateConstDateExpression(date);
252   }
253 
254   {
255     compose_expression.fields.emplace_back(new ComposeExpression_::FieldT);
256     compose_expression.fields.back()->path =
257         CreateUnpackedFieldPath({"repeated_date"});
258     TestDateT date;
259     date.day = 3;
260     date.month = 4;
261     date.year = 2021;
262     compose_expression.fields.back()->value = CreateConstDateExpression(date);
263   }
264 
265   OwnedFlatbuffer<SemanticExpression> expression =
266       CreateExpression(std::move(compose_expression));
267 
268   ComposeEvaluator compose_eval(&const_eval_, semantic_values_schema_.get());
269 
270   StatusOr<const SemanticValue*> result =
271       compose_eval.Apply(/*context=*/{}, expression.get(), &arena_);
272 
273   EXPECT_TRUE(result.ok());
274   const SemanticValue* result_value = result.ValueOrDie();
275   ASSERT_NE(result_value, nullptr);
276   EXPECT_EQ(result_value->type()->name()->str(),
277             "libtextclassifier3.grammar.TestValue");
278   const TestValue* result_test_value = result_value->Table<TestValue>();
279   EXPECT_EQ(result_test_value->repeated_date()->size(), 2);
280   EXPECT_EQ(result_test_value->repeated_date()->Get(0)->day(), 1);
281   EXPECT_EQ(result_test_value->repeated_date()->Get(0)->month(), 2);
282   EXPECT_EQ(result_test_value->repeated_date()->Get(0)->year(), 2020);
283   EXPECT_EQ(result_test_value->repeated_date()->Get(1)->day(), 3);
284   EXPECT_EQ(result_test_value->repeated_date()->Get(1)->month(), 4);
285   EXPECT_EQ(result_test_value->repeated_date()->Get(1)->year(), 2021);
286 }
287 
288 }  // namespace
289 }  // namespace libtextclassifier3::grammar
290