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