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 "annotator/datetime/datetime-grounder.h"
18
19 #include "annotator/datetime/datetime_generated.h"
20 #include "utils/flatbuffers/flatbuffers.h"
21 #include "utils/jvm-test-utils.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24
25 using ::libtextclassifier3::grammar::datetime::AbsoluteDateTimeT;
26 using ::libtextclassifier3::grammar::datetime::ComponentType;
27 using ::libtextclassifier3::grammar::datetime::Meridiem;
28 using ::libtextclassifier3::grammar::datetime::RelativeDatetimeComponentT;
29 using ::libtextclassifier3::grammar::datetime::RelativeDateTimeT;
30 using ::libtextclassifier3::grammar::datetime::TimeZoneT;
31 using ::libtextclassifier3::grammar::datetime::UngroundedDatetime;
32 using ::libtextclassifier3::grammar::datetime::UngroundedDatetimeT;
33 using ::libtextclassifier3::grammar::datetime::RelativeDatetimeComponent_::
34 Modifier;
35 using ::testing::SizeIs;
36
37 namespace libtextclassifier3 {
38
39 class DatetimeGrounderTest : public testing::Test {
40 public:
SetUp()41 void SetUp() override {
42 calendarlib_ = CreateCalendarLibForTesting();
43 datetime_grounder_.reset(new DatetimeGrounder(calendarlib_.get()));
44 }
45
46 protected:
BuildAbsoluteDatetime(const int year,const int month,const int day,const int hour,const int minute,const int second,const Meridiem meridiem)47 OwnedFlatbuffer<UngroundedDatetime, std::string> BuildAbsoluteDatetime(
48 const int year, const int month, const int day, const int hour,
49 const int minute, const int second, const Meridiem meridiem) {
50 grammar::datetime::UngroundedDatetimeT ungrounded_datetime;
51 ungrounded_datetime.absolute_datetime.reset(new AbsoluteDateTimeT);
52
53 // Set absolute datetime value.
54 ungrounded_datetime.absolute_datetime->year = year;
55 ungrounded_datetime.absolute_datetime->month = month;
56 ungrounded_datetime.absolute_datetime->day = day;
57 ungrounded_datetime.absolute_datetime->hour = hour;
58 ungrounded_datetime.absolute_datetime->minute = minute;
59 ungrounded_datetime.absolute_datetime->second = second;
60 ungrounded_datetime.absolute_datetime->meridiem = meridiem;
61
62 return OwnedFlatbuffer<UngroundedDatetime, std::string>(
63 PackFlatbuffer<UngroundedDatetime>(&ungrounded_datetime));
64 }
65
BuildRelativeDatetime(const ComponentType component_type,const Modifier modifier,const int relative_count)66 OwnedFlatbuffer<UngroundedDatetime, std::string> BuildRelativeDatetime(
67 const ComponentType component_type, const Modifier modifier,
68 const int relative_count) {
69 UngroundedDatetimeT ungrounded_datetime;
70 ungrounded_datetime.relative_datetime.reset(new RelativeDateTimeT);
71 ungrounded_datetime.relative_datetime->relative_datetime_component
72 .emplace_back(new RelativeDatetimeComponentT);
73 ungrounded_datetime.relative_datetime->relative_datetime_component.back()
74 ->modifier = modifier;
75 ungrounded_datetime.relative_datetime->relative_datetime_component.back()
76 ->component_type = component_type;
77 ungrounded_datetime.relative_datetime->relative_datetime_component.back()
78 ->value = relative_count;
79 ungrounded_datetime.relative_datetime->base.reset(new AbsoluteDateTimeT);
80 ungrounded_datetime.relative_datetime->base->year = 2020;
81 ungrounded_datetime.relative_datetime->base->month = 6;
82 ungrounded_datetime.relative_datetime->base->day = 30;
83
84 return OwnedFlatbuffer<UngroundedDatetime, std::string>(
85 PackFlatbuffer<UngroundedDatetime>(&ungrounded_datetime));
86 }
87
VerifyValidUngroundedDatetime(const UngroundedDatetime * ungrounded_datetime)88 void VerifyValidUngroundedDatetime(
89 const UngroundedDatetime* ungrounded_datetime) {
90 EXPECT_TRUE(
91 datetime_grounder_->IsValidUngroundedDatetime(ungrounded_datetime));
92 }
93
VerifyInValidUngroundedDatetime(const UngroundedDatetime * ungrounded_datetime)94 void VerifyInValidUngroundedDatetime(
95 const UngroundedDatetime* ungrounded_datetime) {
96 EXPECT_FALSE(
97 datetime_grounder_->IsValidUngroundedDatetime(ungrounded_datetime));
98 }
99
100 std::unique_ptr<DatetimeGrounder> datetime_grounder_;
101 std::unique_ptr<CalendarLib> calendarlib_;
102 };
103
TEST_F(DatetimeGrounderTest,AbsoluteDatetimeTest)104 TEST_F(DatetimeGrounderTest, AbsoluteDatetimeTest) {
105 const OwnedFlatbuffer<UngroundedDatetime, std::string> datetime =
106 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/03, /*day=*/30,
107 /*hour=*/11, /*minute=*/59, /*second=*/59,
108 grammar::datetime::Meridiem_AM);
109 const std::vector<DatetimeParseResult> data =
110 datetime_grounder_
111 ->Ground(
112 /*reference_time_ms_utc=*/0, "Europe/Zurich", "en-US",
113 datetime.get())
114 .ValueOrDie();
115
116 EXPECT_THAT(data, SizeIs(1));
117 EXPECT_EQ(data[0].granularity, DatetimeGranularity::GRANULARITY_SECOND);
118
119 // Meridiem
120 EXPECT_EQ(data[0].datetime_components[0].component_type,
121 DatetimeComponent::ComponentType::MERIDIEM);
122 EXPECT_EQ(data[0].datetime_components[0].value, 0);
123
124 EXPECT_EQ(data[0].datetime_components[1].component_type,
125 DatetimeComponent::ComponentType::SECOND);
126 EXPECT_EQ(data[0].datetime_components[1].component_type,
127 DatetimeComponent::ComponentType::SECOND);
128
129 EXPECT_EQ(data[0].datetime_components[2].component_type,
130 DatetimeComponent::ComponentType::MINUTE);
131 EXPECT_EQ(data[0].datetime_components[2].value, 59);
132
133 EXPECT_EQ(data[0].datetime_components[3].component_type,
134 DatetimeComponent::ComponentType::HOUR);
135 EXPECT_EQ(data[0].datetime_components[3].value, 11);
136
137 EXPECT_EQ(data[0].datetime_components[4].component_type,
138 DatetimeComponent::ComponentType::DAY_OF_MONTH);
139 EXPECT_EQ(data[0].datetime_components[4].value, 30);
140
141 EXPECT_EQ(data[0].datetime_components[5].component_type,
142 DatetimeComponent::ComponentType::MONTH);
143 EXPECT_EQ(data[0].datetime_components[5].value, 3);
144
145 EXPECT_EQ(data[0].datetime_components[6].component_type,
146 DatetimeComponent::ComponentType::YEAR);
147 EXPECT_EQ(data[0].datetime_components[6].value, 2000);
148 }
149
TEST_F(DatetimeGrounderTest,InterpretDatetimeTest)150 TEST_F(DatetimeGrounderTest, InterpretDatetimeTest) {
151 const OwnedFlatbuffer<UngroundedDatetime, std::string> datetime =
152 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/03, /*day=*/30,
153 /*hour=*/11, /*minute=*/59, /*second=*/59,
154 grammar::datetime::Meridiem_UNKNOWN);
155 const std::vector<DatetimeParseResult> data =
156 datetime_grounder_
157 ->Ground(
158 /*reference_time_ms_utc=*/0, "Europe/Zurich", "en-US",
159 datetime.get())
160 .ValueOrDie();
161
162 EXPECT_THAT(data, SizeIs(2));
163 EXPECT_EQ(data[0].granularity, DatetimeGranularity::GRANULARITY_SECOND);
164 EXPECT_EQ(data[1].granularity, DatetimeGranularity::GRANULARITY_SECOND);
165
166 // Check Meridiem's values
167 EXPECT_EQ(data[0].datetime_components[0].component_type,
168 DatetimeComponent::ComponentType::MERIDIEM);
169 EXPECT_EQ(data[0].datetime_components[0].value, 0);
170 EXPECT_EQ(data[1].datetime_components[0].component_type,
171 DatetimeComponent::ComponentType::MERIDIEM);
172 EXPECT_EQ(data[1].datetime_components[0].value, 1);
173 }
174
TEST_F(DatetimeGrounderTest,RelativeDatetimeTest)175 TEST_F(DatetimeGrounderTest, RelativeDatetimeTest) {
176 const OwnedFlatbuffer<UngroundedDatetime, std::string> datetime =
177 BuildRelativeDatetime(ComponentType::ComponentType_DAY_OF_MONTH,
178 Modifier::Modifier_NEXT, 1);
179 const std::vector<DatetimeParseResult> data =
180 datetime_grounder_
181 ->Ground(
182 /*reference_time_ms_utc=*/0, "Europe/Zurich", "en-US",
183 datetime.get())
184 .ValueOrDie();
185
186 EXPECT_THAT(data, SizeIs(1));
187 EXPECT_EQ(data[0].granularity, DatetimeGranularity::GRANULARITY_DAY);
188
189 EXPECT_EQ(data[0].datetime_components[0].component_type,
190 DatetimeComponent::ComponentType::DAY_OF_MONTH);
191 EXPECT_EQ(data[0].datetime_components[0].relative_qualifier,
192 DatetimeComponent::RelativeQualifier::NEXT);
193 EXPECT_EQ(data[0].datetime_components[0].relative_count, 1);
194 EXPECT_EQ(data[0].datetime_components[1].component_type,
195 DatetimeComponent::ComponentType::MONTH);
196 EXPECT_EQ(data[0].datetime_components[2].component_type,
197 DatetimeComponent::ComponentType::YEAR);
198 }
199
TEST_F(DatetimeGrounderTest,TimeZoneTest)200 TEST_F(DatetimeGrounderTest, TimeZoneTest) {
201 grammar::datetime::UngroundedDatetimeT ungrounded_datetime;
202 ungrounded_datetime.absolute_datetime.reset(new AbsoluteDateTimeT);
203 ungrounded_datetime.absolute_datetime->time_zone.reset(new TimeZoneT);
204 ungrounded_datetime.absolute_datetime->time_zone->utc_offset_mins = 120;
205 const OwnedFlatbuffer<UngroundedDatetime, std::string> timezone(
206 PackFlatbuffer<UngroundedDatetime>(&ungrounded_datetime));
207
208 const std::vector<DatetimeParseResult> data =
209 datetime_grounder_
210 ->Ground(
211 /*reference_time_ms_utc=*/0, "Europe/Zurich", "en-US",
212 timezone.get())
213 .ValueOrDie();
214
215 EXPECT_THAT(data, SizeIs(1));
216 EXPECT_EQ(data[0].granularity, DatetimeGranularity::GRANULARITY_UNKNOWN);
217 EXPECT_EQ(data[0].datetime_components[0].component_type,
218 DatetimeComponent::ComponentType::ZONE_OFFSET);
219 EXPECT_EQ(data[0].datetime_components[0].value, 120);
220 }
221
TEST_F(DatetimeGrounderTest,InValidUngroundedDatetime)222 TEST_F(DatetimeGrounderTest, InValidUngroundedDatetime) {
223 VerifyInValidUngroundedDatetime(
224 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/23, /*day=*/30,
225 /*hour=*/11, /*minute=*/59, /*second=*/59,
226 grammar::datetime::Meridiem_AM)
227 .get());
228
229 VerifyInValidUngroundedDatetime(
230 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/03, /*day=*/33,
231 /*hour=*/11, /*minute=*/59, /*second=*/59,
232 grammar::datetime::Meridiem_AM)
233 .get());
234
235 VerifyInValidUngroundedDatetime(
236 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/02, /*day=*/30,
237 /*hour=*/11, /*minute=*/59, /*second=*/59,
238 grammar::datetime::Meridiem_AM)
239 .get());
240
241 VerifyInValidUngroundedDatetime(
242 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/07, /*day=*/31,
243 /*hour=*/24, /*minute=*/59, /*second=*/59,
244 grammar::datetime::Meridiem_AM)
245 .get());
246
247 VerifyInValidUngroundedDatetime(
248 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/02, /*day=*/28,
249 /*hour=*/24, /*minute=*/59, /*second=*/59,
250 grammar::datetime::Meridiem_AM)
251 .get());
252
253 VerifyInValidUngroundedDatetime(
254 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/02, /*day=*/28,
255 /*hour=*/11, /*minute=*/69, /*second=*/59,
256 grammar::datetime::Meridiem_AM)
257 .get());
258
259 VerifyInValidUngroundedDatetime(
260 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/02, /*day=*/28,
261 /*hour=*/11, /*minute=*/59, /*second=*/99,
262 grammar::datetime::Meridiem_AM)
263 .get());
264
265 VerifyInValidUngroundedDatetime(
266 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/00, /*day=*/28,
267 /*hour=*/11, /*minute=*/59, /*second=*/99,
268 grammar::datetime::Meridiem_AM)
269 .get());
270 }
271
TEST_F(DatetimeGrounderTest,ValidUngroundedDatetime)272 TEST_F(DatetimeGrounderTest, ValidUngroundedDatetime) {
273 VerifyValidUngroundedDatetime(
274 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/2, /*day=*/29,
275 /*hour=*/23, /*minute=*/59, /*second=*/59,
276 grammar::datetime::Meridiem_AM)
277 .get());
278
279 VerifyValidUngroundedDatetime(
280 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/7, /*day=*/31,
281 /*hour=*/23, /*minute=*/59, /*second=*/59,
282 grammar::datetime::Meridiem_AM)
283 .get());
284
285 VerifyValidUngroundedDatetime(
286 BuildAbsoluteDatetime(/*year=*/2000, /*month=*/10, /*day=*/31,
287 /*hour=*/23, /*minute=*/59, /*second=*/59,
288 grammar::datetime::Meridiem_AM)
289 .get());
290 }
291
292 } // namespace libtextclassifier3
293