1 /* 2 * Copyright (c) 2007, 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 4830803 4886934 6565620 6959267 7070436 7198195 8032446 8072600 8202771 29 * 8221431 30 * @summary Check that the UnicodeBlock forName() method works as expected 31 * and block ranges are correct for all Unicode characters. 32 * @library /lib/testlibrary/java/lang 33 * @run main CheckBlocks 34 * @author John O'Conner 35 */ 36 37 package test.java.lang.Character.UnicodeBlock; 38 39 import java.io.InputStreamReader; 40 import java.lang.Character.UnicodeBlock; 41 import java.lang.reflect.Field; 42 import java.io.BufferedReader; 43 import java.io.File; 44 import java.io.FileReader; 45 import java.util.HashSet; 46 import java.util.Locale; 47 48 import test.java.lang.UCDFiles; 49 50 public class CheckBlocks { 51 52 static boolean err = false; 53 static Class<?> clazzUnicodeBlock; 54 main(String[] args)55 public static void main(String[] args) throws Exception { 56 generateBlockList(); 57 58 try { 59 clazzUnicodeBlock = Class.forName("java.lang.Character$UnicodeBlock"); 60 } catch (ClassNotFoundException e) { 61 throw new RuntimeException("Class.forName(\"java.lang.Character$UnicodeBlock\") failed."); 62 } 63 64 for (Block blk : blocks) { 65 test4830803_1(blk); 66 test4830803_2(); 67 test4886934(blk); 68 } 69 70 test8202771(); 71 72 if (err) { 73 throw new RuntimeException("Failed"); 74 } else { 75 System.out.println("Passed"); 76 } 77 } 78 79 /** 80 * Check that the UnicodeBlock forName() method works as expected. 81 */ test4830803_1(Block blk)82 private static void test4830803_1(Block blk) throws Exception { 83 84 /* 85 * Try 3 forms of block name in the forName() method. Each form should 86 * produce the same expected block. 87 */ 88 String blkName = blk.getName(); 89 90 // For backward compatibility 91 switch (blkName) { 92 case "COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS": 93 blkName = "COMBINING_MARKS_FOR_SYMBOLS"; 94 System.out.println("*** COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS" 95 + " is replaced with COMBINING_MARKS_FOR_SYMBOLS" 96 + " for backward compatibility."); 97 break; 98 case "GREEK_AND_COPTIC": 99 blkName = "GREEK"; 100 System.out.println("*** GREEK_AND_COPTIC is replaced with GREEK" 101 + " for backward compatibility."); 102 break; 103 case "CYRILLIC_SUPPLEMENT": 104 blkName = "CYRILLIC_SUPPLEMENTARY"; 105 System.out.println("*** CYRILLIC_SUPPLEMENT is replaced with" 106 + " CYRILLIC_SUPPLEMENTARY for backward compatibility."); 107 break; 108 default: 109 break; 110 } 111 112 String expectedBlock = null; 113 try { 114 expectedBlock = clazzUnicodeBlock.getField(blkName).getName(); 115 } catch (NoSuchFieldException | SecurityException e) { 116 System.err.println("Error: " + blkName + " was not found."); 117 err = true; 118 return; 119 } 120 121 String canonicalBlockName = blk.getOriginalName(); 122 String idBlockName = expectedBlock; 123 String regexBlockName = toRegExString(canonicalBlockName); 124 125 if (regexBlockName == null) { 126 System.err.println("Error: Block name which was processed with regex was null."); 127 err = true; 128 return; 129 } 130 131 if (!expectedBlock.equals(UnicodeBlock.forName(canonicalBlockName).toString())) { 132 System.err.println("Error #1: UnicodeBlock.forName(\"" + 133 canonicalBlockName + "\") returned wrong value.\n\tGot: " + 134 UnicodeBlock.forName(canonicalBlockName) + 135 "\n\tExpected: " + expectedBlock); 136 err = true; 137 } 138 139 if (!expectedBlock.equals(UnicodeBlock.forName(idBlockName).toString())) { 140 System.err.println("Error #2: UnicodeBlock.forName(\"" + 141 idBlockName + "\") returned wrong value.\n\tGot: " + 142 UnicodeBlock.forName(idBlockName) + 143 "\n\tExpected: " + expectedBlock); 144 err = true; 145 } 146 147 if (!expectedBlock.equals(UnicodeBlock.forName(regexBlockName).toString())) { 148 System.err.println("Error #3: UnicodeBlock.forName(\"" + 149 regexBlockName + "\") returned wrong value.\n\tGot: " + 150 UnicodeBlock.forName(regexBlockName) + 151 "\n\tExpected: " + expectedBlock); 152 err = true; 153 } 154 } 155 156 /** 157 * now try a bad block name. This should produce an IAE. 158 */ test4830803_2()159 private static void test4830803_2() { 160 boolean threwExpected = false; 161 162 try { 163 UnicodeBlock block = UnicodeBlock.forName("notdefined"); 164 } 165 catch(IllegalArgumentException e) { 166 threwExpected = true; 167 } 168 169 if (threwExpected == false) { 170 System.err.println("Error: UnicodeBlock.forName(\"notdefined\") should throw IllegalArgumentException."); 171 err = true; 172 } 173 } 174 175 /** 176 * Convert the argument to a block name form used by the regex package. 177 * That is, remove all spaces. 178 */ toRegExString(String str)179 private static String toRegExString(String str) { 180 String[] tokens = null; 181 StringBuilder retStr = new StringBuilder(); 182 try { 183 tokens = str.split(" "); 184 } 185 catch(java.util.regex.PatternSyntaxException e) { 186 return null; 187 } 188 for(int x=0; x < tokens.length; ++x) { 189 retStr.append(tokens[x]); 190 } 191 return retStr.toString(); 192 } 193 test4886934(Block blk)194 private static void test4886934(Block blk) { 195 String blkName = blk.getName(); 196 String blkOrigName = blk.getOriginalName(); 197 UnicodeBlock block; 198 String blockName; 199 200 // For backward compatibility 201 switch (blkName) { 202 case "COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS": 203 blkName = "COMBINING_MARKS_FOR_SYMBOLS"; 204 System.out.println("*** COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS" 205 + " is replaced with COMBINING_MARKS_FOR_SYMBOLS" 206 + " for backward compatibility."); 207 break; 208 case "GREEK_AND_COPTIC": 209 blkName = "GREEK"; 210 System.out.println("*** GREEK_AND_COPTIC is replaced with GREEK" 211 + " for backward compatibility."); 212 break; 213 case "CYRILLIC_SUPPLEMENT": 214 blkName = "CYRILLIC_SUPPLEMENTARY"; 215 System.out.println("*** CYRILLIC_SUPPLEMENT is replaced with" 216 + " CYRILLIC_SUPPLEMENTARY for backward compatibility."); 217 break; 218 default: 219 break; 220 } 221 222 for (int ch = blk.getBegin(); ch <= blk.getEnd(); ch++) { 223 block = UnicodeBlock.of(ch); 224 if (block == null) { 225 System.err.println("Error: The block for " + blkName 226 + " is missing. Please check java.lang.Character.UnicodeBlock."); 227 err = true; 228 break; 229 } 230 blockName = block.toString(); 231 if (!blockName.equals(blkName)) { 232 System.err.println("Error: Character(0x" 233 + Integer.toHexString(ch).toUpperCase() 234 + ") should be in \"" + blkName + "\" block " 235 + "(Block name is \"" + blkOrigName + "\")" 236 + " but found in \"" + blockName + "\" block."); 237 err = true; 238 } 239 } 240 } 241 242 /** 243 * Check if every Field of Character.UnicodeBlock is a valid Unicode Block. 244 */ test8202771()245 private static void test8202771() { 246 Field[] fields = clazzUnicodeBlock.getFields(); 247 248 for (Field f : fields) { 249 // Handle Deprecated field "SURROGATES_AREA". 250 if (f.getAnnotation(Deprecated.class) != null) { 251 continue; 252 } 253 254 String blkName = f.getName(); 255 switch (blkName) { 256 case "COMBINING_MARKS_FOR_SYMBOLS": 257 validateBlock("COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS"); 258 break; 259 case "GREEK": 260 validateBlock("GREEK_AND_COPTIC"); 261 break; 262 case "CYRILLIC_SUPPLEMENTARY": 263 validateBlock("CYRILLIC_SUPPLEMENT"); 264 break; 265 default: 266 validateBlock(blkName); 267 break; 268 } 269 } 270 } 271 validateBlock(String blkName)272 private static void validateBlock(String blkName) { 273 for (Block block : blocks) { 274 String blockName = block.getName(); 275 if (blockName.equals(blkName)) { 276 return; 277 } 278 } 279 err = true; 280 System.err.println(blkName + " is not a valid Unicode Block."); 281 } 282 283 // List of all Unicode blocks, their start, and end codepoints. 284 public static HashSet<Block> blocks = new HashSet<>(); 285 generateBlockList()286 private static void generateBlockList() throws Exception { 287 // Android-changed: Unicode data is packaged as resources in CTS. 288 // File blockData = UCDFiles.BLOCKS.toFile(); 289 // try (BufferedReader f = new BufferedReader(new FileReader(blockData))) { 290 try (var f = new BufferedReader(new InputStreamReader(UCDFiles.BLOCKS.openStream()))) { 291 String line; 292 while ((line = f.readLine()) != null) { 293 if (line.length() == 0 || line.charAt(0) == '#') { 294 continue; 295 } 296 297 int index1 = line.indexOf('.'); 298 int begin = Integer.parseInt(line.substring(0, index1), 16); 299 int index2 = line.indexOf(';'); 300 int end = Integer.parseInt(line.substring(index1 + 2, index2), 16); 301 String name = line.substring(index2 + 1).trim(); 302 303 System.out.println(" Adding a Block(" + Integer.toHexString(begin) + ", " + Integer.toHexString(end) 304 + ", " + name + ")"); 305 blocks.add(new Block(begin, end, name)); 306 } 307 } 308 } 309 } 310 311 class Block { 312 Block()313 public Block() { 314 blockBegin = 0; 315 blockEnd = 0; 316 blockName = null; 317 } 318 Block(int begin, int end, String name)319 public Block(int begin, int end, String name) { 320 blockBegin = begin; 321 blockEnd = end; 322 blockName = name.replaceAll("[ -]", "_").toUpperCase(Locale.ENGLISH); 323 originalBlockName = name; 324 } 325 getBegin()326 public int getBegin() { 327 return blockBegin; 328 } 329 getEnd()330 public int getEnd() { 331 return blockEnd; 332 } 333 getName()334 public String getName() { 335 return blockName; 336 } 337 getOriginalName()338 public String getOriginalName() { 339 return originalBlockName; 340 } 341 342 @Override equals(Object obj)343 public boolean equals(Object obj) { 344 if (obj == null) return false; 345 if (!(obj instanceof Block)) return false; 346 347 Block other = (Block)obj; 348 return other.blockBegin == blockBegin && 349 other.blockEnd == blockEnd && 350 other.blockName.equals(blockName) && 351 other.originalBlockName.equals(originalBlockName); 352 } 353 int blockBegin, blockEnd; 354 String blockName, originalBlockName; 355 } 356