1 /* 2 * Copyright (c) 2018, 2019, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @test 28 * @bug 4397357 6565620 6959267 7070436 7198195 8041791 8032446 8072600 29 * 8221431 30 * @summary Confirm special case mappings are handled correctly. 31 * @library /lib/testlibrary/java/lang 32 */ 33 34 import java.io.BufferedReader; 35 import java.io.IOException; 36 import java.nio.file.Files; 37 import java.nio.file.Paths; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Locale; 41 import java.util.StringTokenizer; 42 43 public class SpecialCasingTest { 44 45 private static boolean err = false; 46 47 // Locales which are used for testing 48 private static List<Locale> locales = new ArrayList<>(); 49 static { locales.add(new Locale(R, R))50 locales.add(new Locale("az", "")); java.util.Arrays.asList()51 locales.addAll(java.util.Arrays.asList(Locale.getAvailableLocales())); 52 } 53 54 // Default locale 55 private static String defaultLang; 56 57 // True if the default language is az, lt, or tr which has locale-specific 58 // mappings. 59 private static boolean specificLocale; 60 61 // Additional test cases 62 // Pseudo-locales which are used here: 63 // L1: locales other than lt 64 // L2: locales other than az and tr 65 // L3: locales other than az, lt and tr 66 private static final String[] additionalTestData = { 67 // Format: 68 // <code>; <lower>; <title>; <upper>; (<condition_list>) 69 70 // Counterpart of Final_Sigma test case 71 // 03A3; 03C2; 03A3; 03A3; Final_Sigma 72 "03A3; 03C3; 03A3; 03A3; SunSpecific_Not_Final_Sigma1", 73 "03A3; 03C3; 03A3; 03A3; SunSpecific_Not_Final_Sigma2", 74 75 // Counterpart of After_Soft_Dotted test case 76 // 0307; 0307; ; ; lt After_Soft_Dotted 77 "0307; 0307; 0307; 0307; L1 After_Soft_Dotted", 78 "0307; 0307; 0307; 0307; lt SunSpecific_Not_After_Soft_Dotted", 79 "0307; 0307; 0307; 0307; L1 SunSpecific_Not_After_Soft_Dotted", 80 81 // Counterpart of More_Above test cases 82 // 0049; 0069 0307; 0049; 0049; lt More_Above 83 "0049; 0131 ; 0049; 0049; az More_Above", 84 "0049; 0131 ; 0049; 0049; tr More_Above", 85 "0049; 0069 ; 0049; 0049; L3 More_Above", 86 "0049; 0069 ; 0049; 0049; lt SunSpecific_Not_More_Above", 87 "0049; 0131 ; 0049; 0049; az SunSpecific_Not_More_Above", 88 "0049; 0131 ; 0049; 0049; tr SunSpecific_Not_More_Above", 89 "0049; 0069 ; 0049; 0049; L3 SunSpecific_Not_More_Above", 90 // 004A; 006A 0307; 004A; 004A; lt More_Above 91 "004A; 006A ; 004A; 004A; L1 More_Above", 92 "004A; 006A ; 004A; 004A; lt SunSpecific_Not_More_Above", 93 "004A; 006A ; 004A; 004A; L1 SunSpecific_Not_More_Above", 94 // 012E; 012F 0307; 012E; 012E; lt More_Above 95 "012E; 012F ; 012E; 012E; L1 More_Above", 96 "012E; 012F ; 012E; 012E; lt SunSpecific_Not_More_Above", 97 "012E; 012F ; 012E; 012E; L1 SunSpecific_Not_More_Above", 98 99 // Counterpart of After_I test cases 100 // 0307; ; 0307; 0307; tr After_I 101 // 0307; ; 0307; 0307; az After_I 102 "0307; 0307 0307; 0307; 0307; lt After_I", 103 "0307; 0307 ; 0307; 0307; L3 After_I", 104 "0307; 0307 ; 0307; 0307; tr SunSpecific_Not_After_I", 105 "0307; 0307 ; 0307; 0307; az SunSpecific_Not_After_I", 106 "0307; 0307 ; 0307; 0307; L2 SunSpecific_Not_After_I", 107 108 // Counterpart of Not_Before_Dot test cases 109 // 0049; 0131 ; 0049; 0049; tr Not_Before_Dot 110 // 0049; 0131 ; 0049; 0049; az Not_Before_Dot 111 "0049; 0069 ; 0049; 0049; L2 Not_Before_Dot", 112 "0049; 0069 ; 0049; 0049; tr SunSpecific_Before_Dot", 113 "0049; 0069 ; 0049; 0049; az SunSpecific_Before_Dot", 114 "0049; 0069 0307 0307; 0049; 0049; lt SunSpecific_Before_Dot", 115 "0049; 0069 0307 ; 0049; 0049; L3 SunSpecific_Before_Dot", 116 }; 117 main(String[] args)118 public static void main (String[] args) { 119 SpecialCasingTest specialCasingTest = new SpecialCasingTest(); 120 specialCasingTest.test(); 121 } 122 test()123 private void test () { 124 Locale defaultLocale = Locale.getDefault(); 125 BufferedReader in = null; 126 127 try { 128 int locale_num = locales.size(); 129 for (int l = 0; l < locale_num; l++) { 130 Locale locale = locales.get(l); 131 Locale.setDefault(locale); 132 System.out.println("Testing on " + locale + " locale...."); 133 134 defaultLang = locale.getLanguage(); 135 if (defaultLang.equals("az") || 136 defaultLang.equals("lt") || 137 defaultLang.equals("tr")) { 138 specificLocale = true; 139 } else { 140 specificLocale = false; 141 } 142 in = Files.newBufferedReader(UCDFiles.SPECIAL_CASING.toRealPath()); 143 String line; 144 while ((line = in.readLine()) != null) { 145 if (line.length() == 0 || line.charAt(0) == '#') { 146 continue; 147 } 148 test(line); 149 } 150 in.close(); 151 in = null; 152 System.out.println("Testing with Sun original data...."); 153 for (String additionalTestData1 : additionalTestData) { 154 test(additionalTestData1); 155 } 156 } 157 } 158 catch (IOException e) { 159 err = true; 160 e.printStackTrace(); 161 } 162 finally { 163 if (in != null) { 164 try { 165 in.close(); 166 } 167 catch (IOException e) { 168 } 169 } 170 Locale.setDefault(defaultLocale); 171 if (err) { 172 throw new RuntimeException("SpecialCasingTest failed."); 173 } else { 174 System.out.println("*** SpecialCasingTest passed."); 175 } 176 } 177 } 178 test(String line)179 private void test(String line) { 180 int index = line.indexOf('#'); 181 if (index != -1) { 182 line = line.substring(0, index); 183 } 184 185 String lang = null; 186 String condition = null; 187 String[] fields = line.split("; "); 188 189 for (int i = 0; i < 4; i++) { 190 if (fields[i].length() != 0) { 191 fields[i] = convert(fields[i]); 192 } 193 } 194 if (fields.length != 4) { 195 StringTokenizer st = new StringTokenizer(fields[4]); 196 197 while (st.hasMoreTokens()) { 198 String token = st.nextToken(); 199 200 if (token.equals("Final_Sigma")) { 201 condition = "Final Sigma"; 202 fields[0] = "Abc" + fields[0]; 203 fields[1] = "abc" + fields[1]; 204 fields[3] = "ABC" + fields[3]; 205 } else if (token.equals("SunSpecific_Not_Final_Sigma1")) { 206 condition = "*Sun Specific* Not Final Sigma 1"; 207 fields[0] = "Abc" + fields[0] + "xyz"; 208 fields[1] = "abc" + fields[1] + "xyz"; 209 fields[3] = "ABC" + fields[3] + "XYZ"; 210 } else if (token.equals("SunSpecific_Not_Final_Sigma2")) { 211 condition = "*Sun Specific* Not Final Sigma 2"; 212 } else if (token.equals("After_Soft_Dotted")) { 213 condition = "After Soft-Dotted"; 214 fields[0] = "\u1E2D" + fields[0]; 215 fields[1] = "\u1E2D" + fields[1]; 216 fields[3] = "\u1E2C" + fields[3]; 217 } else if (token.equals("SunSpecific_Not_After_Soft_Dotted")) { 218 condition = "*Sun Specific* Not After Soft-Dotted"; 219 fields[0] = "Dot" + fields[0]; 220 fields[1] = "dot" + fields[1]; 221 fields[3] = "DOT" + fields[3]; 222 } else if (token.equals("More_Above")) { 223 condition = "More Above"; 224 fields[0] = fields[0] + "\u0306"; 225 fields[1] = fields[1] + "\u0306"; 226 fields[3] = fields[3] + "\u0306"; 227 } else if (token.equals("SunSpecific_Not_More_Above")) { 228 condition = "*Sun Specific* Not More Above"; 229 fields[0] = fields[0] + "breve"; 230 fields[1] = fields[1] + "breve"; 231 fields[3] = fields[3] + "BREVE"; 232 } else if (token.equals("After_I")) { 233 condition = "After I"; 234 fields[0] = "I" + fields[0]; 235 fields[1] = "i" + fields[1]; 236 fields[3] = "I" + fields[3]; 237 } else if (token.equals("SunSpecific_Not_After_I")) { 238 condition = "*Sun Specific* Not After I"; 239 fields[0] = "A" + fields[0]; 240 fields[1] = "a" + fields[1]; 241 fields[3] = "A" + fields[3]; 242 } else if (token.equals("Not_Before_Dot")) { 243 condition = "Not Before Dot"; 244 fields[0] = fields[0] + "Z"; 245 fields[1] = fields[1] + "z"; 246 fields[3] = fields[3] + "Z"; 247 } else if (token.equals("SunSpecific_Before_Dot")) { 248 condition = "*Sun Specific* Before Dot"; 249 fields[0] = fields[0] + "\u0307"; 250 fields[3] = fields[3] + "\u0307"; 251 } else if (token.length() == 2) { 252 lang = token; 253 254 if (lang.equals("L1")) { 255 if (defaultLang.equals("lt")) { 256 lang = "en"; 257 } else { 258 lang = defaultLang; 259 } 260 } else if (lang.equals("L2")) { 261 if (defaultLang.equals("az") || 262 defaultLang.equals("tr")) { 263 lang = "en"; 264 } else { 265 lang = defaultLang; 266 } 267 } else if (lang.equals("L3")) { 268 if (defaultLang.equals("az") || 269 defaultLang.equals("lt") || 270 defaultLang.equals("tr")) { 271 lang = "en"; 272 } else { 273 lang = defaultLang; 274 } 275 // I want to have another test case here for double-check. 276 // Current implementation for Character and String considers 277 // only az, lt, and tr locales. I want to detect if other 278 // locales are specified. 279 } else if (!lang.equals("az") && 280 !lang.equals("lt") && 281 !lang.equals("tr")) { 282 throw new RuntimeException("Unsupported locale: " + 283 lang + ". It may need to be considered in ConditionalSpecialCasing.java. Please confirm."); 284 } 285 } else { 286 throw new RuntimeException("Unknown condition: " + token); 287 } 288 } 289 } else if (fields[0].equals("\u0130")) { 290 // special case for \u0130 291 if (defaultLang.equals("az") || 292 defaultLang.equals("tr")) { 293 lang = "en"; 294 } else { 295 lang = defaultLang; 296 } 297 } 298 testLowerCase(fields[0], fields[1], lang, condition); 299 testUpperCase(fields[0], fields[3], lang, condition); 300 } 301 testLowerCase(String orig, String expected, String lang, String condition)302 private void testLowerCase(String orig, String expected, 303 String lang, String condition) { 304 String got = (lang == null) ? 305 orig.toLowerCase() : orig.toLowerCase(new Locale(lang, "")); 306 307 if (!expected.equals(got)) { 308 err = true; 309 System.err.println("toLowerCase(lang=" + lang + 310 ") failed.\n\tOriginal: " + toString(orig) + 311 "\n\tGot: " + toString(got) + 312 "\n\tExpected: " + toString(expected) + 313 ((condition == null) ? "" : ("\n under condition(" + 314 condition + ")"))); 315 } 316 } 317 testUpperCase(String orig, String expected, String lang, String condition)318 private void testUpperCase(String orig, String expected, 319 String lang, String condition) { 320 String got = (lang == null) ? 321 orig.toUpperCase() : orig.toUpperCase(new Locale(lang, "")); 322 323 if (!expected.equals(got)) { 324 err = true; 325 System.err.println("toUpperCase(lang=" + lang + 326 ") failed.\n\tOriginal: " + toString(orig) + 327 "\n\tGot: " + toString(got) + 328 "\n\tExpected: " + toString(expected) + 329 ((condition == null) ? "" : ("\n under condition(" + 330 condition + ")"))); 331 } 332 } 333 StringBuilder sb = new StringBuilder(); 334 convert(String str)335 private String convert(String str) { 336 sb.setLength(0); 337 338 String[] tokens = str.split(" "); 339 for (String token : tokens) { 340 sb.append((char) Integer.parseInt(token, 16)); 341 } 342 return sb.toString(); 343 } 344 toString(String str)345 private String toString(String str) { 346 sb.setLength(0); 347 348 int len = str.length(); 349 for (int i = 0; i < len; i++) { 350 sb.append("0x").append(Integer.toHexString(str.charAt(i)).toUpperCase()).append(" "); 351 } 352 return sb.toString(); 353 } 354 355 } 356