• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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