/** * */ package net.frontlinesms.ui.i18n; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.MissingResourceException; import java.util.Set; import java.util.TimeZone; import net.frontlinesms.FrontlineSMSConstants; import net.frontlinesms.junit.BaseTestCase; import org.apache.log4j.Logger; /** * Test methods for {@link InternationalisationUtils}. * @author Alex */ public class InternationalisationUtilsTest extends BaseTestCase { //> STATIC PROPERTIES /** Date format which shows years, months and days, e.g. 2009-12-31 */ private static final DateFormat DATEFORMAT_DATE_ONLY = new SimpleDateFormat("yyyy/MM/dd"); /** Adds an extra, more intensive date test to {@link #testDateFormats()} */ private static final boolean EXTENSIVE_DATE_TEST = false; //> TEST DATA /** * Test dates in the format {year (4-digit), month (1-indexed), day (1-31; valid for month and year). */ private static final int[][] TEST_DATES = { {2009, 12, 15}, {1888, 3, 31}, {2015, 7, 1}, {1, 1, 1}, {3000, 12, 31}, }; //> INSTANCE VARIABLES /** Logging object */ private final Logger log = Logger.getLogger(this.getClass()); //> TEST METHODS public void testFormatString() { testFormatString("Connecting at %0bps", "Connecting at %0bps"); testFormatString("Connecting at 19600bps", "Connecting at %0bps", "19600"); testFormatString("Connecting at %bps", "Connecting at %bps", "19600"); testFormatString("Connecting at 19600bps on port COM1", "Connecting at %0bps on port %1", "19600", "COM1"); } private void testFormatString(String expected, String i18nString, String... argValues) { assertEquals(expected, InternationalisationUtils.formatString(i18nString, argValues)); } /** * This method loads all date formats from each language bundle, and makes sure that they are valid. * This tests {@link InternationalisationUtils#getDateFormat()} vs {@link InternationalisationUtils#parseDate(String)}. * @throws ParseException * @throws IOException */ public void testDateFormats() throws ParseException, IOException { log.warn("This test has been disabled as it needs modifications to its implementation."); for(LanguageBundle bungle : getLanguageBundles()) { log.info("Testing " + bungle.getLanguageName()); String formatString; try { formatString = bungle.getValue(FrontlineSMSConstants.DATEFORMAT_YMD); } catch(MissingResourceException ex) { // Don't attempt to test when there is no date format specified. continue; } DateFormat dateFormat = new SimpleDateFormat(formatString); for(int[] dateDetails : TEST_DATES) { // Create a date object and format it as a String. Reparse the String and make sure that the returned date is // within an acceptable margin (< a single day) of the original date. Date testDate = getDate(dateDetails); String formattedDate = dateFormat.format(testDate); Date parsedDate = dateFormat.parse(formattedDate); assertEquals("Parsed date was incorrect for language '" + bungle.getLanguageName() + "' - format='" + formatString + "'", DATEFORMAT_DATE_ONLY.format(testDate), DATEFORMAT_DATE_ONLY.format(parsedDate)); } // For a more extensive test, we can check most of the dates from 1AD to the year 3000 if(EXTENSIVE_DATE_TEST) { for(int year=1; year<=3000; ++year) { for(int month=1; month<=12; ++month) { for(int day=1; day<=28; ++day) { // Create a date object and format it as a String. Reparse the String and make sure that the returned date is // within an acceptable margin (< a single day) of the original date. Date testDate = getDate(year, month, day); String formattedDate = dateFormat.format(testDate); Date parsedDate = dateFormat.parse(formattedDate); assertEquals("Parsed date was incorrect for language '" + bungle.getLanguageName() + "'", DATEFORMAT_DATE_ONLY.format(testDate), DATEFORMAT_DATE_ONLY.format(parsedDate)); } } } } } } /** @return {@link LanguageBundle}s loaded from resources dir * @throws IOException */ private Collection<LanguageBundle> getLanguageBundles() throws IOException { Set<LanguageBundle> bundles = new HashSet<LanguageBundle>(); for(File bundleFile : new File("src/main/resources/resources/languages").listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.getName().endsWith(".properties") ; } })) { bundles.add(FileLanguageBundle.create(bundleFile)); } return bundles; } /** * Test method for {@link InternationalisationUtils#mergeMaps(java.util.Map, java.util.Map)} */ public void testMergeMaps() { HashMap<String, String> destination = new HashMap<String, String>(); HashMap<String, String> additionalValue = new HashMap<String, String>(); destination.put("i will be there at the end", "still here"); additionalValue.put("i have come from 2", "new arrival"); destination.put("do not replace me", "original"); additionalValue.put("do not replace me", "new value"); InternationalisationUtils.mergeMaps(destination, additionalValue); // map contents should be merged into destination, with duplicate keys keeping the values from destination assertEquals(destination.get("i will be there at the end"), "still here"); assertEquals(destination.get("i have come from 2"), "new arrival"); assertEquals(destination.get("do not replace me"), "original"); } /** * Test method for {@link InternationalisationUtils#parseCurrency(String)} * @throws ParseException */ public void testCurrencyParsing() throws ParseException { assertEquals(1.4, InternationalisationUtils.parseCurrency("1.4")); assertEquals(1.4, InternationalisationUtils.parseCurrency("1,4")); assertEquals(0.0, InternationalisationUtils.parseCurrency("0")); assertEquals(0.0, InternationalisationUtils.parseCurrency("0.")); assertEquals(1.0, InternationalisationUtils.parseCurrency("1.")); assertEquals(0.5, InternationalisationUtils.parseCurrency("0.5")); assertEquals(0.5, InternationalisationUtils.parseCurrency("0,5")); assertEquals(0.5, InternationalisationUtils.parseCurrency("0.50")); assertEquals(0.5, InternationalisationUtils.parseCurrency("0,50")); assertEquals(0.5, InternationalisationUtils.parseCurrency(".5")); assertNotSame(1.4, InternationalisationUtils.parseCurrency("1.6")); assertNotSame(1.4, InternationalisationUtils.parseCurrency("1,2")); assertNotSame(0.1, InternationalisationUtils.parseCurrency("0")); assertNotSame(0.5, InternationalisationUtils.parseCurrency("0.6")); assertNotSame(0.5, InternationalisationUtils.parseCurrency("0,495")); assertEquals(1111.4, InternationalisationUtils.parseCurrency("1,111.4")); assertEquals(1111.4, InternationalisationUtils.parseCurrency("1.111,4")); assertEquals(11111.0, InternationalisationUtils.parseCurrency("1,11,11")); assertEquals(111.11, InternationalisationUtils.parseCurrency("111,11")); assertEquals(1234567.89, InternationalisationUtils.parseCurrency("1,234,567.89")); assertEquals(1234567.89, InternationalisationUtils.parseCurrency("1.234.567,89")); assertEquals(1.0, InternationalisationUtils.parseCurrency("1")); assertEquals(11111.0, InternationalisationUtils.parseCurrency("11111")); assertEquals(1234567890.123, InternationalisationUtils.parseCurrency("1 234 567 890.123")); assertEquals(1234567890.123, InternationalisationUtils.parseCurrency("$1 234 567 890.123")); assertEquals(1234.567, InternationalisationUtils.parseCurrency("GBP1,234.567")); } public void testPhoneNumberFormatting() { assertEquals("+15559999", InternationalisationUtils.getInternationalPhoneNumber("+15559999")); assertEquals("+15559999", InternationalisationUtils.getInternationalPhoneNumber("0015559999")); assertEquals("+15559999", InternationalisationUtils.getInternationalPhoneNumber("+1-(555)-9999")); assertEquals("+15559999", InternationalisationUtils.getInternationalPhoneNumber("001-(555)-9999")); assertEquals("+33678965454", InternationalisationUtils.getInternationalPhoneNumber("+33(0)6 78 96 54 54")); assertEquals("+33678965454", InternationalisationUtils.getInternationalPhoneNumber("0033(0)678965454")); assertEquals("+33678965454", InternationalisationUtils.getInternationalPhoneNumber("0033(0)6-78-96-54-54")); assertEquals("+33678965454", InternationalisationUtils.getInternationalPhoneNumber("0033(0)6.78.96.54.54")); assertEquals("+447771592981", InternationalisationUtils.getInternationalPhoneNumber("+44 (0) 7771 592981")); } //> INSTANCE HELPER METHODS //> STATIC HELPER METHODS /** * Convert year, month and day of {@link #TEST_DATES} into a java {@link Date} object. * @param dateDetails * @return a {@link Date} object describing the supplied time. */ private static Date getDate(int[] dateDetails) { return getDate(dateDetails[0], dateDetails[1], dateDetails[2]); } /** * Convert year, month and day into a java {@link Date} object. * @param year the year, CE (AD) * @param month 1-indexed year * @param day the day of the month * @return a {@link Date} object describing the supplied time. */ private static Date getDate(int year, int month, int day) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.set(year, month - 1, day); return cal.getTime(); } }