1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 8159943 8154797
27 * @modules java.base/sun.util.locale.provider
28 *          java.base/sun.util.resources
29 *          jdk.localedata
30 * @summary Test for checking consistency between CLDR and COMPAT locale data
31 *          for java.time.
32 */
33
34import java.util.Arrays;
35import java.util.HashMap;
36import java.util.List;
37import java.util.Locale;
38import java.util.Map;
39import java.util.Objects;
40import java.util.ResourceBundle;
41import java.util.Set;
42import java.util.TreeSet;
43import java.util.stream.Collectors;
44import sun.util.locale.provider.LocaleProviderAdapter.Type;
45import sun.util.locale.provider.LocaleProviderAdapter;
46
47public class JavaTimeSupplementaryTest {
48    // COMPAT-to-CLDR locale mapping
49    private static final Map<Locale, Locale> LOCALEMAP;
50    static {
51        LOCALEMAP = new HashMap<>();
52        LOCALEMAP.put(new Locale("hi", "IN"), new Locale("hi"));
53        LOCALEMAP.put(new Locale("no", "NO", "NY"), new Locale("nn", "NO"));
54        LOCALEMAP.put(new Locale("no"), new Locale("nb"));
55        LOCALEMAP.put(Locale.TAIWAN, Locale.forLanguageTag("zh-Hant"));
56        LOCALEMAP.put(new Locale("zh", "HK"), Locale.forLanguageTag("zh-Hant-HK"));
57        LOCALEMAP.put(new Locale("zh", "SG"), Locale.forLanguageTag("zh-Hans-SG"));
58        LOCALEMAP.put(new Locale("sr", "BA"), Locale.forLanguageTag("sr-Cyrl-BA"));
59    }
60
61    private static final String[] PREFIXES = {
62        "Quarter",
63        "java.time.",
64        "calendarname.",
65        "field.",
66        "islamic.",
67        "roc.",
68        "timezone."
69    };
70
71    // All available locales for the COMPAT FormatData resource bundles
72    static final List<Locale> COMPAT_LOCALES
73        = Arrays.asList(LocaleProviderAdapter.forJRE()
74                        .getDateFormatSymbolsProvider().getAvailableLocales());
75
76    static int errors;
77
78    public static void main(String... args) {
79        for (Locale locale : COMPAT_LOCALES) {
80            ResourceBundle compat
81                = LocaleProviderAdapter.forJRE()
82                      .getLocaleResources(locale).getJavaTimeFormatData();
83            if (!compat.getLocale().equals(locale)) {
84                continue;
85            }
86            Locale cldrLocale = toCldrLocale(locale);
87            ResourceBundle cldr
88                = LocaleProviderAdapter.forType(Type.CLDR)
89                      .getLocaleResources(locale).getJavaTimeFormatData();
90            if (!cldr.getLocale().equals(cldrLocale)) {
91                continue;
92            }
93            compareResources(compat, cldr);
94        }
95        if (errors > 0) {
96            throw new RuntimeException(errors + " failure(s)");
97        }
98    }
99
100    private static Locale toCldrLocale(Locale compatLocale) {
101        Locale loc = LOCALEMAP.get(compatLocale);
102        return loc != null ? loc: compatLocale;
103    }
104
105    private static void compareResources(ResourceBundle compat, ResourceBundle cldr) {
106        Set<String> supplementalKeys = getSupplementalKeys(compat);
107        for (String key : supplementalKeys) {
108            Object compatData = compat.getObject(key);
109            String cldrKey = toCldrKey(key);
110            Object cldrData = cldr.containsKey(cldrKey) ? cldr.getObject(cldrKey) : null;
111            if (!Objects.deepEquals(compatData, cldrData)) {
112                // OK if key is for the Buddhist or Japanese calendars which had been
113                // supported before java.time, or if key is "java.time.short.Eras" due
114                // to legacy era names.
115                if (!(key.contains("buddhist") || key.contains("japanese")
116                      || key.equals("java.time.short.Eras"))) {
117                    errors++;
118                    System.out.print("Failure: ");
119                }
120                System.out.println("diff: " + compat.getLocale().toLanguageTag() + "\n"
121                                   + "  COMPAT: " + key + " -> " + toString(compatData) + "\n"
122                                   + "    CLDR: " + cldrKey + " -> " + toString(cldrData));
123            }
124        }
125    }
126
127    private static Set<String> getSupplementalKeys(ResourceBundle rb) {
128        // Collect keys starting with any of PREFIXES
129        Set<String> keys = rb.keySet().stream()
130            .filter(k -> Arrays.stream(PREFIXES).anyMatch(p -> k.startsWith(p)))
131            .collect(Collectors.toCollection(TreeSet::new));
132        return keys;
133    }
134
135    /**
136     * Removes "java.time." prefix where it's unused in CLDR.
137     */
138    private static String toCldrKey(String key) {
139        if (key.contains("short.Eras")) {
140            key = key.replace("short.", "");
141        }
142        if (key.startsWith("java.time.") && key.endsWith(".Eras")) {
143            return key.substring("java.time.".length());
144        }
145        return key;
146    }
147
148    private static String toString(Object data) {
149        if (data instanceof String[]) {
150            return Arrays.toString((String[]) data);
151        }
152        return data.toString();
153    }
154}
155