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