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/grammar-parser.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "annotator/datetime/datetime-grounder.h"
23 #include "annotator/datetime/testing/base-parser-test.h"
24 #include "annotator/datetime/testing/datetime-component-builder.h"
25 #include "utils/grammar/analyzer.h"
26 #include "utils/jvm-test-utils.h"
27 #include "utils/test-data-test-utils.h"
28 #include "gmock/gmock.h"
29 #include "gtest/gtest.h"
30 
31 using ::libtextclassifier3::grammar::Analyzer;
32 using ::libtextclassifier3::grammar::RulesSet;
33 
34 namespace libtextclassifier3 {
35 namespace {
GetModelPath()36 std::string GetModelPath() { return GetTestDataPath("annotator/test_data/"); }
37 
ReadFile(const std::string & file_name)38 std::string ReadFile(const std::string& file_name) {
39   std::ifstream file_stream(file_name);
40   return std::string(std::istreambuf_iterator<char>(file_stream), {});
41 }
42 
43 class GrammarDatetimeParserTest : public DateTimeParserTest {
44  public:
SetUp()45   void SetUp() override {
46     grammar_buffer_ = ReadFile(GetModelPath() + "datetime.fb");
47     unilib_ = CreateUniLibForTesting();
48     calendarlib_ = CreateCalendarLibForTesting();
49     analyzer_ = std::make_unique<Analyzer>(
50         unilib_.get(), flatbuffers::GetRoot<RulesSet>(grammar_buffer_.data()));
51     datetime_grounder_ = std::make_unique<DatetimeGrounder>(calendarlib_.get());
52     parser_.reset(new GrammarDatetimeParser(*analyzer_, *datetime_grounder_,
53                                             /*target_classification_score=*/1.0,
54                                             /*priority_score=*/1.0));
55   }
56 
57   // Exposes the date time parser for tests and evaluations.
DatetimeParserForTests() const58   const DatetimeParser* DatetimeParserForTests() const override {
59     return parser_.get();
60   }
61 
62  private:
63   std::string grammar_buffer_;
64   std::unique_ptr<UniLib> unilib_;
65   std::unique_ptr<CalendarLib> calendarlib_;
66   std::unique_ptr<Analyzer> analyzer_;
67   std::unique_ptr<DatetimeGrounder> datetime_grounder_;
68   std::unique_ptr<DatetimeParser> parser_;
69 };
70 
TEST_F(GrammarDatetimeParserTest,ParseShort)71 TEST_F(GrammarDatetimeParserTest, ParseShort) {
72   EXPECT_TRUE(ParsesCorrectly(
73       "{01/02/2020}", 1580511600000, GRANULARITY_DAY,
74       {DatetimeComponentsBuilder()
75            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
76            .Add(DatetimeComponent::ComponentType::MONTH, 2)
77            .Add(DatetimeComponent::ComponentType::YEAR, 2020)
78            .Build()},
79       /*anchor_start_end=*/false,
80       /*timezone=*/"Europe/Zurich",
81       /*locales=*/"en-GB"));
82 
83   EXPECT_TRUE(ParsesCorrectly(
84       "{01/02/2020}", 1577919600000, GRANULARITY_DAY,
85       {DatetimeComponentsBuilder()
86            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 2)
87            .Add(DatetimeComponent::ComponentType::MONTH, 1)
88            .Add(DatetimeComponent::ComponentType::YEAR, 2020)
89            .Build()}));
90 
91   EXPECT_TRUE(ParsesCorrectly(
92       "{January 1, 1988}", 567990000000, GRANULARITY_DAY,
93       {DatetimeComponentsBuilder()
94            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
95            .Add(DatetimeComponent::ComponentType::MONTH, 1)
96            .Add(DatetimeComponent::ComponentType::YEAR, 1988)
97            .Build()}));
98 }
99 
TEST_F(GrammarDatetimeParserTest,Parse)100 TEST_F(GrammarDatetimeParserTest, Parse) {
101   EXPECT_TRUE(ParsesCorrectly(
102       "{January 1, 1988}", 567990000000, GRANULARITY_DAY,
103       {DatetimeComponentsBuilder()
104            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
105            .Add(DatetimeComponent::ComponentType::MONTH, 1)
106            .Add(DatetimeComponent::ComponentType::YEAR, 1988)
107            .Build()}));
108   EXPECT_TRUE(ParsesCorrectly(
109       "{january 31 2018}", 1517353200000, GRANULARITY_DAY,
110       {DatetimeComponentsBuilder()
111            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 31)
112            .Add(DatetimeComponent::ComponentType::MONTH, 1)
113            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
114            .Build()}));
115   EXPECT_TRUE(ParsesCorrectly(
116       "foo {1 january 2018} bar", 1514761200000, GRANULARITY_DAY,
117       {DatetimeComponentsBuilder()
118            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
119            .Add(DatetimeComponent::ComponentType::MONTH, 1)
120            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
121            .Build()}));
122   EXPECT_TRUE(ParsesCorrectly(
123       "{09/Mar/2004 22:02:40}", 1078866160000, GRANULARITY_SECOND,
124       {DatetimeComponentsBuilder()
125            .Add(DatetimeComponent::ComponentType::SECOND, 40)
126            .Add(DatetimeComponent::ComponentType::MINUTE, 02)
127            .Add(DatetimeComponent::ComponentType::HOUR, 22)
128            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 9)
129            .Add(DatetimeComponent::ComponentType::MONTH, 3)
130            .Add(DatetimeComponent::ComponentType::YEAR, 2004)
131            .Build()}));
132   EXPECT_TRUE(ParsesCorrectly(
133       "{Dec 2, 2010 2:39:58 AM}", 1291253998000, GRANULARITY_SECOND,
134       {DatetimeComponentsBuilder()
135            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
136            .Add(DatetimeComponent::ComponentType::SECOND, 58)
137            .Add(DatetimeComponent::ComponentType::MINUTE, 39)
138            .Add(DatetimeComponent::ComponentType::HOUR, 2)
139            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 2)
140            .Add(DatetimeComponent::ComponentType::MONTH, 12)
141            .Add(DatetimeComponent::ComponentType::YEAR, 2010)
142            .Build()}));
143   EXPECT_TRUE(ParsesCorrectly(
144       "{Jun 09 2011 15:28:14}", 1307626094000, GRANULARITY_SECOND,
145       {DatetimeComponentsBuilder()
146            .Add(DatetimeComponent::ComponentType::SECOND, 14)
147            .Add(DatetimeComponent::ComponentType::MINUTE, 28)
148            .Add(DatetimeComponent::ComponentType::HOUR, 15)
149            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 9)
150            .Add(DatetimeComponent::ComponentType::MONTH, 6)
151            .Add(DatetimeComponent::ComponentType::YEAR, 2011)
152            .Build()}));
153   EXPECT_TRUE(ParsesCorrectly(
154       "{2010-06-26 02:31:29}", {1277512289000, 1277555489000},
155       GRANULARITY_SECOND,
156       {DatetimeComponentsBuilder()
157            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
158            .Add(DatetimeComponent::ComponentType::SECOND, 29)
159            .Add(DatetimeComponent::ComponentType::MINUTE, 31)
160            .Add(DatetimeComponent::ComponentType::HOUR, 2)
161            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 26)
162            .Add(DatetimeComponent::ComponentType::MONTH, 6)
163            .Add(DatetimeComponent::ComponentType::YEAR, 2010)
164            .Build(),
165        DatetimeComponentsBuilder()
166            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
167            .Add(DatetimeComponent::ComponentType::SECOND, 29)
168            .Add(DatetimeComponent::ComponentType::MINUTE, 31)
169            .Add(DatetimeComponent::ComponentType::HOUR, 2)
170            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 26)
171            .Add(DatetimeComponent::ComponentType::MONTH, 6)
172            .Add(DatetimeComponent::ComponentType::YEAR, 2010)
173            .Build()}));
174   EXPECT_TRUE(ParsesCorrectly(
175       "{2006/01/22 04:11:05}", {1137899465000, 1137942665000},
176       GRANULARITY_SECOND,
177       {DatetimeComponentsBuilder()
178            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
179            .Add(DatetimeComponent::ComponentType::SECOND, 5)
180            .Add(DatetimeComponent::ComponentType::MINUTE, 11)
181            .Add(DatetimeComponent::ComponentType::HOUR, 4)
182            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 22)
183            .Add(DatetimeComponent::ComponentType::MONTH, 1)
184            .Add(DatetimeComponent::ComponentType::YEAR, 2006)
185            .Build(),
186        DatetimeComponentsBuilder()
187            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
188            .Add(DatetimeComponent::ComponentType::SECOND, 5)
189            .Add(DatetimeComponent::ComponentType::MINUTE, 11)
190            .Add(DatetimeComponent::ComponentType::HOUR, 4)
191            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 22)
192            .Add(DatetimeComponent::ComponentType::MONTH, 1)
193            .Add(DatetimeComponent::ComponentType::YEAR, 2006)
194            .Build()}));
195   EXPECT_TRUE(
196       ParsesCorrectly("{11:42:35}", {38555000, 81755000}, GRANULARITY_SECOND,
197                       {DatetimeComponentsBuilder()
198                            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
199                            .Add(DatetimeComponent::ComponentType::SECOND, 35)
200                            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
201                            .Add(DatetimeComponent::ComponentType::HOUR, 11)
202                            .Build(),
203                        DatetimeComponentsBuilder()
204                            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
205                            .Add(DatetimeComponent::ComponentType::SECOND, 35)
206                            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
207                            .Add(DatetimeComponent::ComponentType::HOUR, 11)
208                            .Build()}));
209   EXPECT_TRUE(ParsesCorrectly(
210       "{23/Apr 11:42:35}", {9715355000, 9758555000}, GRANULARITY_SECOND,
211       {DatetimeComponentsBuilder()
212            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
213            .Add(DatetimeComponent::ComponentType::SECOND, 35)
214            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
215            .Add(DatetimeComponent::ComponentType::HOUR, 11)
216            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
217            .Add(DatetimeComponent::ComponentType::MONTH, 4)
218            .Build(),
219        DatetimeComponentsBuilder()
220            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
221            .Add(DatetimeComponent::ComponentType::SECOND, 35)
222            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
223            .Add(DatetimeComponent::ComponentType::HOUR, 11)
224            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
225            .Add(DatetimeComponent::ComponentType::MONTH, 4)
226            .Build()}));
227   EXPECT_TRUE(ParsesCorrectly(
228       "{23/Apr/2015 11:42:35}", {1429782155000, 1429825355000},
229       GRANULARITY_SECOND,
230       {DatetimeComponentsBuilder()
231            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
232            .Add(DatetimeComponent::ComponentType::SECOND, 35)
233            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
234            .Add(DatetimeComponent::ComponentType::HOUR, 11)
235            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
236            .Add(DatetimeComponent::ComponentType::MONTH, 4)
237            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
238            .Build(),
239        DatetimeComponentsBuilder()
240            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
241            .Add(DatetimeComponent::ComponentType::SECOND, 35)
242            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
243            .Add(DatetimeComponent::ComponentType::HOUR, 11)
244            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
245            .Add(DatetimeComponent::ComponentType::MONTH, 4)
246            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
247            .Build()}));
248   EXPECT_TRUE(ParsesCorrectly(
249       "{23-Apr-2015 11:42:35}", {1429782155000, 1429825355000},
250       GRANULARITY_SECOND,
251       {DatetimeComponentsBuilder()
252            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
253            .Add(DatetimeComponent::ComponentType::SECOND, 35)
254            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
255            .Add(DatetimeComponent::ComponentType::HOUR, 11)
256            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
257            .Add(DatetimeComponent::ComponentType::MONTH, 4)
258            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
259            .Build(),
260        DatetimeComponentsBuilder()
261            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
262            .Add(DatetimeComponent::ComponentType::SECOND, 35)
263            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
264            .Add(DatetimeComponent::ComponentType::HOUR, 11)
265            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
266            .Add(DatetimeComponent::ComponentType::MONTH, 4)
267            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
268            .Build()}));
269   EXPECT_TRUE(ParsesCorrectly(
270       "{23 Apr 2015 11:42:35}", {1429782155000, 1429825355000},
271       GRANULARITY_SECOND,
272       {DatetimeComponentsBuilder()
273            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
274            .Add(DatetimeComponent::ComponentType::SECOND, 35)
275            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
276            .Add(DatetimeComponent::ComponentType::HOUR, 11)
277            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
278            .Add(DatetimeComponent::ComponentType::MONTH, 4)
279            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
280            .Build(),
281        DatetimeComponentsBuilder()
282            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
283            .Add(DatetimeComponent::ComponentType::SECOND, 35)
284            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
285            .Add(DatetimeComponent::ComponentType::HOUR, 11)
286            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
287            .Add(DatetimeComponent::ComponentType::MONTH, 4)
288            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
289            .Build()}));
290   EXPECT_TRUE(ParsesCorrectly(
291       "Are sentiments apartments decisively the especially alteration. "
292       "Thrown shy denote ten ladies though ask saw. Or by to he going "
293       "think order event music. Incommode so intention defective at "
294       "convinced. Led income months itself and houses you. After nor "
295       "you leave might share court balls. {19/apr/2010 06:36:15} Are "
296       "sentiments apartments decisively the especially alteration. "
297       "Thrown shy denote ten ladies though ask saw. Or by to he going "
298       "think order event music. Incommode so intention defective at "
299       "convinced. Led income months itself and houses you. After nor "
300       "you leave might share court balls. ",
301       {1271651775000, 1271694975000}, GRANULARITY_SECOND,
302       {DatetimeComponentsBuilder()
303            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
304            .Add(DatetimeComponent::ComponentType::SECOND, 15)
305            .Add(DatetimeComponent::ComponentType::MINUTE, 36)
306            .Add(DatetimeComponent::ComponentType::HOUR, 6)
307            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 19)
308            .Add(DatetimeComponent::ComponentType::MONTH, 4)
309            .Add(DatetimeComponent::ComponentType::YEAR, 2010)
310            .Build(),
311        DatetimeComponentsBuilder()
312            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
313            .Add(DatetimeComponent::ComponentType::SECOND, 15)
314            .Add(DatetimeComponent::ComponentType::MINUTE, 36)
315            .Add(DatetimeComponent::ComponentType::HOUR, 6)
316            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 19)
317            .Add(DatetimeComponent::ComponentType::MONTH, 4)
318            .Add(DatetimeComponent::ComponentType::YEAR, 2010)
319            .Build()}));
320 
321   EXPECT_TRUE(ParsesCorrectly(
322       "{january 1 2018 at 4:30}", {1514777400000, 1514820600000},
323       GRANULARITY_MINUTE,
324       {DatetimeComponentsBuilder()
325            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
326            .Add(DatetimeComponent::ComponentType::MINUTE, 30)
327            .Add(DatetimeComponent::ComponentType::HOUR, 4)
328            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
329            .Add(DatetimeComponent::ComponentType::MONTH, 1)
330            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
331            .Build(),
332        DatetimeComponentsBuilder()
333            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
334            .Add(DatetimeComponent::ComponentType::MINUTE, 30)
335            .Add(DatetimeComponent::ComponentType::HOUR, 4)
336            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
337            .Add(DatetimeComponent::ComponentType::MONTH, 1)
338            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
339            .Build()}));
340   EXPECT_TRUE(ParsesCorrectly(
341       "{january 1 2018 at 4:30 am}", 1514777400000, GRANULARITY_MINUTE,
342       {DatetimeComponentsBuilder()
343            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
344            .Add(DatetimeComponent::ComponentType::MINUTE, 30)
345            .Add(DatetimeComponent::ComponentType::HOUR, 4)
346            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
347            .Add(DatetimeComponent::ComponentType::MONTH, 1)
348            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
349            .Build()}));
350   EXPECT_TRUE(ParsesCorrectly(
351       "{january 1 2018 at 4pm}", 1514818800000, GRANULARITY_HOUR,
352       {DatetimeComponentsBuilder()
353            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
354            .Add(DatetimeComponent::ComponentType::HOUR, 4)
355            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
356            .Add(DatetimeComponent::ComponentType::MONTH, 1)
357            .Add(DatetimeComponent::ComponentType::YEAR, 2018)
358            .Build()}));
359 
360   EXPECT_TRUE(ParsesCorrectly(
361       "{today at 0:00}", {-3600000, 39600000}, GRANULARITY_MINUTE,
362       {DatetimeComponentsBuilder()
363            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
364            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
365            .Add(DatetimeComponent::ComponentType::HOUR, 0)
366            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
367                 DatetimeComponent::RelativeQualifier::NOW, 0)
368            .Build(),
369        DatetimeComponentsBuilder()
370            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
371            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
372            .Add(DatetimeComponent::ComponentType::HOUR, 0)
373            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
374                 DatetimeComponent::RelativeQualifier::NOW, 0)
375            .Build()}));
376   EXPECT_TRUE(ParsesCorrectly(
377       "{today at 0:00}", {-57600000, -14400000}, GRANULARITY_MINUTE,
378       {DatetimeComponentsBuilder()
379            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
380            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
381            .Add(DatetimeComponent::ComponentType::HOUR, 0)
382            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
383                 DatetimeComponent::RelativeQualifier::NOW, 0)
384            .Build(),
385        DatetimeComponentsBuilder()
386            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
387            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
388            .Add(DatetimeComponent::ComponentType::HOUR, 0)
389            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
390                 DatetimeComponent::RelativeQualifier::NOW, 0)
391            .Build()},
392       /*anchor_start_end=*/false, "America/Los_Angeles"));
393   EXPECT_TRUE(ParsesCorrectly(
394       "{tomorrow at 4:00}", {97200000, 140400000}, GRANULARITY_MINUTE,
395       {DatetimeComponentsBuilder()
396            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
397            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
398            .Add(DatetimeComponent::ComponentType::HOUR, 4)
399            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
400                 DatetimeComponent::RelativeQualifier::TOMORROW, 1)
401            .Build(),
402        DatetimeComponentsBuilder()
403            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
404            .Add(DatetimeComponent::ComponentType::MINUTE, 0)
405            .Add(DatetimeComponent::ComponentType::HOUR, 4)
406            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
407                 DatetimeComponent::RelativeQualifier::TOMORROW, 1)
408            .Build()}));
409   EXPECT_TRUE(ParsesCorrectly(
410       "{tomorrow at 4am}", 97200000, GRANULARITY_HOUR,
411       {DatetimeComponentsBuilder()
412            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
413            .Add(DatetimeComponent::ComponentType::HOUR, 4)
414            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
415                 DatetimeComponent::RelativeQualifier::TOMORROW, 1)
416            .Build()}));
417   EXPECT_TRUE(ParsesCorrectly(
418       "last seen {today at 9:01 PM}", 72060000, GRANULARITY_MINUTE,
419       {DatetimeComponentsBuilder()
420            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
421            .Add(DatetimeComponent::ComponentType::MINUTE, 1)
422            .Add(DatetimeComponent::ComponentType::HOUR, 9)
423            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
424                 DatetimeComponent::RelativeQualifier::NOW, 0)
425            .Build()}));
426   EXPECT_TRUE(
427       ParsesCorrectly("set an alarm for {7 a.m}", 21600000, GRANULARITY_HOUR,
428                       {DatetimeComponentsBuilder()
429                            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
430                            .Add(DatetimeComponent::ComponentType::HOUR, 7)
431                            .Build()}));
432 
433   EXPECT_TRUE(ParsesCorrectly(
434       "{04/23/15 11:42:35}", {1429782155000, 1429825355000}, GRANULARITY_SECOND,
435       {DatetimeComponentsBuilder()
436            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
437            .Add(DatetimeComponent::ComponentType::SECOND, 35)
438            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
439            .Add(DatetimeComponent::ComponentType::HOUR, 11)
440            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
441            .Add(DatetimeComponent::ComponentType::MONTH, 4)
442            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
443            .Build(),
444        DatetimeComponentsBuilder()
445            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
446            .Add(DatetimeComponent::ComponentType::SECOND, 35)
447            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
448            .Add(DatetimeComponent::ComponentType::HOUR, 11)
449            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
450            .Add(DatetimeComponent::ComponentType::MONTH, 4)
451            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
452            .Build()}));
453 
454   EXPECT_TRUE(ParsesCorrectly(
455       "{04/23/2015 11:42:35}", {1429782155000, 1429825355000},
456       GRANULARITY_SECOND,
457       {DatetimeComponentsBuilder()
458            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
459            .Add(DatetimeComponent::ComponentType::SECOND, 35)
460            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
461            .Add(DatetimeComponent::ComponentType::HOUR, 11)
462            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
463            .Add(DatetimeComponent::ComponentType::MONTH, 4)
464            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
465            .Build(),
466        DatetimeComponentsBuilder()
467            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
468            .Add(DatetimeComponent::ComponentType::SECOND, 35)
469            .Add(DatetimeComponent::ComponentType::MINUTE, 42)
470            .Add(DatetimeComponent::ComponentType::HOUR, 11)
471            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 23)
472            .Add(DatetimeComponent::ComponentType::MONTH, 4)
473            .Add(DatetimeComponent::ComponentType::YEAR, 2015)
474            .Build()}));
475 
476   EXPECT_TRUE(ParsesCorrectly(
477       "{9/28/2011 2:23:15 PM}", 1317212595000, GRANULARITY_SECOND,
478       {DatetimeComponentsBuilder()
479            .Add(DatetimeComponent::ComponentType::MERIDIEM, 1)
480            .Add(DatetimeComponent::ComponentType::SECOND, 15)
481            .Add(DatetimeComponent::ComponentType::MINUTE, 23)
482            .Add(DatetimeComponent::ComponentType::HOUR, 2)
483            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 28)
484            .Add(DatetimeComponent::ComponentType::MONTH, 9)
485            .Add(DatetimeComponent::ComponentType::YEAR, 2011)
486            .Build()}));
487 }
488 
TEST_F(GrammarDatetimeParserTest,DateValidation)489 TEST_F(GrammarDatetimeParserTest, DateValidation) {
490   EXPECT_TRUE(ParsesCorrectly(
491       "{01/02/2020}", 1577919600000, GRANULARITY_DAY,
492       {DatetimeComponentsBuilder()
493            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 2)
494            .Add(DatetimeComponent::ComponentType::MONTH, 1)
495            .Add(DatetimeComponent::ComponentType::YEAR, 2020)
496            .Build()}));
497   EXPECT_TRUE(ParsesCorrectly(
498       "{21/02/2020}", 1582239600000, GRANULARITY_DAY,
499       {DatetimeComponentsBuilder()
500            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 21)
501            .Add(DatetimeComponent::ComponentType::MONTH, 2)
502            .Add(DatetimeComponent::ComponentType::YEAR, 2020)
503            .Build()}));
504 }
505 
TEST_F(GrammarDatetimeParserTest,OnlyRelativeDatetime)506 TEST_F(GrammarDatetimeParserTest, OnlyRelativeDatetime) {
507   EXPECT_TRUE(
508       ParsesCorrectly("{in 3 hours}", 10800000, GRANULARITY_HOUR,
509                       {DatetimeComponentsBuilder()
510                            .Add(DatetimeComponent::ComponentType::HOUR, 0,
511                                 DatetimeComponent::RelativeQualifier::FUTURE, 3)
512                            .Build()}));
513   EXPECT_TRUE(ParsesCorrectly(
514       "{wednesday at 4am}", 529200000, GRANULARITY_HOUR,
515       {DatetimeComponentsBuilder()
516            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
517            .Add(DatetimeComponent::ComponentType::HOUR, 4)
518            .Add(DatetimeComponent::ComponentType::DAY_OF_WEEK, 4,
519                 DatetimeComponent::RelativeQualifier::THIS, 0)
520            .Build()}));
521   EXPECT_TRUE(ParsesCorrectly(
522       "set an alarm for {7am tomorrow}", 108000000, GRANULARITY_HOUR,
523       {DatetimeComponentsBuilder()
524            .Add(DatetimeComponent::ComponentType::MERIDIEM, 0)
525            .Add(DatetimeComponent::ComponentType::HOUR, 7)
526            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 0,
527                 DatetimeComponent::RelativeQualifier::TOMORROW, 1)
528            .Build()}));
529   EXPECT_TRUE(ParsesCorrectly(
530       "called you {last Saturday}",
531       -432000000 /* Fri 1969-12-26 16:00:00 PST */, GRANULARITY_DAY,
532       {DatetimeComponentsBuilder()
533            .Add(DatetimeComponent::ComponentType::DAY_OF_WEEK, 7,
534                 DatetimeComponent::RelativeQualifier::PAST, -1)
535            .Build()},
536       /*anchor_start_end=*/false,
537       /*timezone=*/"Europe/Zurich", /*locales=*/"en-US",
538       /*annotation_usecase=*/AnnotationUsecase_ANNOTATION_USECASE_RAW));
539 }
540 
TEST_F(GrammarDatetimeParserTest,NamedMonthDate)541 TEST_F(GrammarDatetimeParserTest, NamedMonthDate) {
542   EXPECT_TRUE(ParsesCorrectly(
543       "{march 1, 2017}", 1488355200000, GRANULARITY_DAY,
544       {DatetimeComponentsBuilder()
545            .Add(DatetimeComponent::ComponentType::DAY_OF_MONTH, 1)
546            .Add(DatetimeComponent::ComponentType::MONTH, 3)
547            .Add(DatetimeComponent::ComponentType::YEAR, 2017)
548            .Build()},
549       false, "America/Los_Angeles", "en-US",
550       AnnotationUsecase_ANNOTATION_USECASE_SMART));
551 }
552 
553 }  // namespace
554 }  // namespace libtextclassifier3
555