Home | History | Annotate | Download | only in tests
      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 SUCH
     23  * DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/platform/text/mac/LocaleMac.h"
     28 
     29 #include <gtest/gtest.h>
     30 #include "core/platform/DateComponents.h"
     31 #include "wtf/DateMath.h"
     32 #include "wtf/MathExtras.h"
     33 #include "wtf/PassOwnPtr.h"
     34 #include "wtf/text/CString.h"
     35 
     36 using namespace WebCore;
     37 
     38 class LocaleMacTest : public ::testing::Test {
     39 protected:
     40     enum {
     41         January = 0, February, March,
     42         April, May, June,
     43         July, August, September,
     44         October, November, December,
     45     };
     46 
     47     enum {
     48         Sunday = 0, Monday, Tuesday,
     49         Wednesday, Thursday, Friday,
     50         Saturday,
     51     };
     52 
     53     DateComponents dateComponents(int year, int month, int day)
     54     {
     55         DateComponents date;
     56         date.setMillisecondsSinceEpochForDate(msForDate(year, month, day));
     57         return date;
     58     }
     59 
     60     DateComponents timeComponents(int hour, int minute, int second, int millisecond)
     61     {
     62         DateComponents date;
     63         date.setMillisecondsSinceMidnight(hour * msPerHour + minute * msPerMinute + second * msPerSecond + millisecond);
     64         return date;
     65     }
     66 
     67     double msForDate(int year, int month, int day)
     68     {
     69         return dateToDaysFrom1970(year, month, day) * msPerDay;
     70     }
     71 
     72     String formatWeek(const String& localeString, const String& isoString)
     73     {
     74         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
     75         DateComponents date;
     76         unsigned end;
     77         date.parseWeek(isoString, 0, end);
     78         return locale->formatDateTime(date);
     79     }
     80 
     81     String formatMonth(const String& localeString, const String& isoString, bool useShortFormat)
     82     {
     83         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
     84         DateComponents date;
     85         unsigned end;
     86         date.parseMonth(isoString, 0, end);
     87         return locale->formatDateTime(date, (useShortFormat ? Locale::FormatTypeShort : Locale::FormatTypeMedium));
     88     }
     89 
     90     String formatDate(const String& localeString, int year, int month, int day)
     91     {
     92         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
     93         return locale->formatDateTime(dateComponents(year, month, day));
     94     }
     95 
     96     String formatTime(const String& localeString, int hour, int minute, int second, int millisecond, bool useShortFormat)
     97     {
     98         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
     99         return locale->formatDateTime(timeComponents(hour, minute, second, millisecond), (useShortFormat ? Locale::FormatTypeShort : Locale::FormatTypeMedium));
    100     }
    101 
    102 #if ENABLE(CALENDAR_PICKER)
    103     unsigned firstDayOfWeek(const String& localeString)
    104     {
    105         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    106         return locale->firstDayOfWeek();
    107     }
    108 
    109     String monthLabel(const String& localeString, unsigned index)
    110     {
    111         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    112         return locale->monthLabels()[index];
    113     }
    114 
    115     String weekDayShortLabel(const String& localeString, unsigned index)
    116     {
    117         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    118         return locale->weekDayShortLabels()[index];
    119     }
    120 
    121     bool isRTL(const String& localeString)
    122     {
    123         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    124         return locale->isRTL();
    125     }
    126 #endif
    127 
    128 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
    129     String monthFormat(const String& localeString)
    130     {
    131         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    132         return locale->monthFormat();
    133     }
    134 
    135     String timeFormat(const String& localeString)
    136     {
    137         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    138         return locale->timeFormat();
    139     }
    140 
    141     String shortTimeFormat(const String& localeString)
    142     {
    143         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    144         return locale->shortTimeFormat();
    145     }
    146 
    147     String shortMonthLabel(const String& localeString, unsigned index)
    148     {
    149         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    150         return locale->shortMonthLabels()[index];
    151     }
    152 
    153     String standAloneMonthLabel(const String& localeString, unsigned index)
    154     {
    155         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    156         return locale->standAloneMonthLabels()[index];
    157     }
    158 
    159     String shortStandAloneMonthLabel(const String& localeString, unsigned index)
    160     {
    161         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    162         return locale->shortStandAloneMonthLabels()[index];
    163     }
    164 
    165     String timeAMPMLabel(const String& localeString, unsigned index)
    166     {
    167         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    168         return locale->timeAMPMLabels()[index];
    169     }
    170 
    171     String decimalSeparator(const String& localeString)
    172     {
    173         OwnPtr<LocaleMac> locale = LocaleMac::create(localeString);
    174         return locale->localizedDecimalSeparator();
    175     }
    176 #endif
    177 };
    178 
    179 TEST_F(LocaleMacTest, formatWeek)
    180 {
    181     EXPECT_STREQ("Week 04, 2005", formatWeek("en_US", "2005-W04").utf8().data());
    182     EXPECT_STREQ("Week 52, 2005", formatWeek("en_US", "2005-W52").utf8().data());
    183 }
    184 
    185 TEST_F(LocaleMacTest, formatMonth)
    186 {
    187     EXPECT_STREQ("April 2005", formatMonth("en_US", "2005-04", false).utf8().data());
    188     EXPECT_STREQ("avril 2005", formatMonth("fr_FR", "2005-04", false).utf8().data());
    189     EXPECT_STREQ("2005\xE5\xB9\xB4" "04\xE6\x9C\x88", formatMonth("ja_JP", "2005-04", false).utf8().data());
    190 
    191     EXPECT_STREQ("Apr 2005", formatMonth("en_US", "2005-04", true).utf8().data());
    192     EXPECT_STREQ("avr. 2005", formatMonth("fr_FR", "2005-04", true).utf8().data());
    193     EXPECT_STREQ("2005\xE5\xB9\xB4" "04\xE6\x9C\x88", formatMonth("ja_JP", "2005-04", true).utf8().data());
    194 }
    195 
    196 TEST_F(LocaleMacTest, formatDate)
    197 {
    198     EXPECT_STREQ("04/27/2005", formatDate("en_US", 2005, April, 27).utf8().data());
    199     EXPECT_STREQ("27/04/2005", formatDate("fr_FR", 2005, April, 27).utf8().data());
    200     // Do not test ja_JP locale. OS X 10.8 and 10.7 have different formats.
    201 }
    202 
    203 TEST_F(LocaleMacTest, formatTime)
    204 {
    205     EXPECT_STREQ("1:23 PM", formatTime("en_US", 13, 23, 00, 000, true).utf8().data());
    206     EXPECT_STREQ("13:23", formatTime("fr_FR", 13, 23, 00, 000, true).utf8().data());
    207     EXPECT_STREQ("13:23", formatTime("ja_JP", 13, 23, 00, 000, true).utf8().data());
    208     EXPECT_STREQ("\xD9\xA1:\xD9\xA2\xD9\xA3 \xD9\x85", formatTime("ar", 13, 23, 00, 000, true).utf8().data());
    209     EXPECT_STREQ("\xDB\xB1\xDB\xB3:\xDB\xB2\xDB\xB3", formatTime("fa", 13, 23, 00, 000, true).utf8().data());
    210 
    211     EXPECT_STREQ("12:00 AM", formatTime("en_US", 00, 00, 00, 000, true).utf8().data());
    212     EXPECT_STREQ("00:00", formatTime("fr_FR", 00, 00, 00, 000, true).utf8().data());
    213     EXPECT_STREQ("0:00", formatTime("ja_JP", 00, 00, 00, 000, true).utf8().data());
    214     EXPECT_STREQ("\xD9\xA1\xD9\xA2:\xD9\xA0\xD9\xA0 \xD8\xB5", formatTime("ar", 00, 00, 00, 000, true).utf8().data());
    215     EXPECT_STREQ("\xDB\xB0:\xDB\xB0\xDB\xB0", formatTime("fa", 00, 00, 00, 000, true).utf8().data());
    216 
    217     EXPECT_STREQ("7:07:07.007 AM", formatTime("en_US", 07, 07, 07, 007, false).utf8().data());
    218     EXPECT_STREQ("07:07:07,007", formatTime("fr_FR", 07, 07, 07, 007, false).utf8().data());
    219     EXPECT_STREQ("7:07:07.007", formatTime("ja_JP", 07, 07, 07, 007, false).utf8().data());
    220     EXPECT_STREQ("\xD9\xA7:\xD9\xA0\xD9\xA7:\xD9\xA0\xD9\xA7\xD9\xAB\xD9\xA0\xD9\xA0\xD9\xA7 \xD8\xB5", formatTime("ar", 07, 07, 07, 007, false).utf8().data());
    221     EXPECT_STREQ("\xDB\xB7:\xDB\xB0\xDB\xB7:\xDB\xB0\xDB\xB7\xD9\xAB\xDB\xB0\xDB\xB0\xDB\xB7", formatTime("fa", 07, 07, 07, 007, false).utf8().data());
    222 }
    223 
    224 #if ENABLE(CALENDAR_PICKER)
    225 TEST_F(LocaleMacTest, firstDayOfWeek)
    226 {
    227     EXPECT_EQ(Sunday, firstDayOfWeek("en_US"));
    228     EXPECT_EQ(Monday, firstDayOfWeek("fr_FR"));
    229     EXPECT_EQ(Sunday, firstDayOfWeek("ja_JP"));
    230 }
    231 
    232 TEST_F(LocaleMacTest, monthLabels)
    233 {
    234     EXPECT_STREQ("January", monthLabel("en_US", January).utf8().data());
    235     EXPECT_STREQ("June", monthLabel("en_US", June).utf8().data());
    236     EXPECT_STREQ("December", monthLabel("en_US", December).utf8().data());
    237 
    238     EXPECT_STREQ("janvier", monthLabel("fr_FR", January).utf8().data());
    239     EXPECT_STREQ("juin", monthLabel("fr_FR", June).utf8().data());
    240     EXPECT_STREQ("d\xC3\xA9" "cembre", monthLabel("fr_FR", December).utf8().data());
    241 
    242     EXPECT_STREQ("1\xE6\x9C\x88", monthLabel("ja_JP", January).utf8().data());
    243     EXPECT_STREQ("6\xE6\x9C\x88", monthLabel("ja_JP", June).utf8().data());
    244     EXPECT_STREQ("12\xE6\x9C\x88", monthLabel("ja_JP", December).utf8().data());
    245 }
    246 
    247 TEST_F(LocaleMacTest, weekDayShortLabels)
    248 {
    249     EXPECT_STREQ("Sun", weekDayShortLabel("en_US", Sunday).utf8().data());
    250     EXPECT_STREQ("Wed", weekDayShortLabel("en_US", Wednesday).utf8().data());
    251     EXPECT_STREQ("Sat", weekDayShortLabel("en_US", Saturday).utf8().data());
    252 
    253     EXPECT_STREQ("dim.", weekDayShortLabel("fr_FR", Sunday).utf8().data());
    254     EXPECT_STREQ("mer.", weekDayShortLabel("fr_FR", Wednesday).utf8().data());
    255     EXPECT_STREQ("sam.", weekDayShortLabel("fr_FR", Saturday).utf8().data());
    256 
    257     EXPECT_STREQ("\xE6\x97\xA5", weekDayShortLabel("ja_JP", Sunday).utf8().data());
    258     EXPECT_STREQ("\xE6\xB0\xB4", weekDayShortLabel("ja_JP", Wednesday).utf8().data());
    259     EXPECT_STREQ("\xE5\x9C\x9F", weekDayShortLabel("ja_JP", Saturday).utf8().data());
    260 }
    261 
    262 TEST_F(LocaleMacTest, isRTL)
    263 {
    264     EXPECT_TRUE(isRTL("ar-eg"));
    265     EXPECT_FALSE(isRTL("en-us"));
    266     EXPECT_FALSE(isRTL("ja-jp"));
    267     EXPECT_FALSE(isRTL("**invalid**"));
    268 }
    269 #endif
    270 
    271 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
    272 TEST_F(LocaleMacTest, monthFormat)
    273 {
    274     EXPECT_STREQ("MMMM yyyy", monthFormat("en_US").utf8().data());
    275     EXPECT_STREQ("yyyy\xE5\xB9\xB4M\xE6\x9C\x88", monthFormat("ja_JP").utf8().data());
    276 
    277     // fr_FR and ru return different results on OS versions.
    278     //  "MMM yyyy" "LLL yyyy" on 10.6 and 10.7
    279     //  "MMM y" "LLL y" on 10.8
    280 }
    281 
    282 TEST_F(LocaleMacTest, timeFormat)
    283 {
    284     EXPECT_STREQ("h:mm:ss a", timeFormat("en_US").utf8().data());
    285     EXPECT_STREQ("HH:mm:ss", timeFormat("fr_FR").utf8().data());
    286     EXPECT_STREQ("H:mm:ss", timeFormat("ja_JP").utf8().data());
    287 }
    288 
    289 TEST_F(LocaleMacTest, shortTimeFormat)
    290 {
    291     EXPECT_STREQ("h:mm a", shortTimeFormat("en_US").utf8().data());
    292     EXPECT_STREQ("HH:mm", shortTimeFormat("fr_FR").utf8().data());
    293     EXPECT_STREQ("H:mm", shortTimeFormat("ja_JP").utf8().data());
    294 }
    295 
    296 TEST_F(LocaleMacTest, standAloneMonthLabels)
    297 {
    298     EXPECT_STREQ("January", standAloneMonthLabel("en_US", January).utf8().data());
    299     EXPECT_STREQ("June", standAloneMonthLabel("en_US", June).utf8().data());
    300     EXPECT_STREQ("December", standAloneMonthLabel("en_US", December).utf8().data());
    301 
    302     EXPECT_STREQ("janvier", standAloneMonthLabel("fr_FR", January).utf8().data());
    303     EXPECT_STREQ("juin", standAloneMonthLabel("fr_FR", June).utf8().data());
    304     EXPECT_STREQ("d\xC3\xA9" "cembre", standAloneMonthLabel("fr_FR", December).utf8().data());
    305 
    306     EXPECT_STREQ("1\xE6\x9C\x88", standAloneMonthLabel("ja_JP", January).utf8().data());
    307     EXPECT_STREQ("6\xE6\x9C\x88", standAloneMonthLabel("ja_JP", June).utf8().data());
    308     EXPECT_STREQ("12\xE6\x9C\x88", standAloneMonthLabel("ja_JP", December).utf8().data());
    309 }
    310 
    311 TEST_F(LocaleMacTest, shortMonthLabels)
    312 {
    313     EXPECT_STREQ("Jan", shortMonthLabel("en_US", 0).utf8().data());
    314     EXPECT_STREQ("Jan", shortStandAloneMonthLabel("en_US", 0).utf8().data());
    315     EXPECT_STREQ("Dec", shortMonthLabel("en_US", 11).utf8().data());
    316     EXPECT_STREQ("Dec", shortStandAloneMonthLabel("en_US", 11).utf8().data());
    317 
    318     EXPECT_STREQ("janv.", shortMonthLabel("fr_FR", 0).utf8().data());
    319     EXPECT_STREQ("janv.", shortStandAloneMonthLabel("fr_FR", 0).utf8().data());
    320     EXPECT_STREQ("d\xC3\xA9" "c.", shortMonthLabel("fr_FR", 11).utf8().data());
    321     EXPECT_STREQ("d\xC3\xA9" "c.", shortStandAloneMonthLabel("fr_FR", 11).utf8().data());
    322 
    323     EXPECT_STREQ("1\xE6\x9C\x88", shortMonthLabel("ja_JP", 0).utf8().data());
    324     EXPECT_STREQ("1\xE6\x9C\x88", shortStandAloneMonthLabel("ja_JP", 0).utf8().data());
    325     EXPECT_STREQ("12\xE6\x9C\x88", shortMonthLabel("ja_JP", 11).utf8().data());
    326     EXPECT_STREQ("12\xE6\x9C\x88", shortStandAloneMonthLabel("ja_JP", 11).utf8().data());
    327 
    328     EXPECT_STREQ("\xD0\xBC\xD0\xB0\xD1\x80\xD1\x82\xD0\xB0", shortMonthLabel("ru_RU", 2).utf8().data());
    329     EXPECT_STREQ("\xD0\xBC\xD0\xB0\xD1\x8F", shortMonthLabel("ru_RU", 4).utf8().data());
    330     // The ru_RU locale returns different stand-alone month labels on OS versions.
    331     //  "\xD0\xBC\xD0\xB0\xD1\x80\xD1\x82" "\xD0\xBC\xD0\xB0\xD0\xB9" on 10.6 and 10.7
    332     //  "\xD0\x9C\xD0\xB0\xD1\x80\xD1\x82" "\xD0\x9C\xD0\xB0\xD0\xB9" on 10.8
    333 }
    334 
    335 TEST_F(LocaleMacTest, timeAMPMLabels)
    336 {
    337     EXPECT_STREQ("AM", timeAMPMLabel("en_US", 0).utf8().data());
    338     EXPECT_STREQ("PM", timeAMPMLabel("en_US", 1).utf8().data());
    339 
    340     EXPECT_STREQ("AM", timeAMPMLabel("fr_FR", 0).utf8().data());
    341     EXPECT_STREQ("PM", timeAMPMLabel("fr_FR", 1).utf8().data());
    342 
    343     EXPECT_STREQ("\xE5\x8D\x88\xE5\x89\x8D", timeAMPMLabel("ja_JP", 0).utf8().data());
    344     EXPECT_STREQ("\xE5\x8D\x88\xE5\xBE\x8C", timeAMPMLabel("ja_JP", 1).utf8().data());
    345 }
    346 
    347 TEST_F(LocaleMacTest, decimalSeparator)
    348 {
    349     EXPECT_STREQ(".", decimalSeparator("en_US").utf8().data());
    350     EXPECT_STREQ(",", decimalSeparator("fr_FR").utf8().data());
    351 }
    352 #endif
    353 
    354 TEST_F(LocaleMacTest, invalidLocale)
    355 {
    356     EXPECT_STREQ(monthLabel("en_US", January).utf8().data(), monthLabel("foo", January).utf8().data());
    357     EXPECT_STREQ(decimalSeparator("en_US").utf8().data(), decimalSeparator("foo").utf8().data());
    358 }
    359 
    360 static void testNumberIsReversible(const AtomicString& localeString, const char* original, const char* shouldHave = 0)
    361 {
    362     OwnPtr<Locale> locale = Locale::create(localeString);
    363     String localized = locale->convertToLocalizedNumber(original);
    364     if (shouldHave)
    365         EXPECT_TRUE(localized.contains(shouldHave));
    366     String converted = locale->convertFromLocalizedNumber(localized);
    367     EXPECT_STREQ(original, converted.utf8().data());
    368 }
    369 
    370 void testNumbers(const AtomicString& localeString, const char* decimalSeparatorShouldBe = 0)
    371 {
    372     testNumberIsReversible(localeString, "123456789012345678901234567890");
    373     testNumberIsReversible(localeString, "-123.456", decimalSeparatorShouldBe);
    374     testNumberIsReversible(localeString, ".456", decimalSeparatorShouldBe);
    375     testNumberIsReversible(localeString, "-0.456", decimalSeparatorShouldBe);
    376 }
    377 
    378 TEST_F(LocaleMacTest, localizedNumberRoundTrip)
    379 {
    380     // Test some of major locales.
    381     testNumbers("en_US", ".");
    382     testNumbers("fr_FR", ",");
    383     testNumbers("ar");
    384     testNumbers("de_DE");
    385     testNumbers("es_ES");
    386     testNumbers("fa");
    387     testNumbers("ja_JP");
    388     testNumbers("ko_KR");
    389     testNumbers("zh_CN");
    390     testNumbers("zh_HK");
    391     testNumbers("zh_TW");
    392 }
    393