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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8202771
27  * @summary Check j.l.Character.isDigit/isLetter/isLetterOrDigit/isSpaceChar
28  * /isWhitespace/isTitleCase/isISOControl/isIdentifierIgnorable
29  * /isJavaIdentifierStart/isJavaIdentifierPart/isUnicodeIdentifierStart
30  * /isUnicodeIdentifierPart
31  * @run main CharPropTest
32  */
33 
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.util.stream.Stream;
38 
39 public class CharPropTest {
40     private static int diffs = 0;
41     private static int rangeStart = 0x0000;
42     private static boolean isRange = false;
43 
main(String[] args)44     public static void main(String[] args) throws Exception {
45         Path path = Paths.get(System.getProperty("test.src", "."),
46                 "UnicodeData.txt");
47         try (Stream<String> lines = Files.lines(path)) {
48             lines.map(String::trim)
49                  .filter(line -> line.length() != 0 && line.charAt(0) != '#')
50                  .forEach(line -> handleOneLine(line));
51 
52             if (diffs != 0) {
53                 throw new RuntimeException("Total differences: " + diffs);
54             }
55         }
56     }
57 
handleOneLine(String line)58     private static void handleOneLine(String line) {
59         String[] fields = line.split(";");
60         int currentCp = Integer.parseInt(fields[0], 16);
61         String name = fields[1];
62         String category = fields[2];
63 
64         // Except single code point, also handle ranges like the following:
65         // 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
66         // 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;
67         if (isRange) {
68             if (name.endsWith("Last>")) {
69                 for (int cp = rangeStart; cp <= currentCp; cp++) {
70                     testCodePoint(cp, category);
71                 }
72             } else {
73                 throw new RuntimeException("Not a valid range, first range <"
74                         + Integer.toHexString(rangeStart) + "> without last.");
75             }
76             isRange = false;
77         } else {
78             if (name.endsWith("First>")) {
79                 rangeStart = currentCp;
80                 isRange = true;
81             } else {
82                 testCodePoint(currentCp, category);
83             }
84         }
85     }
86 
testCodePoint(int codePoint, String category)87     private static void testCodePoint(int codePoint, String category) {
88         isDigitTest(codePoint, category);
89         isLetterTest(codePoint, category);
90         isLetterOrDigitTest(codePoint, category);
91 
92         isSpaceCharTest(codePoint, category);
93         isWhitespaceTest(codePoint, category);
94 
95         isTitleCaseTest(codePoint, category);
96 
97         isISOControlTest(codePoint);
98 
99         isIdentifierIgnorableTest(codePoint, category);
100         isJavaIdentifierStartTest(codePoint, category);
101         isJavaIdentifierPartTest(codePoint, category);
102         isUnicodeIdentifierStartTest(codePoint, category);
103         isUnicodeIdentifierPartTest(codePoint, category);
104     }
105 
isDigitTest(int codePoint, String category)106     private static void isDigitTest(int codePoint, String category) {
107         boolean actual = Character.isDigit(codePoint);
108         boolean expected = category.equals("Nd");
109         if (actual != expected) {
110             printDiff(codePoint, "isDigit", actual, expected);
111         }
112     }
113 
isLetterTest(int codePoint, String category)114     private static void isLetterTest(int codePoint, String category) {
115         boolean actual = Character.isLetter(codePoint);
116         boolean expected = isLetter(category);
117         if (actual != expected) {
118             printDiff(codePoint, "isLetter", actual, expected);
119         }
120     }
121 
isLetterOrDigitTest(int codePoint, String category)122     private static void isLetterOrDigitTest(int codePoint, String category) {
123         boolean actual = Character.isLetterOrDigit(codePoint);
124         boolean expected = isLetter(category) || category.equals("Nd");
125         if (actual != expected) {
126             printDiff(codePoint, "isLetterOrDigit", actual, expected);
127         }
128     }
129 
isSpaceCharTest(int codePoint, String category)130     private static void isSpaceCharTest(int codePoint, String category) {
131         boolean actual = Character.isSpaceChar(codePoint);
132         boolean expected = isSpaceChar(category);
133         if (actual != expected) {
134             printDiff(codePoint, "isSpaceChar", actual, expected);
135         }
136     }
137 
isWhitespaceTest(int codePoint, String category)138     private static void isWhitespaceTest(int codePoint, String category) {
139         boolean actual = Character.isWhitespace(codePoint);
140         boolean expected = isWhitespace(codePoint, category);
141         if (actual != expected) {
142             printDiff(codePoint, "isWhitespace", actual, expected);
143         }
144     }
145 
isTitleCaseTest(int codePoint, String category)146     private static void isTitleCaseTest(int codePoint, String category) {
147         boolean actual = Character.isTitleCase(codePoint);
148         boolean expected = category.equals("Lt");
149         if (actual != expected) {
150             printDiff(codePoint, "isTitleCase", actual, expected);
151         }
152     }
153 
isISOControlTest(int codePoint)154     private static void isISOControlTest(int codePoint) {
155         boolean actual = Character.isISOControl(codePoint);
156         boolean expected = isISOControl(codePoint);
157         if (actual != expected) {
158             printDiff(codePoint, "isISOControl", actual, expected);
159         }
160     }
161 
isIdentifierIgnorableTest(int codePoint, String category)162     private static void isIdentifierIgnorableTest(int codePoint, String category) {
163         boolean actual = Character.isIdentifierIgnorable(codePoint);
164         boolean expected = isIdentifierIgnorable(codePoint, category);
165         if (actual != expected) {
166             printDiff(codePoint, "isIdentifierIgnorable", actual, expected);
167         }
168     }
169 
isJavaIdentifierStartTest(int codePoint, String category)170     private static void isJavaIdentifierStartTest(int codePoint, String category) {
171         boolean actual = Character.isJavaIdentifierStart(codePoint);
172         boolean expected = isJavaIdentifierStart(category);
173         if (actual != expected) {
174             printDiff(codePoint, "isJavaIdentifierStart", actual, expected);
175         }
176     }
177 
isJavaIdentifierPartTest(int codePoint, String category)178     private static void isJavaIdentifierPartTest(int codePoint, String category) {
179         boolean actual = Character.isJavaIdentifierPart(codePoint);
180         boolean expected = isJavaIdentifierPart(codePoint, category);
181         if (actual != expected) {
182             printDiff(codePoint, "isJavaIdentifierPart", actual, expected);
183         }
184     }
185 
isUnicodeIdentifierStartTest(int codePoint, String category)186     private static void isUnicodeIdentifierStartTest(int codePoint, String category) {
187         boolean actual = Character.isUnicodeIdentifierStart(codePoint);
188         boolean expected = isUnicodeIdentifierStart(category);
189         if (actual != expected) {
190             printDiff(codePoint, "isUnicodeIdentifierStart", actual, expected);
191         }
192     }
193 
isUnicodeIdentifierPartTest(int codePoint, String category)194     private static void isUnicodeIdentifierPartTest(int codePoint, String category) {
195         boolean actual = Character.isUnicodeIdentifierPart(codePoint);
196         boolean expected = isUnicodeIdentifierPart(codePoint, category);
197         if (actual != expected) {
198             printDiff(codePoint, "isUnicodeIdentifierPart", actual, expected);
199         }
200     }
201 
isLetter(String category)202     private static boolean isLetter(String category) {
203         return category.equals("Lu") || category.equals("Ll")
204                || category.equals("Lt") || category.equals("Lm")
205                || category.equals("Lo");
206     }
207 
isSpaceChar(String category)208     private static boolean isSpaceChar(String category) {
209         return category.equals("Zs") || category.equals("Zl")
210                || category.equals("Zp");
211     }
212 
isWhitespace(int codePoint, String category)213     private static boolean isWhitespace(int codePoint, String category) {
214         if (isSpaceChar(category) && codePoint != Integer.parseInt("00A0", 16)
215                 && codePoint != Integer.parseInt("2007", 16)
216                 && codePoint != Integer.parseInt("202F", 16)) {
217             return true;
218         } else {
219             if (codePoint == Integer.parseInt("0009", 16)
220                     || codePoint == Integer.parseInt("000A", 16)
221                     || codePoint == Integer.parseInt("000B", 16)
222                     || codePoint == Integer.parseInt("000C", 16)
223                     || codePoint == Integer.parseInt("000D", 16)
224                     || codePoint == Integer.parseInt("001C", 16)
225                     || codePoint == Integer.parseInt("001D", 16)
226                     || codePoint == Integer.parseInt("001E", 16)
227                     || codePoint == Integer.parseInt("001F", 16)) {
228                 return true;
229             }
230         }
231         return false;
232     }
233 
isISOControl(int codePoint)234     private static boolean isISOControl(int codePoint) {
235         return (codePoint > 0x00 && codePoint < 0x1f)
236                || (codePoint > 0x7f && codePoint < 0x9f)
237                || (codePoint == 0x00 || codePoint == 0x1f || codePoint == 0x7f || codePoint == 0x9f);
238     }
239 
isIdentifierIgnorable(int codePoint, String category)240     private static boolean isIdentifierIgnorable(int codePoint, String category) {
241         if (category.equals("Cf")) {
242             return true;
243         } else {
244             int a1 = Integer.parseInt("0000", 16);
245             int a2 = Integer.parseInt("0008", 16);
246             int b1 = Integer.parseInt("000E", 16);
247             int b2 = Integer.parseInt("001B", 16);
248             int c1 = Integer.parseInt("007F", 16);
249             int c2 = Integer.parseInt("009F", 16);
250 
251             if ((codePoint > a1 && codePoint < a2) || (codePoint > b1 && codePoint < b2)
252                     || (codePoint > c1 && codePoint < c2) || (codePoint == a1 || codePoint == a2
253                     || codePoint == b1 || codePoint == b2 || codePoint == c1 || codePoint == c2)) {
254                 return true;
255             }
256         }
257         return false;
258     }
259 
isJavaIdentifierStart(String category)260     private static boolean isJavaIdentifierStart(String category) {
261         return isLetter(category) || category.equals("Nl") || category.equals("Sc")
262                || category.equals("Pc");
263     }
264 
isJavaIdentifierPart(int codePoint, String category)265     private static boolean isJavaIdentifierPart(int codePoint, String category) {
266         return isLetter(category) || category.equals("Sc") || category.equals("Pc")
267                || category.equals("Nd") || category.equals("Nl")
268                || category.equals("Mc") || category.equals("Mn")
269                || isIdentifierIgnorable(codePoint, category);
270     }
271 
isUnicodeIdentifierStart(String category)272     private static boolean isUnicodeIdentifierStart(String category) {
273         return isLetter(category) || category.equals("Nl");
274     }
275 
isUnicodeIdentifierPart(int codePoint, String category)276     private static boolean isUnicodeIdentifierPart(int codePoint, String category) {
277         return isLetter(category) || category.equals("Pc") || category.equals("Nd")
278                || category.equals("Nl") || category.equals("Mc") || category.equals("Mn")
279                || isIdentifierIgnorable(codePoint, category);
280     }
281 
printDiff(int codePoint, String method, boolean actual, boolean expected)282     private static void printDiff(int codePoint, String method, boolean actual, boolean expected) {
283         System.out.println("Not equal at codePoint <" + Integer.toHexString(codePoint)
284                 + ">, method: " + method
285                 + ", actual: " + actual + ", expected: " + expected);
286         diffs++;
287     }
288 }
289