Home | History | Annotate | Download | only in test
      1 package org.unicode.cldr.test;
      2 
      3 import java.io.File;
      4 import java.io.IOException;
      5 import java.io.InputStream;
      6 import java.util.Arrays;
      7 import java.util.Date;
      8 import java.util.EnumSet;
      9 import java.util.HashSet;
     10 import java.util.Iterator;
     11 import java.util.Objects;
     12 import java.util.Set;
     13 import java.util.TreeMap;
     14 import java.util.TreeSet;
     15 import java.util.regex.Matcher;
     16 
     17 import org.unicode.cldr.tool.ToolConfig;
     18 import org.unicode.cldr.util.CLDRConfig;
     19 import org.unicode.cldr.util.CLDRFile;
     20 import org.unicode.cldr.util.CLDRPaths;
     21 import org.unicode.cldr.util.CldrUtility;
     22 import org.unicode.cldr.util.DateTimeFormats;
     23 import org.unicode.cldr.util.DtdType;
     24 import org.unicode.cldr.util.Factory;
     25 import org.unicode.cldr.util.InputStreamFactory;
     26 import org.unicode.cldr.util.LanguageTagParser;
     27 import org.unicode.cldr.util.Level;
     28 import org.unicode.cldr.util.Organization;
     29 import org.unicode.cldr.util.PatternCache;
     30 import org.unicode.cldr.util.PrettyPath;
     31 import org.unicode.cldr.util.StandardCodes;
     32 import org.unicode.cldr.util.XMLFileReader;
     33 import org.unicode.cldr.util.XPathParts;
     34 import org.xml.sax.ErrorHandler;
     35 import org.xml.sax.InputSource;
     36 import org.xml.sax.SAXException;
     37 import org.xml.sax.SAXParseException;
     38 import org.xml.sax.XMLReader;
     39 
     40 import com.ibm.icu.impl.Relation;
     41 import com.ibm.icu.text.DateFormatSymbols;
     42 import com.ibm.icu.text.SimpleDateFormat;
     43 import com.ibm.icu.util.ULocale;
     44 
     45 /**
     46  * Simple test that loads each file in the cldr directory, thus verifying that
     47  * the DTD works, and also checks that the PrettyPaths work.
     48  *
     49  * @author markdavis
     50  */
     51 public class QuickCheck {
     52     private static final Set<String> skipAttributes = new HashSet<String>(Arrays.asList(new String[] {
     53         "alt", "draft", "references" }));
     54 
     55     private static String localeRegex;
     56 
     57     private static boolean showInfo = false;
     58 
     59     private static String commonDirectory;
     60     private static String mainDirectory;
     61 
     62     private static boolean resolved;
     63 
     64     private static Exception[] internalException = new Exception[1];
     65 
     66     private static boolean verbose;
     67 
     68     public static void main(String[] args) throws IOException {
     69         CLDRConfig testInfo = ToolConfig.getToolInstance();
     70         Factory factory = testInfo.getCldrFactory();
     71         checkStock(factory);
     72         if (true) return;
     73         verbose = CldrUtility.getProperty("verbose", "false", "true").matches("(?i)T|TRUE");
     74         localeRegex = CldrUtility.getProperty("locale", ".*");
     75 
     76         showInfo = CldrUtility.getProperty("showinfo", "false", "true").matches("(?i)T|TRUE");
     77 
     78         commonDirectory = CLDRPaths.COMMON_DIRECTORY; // Utility.getProperty("common", Utility.COMMON_DIRECTORY);
     79         // if (commonDirectory == null) commonDirectory = Utility.COMMON_DIRECTORY
     80         // System.out.println("Main Source Directory: " + commonDirectory +
     81         // "\t\t(to change, use -DSOURCE=xxx, eg -DSOURCE=C:/cvsdata/unicode/cldr/incoming/proposed/main)");
     82 
     83         mainDirectory = CldrUtility.getProperty("main", CLDRPaths.COMMON_DIRECTORY + "/main");
     84         // System.out.println("Main Source Directory: " + commonDirectory +
     85         // "\t\t(to change, use -DSOURCE=xxx, eg -DSOURCE=C:/cvsdata/unicode/cldr/incoming/proposed/main)");
     86 
     87         resolved = CldrUtility.getProperty("resolved", "false", "true").matches("(?i)T|TRUE");
     88 
     89         boolean paths = CldrUtility.getProperty("paths", "true").matches("(?i)T|TRUE");
     90 
     91         pretty = CldrUtility.getProperty("pretty", "true").matches("(?i)T|TRUE");
     92 
     93         double startTime = System.currentTimeMillis();
     94         checkDtds();
     95         double deltaTime = System.currentTimeMillis() - startTime;
     96         System.out.println("Elapsed: " + deltaTime / 1000.0 + " seconds");
     97 
     98         if (paths) {
     99             System.out.println("Checking paths");
    100             checkPaths();
    101             deltaTime = System.currentTimeMillis() - startTime;
    102             System.out.println("Elapsed: " + deltaTime / 1000.0 + " seconds");
    103             System.out.println("Basic Test Passes");
    104         }
    105     }
    106 
    107     private static void checkDtds() throws IOException {
    108         checkDtds(commonDirectory + "supplemental");
    109         checkDtds(commonDirectory + "collation");
    110         checkDtds(commonDirectory + "main");
    111         checkDtds(commonDirectory + "rbnf");
    112         checkDtds(commonDirectory + "segments");
    113         checkDtds(commonDirectory + "../test");
    114         checkDtds(commonDirectory + "transforms");
    115     }
    116 
    117     private static void checkDtds(String directory) throws IOException {
    118         File directoryFile = new File(directory);
    119         File[] listFiles = directoryFile.listFiles();
    120         String canonicalPath = directoryFile.getCanonicalPath();
    121         if (listFiles == null) {
    122             throw new IllegalArgumentException("Empty directory: " + canonicalPath);
    123         }
    124         System.out.println("Checking files for DTD errors in: " + canonicalPath);
    125         for (File fileName : listFiles) {
    126             if (!fileName.toString().endsWith(".xml")) {
    127                 continue;
    128             }
    129             check(fileName);
    130         }
    131     }
    132 
    133     static class MyErrorHandler implements ErrorHandler {
    134         public void error(SAXParseException exception) throws SAXException {
    135             System.out.println("\nerror: " + XMLFileReader.showSAX(exception));
    136             throw exception;
    137         }
    138 
    139         public void fatalError(SAXParseException exception) throws SAXException {
    140             System.out.println("\nfatalError: " + XMLFileReader.showSAX(exception));
    141             throw exception;
    142         }
    143 
    144         public void warning(SAXParseException exception) throws SAXException {
    145             System.out.println("\nwarning: " + XMLFileReader.showSAX(exception));
    146             throw exception;
    147         }
    148     }
    149 
    150     public static void check(File systemID) {
    151         try (InputStream fis = InputStreamFactory.createInputStream(systemID)) {
    152 //            FileInputStream fis = new FileInputStream(systemID);
    153             XMLReader xmlReader = XMLFileReader.createXMLReader(true);
    154             xmlReader.setErrorHandler(new MyErrorHandler());
    155             InputSource is = new InputSource(fis);
    156             is.setSystemId(systemID.toString());
    157             xmlReader.parse(is);
    158 //            fis.close();
    159         } catch (SAXException | IOException e) { // SAXParseException is a Subtype of SaxException
    160             System.out.println("\t" + "Can't read " + systemID);
    161             System.out.println("\t" + e.getClass() + "\t" + e.getMessage());
    162         }
    163 //        catch (SAXException e) {
    164 //            System.out.println("\t" + "Can't read " + systemID);
    165 //            System.out.println("\t" + e.getClass() + "\t" + e.getMessage());
    166 //        } catch (IOException e) {
    167 //            System.out.println("\t" + "Can't read " + systemID);
    168 //            System.out.println("\t" + e.getClass() + "\t" + e.getMessage());
    169 //        }
    170     }
    171 
    172     static Matcher skipPaths = PatternCache.get("/identity" + "|/alias" + "|\\[@alt=\"proposed").matcher("");
    173 
    174     private static boolean pretty;
    175 
    176     private static void checkPaths() {
    177         Relation<String, String> distinguishing = Relation.<String, String> of(new TreeMap<String, Set<String>>(), TreeSet.class, null);
    178         Relation<String, String> nonDistinguishing = Relation.<String, String> of(new TreeMap<String, Set<String>>(), TreeSet.class, null);
    179         XPathParts parts = new XPathParts();
    180         Factory cldrFactory = Factory.make(mainDirectory, localeRegex);
    181         CLDRFile english = cldrFactory.make("en", true);
    182 
    183         Relation<String, String> pathToLocale = Relation.of(
    184             new TreeMap<String, Set<String>>(CLDRFile.getComparator(DtdType.ldml)),
    185             TreeSet.class, null);
    186         for (String locale : cldrFactory.getAvailable()) {
    187             // if (locale.equals("root") && !localeRegex.equals("root"))
    188             // continue;
    189             CLDRFile file;
    190             try {
    191                 file = cldrFactory.make(locale, resolved);
    192             } catch (Exception e) {
    193                 System.out.println("\nfatalError: " + e.getMessage());
    194                 continue;
    195             }
    196             if (file.isNonInheriting())
    197                 continue;
    198             DisplayAndInputProcessor displayAndInputProcessor = new DisplayAndInputProcessor(file, false);
    199 
    200             System.out.println(locale + "\t-\t" + english.getName(locale));
    201             DtdType dtdType = null;
    202 
    203             for (Iterator<String> it = file.iterator(); it.hasNext();) {
    204                 String path = it.next();
    205                 if (path.endsWith("/alias")) {
    206                     continue;
    207                 }
    208                 String value = file.getStringValue(path);
    209                 if (value == null) {
    210                     throw new IllegalArgumentException(locale + "\tError: in null value at " + path);
    211                 }
    212                 String displayValue = displayAndInputProcessor.processForDisplay(path, value);
    213                 if (!displayValue.equals(value)) {
    214                     System.out.println("\t" + locale + "\tdisplayAndInputProcessor changes display value <" + value
    215                         + ">\t=>\t<" + displayValue + ">\t\t" + path);
    216                 }
    217                 String inputValue = displayAndInputProcessor.processInput(path, value, internalException);
    218                 if (internalException[0] != null) {
    219                     System.out.println("\t" + locale + "\tdisplayAndInputProcessor internal error <" + value
    220                         + ">\t=>\t<" + inputValue + ">\t\t" + path);
    221                     internalException[0].printStackTrace(System.out);
    222                 }
    223                 if (verbose && !inputValue.equals(value)) {
    224                     displayAndInputProcessor.processInput(path, value, internalException); // for debugging
    225                     System.out.println("\t" + locale + "\tdisplayAndInputProcessor changes input value <" + value
    226                         + ">\t=>\t<" + inputValue + ">\t\t" + path);
    227                 }
    228 
    229                 pathToLocale.put(path, locale);
    230 
    231                 // also check for non-distinguishing attributes
    232                 if (path.contains("/identity")) continue;
    233 
    234                 // make sure we don't have problem alts
    235                 if (path.contains("proposed")) {
    236                     String sourceLocale = file.getSourceLocaleID(path, null);
    237                     if (locale.equals(sourceLocale)) {
    238                         String nonAltPath = CLDRFile.getNondraftNonaltXPath(path);
    239                         if (!path.equals(nonAltPath)) {
    240                             String nonAltLocale = file.getSourceLocaleID(nonAltPath, null);
    241                             String nonAltValue = file.getStringValue(nonAltPath);
    242                             if (nonAltValue == null || !locale.equals(nonAltLocale)) {
    243                                 System.out.println("\t" + locale + "\tProblem alt=proposed <" + value + ">\t\t" + path);
    244                             }
    245                         }
    246                     }
    247                 }
    248 
    249                 String fullPath = file.getFullXPath(path);
    250                 parts.set(fullPath);
    251                 if (dtdType == null) {
    252                     dtdType = DtdType.valueOf(parts.getElement(0));
    253                 }
    254                 for (int i = 0; i < parts.size(); ++i) {
    255                     if (parts.getAttributeCount(i) == 0) continue;
    256                     String element = parts.getElement(i);
    257                     for (String attribute : parts.getAttributeKeys(i)) {
    258                         if (skipAttributes.contains(attribute)) continue;
    259                         if (CLDRFile.isDistinguishing(dtdType, element, attribute)) {
    260                             distinguishing.put(element, attribute);
    261                         } else {
    262                             nonDistinguishing.put(element, attribute);
    263                         }
    264                     }
    265                 }
    266             }
    267         }
    268         System.out.println();
    269 
    270         System.out.format("Distinguishing Elements: %s" + CldrUtility.LINE_SEPARATOR, distinguishing);
    271         System.out.format("Nondistinguishing Elements: %s" + CldrUtility.LINE_SEPARATOR, nonDistinguishing);
    272         System.out.format("Skipped %s" + CldrUtility.LINE_SEPARATOR, skipAttributes);
    273 
    274         if (pretty) {
    275             if (showInfo) {
    276                 System.out.println(CldrUtility.LINE_SEPARATOR + "Showing Path to PrettyPath mapping"
    277                     + CldrUtility.LINE_SEPARATOR);
    278             }
    279             PrettyPath prettyPath = new PrettyPath().setShowErrors(true);
    280             Set<String> badPaths = new TreeSet<String>();
    281             for (String path : pathToLocale.keySet()) {
    282                 String prettied = prettyPath.getPrettyPath(path, false);
    283                 if (showInfo) System.out.println(prettied + "\t\t" + path);
    284                 if (prettied.contains("%%") && !path.contains("/alias")) {
    285                     badPaths.add(path);
    286                 }
    287             }
    288             // now remove root
    289 
    290             if (showInfo) {
    291                 System.out.println(CldrUtility.LINE_SEPARATOR + "Showing Paths not in root"
    292                     + CldrUtility.LINE_SEPARATOR);
    293             }
    294 
    295             CLDRFile root = cldrFactory.make("root", true);
    296             for (Iterator<String> it = root.iterator(); it.hasNext();) {
    297                 pathToLocale.removeAll(it.next());
    298             }
    299             if (showInfo) for (String path : pathToLocale.keySet()) {
    300                 if (skipPaths.reset(path).find()) {
    301                     continue;
    302                 }
    303                 System.out.println(path + "\t" + pathToLocale.getAll(path));
    304             }
    305 
    306             if (badPaths.size() != 0) {
    307                 System.out.println("Error: " + badPaths.size()
    308                     + " Paths were not prettied: use -DSHOW and look for ones with %% in them.");
    309             }
    310         }
    311     }
    312 
    313     static void checkStock(Factory factory) {
    314         String[][] items = {
    315             { "full", "yMMMMEEEEd", "jmmsszzzz" },
    316             { "long", "yMMMMd", "jmmssz" },
    317             { "medium", "yMMMd", "jmmss" },
    318             { "short", "yMd", "jmm" },
    319         };
    320         String calendarID = "gregorian";
    321         String datetimePathPrefix = "//ldml/dates/calendars/calendar[@type=\"" + calendarID + "\"]/";
    322 
    323         int total = 0;
    324         int mismatch = 0;
    325         LanguageTagParser ltp = new LanguageTagParser();
    326         Iterable<String> locales = StandardCodes.make().getLocaleCoverageLocales(Organization.cldr, EnumSet.of(Level.MODERN));
    327         for (String locale : locales) {
    328             if (!ltp.set(locale).getRegion().isEmpty()) {
    329                 continue;
    330             }
    331             CLDRFile file = factory.make(locale, false);
    332             DateTimeFormats dtf = new DateTimeFormats();
    333             dtf.set(file, "gregorian", false);
    334             for (String[] stockInfo : items) {
    335                 String length = stockInfo[0];
    336                 //ldml/dates/calendars/calendar[@type="gregorian"]/dateFormats/dateFormatLength[@type="full"]/dateFormat[@type="standard"]/pattern[@type="standard"]
    337                 String path = datetimePathPrefix + "dateFormats/dateFormatLength[@type=\"" +
    338                     length + "\"]/dateFormat[@type=\"standard\"]/pattern[@type=\"standard\"]";
    339                 String stockDatePattern = file.getStringValue(path);
    340                 String flexibleDatePattern = dtf.getBestPattern(stockInfo[1]);
    341                 mismatch += showStatus(++total, locale, "date", length, stockInfo[1], stockDatePattern, flexibleDatePattern);
    342                 path = datetimePathPrefix + "timeFormats/timeFormatLength[@type=\"" + length +
    343                     "\"]/timeFormat[@type=\"standard\"]/pattern[@type=\"standard\"]";
    344                 String stockTimePattern = file.getStringValue(path);
    345                 String flexibleTimePattern = dtf.getBestPattern(stockInfo[2]);
    346                 mismatch += showStatus(++total, locale, "time", length, stockInfo[2], stockTimePattern, flexibleTimePattern);
    347             }
    348         }
    349         System.out.println("Mismatches:\t" + mismatch + "\tTotal:\t" + total);
    350     }
    351 
    352     static final Date SAMPLE_DATE = new Date(2013 - 1900, 1 - 1, 29, 13, 59, 59);
    353 
    354     private static int showStatus(int total, String locale, String type, String length,
    355         String skeleton, String stockPattern, String flexiblePattern) {
    356         ULocale ulocale = new ULocale(locale);
    357         DateFormatSymbols dfs = new DateFormatSymbols(ulocale); // just use ICU for now
    358         boolean areSame = Objects.equals(stockPattern, flexiblePattern);
    359         System.out.println(total
    360             + "\t" + (areSame ? "ok" : "diff")
    361             + "\t" + locale
    362             + "\t" + type
    363             + "\t" + length
    364             + "\t" + skeleton
    365             + "\t" + stockPattern
    366             + "\t" + (areSame ? "" : flexiblePattern)
    367             + "\t'" + new SimpleDateFormat(stockPattern, dfs, ulocale).format(SAMPLE_DATE)
    368             + "\t'" + (areSame ? "" : new SimpleDateFormat(flexiblePattern, dfs, ulocale).format(SAMPLE_DATE)));
    369         return areSame ? 0 : 1;
    370     }
    371 
    372 }