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/jvm-test-utils.h"
18 #include "gtest/gtest.h"
19 
20 namespace libtextclassifier3 {
21 namespace {
22 
23 class CalendarTest : public ::testing::Test {
24  protected:
CalendarTest()25   CalendarTest()
26       : calendarlib_(libtextclassifier3::CreateCalendarLibForTesting()) {}
27 
28   static constexpr int kWednesday = 4;
29   std::unique_ptr<CalendarLib> calendarlib_;
30 };
31 
TEST_F(CalendarTest,Interface)32 TEST_F(CalendarTest, Interface) {
33   int64 time;
34   DatetimeGranularity granularity;
35   std::string timezone;
36   DatetimeParsedData data;
37   bool result = calendarlib_->InterpretParseData(
38       data, /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Zurich",
39       /*reference_locale=*/"en-CH",
40       /*prefer_future_for_unspecified_date=*/false, &time, &granularity);
41   TC3_LOG(INFO) << result;
42 }
43 
TEST_F(CalendarTest,SetsZeroTimeWhenNotRelative)44 TEST_F(CalendarTest, SetsZeroTimeWhenNotRelative) {
45   int64 time;
46   DatetimeGranularity granularity;
47   DatetimeParsedData data;
48   data.SetAbsoluteValue(DatetimeComponent::ComponentType::YEAR, 2018);
49 
50   ASSERT_TRUE(calendarlib_->InterpretParseData(
51       data,
52       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
53       /*reference_locale=*/"en-CH",
54       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
55   EXPECT_EQ(time, 1514761200000L /* Jan 01 2018 00:00:00 */);
56 
57   ASSERT_TRUE(calendarlib_->InterpretParseData(
58       data,
59       /*reference_time_ms_utc=*/1L, /*reference_timezone=*/"Europe/Zurich",
60       /*reference_locale=*/"en-CH",
61       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
62   EXPECT_EQ(time, 1514761200000L /* Jan 01 2018 00:00:00 */);
63 }
64 
TEST_F(CalendarTest,SetsTimeZone)65 TEST_F(CalendarTest, SetsTimeZone) {
66   int64 time;
67   DatetimeGranularity granularity;
68   DatetimeParsedData data;
69   data.SetAbsoluteValue(DatetimeComponent::ComponentType::YEAR, 2018);
70   data.SetAbsoluteValue(DatetimeComponent::ComponentType::HOUR, 7);
71   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MINUTE, 30);
72   data.SetAbsoluteValue(DatetimeComponent::ComponentType::SECOND, 10);
73 
74   ASSERT_TRUE(calendarlib_->InterpretParseData(
75       data,
76       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
77       /*reference_locale=*/"en-CH",
78       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
79   EXPECT_EQ(time, 1514788210000L /* Jan 01 2018 07:30:10 GMT+01:00 */);
80 
81   data.SetAbsoluteValue(DatetimeComponent::ComponentType::ZONE_OFFSET,
82                         60);  // GMT+01:00
83   ASSERT_TRUE(calendarlib_->InterpretParseData(
84       data,
85       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
86       /*reference_locale=*/"en-CH",
87       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
88   EXPECT_EQ(time, 1514788210000L /* Jan 01 2018 07:30:10 GMT+01:00 */);
89 
90   // Now the hour is in terms of GMT+02:00 which is one hour ahead of
91   // GMT+01:00.
92   data.SetAbsoluteValue(DatetimeComponent::ComponentType::ZONE_OFFSET,
93                         120);  // GMT+02:00
94   ASSERT_TRUE(calendarlib_->InterpretParseData(
95       data,
96       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
97       /*reference_locale=*/"en-CH",
98       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
99   EXPECT_EQ(time, 1514784610000L /* Jan 01 2018 06:30:10 GMT+01:00 */);
100 }
101 
TEST_F(CalendarTest,RoundingToGranularityBasic)102 TEST_F(CalendarTest, RoundingToGranularityBasic) {
103   int64 time;
104   DatetimeGranularity granularity;
105   DatetimeParsedData data;
106 
107   data.SetAbsoluteValue(DatetimeComponent::ComponentType::YEAR, 2018);
108   ASSERT_TRUE(calendarlib_->InterpretParseData(
109       data,
110       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
111       /*reference_locale=*/"en-CH",
112       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
113   EXPECT_EQ(time, 1514761200000L /* Jan 01 2018 00:00:00 */);
114 
115   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MONTH, 4);
116   ASSERT_TRUE(calendarlib_->InterpretParseData(
117       data,
118       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
119       /*reference_locale=*/"en-CH",
120       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
121   EXPECT_EQ(time, 1522533600000L /* Apr 01 2018 00:00:00 */);
122 
123   data.SetAbsoluteValue(DatetimeComponent::ComponentType::DAY_OF_MONTH, 25);
124   ASSERT_TRUE(calendarlib_->InterpretParseData(
125       data,
126       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
127       /*reference_locale=*/"en-CH",
128       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
129   EXPECT_EQ(time, 1524607200000L /* Apr 25 2018 00:00:00 */);
130 
131   data.SetAbsoluteValue(DatetimeComponent::ComponentType::HOUR, 9);
132   ASSERT_TRUE(calendarlib_->InterpretParseData(
133       data,
134       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
135       /*reference_locale=*/"en-CH",
136       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
137   EXPECT_EQ(time, 1524639600000L /* Apr 25 2018 09:00:00 */);
138 
139   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MINUTE, 33);
140   ASSERT_TRUE(calendarlib_->InterpretParseData(
141       data,
142       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
143       /*reference_locale=*/"en-CH",
144       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
145   EXPECT_EQ(time, 1524641580000 /* Apr 25 2018 09:33:00 */);
146 
147   data.SetAbsoluteValue(DatetimeComponent::ComponentType::SECOND, 59);
148   ASSERT_TRUE(calendarlib_->InterpretParseData(
149       data,
150       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
151       /*reference_locale=*/"en-CH",
152       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
153   EXPECT_EQ(time, 1524641639000 /* Apr 25 2018 09:33:59 */);
154 }
155 
TEST_F(CalendarTest,RoundingToGranularityWeek)156 TEST_F(CalendarTest, RoundingToGranularityWeek) {
157   int64 time;
158   DatetimeGranularity granularity;
159   // Prepare data structure that means: "next week"
160   DatetimeParsedData data;
161   data.SetRelativeValue(DatetimeComponent::ComponentType::WEEK,
162                         DatetimeComponent::RelativeQualifier::NEXT);
163   data.SetRelativeCount(DatetimeComponent::ComponentType::WEEK, 1);
164 
165   ASSERT_TRUE(calendarlib_->InterpretParseData(
166       data,
167       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
168       /*reference_locale=*/"de-CH",
169       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
170   EXPECT_EQ(time, 342000000L /* Mon Jan 05 1970 00:00:00 */);
171 
172   ASSERT_TRUE(calendarlib_->InterpretParseData(
173       data,
174       /*reference_time_ms_utc=*/0L, /*reference_timezone=*/"Europe/Zurich",
175       /*reference_locale=*/"en-US",
176       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
177   EXPECT_EQ(time, 255600000L /* Sun Jan 04 1970 00:00:00 */);
178 }
179 
TEST_F(CalendarTest,RelativeTime)180 TEST_F(CalendarTest, RelativeTime) {
181   const int64 ref_time = 1524648839000L; /* 25 April 2018 09:33:59 */
182   int64 time;
183   DatetimeGranularity granularity;
184 
185   // Two Weds from now.
186   DatetimeParsedData future_wed_parse;
187   future_wed_parse.SetRelativeValue(
188       DatetimeComponent::ComponentType::DAY_OF_WEEK,
189       DatetimeComponent::RelativeQualifier::FUTURE);
190   future_wed_parse.SetRelativeCount(
191       DatetimeComponent::ComponentType::DAY_OF_WEEK, 2);
192   future_wed_parse.SetAbsoluteValue(
193       DatetimeComponent::ComponentType::DAY_OF_WEEK, kWednesday);
194 
195   ASSERT_TRUE(calendarlib_->InterpretParseData(
196       future_wed_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
197       /*reference_locale=*/"en-US",
198       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
199   EXPECT_EQ(time, 1525858439000L /* Wed May 09 2018 11:33:59 */);
200   EXPECT_EQ(granularity, GRANULARITY_DAY);
201 
202   // Next Wed.
203   DatetimeParsedData next_wed_parse;
204   next_wed_parse.SetAbsoluteValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
205                                   kWednesday);
206   next_wed_parse.SetRelativeValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
207                                   DatetimeComponent::RelativeQualifier::NEXT);
208   next_wed_parse.SetRelativeCount(DatetimeComponent::ComponentType::DAY_OF_WEEK,
209                                   1);
210 
211   ASSERT_TRUE(calendarlib_->InterpretParseData(
212       next_wed_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
213       /*reference_locale=*/"en-US",
214       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
215   EXPECT_EQ(time, 1525212000000L /* Wed May 02 2018 00:00:00 */);
216   EXPECT_EQ(granularity, GRANULARITY_DAY);
217 
218   // Same Wed.
219   DatetimeParsedData same_wed_parse;
220   same_wed_parse.SetRelativeValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
221                                   DatetimeComponent::RelativeQualifier::THIS);
222   same_wed_parse.SetAbsoluteValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
223                                   kWednesday);
224   same_wed_parse.SetRelativeCount(DatetimeComponent::ComponentType::DAY_OF_WEEK,
225                                   1);
226 
227   ASSERT_TRUE(calendarlib_->InterpretParseData(
228       same_wed_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
229       /*reference_locale=*/"en-US",
230       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
231   EXPECT_EQ(time, 1524607200000L /* Wed Apr 25 2018 00:00:00 */);
232   EXPECT_EQ(granularity, GRANULARITY_DAY);
233 
234   // Previous Wed.
235   DatetimeParsedData last_wed_parse;
236   last_wed_parse.SetRelativeValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
237                                   DatetimeComponent::RelativeQualifier::LAST);
238   last_wed_parse.SetAbsoluteValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
239                                   kWednesday);
240   last_wed_parse.SetRelativeCount(DatetimeComponent::ComponentType::DAY_OF_WEEK,
241                                   1);
242 
243   ASSERT_TRUE(calendarlib_->InterpretParseData(
244       last_wed_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
245       /*reference_locale=*/"en-US",
246       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
247   EXPECT_EQ(time, 1524002400000L /* Wed Apr 18 2018 00:00:00 */);
248   EXPECT_EQ(granularity, GRANULARITY_DAY);
249 
250   // Two Weds ago.
251   DatetimeParsedData past_wed_parse;
252   past_wed_parse.SetRelativeValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
253                                   DatetimeComponent::RelativeQualifier::PAST);
254   past_wed_parse.SetAbsoluteValue(DatetimeComponent::ComponentType::DAY_OF_WEEK,
255                                   kWednesday);
256   past_wed_parse.SetRelativeCount(DatetimeComponent::ComponentType::DAY_OF_WEEK,
257                                   -2);
258 
259   ASSERT_TRUE(calendarlib_->InterpretParseData(
260       past_wed_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
261       /*reference_locale=*/"en-US",
262       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
263   EXPECT_EQ(time, 1523439239000L /* Wed Apr 11 2018 11:33:59 */);
264   EXPECT_EQ(granularity, GRANULARITY_DAY);
265 
266   // In 3 hours.
267   DatetimeParsedData in_3_hours_parse;
268   in_3_hours_parse.SetRelativeValue(
269       DatetimeComponent::ComponentType::HOUR,
270       DatetimeComponent::RelativeQualifier::FUTURE);
271   in_3_hours_parse.SetRelativeCount(DatetimeComponent::ComponentType::HOUR, 3);
272 
273   ASSERT_TRUE(calendarlib_->InterpretParseData(
274       in_3_hours_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
275       /*reference_locale=*/"en-US",
276       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
277   EXPECT_EQ(time, 1524659639000L /* Wed Apr 25 2018 14:33:59 */);
278   EXPECT_EQ(granularity, GRANULARITY_HOUR);
279 
280   // In 5 minutes.
281   DatetimeParsedData in_5_minutes_parse;
282   in_5_minutes_parse.SetRelativeValue(
283       DatetimeComponent::ComponentType::MINUTE,
284       DatetimeComponent::RelativeQualifier::FUTURE);
285   in_5_minutes_parse.SetRelativeCount(DatetimeComponent::ComponentType::MINUTE,
286                                       5);
287 
288   ASSERT_TRUE(calendarlib_->InterpretParseData(
289       in_5_minutes_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
290       /*reference_locale=*/"en-US",
291       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
292   EXPECT_EQ(time, 1524649139000L /* Wed Apr 25 2018 14:33:59 */);
293   EXPECT_EQ(granularity, GRANULARITY_MINUTE);
294 
295   // In 10 seconds.
296   DatetimeParsedData in_10_seconds_parse;
297   in_10_seconds_parse.SetRelativeValue(
298       DatetimeComponent::ComponentType::SECOND,
299       DatetimeComponent::RelativeQualifier::FUTURE);
300   in_10_seconds_parse.SetRelativeCount(DatetimeComponent::ComponentType::SECOND,
301                                        10);
302 
303   ASSERT_TRUE(calendarlib_->InterpretParseData(
304       in_10_seconds_parse, ref_time, /*reference_timezone=*/"Europe/Zurich",
305       /*reference_locale=*/"en-US",
306       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
307   EXPECT_EQ(time, 1524648849000L /* Wed Apr 25 2018 14:33:59 */);
308   EXPECT_EQ(granularity, GRANULARITY_SECOND);
309 }
310 
TEST_F(CalendarTest,AddsADayWhenTimeInThePastAndDayNotSpecified)311 TEST_F(CalendarTest, AddsADayWhenTimeInThePastAndDayNotSpecified) {
312   int64 time;
313   DatetimeGranularity granularity;
314   DatetimeParsedData data;
315   data.SetAbsoluteValue(DatetimeComponent::ComponentType::HOUR, 7);
316   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MINUTE, 10);
317 
318   ASSERT_TRUE(calendarlib_->InterpretParseData(
319       data,
320       /*reference_time_ms_utc=*/1567317600000L /* Sept 01 2019 00:00:00 */,
321       /*reference_timezone=*/"Europe/Zurich",
322       /*reference_locale=*/"en-CH", /*prefer_future_for_unspecified_date=*/true,
323       &time, &granularity));
324   EXPECT_EQ(time, 1567401000000L /* Sept 02 2019 07:10:00 */);
325 }
326 
TEST_F(CalendarTest,DoesntAddADayWhenTimeInThePastAndDayNotSpecifiedAndDisabled)327 TEST_F(CalendarTest,
328        DoesntAddADayWhenTimeInThePastAndDayNotSpecifiedAndDisabled) {
329   int64 time;
330   DatetimeGranularity granularity;
331   DatetimeParsedData data;
332   data.SetAbsoluteValue(DatetimeComponent::ComponentType::HOUR, 7);
333   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MINUTE, 10);
334 
335   ASSERT_TRUE(calendarlib_->InterpretParseData(
336       data,
337       /*reference_time_ms_utc=*/1567317600000L /* Sept 01 2019 00:00:00 */,
338       /*reference_timezone=*/"Europe/Zurich",
339       /*reference_locale=*/"en-CH",
340       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
341   EXPECT_EQ(time, 1567314600000L /* Sept 01 2019 07:10:00 */);
342 }
343 
TEST_F(CalendarTest,DoesntAddADayWhenTimeInTheFutureAndDayNotSpecified)344 TEST_F(CalendarTest, DoesntAddADayWhenTimeInTheFutureAndDayNotSpecified) {
345   int64 time;
346   DatetimeGranularity granularity;
347   DatetimeParsedData data;
348   data.SetAbsoluteValue(DatetimeComponent::ComponentType::HOUR, 9);
349   data.SetAbsoluteValue(DatetimeComponent::ComponentType::MINUTE, 10);
350 
351   ASSERT_TRUE(calendarlib_->InterpretParseData(
352       data,
353       /*reference_time_ms_utc=*/1567317600000L /* Sept 01 2019 00:00:00 */,
354       /*reference_timezone=*/"Europe/Zurich",
355       /*reference_locale=*/"en-CH", /*prefer_future_for_unspecified_date=*/true,
356       &time, &granularity));
357   EXPECT_EQ(time, 1567321800000L /* Sept 01 2019 09:10:00 */);
358 
359   ASSERT_TRUE(calendarlib_->InterpretParseData(
360       data,
361       /*reference_time_ms_utc=*/1567317600000L /* Sept 01 2019 00:00:00 */,
362       /*reference_timezone=*/"Europe/Zurich",
363       /*reference_locale=*/"en-CH",
364       /*prefer_future_for_unspecified_date=*/false, &time, &granularity));
365   EXPECT_EQ(time, 1567321800000L /* Sept 01 2019 09:10:00 */);
366 }
367 
368 }  // namespace
369 }  // namespace libtextclassifier3
370