blob: 2cb0652943ebc90fa7e17252a87112c49b2f4406 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "third_party/blink/renderer/platform/text/date_time_format.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/cstring.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
class DateTimeFormatTest : public testing::Test {
public:
using FieldType = DateTimeFormat::FieldType;
struct Token {
String string;
int count;
FieldType field_type;
Token(FieldType field_type, int count = 1)
: count(count), field_type(field_type) {
DCHECK_NE(field_type, DateTimeFormat::kFieldTypeLiteral);
}
Token(const String& string)
: string(string),
count(0),
field_type(DateTimeFormat::kFieldTypeLiteral) {}
bool operator==(const Token& other) const {
return field_type == other.field_type && count == other.count &&
string == other.string;
}
String ToString() const {
switch (field_type) {
case DateTimeFormat::kFieldTypeInvalid:
return "*invalid*";
case DateTimeFormat::kFieldTypeLiteral: {
StringBuilder builder;
builder.Append('"');
builder.Append(string);
builder.Append('"');
return builder.ToString();
}
default:
return String::Format("Token(%d, %d)", field_type, count);
}
}
};
class Tokens {
public:
Tokens() = default;
explicit Tokens(const Vector<Token> tokens) : tokens_(tokens) {}
explicit Tokens(const String& string) { tokens_.push_back(Token(string)); }
explicit Tokens(Token token1) { tokens_.push_back(token1); }
Tokens(Token token1, Token token2) {
tokens_.push_back(token1);
tokens_.push_back(token2);
}
Tokens(Token token1, Token token2, Token token3) {
tokens_.push_back(token1);
tokens_.push_back(token2);
tokens_.push_back(token3);
}
Tokens(Token token1, Token token2, Token token3, Token token4) {
tokens_.push_back(token1);
tokens_.push_back(token2);
tokens_.push_back(token3);
tokens_.push_back(token4);
}
Tokens(Token token1,
Token token2,
Token token3,
Token token4,
Token token5) {
tokens_.push_back(token1);
tokens_.push_back(token2);
tokens_.push_back(token3);
tokens_.push_back(token4);
tokens_.push_back(token5);
}
Tokens(Token token1,
Token token2,
Token token3,
Token token4,
Token token5,
Token token6) {
tokens_.push_back(token1);
tokens_.push_back(token2);
tokens_.push_back(token3);
tokens_.push_back(token4);
tokens_.push_back(token5);
tokens_.push_back(token6);
}
bool operator==(const Tokens& other) const {
return tokens_ == other.tokens_;
}
String ToString() const {
StringBuilder builder;
builder.Append("Tokens(");
for (unsigned index = 0; index < tokens_.size(); ++index) {
if (index)
builder.Append(',');
builder.Append(tokens_[index].ToString());
}
builder.Append(')');
return builder.ToString();
}
private:
Vector<Token> tokens_;
};
protected:
Tokens Parse(const String& format_string) {
TokenHandler handler;
if (!DateTimeFormat::Parse(format_string, handler))
return Tokens(Token("*failed*"));
return handler.GetTokens();
}
FieldType Single(const char ch) {
char format_string[2];
format_string[0] = ch;
format_string[1] = 0;
TokenHandler handler;
if (!DateTimeFormat::Parse(format_string, handler))
return DateTimeFormat::kFieldTypeInvalid;
return handler.GetFieldType(0);
}
private:
class TokenHandler : public DateTimeFormat::TokenHandler {
public:
~TokenHandler() override = default;
FieldType GetFieldType(int index) const {
return index >= 0 && index < static_cast<int>(tokens_.size())
? tokens_[index].field_type
: DateTimeFormat::kFieldTypeInvalid;
}
Tokens GetTokens() const { return Tokens(tokens_); }
private:
void VisitField(FieldType field_type, int count) override {
tokens_.push_back(Token(field_type, count));
}
void VisitLiteral(const String& string) override {
tokens_.push_back(Token(string));
}
Vector<Token> tokens_;
};
};
std::ostream& operator<<(std::ostream& os,
const DateTimeFormatTest::Tokens& tokens) {
return os << tokens.ToString().Ascii().data();
}
TEST_F(DateTimeFormatTest, CommonPattern) {
EXPECT_EQ(Tokens(), Parse(""));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeYear, 4), Token("-"),
Token(DateTimeFormat::kFieldTypeMonth, 2), Token("-"),
Token(DateTimeFormat::kFieldTypeDayOfMonth, 2)),
Parse("yyyy-MM-dd"));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeHour24, 2), Token(":"),
Token(DateTimeFormat::kFieldTypeMinute, 2), Token(":"),
Token(DateTimeFormat::kFieldTypeSecond, 2)),
Parse("kk:mm:ss"));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeHour12), Token(":"),
Token(DateTimeFormat::kFieldTypeMinute), Token(" "),
Token(DateTimeFormat::kFieldTypePeriod)),
Parse("h:m a"));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeYear), Token("Nen "),
Token(DateTimeFormat::kFieldTypeMonth), Token("Getsu "),
Token(DateTimeFormat::kFieldTypeDayOfMonth), Token("Nichi")),
Parse("y'Nen' M'Getsu' d'Nichi'"));
}
TEST_F(DateTimeFormatTest, MissingClosingQuote) {
EXPECT_EQ(Tokens("*failed*"), Parse("'foo"));
EXPECT_EQ(Tokens("*failed*"), Parse("fo'o"));
EXPECT_EQ(Tokens("*failed*"), Parse("foo'"));
}
TEST_F(DateTimeFormatTest, Quote) {
EXPECT_EQ(Tokens("FooBar"), Parse("'FooBar'"));
EXPECT_EQ(Tokens("'"), Parse("''"));
EXPECT_EQ(Tokens("'-'"), Parse("''-''"));
EXPECT_EQ(Tokens("Foo'Bar"), Parse("'Foo''Bar'"));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeEra), Token("'s")),
Parse("G'''s'"));
EXPECT_EQ(Tokens(Token(DateTimeFormat::kFieldTypeEra), Token("'"),
Token(DateTimeFormat::kFieldTypeSecond)),
Parse("G''s"));
}
TEST_F(DateTimeFormatTest, SingleLowerCaseCharacter) {
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('b'));
EXPECT_EQ(DateTimeFormat::kFieldTypeLocalDayOfWeekStandAlon, Single('c'));
EXPECT_EQ(DateTimeFormat::kFieldTypeDayOfMonth, Single('d'));
EXPECT_EQ(DateTimeFormat::kFieldTypeLocalDayOfWeek, Single('e'));
EXPECT_EQ(DateTimeFormat::kFieldTypeModifiedJulianDay, Single('g'));
EXPECT_EQ(DateTimeFormat::kFieldTypeHour12, Single('h'));
EXPECT_EQ(DateTimeFormat::kFieldTypeHour24, Single('k'));
EXPECT_EQ(DateTimeFormat::kFieldTypeMinute, Single('m'));
EXPECT_EQ(DateTimeFormat::kFieldTypeQuaterStandAlone, Single('q'));
EXPECT_EQ(DateTimeFormat::kFieldTypeSecond, Single('s'));
EXPECT_EQ(DateTimeFormat::kFieldTypeExtendedYear, Single('u'));
EXPECT_EQ(DateTimeFormat::kFieldTypeNonLocationZone, Single('v'));
EXPECT_EQ(DateTimeFormat::kFieldTypeWeekOfMonth, Single('W'));
EXPECT_EQ(DateTimeFormat::kFieldTypeYear, Single('y'));
EXPECT_EQ(DateTimeFormat::kFieldTypeZone, Single('z'));
}
TEST_F(DateTimeFormatTest, SingleLowerCaseInvalid) {
EXPECT_EQ(DateTimeFormat::kFieldTypePeriod, Single('a'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('f'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('i'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('j'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('l'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('n'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('o'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('p'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('r'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('t'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('x'));
}
TEST_F(DateTimeFormatTest, SingleUpperCaseCharacter) {
EXPECT_EQ(DateTimeFormat::kFieldTypeMillisecondsInDay, Single('A'));
EXPECT_EQ(DateTimeFormat::kFieldTypeDayOfYear, Single('D'));
EXPECT_EQ(DateTimeFormat::kFieldTypeDayOfWeek, Single('E'));
EXPECT_EQ(DateTimeFormat::kFieldTypeDayOfWeekInMonth, Single('F'));
EXPECT_EQ(DateTimeFormat::kFieldTypeEra, Single('G'));
EXPECT_EQ(DateTimeFormat::kFieldTypeHour23, Single('H'));
EXPECT_EQ(DateTimeFormat::kFieldTypeHour11, Single('K'));
EXPECT_EQ(DateTimeFormat::kFieldTypeMonthStandAlone, Single('L'));
EXPECT_EQ(DateTimeFormat::kFieldTypeMonth, Single('M'));
EXPECT_EQ(DateTimeFormat::kFieldTypeQuater, Single('Q'));
EXPECT_EQ(DateTimeFormat::kFieldTypeFractionalSecond, Single('S'));
EXPECT_EQ(DateTimeFormat::kFieldTypeWeekOfYear, Single('w'));
EXPECT_EQ(DateTimeFormat::kFieldTypeYearOfWeekOfYear, Single('Y'));
EXPECT_EQ(DateTimeFormat::kFieldTypeRFC822Zone, Single('Z'));
}
TEST_F(DateTimeFormatTest, SingleUpperCaseInvalid) {
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('B'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('C'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('I'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('J'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('N'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('O'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('P'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('R'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('T'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('U'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('V'));
EXPECT_EQ(DateTimeFormat::kFieldTypeInvalid, Single('X'));
}
} // namespace blink