1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *     notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *     notice, this list of conditions and the following disclaimer in the
11 *     documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "platform/text/DateTimeFormat.h"
28
29#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
30#include "wtf/text/CString.h"
31#include "wtf/text/StringBuilder.h"
32#include <gtest/gtest.h>
33
34using namespace blink;
35
36class DateTimeFormatTest : public ::testing::Test {
37public:
38    typedef DateTimeFormat::FieldType FieldType;
39
40    struct Token {
41        String string;
42        int count;
43        FieldType fieldType;
44
45        Token(FieldType fieldType, int count = 1)
46            : count(count)
47            , fieldType(fieldType)
48        {
49            ASSERT(fieldType != DateTimeFormat::FieldTypeLiteral);
50        }
51
52        Token(const String& string)
53            : string(string)
54            , count(0)
55            , fieldType(DateTimeFormat::FieldTypeLiteral)
56        {
57        }
58
59        bool operator==(const Token& other) const
60        {
61            return fieldType == other.fieldType && count == other.count && string == other.string;
62        }
63
64        String toString() const
65        {
66            switch (fieldType) {
67            case DateTimeFormat::FieldTypeInvalid:
68                return "*invalid*";
69            case DateTimeFormat::FieldTypeLiteral: {
70                StringBuilder builder;
71                builder.append('"');
72                builder.append(string);
73                builder.append('"');
74                return builder.toString();
75            }
76            default:
77                return String::format("Token(%d, %d)", fieldType, count);
78            }
79        }
80    };
81
82    class Tokens {
83    public:
84        Tokens() { }
85
86        explicit Tokens(const Vector<Token> tokens)
87            : m_tokens(tokens)
88        {
89        }
90
91        explicit Tokens(const String& string)
92        {
93            m_tokens.append(Token(string));
94        }
95
96        explicit Tokens(Token token1)
97        {
98            m_tokens.append(token1);
99        }
100
101        Tokens(Token token1, Token token2)
102        {
103            m_tokens.append(token1);
104            m_tokens.append(token2);
105        }
106
107        Tokens(Token token1, Token token2, Token token3)
108        {
109            m_tokens.append(token1);
110            m_tokens.append(token2);
111            m_tokens.append(token3);
112        }
113
114        Tokens(Token token1, Token token2, Token token3, Token token4)
115        {
116            m_tokens.append(token1);
117            m_tokens.append(token2);
118            m_tokens.append(token3);
119            m_tokens.append(token4);
120        }
121
122        Tokens(Token token1, Token token2, Token token3, Token token4, Token token5)
123        {
124            m_tokens.append(token1);
125            m_tokens.append(token2);
126            m_tokens.append(token3);
127            m_tokens.append(token4);
128            m_tokens.append(token5);
129        }
130
131        Tokens(Token token1, Token token2, Token token3, Token token4, Token token5, Token token6)
132        {
133            m_tokens.append(token1);
134            m_tokens.append(token2);
135            m_tokens.append(token3);
136            m_tokens.append(token4);
137            m_tokens.append(token5);
138            m_tokens.append(token6);
139        }
140
141        bool operator==(const Tokens& other) const
142        {
143            return m_tokens == other.m_tokens;
144        }
145
146        String toString() const
147        {
148            StringBuilder builder;
149            builder.append("Tokens(");
150            for (unsigned index = 0; index < m_tokens.size(); ++index) {
151                if (index)
152                    builder.append(",");
153                builder.append(m_tokens[index].toString());
154            }
155            builder.append(")");
156            return builder.toString();
157        }
158
159    private:
160        Vector<Token> m_tokens;
161    };
162
163protected:
164    Tokens parse(const String& formatString)
165    {
166        TokenHandler handler;
167        if (!DateTimeFormat::parse(formatString, handler))
168            return Tokens(Token("*failed*"));
169        return handler.tokens();
170    }
171
172    FieldType single(const char ch)
173    {
174        char formatString[2];
175        formatString[0] = ch;
176        formatString[1] = 0;
177        TokenHandler handler;
178        if (!DateTimeFormat::parse(formatString, handler))
179            return DateTimeFormat::FieldTypeInvalid;
180        return handler.fieldType(0);
181    }
182
183private:
184    class TokenHandler : public DateTimeFormat::TokenHandler {
185    public:
186        virtual ~TokenHandler() { }
187
188        FieldType fieldType(int index) const
189        {
190            return index >=0 && index < static_cast<int>(m_tokens.size()) ? m_tokens[index].fieldType : DateTimeFormat::FieldTypeInvalid;
191        }
192
193        Tokens tokens() const { return Tokens(m_tokens); }
194
195    private:
196        virtual void visitField(FieldType fieldType, int count) OVERRIDE
197        {
198            m_tokens.append(Token(fieldType, count));
199        }
200
201        virtual void visitLiteral(const String& string) OVERRIDE
202        {
203            m_tokens.append(Token(string));
204        }
205
206        Vector<Token> m_tokens;
207    };
208};
209
210std::ostream& operator<<(std::ostream& os, const DateTimeFormatTest::Tokens& tokens)
211{
212    return os << tokens.toString().ascii().data();
213}
214
215TEST_F(DateTimeFormatTest, CommonPattern)
216{
217    EXPECT_EQ(Tokens(), parse(""));
218
219    EXPECT_EQ(
220        Tokens(
221            Token(DateTimeFormat::FieldTypeYear, 4), Token("-"),
222            Token(DateTimeFormat::FieldTypeMonth, 2), Token("-"),
223            Token(DateTimeFormat::FieldTypeDayOfMonth, 2)),
224        parse("yyyy-MM-dd"));
225
226    EXPECT_EQ(
227        Tokens(
228            Token(DateTimeFormat::FieldTypeHour24, 2), Token(":"),
229            Token(DateTimeFormat::FieldTypeMinute, 2), Token(":"),
230            Token(DateTimeFormat::FieldTypeSecond, 2)),
231        parse("kk:mm:ss"));
232
233    EXPECT_EQ(
234        Tokens(
235            Token(DateTimeFormat::FieldTypeHour12), Token(":"),
236            Token(DateTimeFormat::FieldTypeMinute), Token(" "),
237            Token(DateTimeFormat::FieldTypePeriod)),
238        parse("h:m a"));
239
240    EXPECT_EQ(
241        Tokens(
242            Token(DateTimeFormat::FieldTypeYear), Token("Nen "),
243            Token(DateTimeFormat::FieldTypeMonth), Token("Getsu "),
244            Token(DateTimeFormat::FieldTypeDayOfMonth), Token("Nichi")),
245        parse("y'Nen' M'Getsu' d'Nichi'"));
246}
247
248TEST_F(DateTimeFormatTest, MissingClosingQuote)
249{
250    EXPECT_EQ(Tokens("*failed*"), parse("'foo"));
251    EXPECT_EQ(Tokens("*failed*"), parse("fo'o"));
252    EXPECT_EQ(Tokens("*failed*"), parse("foo'"));
253}
254
255TEST_F(DateTimeFormatTest, Quote)
256{
257    EXPECT_EQ(Tokens("FooBar"), parse("'FooBar'"));
258    EXPECT_EQ(Tokens("'"), parse("''"));
259    EXPECT_EQ(Tokens("'-'"), parse("''-''"));
260    EXPECT_EQ(Tokens("Foo'Bar"), parse("'Foo''Bar'"));
261    EXPECT_EQ(
262        Tokens(Token(DateTimeFormat::FieldTypeEra), Token("'s")),
263        parse("G'''s'"));
264    EXPECT_EQ(
265        Tokens(Token(DateTimeFormat::FieldTypeEra), Token("'"), Token(DateTimeFormat::FieldTypeSecond)),
266        parse("G''s"));
267}
268
269TEST_F(DateTimeFormatTest, SingleLowerCaseCharacter)
270{
271    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('b'));
272    EXPECT_EQ(DateTimeFormat::FieldTypeLocalDayOfWeekStandAlon, single('c'));
273    EXPECT_EQ(DateTimeFormat::FieldTypeDayOfMonth, single('d'));
274    EXPECT_EQ(DateTimeFormat::FieldTypeLocalDayOfWeek, single('e'));
275    EXPECT_EQ(DateTimeFormat::FieldTypeModifiedJulianDay, single('g'));
276    EXPECT_EQ(DateTimeFormat::FieldTypeHour12, single('h'));
277    EXPECT_EQ(DateTimeFormat::FieldTypeHour24, single('k'));
278    EXPECT_EQ(DateTimeFormat::FieldTypeMinute, single('m'));
279    EXPECT_EQ(DateTimeFormat::FieldTypeQuaterStandAlone, single('q'));
280    EXPECT_EQ(DateTimeFormat::FieldTypeSecond, single('s'));
281    EXPECT_EQ(DateTimeFormat::FieldTypeExtendedYear, single('u'));
282    EXPECT_EQ(DateTimeFormat::FieldTypeNonLocationZone, single('v'));
283    EXPECT_EQ(DateTimeFormat::FieldTypeWeekOfMonth, single('W'));
284    EXPECT_EQ(DateTimeFormat::FieldTypeYear, single('y'));
285    EXPECT_EQ(DateTimeFormat::FieldTypeZone, single('z'));
286}
287
288TEST_F(DateTimeFormatTest, SingleLowerCaseInvalid)
289{
290    EXPECT_EQ(DateTimeFormat::FieldTypePeriod, single('a'));
291    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('f'));
292    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('i'));
293    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('j'));
294    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('l'));
295    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('n'));
296    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('o'));
297    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('p'));
298    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('r'));
299    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('t'));
300    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('x'));
301}
302
303TEST_F(DateTimeFormatTest, SingleUpperCaseCharacter)
304{
305    EXPECT_EQ(DateTimeFormat::FieldTypeMillisecondsInDay, single('A'));
306    EXPECT_EQ(DateTimeFormat::FieldTypeDayOfYear, single('D'));
307    EXPECT_EQ(DateTimeFormat::FieldTypeDayOfWeek, single('E'));
308    EXPECT_EQ(DateTimeFormat::FieldTypeDayOfWeekInMonth, single('F'));
309    EXPECT_EQ(DateTimeFormat::FieldTypeEra, single('G'));
310    EXPECT_EQ(DateTimeFormat::FieldTypeHour23, single('H'));
311    EXPECT_EQ(DateTimeFormat::FieldTypeHour11, single('K'));
312    EXPECT_EQ(DateTimeFormat::FieldTypeMonthStandAlone, single('L'));
313    EXPECT_EQ(DateTimeFormat::FieldTypeMonth, single('M'));
314    EXPECT_EQ(DateTimeFormat::FieldTypeQuater, single('Q'));
315    EXPECT_EQ(DateTimeFormat::FieldTypeFractionalSecond, single('S'));
316    EXPECT_EQ(DateTimeFormat::FieldTypeWeekOfYear, single('w'));
317    EXPECT_EQ(DateTimeFormat::FieldTypeYearOfWeekOfYear, single('Y'));
318    EXPECT_EQ(DateTimeFormat::FieldTypeRFC822Zone, single('Z'));
319}
320
321TEST_F(DateTimeFormatTest, SingleUpperCaseInvalid)
322{
323    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('B'));
324    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('C'));
325    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('I'));
326    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('J'));
327    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('N'));
328    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('O'));
329    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('P'));
330    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('R'));
331    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('T'));
332    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('U'));
333    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('V'));
334    EXPECT_EQ(DateTimeFormat::FieldTypeInvalid, single('X'));
335}
336
337#endif
338