1 /*
   2  * Copyright (c) 2016, 2020, 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 8040211 8191404 8203872 8222980 8225435 8241082 8242010
  27  * @summary Checks the IANA language subtag registry data update
  28  *          (LSR Revision: 2020-04-01) with Locale and Locale.LanguageRange
  29  *          class methods.
  30  * @run main Bug8040211
  31  */
  32 
  33 import java.util.ArrayList;
  34 import java.util.Iterator;
  35 import java.util.Locale;
  36 import java.util.List;
  37 import java.util.Locale.LanguageRange;
  38 import java.util.Locale.FilteringMode;
  39 import static java.util.Locale.FilteringMode.EXTENDED_FILTERING;
  40 
  41 public class Bug8040211 {
  42 
  43     static boolean err = false;
  44 
  45     private static final String ACCEPT_LANGUAGE =
  46         "Accept-Language: aam, adp, aog, aue, bcg, bpp, cey, cnp, cqu, csp, dif, dmw, ema,"
  47         + " en-gb-oed, gti, kdz, koj, kru, kwq, kxe, kzk, lii, lmm, lsn, lsv, lvi, mtm,"
  48         + " ngv, nns, oyb, phr, pnd, pub, scv, snz, suj, szy, taj, tjj, tjp, tvx,"
  49         + " uss, uth, wkr;q=0.9, ar-hyw;q=0.8, yug;q=0.5, gfx;q=0.4";
  50     private static final List<LanguageRange> EXPECTED_RANGE_LIST = List.of(
  51             new LanguageRange("aam", 1.0),
  52             new LanguageRange("aas", 1.0),
  53             new LanguageRange("adp", 1.0),
  54             new LanguageRange("dz", 1.0),
  55             new LanguageRange("aog", 1.0),
  56             new LanguageRange("myd", 1.0),
  57             new LanguageRange("aue", 1.0),
  58             new LanguageRange("ktz", 1.0),
  59             new LanguageRange("bcg", 1.0),
  60             new LanguageRange("bgm", 1.0),
  61             new LanguageRange("bpp", 1.0),
  62             new LanguageRange("nxu", 1.0),
  63             new LanguageRange("cey", 1.0),
  64             new LanguageRange("cnp", 1.0),
  65             new LanguageRange("zh-cnp", 1.0),
  66             new LanguageRange("cqu", 1.0),
  67             new LanguageRange("quh", 1.0),
  68             new LanguageRange("csp", 1.0),
  69             new LanguageRange("zh-csp", 1.0),
  70             new LanguageRange("dif", 1.0),
  71             new LanguageRange("dit", 1.0),
  72             new LanguageRange("dmw", 1.0),
  73             new LanguageRange("xrq", 1.0),
  74             new LanguageRange("ema", 1.0),
  75             new LanguageRange("uok", 1.0),
  76             new LanguageRange("en-gb-oed", 1.0),
  77             new LanguageRange("en-gb-oxendict", 1.0),
  78             new LanguageRange("gti", 1.0),
  79             new LanguageRange("nyc", 1.0),
  80             new LanguageRange("kdz", 1.0),
  81             new LanguageRange("ncp", 1.0),
  82             new LanguageRange("koj", 1.0),
  83             new LanguageRange("kwv", 1.0),
  84             new LanguageRange("kru", 1.0),
  85             new LanguageRange("kxl", 1.0),
  86             new LanguageRange("kwq", 1.0),
  87             new LanguageRange("yam", 1.0),
  88             new LanguageRange("kxe", 1.0),
  89             new LanguageRange("tvd", 1.0),
  90             new LanguageRange("kzk", 1.0),
  91             new LanguageRange("gli", 1.0),
  92             new LanguageRange("drr", 1.0),
  93             new LanguageRange("lii", 1.0),
  94             new LanguageRange("raq", 1.0),
  95             new LanguageRange("lmm", 1.0),
  96             new LanguageRange("rmx", 1.0),
  97             new LanguageRange("lsn", 1.0),
  98             new LanguageRange("sgn-lsn", 1.0),
  99             new LanguageRange("lsv", 1.0),
 100             new LanguageRange("sgn-lsv", 1.0),
 101             new LanguageRange("lvi", 1.0),
 102             new LanguageRange("mtm", 1.0),
 103             new LanguageRange("ymt", 1.0),
 104             new LanguageRange("ngv", 1.0),
 105             new LanguageRange("nnx", 1.0),
 106             new LanguageRange("nns", 1.0),
 107             new LanguageRange("nbr", 1.0),
 108             new LanguageRange("oyb", 1.0),
 109             new LanguageRange("thx", 1.0),
 110             new LanguageRange("skk", 1.0),
 111             new LanguageRange("jeg", 1.0),
 112             new LanguageRange("phr", 1.0),
 113             new LanguageRange("pmu", 1.0),
 114             new LanguageRange("pnd", 1.0),
 115             new LanguageRange("pub", 1.0),
 116             new LanguageRange("puz", 1.0),
 117             new LanguageRange("scv", 1.0),
 118             new LanguageRange("zir", 1.0),
 119             new LanguageRange("snz", 1.0),
 120             new LanguageRange("asd", 1.0),
 121             new LanguageRange("suj", 1.0),
 122             new LanguageRange("szy", 1.0),
 123             new LanguageRange("taj", 1.0),
 124             new LanguageRange("tsf", 1.0),
 125             new LanguageRange("tjj", 1.0),
 126             new LanguageRange("tjp", 1.0),
 127             new LanguageRange("tvx", 1.0),
 128             new LanguageRange("uss", 1.0),
 129             new LanguageRange("uth", 1.0),
 130             new LanguageRange("wkr", 0.9),
 131             new LanguageRange("ar-hyw", 0.8),
 132             new LanguageRange("yug", 0.5),
 133             new LanguageRange("yuu", 0.5),
 134             new LanguageRange("gfx", 0.4),
 135             new LanguageRange("oun", 0.4),
 136             new LanguageRange("mwj", 0.4),
 137             new LanguageRange("vaj", 0.4)
 138         );
 139 
 140     public static void main(String[] args) {
 141         testLanguageRange();
 142         testLocale();
 143 
 144         if (err) {
 145             throw new RuntimeException("Failed.");
 146         }
 147     }
 148 
 149     private static void testLanguageRange() {
 150         System.out.println("Test LanguageRange class parse method...");
 151         test_parse();
 152     }
 153 
 154     private static void testLocale() {
 155         System.out.println("Test Locale class methods...");
 156         test_filter();
 157         test_filterTags();
 158         test_lookup();
 159         test_lookupTag();
 160     }
 161 
 162     private static void test_parse() {
 163         boolean error = false;
 164         List<LanguageRange> got = LanguageRange.parse(ACCEPT_LANGUAGE);
 165         if (!areEqual(EXPECTED_RANGE_LIST, got)) {
 166             error = true;
 167             System.err.println("    language parse() test failed.");
 168         }
 169 
 170         if (error) {
 171             err = true;
 172             System.out.println("  test_parse() failed.");
 173         } else {
 174             System.out.println("  test_parse() passed.");
 175         }
 176 
 177     }
 178 
 179     private static boolean areEqual(List<LanguageRange> expected,
 180             List<LanguageRange> got) {
 181         boolean error = false;
 182 
 183         int expectedSize = expected.size();
 184         int actualSize = got.size();
 185 
 186         if (expectedSize != actualSize) {
 187             error = true;
 188 
 189             System.err.println("  Expected size=" + expectedSize);
 190             for (LanguageRange lr : expected) {
 191                 System.err.println("    range=" + lr.getRange()
 192                         + ", weight=" + lr.getWeight());
 193             }
 194 
 195             System.err.println("  Actual size=" + actualSize);
 196             for (LanguageRange lr : got) {
 197                 System.err.println("    range=" + lr.getRange()
 198                         + ", weight=" + lr.getWeight());
 199             }
 200         } else {
 201             for (int i = 0; i < expectedSize; i++) {
 202                 LanguageRange lr1 = expected.get(i);
 203                 LanguageRange lr2 = got.get(i);
 204 
 205                 if (!lr1.getRange().equals(lr2.getRange())
 206                         || lr1.getWeight() != lr2.getWeight()) {
 207                     error = true;
 208                     System.err.println("  " + i + ": Expected: range=" + lr1.getRange()
 209                             + ", weight=" + lr1.getWeight());
 210                     System.err.println("  " + i + ": Actual:   range=" + lr2.getRange()
 211                             + ", weight=" + lr2.getWeight());
 212                 }
 213             }
 214         }
 215 
 216         return !error;
 217     }
 218 
 219     private static void test_filter() {
 220         boolean error = false;
 221 
 222         String ranges = "mtm-RU, en-gb-oed, coy, ar-HY";
 223         String tags = "de-DE, en, mtm-RU, ymt-RU, en-gb-oxendict, ja-JP, pij, nts, ar-arevela";
 224         FilteringMode mode = EXTENDED_FILTERING;
 225 
 226         List<LanguageRange> priorityList = LanguageRange.parse(ranges);
 227         List<Locale> tagList = generateLocales(tags);
 228         String actualLocales
 229                 = showLocales(Locale.filter(priorityList, tagList, mode));
 230         String expectedLocales = "mtm-RU, ymt-RU, en-GB-oxendict, nts, pij";
 231 
 232         if (!expectedLocales.equals(actualLocales)) {
 233             error = true;
 234             showErrorMessage("#1 filter(" + mode + ")",
 235                     ranges, tags, expectedLocales, actualLocales);
 236         }
 237 
 238         ranges = "phr-*-IN, ja-JP";
 239         tags = "en, pmu-Guru-IN, ja-Latn-JP, iw";
 240         mode = EXTENDED_FILTERING;
 241 
 242         priorityList = LanguageRange.parse(ranges);
 243         tagList = generateLocales(tags);
 244         actualLocales = showLocales(Locale.filter(priorityList, tagList, mode));
 245         expectedLocales = "pmu-Guru-IN, ja-Latn-JP";
 246 
 247         if (!expectedLocales.equals(actualLocales)) {
 248             error = true;
 249             showErrorMessage("#2 filter(" + mode + ")",
 250                     ranges, tags, expectedLocales, actualLocales);
 251         }
 252 
 253         if (error) {
 254             err = true;
 255             System.out.println("  test_filter() failed.");
 256         } else {
 257             System.out.println("  test_filter() passed.");
 258         }
 259     }
 260 
 261     private static void test_filterTags() {
 262         boolean error = false;
 263 
 264         String ranges = "gti;q=0.2, gfx, kzj";
 265         String tags = "de-DE, gti, he, nyc, mwj, vaj, ktr, dtp";
 266 
 267         List<LanguageRange> priorityList = LanguageRange.parse(ranges);
 268         List<String> tagList = generateLanguageTags(tags);
 269         String actualTags
 270                 = showLanguageTags(Locale.filterTags(priorityList, tagList));
 271         String expectedTags = "mwj, vaj, ktr, dtp, gti, nyc";
 272 
 273         if (!expectedTags.equals(actualTags)) {
 274             error = true;
 275             showErrorMessage("filterTags()",
 276                     ranges, tags, expectedTags, actualTags);
 277         }
 278 
 279         if (error) {
 280             err = true;
 281             System.out.println("  test_filterTags() failed.");
 282         } else {
 283             System.out.println("  test_filterTags() passed.");
 284         }
 285     }
 286 
 287     private static void test_lookup() {
 288         boolean error = false;
 289 
 290         String ranges = "en;q=0.2, yam, rmx;q=0.9";
 291         String tags = "de-DE, en, kwq, lmm";
 292         List<LanguageRange> priorityList = LanguageRange.parse(ranges);
 293         List<Locale> localeList = generateLocales(tags);
 294         String actualLocale
 295                 = Locale.lookup(priorityList, localeList).toLanguageTag();
 296         String expectedLocale = "kwq";
 297 
 298         if (!expectedLocale.equals(actualLocale)) {
 299             error = true;
 300             showErrorMessage("lookup()", ranges, tags, expectedLocale, actualLocale);
 301         }
 302 
 303         if (error) {
 304             err = true;
 305             System.out.println("  test_lookup() failed.");
 306         } else {
 307             System.out.println("  test_lookup() passed.");
 308         }
 309     }
 310 
 311     private static void test_lookupTag() {
 312         boolean error = false;
 313 
 314         String ranges = "en, tsf;q=0.2";
 315         String tags = "es, ja-JP, taj";
 316         List<LanguageRange> priorityList = LanguageRange.parse(ranges);
 317         List<String> tagList = generateLanguageTags(tags);
 318         String actualTag = Locale.lookupTag(priorityList, tagList);
 319         String expectedTag = "taj";
 320 
 321         if (!expectedTag.equals(actualTag)) {
 322             error = true;
 323             showErrorMessage("lookupTag()", ranges, tags, expectedTag, actualTag);
 324         }
 325 
 326         if (error) {
 327             err = true;
 328             System.out.println("  test_lookupTag() failed.");
 329         } else {
 330             System.out.println("  test_lookupTag() passed.");
 331         }
 332     }
 333 
 334     private static List<Locale> generateLocales(String tags) {
 335         if (tags == null) {
 336             return null;
 337         }
 338 
 339         List<Locale> localeList = new ArrayList<>();
 340         if (tags.equals("")) {
 341             return localeList;
 342         }
 343         String[] t = tags.split(", ");
 344         for (String tag : t) {
 345             localeList.add(Locale.forLanguageTag(tag));
 346         }
 347         return localeList;
 348     }
 349 
 350     private static List<String> generateLanguageTags(String tags) {
 351         List<String> tagList = new ArrayList<>();
 352         String[] t = tags.split(", ");
 353         for (String tag : t) {
 354             tagList.add(tag);
 355         }
 356         return tagList;
 357     }
 358 
 359     private static String showLanguageTags(List<String> tags) {
 360         StringBuilder sb = new StringBuilder();
 361 
 362         Iterator<String> itr = tags.iterator();
 363         if (itr.hasNext()) {
 364             sb.append(itr.next());
 365         }
 366         while (itr.hasNext()) {
 367             sb.append(", ");
 368             sb.append(itr.next());
 369         }
 370 
 371         return sb.toString().trim();
 372     }
 373 
 374     private static String showLocales(List<Locale> locales) {
 375         StringBuilder sb = new StringBuilder();
 376 
 377         java.util.Iterator<Locale> itr = locales.iterator();
 378         if (itr.hasNext()) {
 379             sb.append(itr.next().toLanguageTag());
 380         }
 381         while (itr.hasNext()) {
 382             sb.append(", ");
 383             sb.append(itr.next().toLanguageTag());
 384         }
 385 
 386         return sb.toString().trim();
 387     }
 388 
 389     private static void showErrorMessage(String methodName,
 390             String priorityList,
 391             String tags,
 392             String expectedTags,
 393             String actualTags) {
 394         System.err.println("\nIncorrect " + methodName + " result.");
 395         System.err.println("  Priority list  :  " + priorityList);
 396         System.err.println("  Language tags  :  " + tags);
 397         System.err.println("  Expected value : " + expectedTags);
 398         System.err.println("  Actual value   : " + actualTags);
 399     }
 400 
 401 }
 402