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