| // Copyright 2015 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/i18n/message_formatter.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/i18n/rtl.h" | 
 | #include "base/strings/string_piece.h" | 
 | #include "base/strings/string_util.h" | 
 | #include "base/strings/utf_string_conversions.h" | 
 | #include "base/time/time.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "third_party/icu/source/common/unicode/unistr.h" | 
 | #include "third_party/icu/source/i18n/unicode/datefmt.h" | 
 | #include "third_party/icu/source/i18n/unicode/msgfmt.h" | 
 |  | 
 | typedef testing::Test MessageFormatterTest; | 
 |  | 
 | namespace base { | 
 | namespace i18n { | 
 |  | 
 | class MessageFormatterTest : public testing::Test { | 
 |  protected: | 
 |   MessageFormatterTest() { | 
 |     original_locale_ = GetConfiguredLocale(); | 
 |     SetICUDefaultLocale("en-US"); | 
 |   } | 
 |   ~MessageFormatterTest() override { | 
 |     SetICUDefaultLocale(original_locale_); | 
 |   } | 
 |  | 
 |  private: | 
 |   std::string original_locale_; | 
 | }; | 
 |  | 
 | namespace { | 
 |  | 
 | void AppendFormattedDateTime(const std::unique_ptr<icu::DateFormat>& df, | 
 |                              const Time& now, | 
 |                              std::string* result) { | 
 |   icu::UnicodeString formatted; | 
 |   df->format(static_cast<UDate>(now.ToJsTime()), formatted). | 
 |       toUTF8String(*result); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST_F(MessageFormatterTest, PluralNamedArgs) { | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "{num_people, plural, " | 
 |       "=0 {I met nobody in {place}.}" | 
 |       "=1 {I met a person in {place}.}" | 
 |       "other {I met # people in {place}.}}"); | 
 |  | 
 |   std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 0, "place", "Paris")); | 
 |   EXPECT_EQ("I met nobody in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 1, "place", "Paris")); | 
 |   EXPECT_EQ("I met a person in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 5, "place", "Paris")); | 
 |   EXPECT_EQ("I met 5 people in Paris.", result); | 
 | } | 
 |  | 
 | TEST_F(MessageFormatterTest, PluralNamedArgsWithOffset) { | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "{num_people, plural, offset:1 " | 
 |       "=0 {I met nobody in {place}.}" | 
 |       "=1 {I met {person} in {place}.}" | 
 |       "=2 {I met {person} and one other person in {place}.}" | 
 |       "=13 {I met {person} and a dozen other people in {place}.}" | 
 |       "other {I met {person} and # other people in {place}.}}"); | 
 |  | 
 |   std::string result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 0, "place", "Paris")); | 
 |   EXPECT_EQ("I met nobody in Paris.", result); | 
 |   // {person} is ignored if {num_people} is 0. | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 0, "place", "Paris", "person", "Peter")); | 
 |   EXPECT_EQ("I met nobody in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 1, "place", "Paris", "person", "Peter")); | 
 |   EXPECT_EQ("I met Peter in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 2, "place", "Paris", "person", "Peter")); | 
 |   EXPECT_EQ("I met Peter and one other person in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 13, "place", "Paris", "person", "Peter")); | 
 |   EXPECT_EQ("I met Peter and a dozen other people in Paris.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNamedArgs( | 
 |       pattern, "num_people", 50, "place", "Paris", "person", "Peter")); | 
 |   EXPECT_EQ("I met Peter and 49 other people in Paris.", result); | 
 | } | 
 |  | 
 | TEST_F(MessageFormatterTest, PluralNumberedArgs) { | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "{1, plural, " | 
 |       "=1 {The cert for {0} expired yesterday.}" | 
 |       "=7 {The cert for {0} expired a week ago.}" | 
 |       "other {The cert for {0} expired # days ago.}}"); | 
 |  | 
 |   std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "example.com", 1)); | 
 |   EXPECT_EQ("The cert for example.com expired yesterday.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "example.com", 7)); | 
 |   EXPECT_EQ("The cert for example.com expired a week ago.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "example.com", 15)); | 
 |   EXPECT_EQ("The cert for example.com expired 15 days ago.", result); | 
 | } | 
 |  | 
 | TEST_F(MessageFormatterTest, PluralNumberedArgsWithDate) { | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "{1, plural, " | 
 |       "=1 {The cert for {0} expired yesterday. Today is {2,date,full}}" | 
 |       "other {The cert for {0} expired # days ago. Today is {2,date,full}}}"); | 
 |  | 
 |   base::Time now = base::Time::Now(); | 
 |   using icu::DateFormat; | 
 |   std::unique_ptr<DateFormat> df( | 
 |       DateFormat::createDateInstance(DateFormat::FULL)); | 
 |   std::string second_sentence = " Today is "; | 
 |   AppendFormattedDateTime(df, now, &second_sentence); | 
 |  | 
 |   std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "example.com", 1, now)); | 
 |   EXPECT_EQ("The cert for example.com expired yesterday." + second_sentence, | 
 |             result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "example.com", 15, now)); | 
 |   EXPECT_EQ("The cert for example.com expired 15 days ago." + second_sentence, | 
 |             result); | 
 | } | 
 |  | 
 | TEST_F(MessageFormatterTest, DateTimeAndNumber) { | 
 |   // Note that using 'mph' for all locales is not a good i18n practice. | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "At {0,time, short} on {0,date, medium}, " | 
 |       "there was {1} at building {2,number,integer}. " | 
 |       "The speed of the wind was {3,number,###.#} mph."); | 
 |  | 
 |   using icu::DateFormat; | 
 |   std::unique_ptr<DateFormat> tf( | 
 |       DateFormat::createTimeInstance(DateFormat::SHORT)); | 
 |   std::unique_ptr<DateFormat> df( | 
 |       DateFormat::createDateInstance(DateFormat::MEDIUM)); | 
 |  | 
 |   base::Time now = base::Time::Now(); | 
 |   std::string expected = "At "; | 
 |   AppendFormattedDateTime(tf, now, &expected); | 
 |   expected.append(" on "); | 
 |   AppendFormattedDateTime(df, now, &expected); | 
 |   expected.append(", there was an explosion at building 3. " | 
 |                   "The speed of the wind was 37.4 mph."); | 
 |  | 
 |   EXPECT_EQ(expected, UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, now, "an explosion", 3, 37.413))); | 
 | } | 
 |  | 
 | TEST_F(MessageFormatterTest, SelectorSingleOrMultiple) { | 
 |   const string16 pattern = ASCIIToUTF16( | 
 |       "{0, select," | 
 |       "single {Select a file to upload.}" | 
 |       "multiple {Select files to upload.}" | 
 |       "other {UNUSED}}"); | 
 |  | 
 |   std::string result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "single")); | 
 |   EXPECT_EQ("Select a file to upload.", result); | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "multiple")); | 
 |   EXPECT_EQ("Select files to upload.", result); | 
 |  | 
 |   // fallback if a parameter is not selectors specified in the message pattern. | 
 |   result = UTF16ToASCII(MessageFormatter::FormatWithNumberedArgs( | 
 |       pattern, "foobar")); | 
 |   EXPECT_EQ("UNUSED", result); | 
 | } | 
 |  | 
 | }  // namespace i18n | 
 | }  // namespace base |