author | duke |
Wed, 05 Jul 2017 21:46:33 +0200 | |
changeset 38602 | b72e50a81d43 |
parent 23010 | 6dadb192ad81 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
16714
diff
changeset
|
2 |
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 22 |
*/ |
23 |
||
24 |
/* |
|
25 |
* |
|
26 |
* @test |
|
27 |
* @bug 4533872 4915683 4985217 5017280 |
|
28 |
* @summary Unit tests for supplementary character support (JSR-204) |
|
29 |
*/ |
|
30 |
||
31 |
public class Supplementary { |
|
32 |
||
33 |
public static void main(String[] args) { |
|
34 |
test1(); // Test for codePointAt(int index) |
|
35 |
test2(); // Test for codePointBefore(int index) |
|
36 |
test3(); // Test for reverse() |
|
37 |
test4(); // Test for appendCodePoint(int codePoint) |
|
38 |
test5(); // Test for codePointCount(int beginIndex, int endIndex) |
|
39 |
test6(); // Test for offsetByCodePoints(int index, int offset) |
|
16714
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
40 |
testDontReadOutOfBoundsTrailingSurrogate(); |
2 | 41 |
} |
42 |
||
43 |
/* Text strings which are used as input data. |
|
44 |
* The comment above each text string means the index of each 16-bit char |
|
45 |
* for convenience. |
|
46 |
*/ |
|
47 |
static final String[] input = { |
|
48 |
/* 111 1 111111 22222 |
|
49 |
0123 4 5678 9 012 3 456789 01234 */ |
|
50 |
"abc\uD800\uDC00def\uD800\uD800ab\uD800\uDC00cdefa\uDC00bcdef", |
|
51 |
/* 1 1111 1111 1 222 |
|
52 |
0 12345 6789 0 1234 5678 9 012 */ |
|
53 |
"\uD800defg\uD800hij\uD800\uDC00klm\uDC00nop\uDC00\uD800rt\uDC00", |
|
54 |
/* 11 1 1111 1 112 222 |
|
55 |
0 12345 6 78901 2 3456 7 890 123 */ |
|
56 |
"\uDC00abcd\uDBFF\uDFFFefgh\uD800\uDC009ik\uDC00\uDC00lm\uDC00no\uD800", |
|
57 |
/* 111 111111 1 22 2 |
|
58 |
0 1 2345 678 9 012 345678 9 01 2 */ |
|
59 |
"\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00", |
|
60 |
||
5987
caec61968454
6937112: String.lastIndexOf confused by unpaired trailing surrogate
martin
parents:
5506
diff
changeset
|
61 |
// includes an undefined supplementary character in Unicode 4.0.0 |
2 | 62 |
/* 1 11 1 1111 1 |
63 |
0 1 2345 6 789 0 12 3 4567 8 */ |
|
64 |
"\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02", |
|
65 |
}; |
|
66 |
||
67 |
||
68 |
/* Expected results for: |
|
69 |
* test1(): for codePointAt() |
|
70 |
* |
|
71 |
* Each character in each array is the golden data for each text string |
|
72 |
* in the above input data. For example, the first data in each array is |
|
73 |
* for the first input string. |
|
74 |
*/ |
|
75 |
static final int[][] golden1 = { |
|
76 |
{'a', 0xD800, 0xDC00, 0x10000, 0xE0200}, // codePointAt(0) |
|
77 |
{0xD800, 0x10000, 'g', 0xDC00, 0xE0202}, // codePointAt(9) |
|
78 |
{'f', 0xDC00, 0xD800, 0xDC00, 0xDE02}, // codePointAt(length-1) |
|
79 |
}; |
|
80 |
||
81 |
/* |
|
82 |
* Test for codePointAt(int index) method |
|
83 |
*/ |
|
84 |
static void test1() { |
|
85 |
||
86 |
for (int i = 0; i < input.length; i++) { |
|
87 |
StringBuilder sb = new StringBuilder(input[i]); |
|
88 |
||
89 |
/* |
|
90 |
* Normal case |
|
91 |
*/ |
|
92 |
testCodePoint(At, sb, 0, golden1[0][i]); |
|
93 |
testCodePoint(At, sb, 9, golden1[1][i]); |
|
94 |
testCodePoint(At, sb, sb.length()-1, golden1[2][i]); |
|
95 |
||
96 |
/* |
|
97 |
* Abnormal case - verify that an exception is thrown. |
|
98 |
*/ |
|
99 |
testCodePoint(At, sb, -1); |
|
100 |
testCodePoint(At, sb, sb.length()); |
|
101 |
} |
|
102 |
} |
|
103 |
||
104 |
||
105 |
/* Expected results for: |
|
106 |
* test2(): for codePointBefore() |
|
107 |
* |
|
108 |
* Each character in each array is the golden data for each text string |
|
109 |
* in the above input data. For example, the first data in each array is |
|
110 |
* for the first input string. |
|
111 |
*/ |
|
112 |
static final int[][] golden2 = { |
|
113 |
{'a', 0xD800, 0xDC00, 0xD800, 0xDB40}, // codePointBefore(1) |
|
114 |
{0xD800, 'l', 0x10000, 0xDC00, 0xDB40}, // codePointBefore(13) |
|
115 |
{'f', 0xDC00, 0xD800, 0x10000, 0xE0202}, // codePointBefore(length) |
|
116 |
}; |
|
117 |
||
118 |
/* |
|
119 |
* Test for codePointBefore(int index) method |
|
120 |
*/ |
|
121 |
static void test2() { |
|
122 |
||
123 |
for (int i = 0; i < input.length; i++) { |
|
124 |
StringBuilder sb = new StringBuilder(input[i]); |
|
125 |
||
126 |
/* |
|
127 |
* Normal case |
|
128 |
*/ |
|
129 |
testCodePoint(Before, sb, 1, golden2[0][i]); |
|
130 |
testCodePoint(Before, sb, 13, golden2[1][i]); |
|
131 |
testCodePoint(Before, sb, sb.length(), golden2[2][i]); |
|
132 |
||
133 |
/* |
|
134 |
* Abnormal case - verify that an exception is thrown. |
|
135 |
*/ |
|
136 |
testCodePoint(Before, sb, 0); |
|
137 |
testCodePoint(Before, sb, sb.length()+1); |
|
138 |
} |
|
139 |
} |
|
140 |
||
141 |
||
142 |
/* Expected results for: |
|
143 |
* test3(): for reverse() |
|
144 |
* |
|
145 |
* Unlike golden1 and golden2, each array is the golden data for each text |
|
146 |
* string in the above input data. For example, the first array is for |
|
147 |
* the first input string. |
|
148 |
*/ |
|
149 |
static final String[] golden3 = { |
|
150 |
"fedcb\uDC00afedc\uD800\uDC00ba\uD800\uD800fed\uD800\uDC00cba", |
|
151 |
"\uDC00tr\uD800\uDC00pon\uDC00mlk\uD800\uDC00jih\uD800gfed\uD800", |
|
152 |
"\uD800on\uDC00ml\uDC00\uDC00ki9\uD800\uDC00hgfe\uDBFF\uDFFFdcba\uDC00", |
|
153 |
"\uD800\uDC00@\\\uDC00^=;><\uDC00+;\uD800\uDC00&%\uD800$#!\uD800\uDC00", |
|
154 |
||
5987
caec61968454
6937112: String.lastIndexOf confused by unpaired trailing surrogate
martin
parents:
5506
diff
changeset
|
155 |
// includes an undefined supplementary character in Unicode 4.0.0 |
2 | 156 |
"\uDB40\uDE02ihg\uDB40\uDE03f\uDB40\uDE02ed\uDB40\uDE01cba\uDB40\uDE00", |
157 |
}; |
|
158 |
||
159 |
// Additional input data & expected result for test3() |
|
160 |
static final String[][] testdata1 = { |
|
161 |
{"a\uD800\uDC00", "\uD800\uDC00a"}, |
|
162 |
{"a\uDC00\uD800", "\uD800\uDC00a"}, |
|
163 |
{"\uD800\uDC00a", "a\uD800\uDC00"}, |
|
164 |
{"\uDC00\uD800a", "a\uD800\uDC00"}, |
|
165 |
{"\uDC00\uD800\uD801", "\uD801\uD800\uDC00"}, |
|
166 |
{"\uDC00\uD800\uDC01", "\uD800\uDC01\uDC00"}, |
|
167 |
{"\uD801\uD800\uDC00", "\uD800\uDC00\uD801"}, |
|
168 |
{"\uD800\uDC01\uDC00", "\uDC00\uD800\uDC01"}, |
|
169 |
{"\uD800\uDC00\uDC01\uD801", "\uD801\uDC01\uD800\uDC00"}, |
|
170 |
}; |
|
171 |
||
172 |
/* |
|
173 |
* Test for reverse() method |
|
174 |
*/ |
|
175 |
static void test3() { |
|
176 |
for (int i = 0; i < input.length; i++) { |
|
177 |
StringBuilder sb = new StringBuilder(input[i]).reverse(); |
|
178 |
||
179 |
check(!golden3[i].equals(sb.toString()), |
|
180 |
"reverse() for <" + toHexString(input[i]) + ">", |
|
181 |
sb, golden3[i]); |
|
182 |
} |
|
183 |
||
184 |
for (int i = 0; i < testdata1.length; i++) { |
|
185 |
StringBuilder sb = new StringBuilder(testdata1[i][0]).reverse(); |
|
186 |
||
187 |
check(!testdata1[i][1].equals(sb.toString()), |
|
188 |
"reverse() for <" + toHexString(testdata1[i][0]) + ">", |
|
189 |
sb, testdata1[i][1]); |
|
190 |
} |
|
191 |
} |
|
192 |
||
193 |
/** |
|
194 |
* Test for appendCodePoint() method |
|
195 |
*/ |
|
196 |
static void test4() { |
|
197 |
for (int i = 0; i < input.length; i++) { |
|
198 |
String s = input[i]; |
|
199 |
StringBuilder sb = new StringBuilder(); |
|
200 |
int c; |
|
201 |
for (int j = 0; j < s.length(); j += Character.charCount(c)) { |
|
202 |
c = s.codePointAt(j); |
|
203 |
StringBuilder rsb = sb.appendCodePoint(c); |
|
204 |
check(sb != rsb, "appendCodePoint returned a wrong object"); |
|
205 |
int sbc = sb.codePointAt(j); |
|
206 |
check(sbc != c, "appendCodePoint("+j+") != c", sbc, c); |
|
207 |
} |
|
208 |
check(!s.equals(sb.toString()), |
|
209 |
"appendCodePoint() produced a wrong result with input["+i+"]"); |
|
210 |
} |
|
211 |
||
212 |
// test exception |
|
213 |
testAppendCodePoint(-1, IllegalArgumentException.class); |
|
214 |
testAppendCodePoint(Character.MAX_CODE_POINT+1, IllegalArgumentException.class); |
|
215 |
} |
|
216 |
||
217 |
/** |
|
218 |
* Test codePointCount(int, int) |
|
219 |
* |
|
220 |
* This test case assumes that |
|
221 |
* Character.codePointCount(CharSequence, int, int) works |
|
222 |
* correctly. |
|
223 |
*/ |
|
224 |
static void test5() { |
|
225 |
for (int i = 0; i < input.length; i++) { |
|
226 |
String s = input[i]; |
|
227 |
StringBuilder sb = new StringBuilder(s); |
|
228 |
int length = sb.length(); |
|
229 |
for (int j = 0; j <= length; j++) { |
|
230 |
int result = sb.codePointCount(j, length); |
|
231 |
int expected = Character.codePointCount(sb, j, length); |
|
232 |
check(result != expected, "codePointCount(input["+i+"], "+j+", "+length+")", |
|
233 |
result, expected); |
|
234 |
} |
|
235 |
for (int j = length; j >= 0; j--) { |
|
236 |
int result = sb.codePointCount(0, j); |
|
237 |
int expected = Character.codePointCount(sb, 0, j); |
|
238 |
check(result != expected, "codePointCount(input["+i+"], 0, "+j+")", |
|
239 |
result, expected); |
|
240 |
} |
|
241 |
||
242 |
// test exceptions |
|
243 |
testCodePointCount(null, 0, 0, NullPointerException.class); |
|
244 |
testCodePointCount(sb, -1, length, IndexOutOfBoundsException.class); |
|
245 |
testCodePointCount(sb, 0, length+1, IndexOutOfBoundsException.class); |
|
246 |
testCodePointCount(sb, length, length-1, IndexOutOfBoundsException.class); |
|
247 |
} |
|
248 |
} |
|
249 |
||
250 |
/** |
|
251 |
* Test offsetByCodePoints(int, int) |
|
252 |
* |
|
253 |
* This test case assumes that |
|
254 |
* Character.codePointCount(CharSequence, int, int) works |
|
255 |
* correctly. |
|
256 |
*/ |
|
257 |
static void test6() { |
|
258 |
for (int i = 0; i < input.length; i++) { |
|
259 |
String s = input[i]; |
|
260 |
StringBuilder sb = new StringBuilder(s); |
|
261 |
int length = s.length(); |
|
262 |
for (int j = 0; j <= length; j++) { |
|
263 |
int nCodePoints = Character.codePointCount(sb, j, length); |
|
264 |
int result = sb.offsetByCodePoints(j, nCodePoints); |
|
265 |
check(result != length, |
|
266 |
"offsetByCodePoints(input["+i+"], "+j+", "+nCodePoints+")", |
|
267 |
result, length); |
|
268 |
result = sb.offsetByCodePoints(length, -nCodePoints); |
|
269 |
int expected = j; |
|
270 |
if (j > 0 && j < length) { |
|
271 |
int cp = sb.codePointBefore(j+1); |
|
272 |
if (Character.isSupplementaryCodePoint(cp)) { |
|
273 |
expected--; |
|
274 |
} |
|
275 |
} |
|
276 |
check(result != expected, |
|
277 |
"offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", |
|
278 |
result, expected); |
|
279 |
} |
|
280 |
for (int j = length; j >= 0; j--) { |
|
281 |
int nCodePoints = Character.codePointCount(sb, 0, j); |
|
282 |
int result = sb.offsetByCodePoints(0, nCodePoints); |
|
283 |
int expected = j; |
|
284 |
if (j > 0 && j < length) { |
|
285 |
int cp = sb.codePointAt(j-1); |
|
286 |
if (Character.isSupplementaryCodePoint(cp)) { |
|
287 |
expected++; |
|
288 |
} |
|
289 |
} |
|
290 |
check(result != expected, |
|
291 |
"offsetByCodePoints(input["+i+"], 0, "+nCodePoints+")", |
|
292 |
result, expected); |
|
293 |
result = sb.offsetByCodePoints(j, -nCodePoints); |
|
294 |
check(result != 0, |
|
295 |
"offsetBycodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", |
|
296 |
result, 0); |
|
297 |
} |
|
298 |
||
299 |
// test exceptions |
|
300 |
testOffsetByCodePoints(null, 0, 0, NullPointerException.class); |
|
301 |
testOffsetByCodePoints(sb, -1, length, IndexOutOfBoundsException.class); |
|
302 |
testOffsetByCodePoints(sb, 0, length+1, IndexOutOfBoundsException.class); |
|
303 |
testOffsetByCodePoints(sb, 1, -2, IndexOutOfBoundsException.class); |
|
304 |
testOffsetByCodePoints(sb, length, length-1, IndexOutOfBoundsException.class); |
|
305 |
testOffsetByCodePoints(sb, length, -(length+1), IndexOutOfBoundsException.class); |
|
306 |
} |
|
307 |
} |
|
308 |
||
16714
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
309 |
static void testDontReadOutOfBoundsTrailingSurrogate() { |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
310 |
StringBuilder sb = new StringBuilder(); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
311 |
int suppl = Character.MIN_SUPPLEMENTARY_CODE_POINT; |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
312 |
sb.appendCodePoint(suppl); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
313 |
check(sb.codePointAt(0) != (int) suppl, |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
314 |
"codePointAt(0)", sb.codePointAt(0), suppl); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
315 |
check(sb.length() != 2, "sb.length()"); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
316 |
sb.setLength(1); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
317 |
check(sb.length() != 1, "sb.length()"); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
318 |
check(sb.codePointAt(0) != Character.highSurrogate(suppl), |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
319 |
"codePointAt(0)", |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
320 |
sb.codePointAt(0), Character.highSurrogate(suppl)); |
cb235d5f8bd4
8010316: Improve handling of char sequences containing surrogates
martin
parents:
7668
diff
changeset
|
321 |
} |
2 | 322 |
|
323 |
static final boolean At = true, Before = false; |
|
324 |
||
325 |
static void testCodePoint(boolean isAt, StringBuilder sb, int index, int expected) { |
|
326 |
int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index); |
|
327 |
||
328 |
check(c != expected, |
|
329 |
"codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <" |
|
330 |
+ sb + ">", c, expected); |
|
331 |
} |
|
332 |
||
333 |
static void testCodePoint(boolean isAt, StringBuilder sb, int index) { |
|
334 |
boolean exceptionOccurred = false; |
|
335 |
||
336 |
try { |
|
337 |
int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index); |
|
338 |
} |
|
339 |
catch (StringIndexOutOfBoundsException e) { |
|
340 |
exceptionOccurred = true; |
|
341 |
} |
|
342 |
check(!exceptionOccurred, |
|
343 |
"codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <" |
|
344 |
+ sb + "> should throw StringIndexOutOfBoundsPointerException."); |
|
345 |
} |
|
346 |
||
347 |
static void testAppendCodePoint(int codePoint, Class expectedException) { |
|
348 |
try { |
|
349 |
new StringBuilder().appendCodePoint(codePoint); |
|
350 |
} catch (Exception e) { |
|
351 |
if (expectedException.isInstance(e)) { |
|
352 |
return; |
|
353 |
} |
|
354 |
throw new RuntimeException("Error: Unexpected exception", e); |
|
355 |
} |
|
356 |
check(true, "appendCodePoint(" + toHexString(codePoint) + ") didn't throw " |
|
357 |
+ expectedException.getName()); |
|
358 |
} |
|
359 |
||
360 |
static void testCodePointCount(StringBuilder sb, int beginIndex, int endIndex, |
|
361 |
Class expectedException) { |
|
362 |
try { |
|
363 |
int n = sb.codePointCount(beginIndex, endIndex); |
|
364 |
} catch (Exception e) { |
|
365 |
if (expectedException.isInstance(e)) { |
|
366 |
return; |
|
367 |
} |
|
368 |
throw new RuntimeException("Error: Unexpected exception", e); |
|
369 |
} |
|
370 |
check(true, "codePointCount() didn't throw " + expectedException.getName()); |
|
371 |
} |
|
372 |
||
373 |
static void testOffsetByCodePoints(StringBuilder sb, int index, int offset, |
|
374 |
Class expectedException) { |
|
375 |
try { |
|
376 |
int n = sb.offsetByCodePoints(index, offset); |
|
377 |
} catch (Exception e) { |
|
378 |
if (expectedException.isInstance(e)) { |
|
379 |
return; |
|
380 |
} |
|
381 |
throw new RuntimeException("Error: Unexpected exception", e); |
|
382 |
} |
|
383 |
check(true, "offsetByCodePoints() didn't throw " + expectedException.getName()); |
|
384 |
} |
|
385 |
||
386 |
static void check(boolean err, String msg) { |
|
387 |
if (err) { |
|
388 |
throw new RuntimeException("Error: " + msg); |
|
389 |
} |
|
390 |
} |
|
391 |
||
392 |
static void check(boolean err, String s, int got, int expected) { |
|
393 |
if (err) { |
|
394 |
throw new RuntimeException("Error: " + s |
|
395 |
+ " returned an unexpected value. got " |
|
396 |
+ toHexString(got) |
|
397 |
+ ", expected " |
|
398 |
+ toHexString(expected)); |
|
399 |
} |
|
400 |
} |
|
401 |
||
402 |
static void check(boolean err, String s, StringBuilder got, String expected) { |
|
403 |
if (err) { |
|
404 |
throw new RuntimeException("Error: " + s |
|
405 |
+ " returned an unexpected value. got <" |
|
406 |
+ toHexString(got.toString()) |
|
407 |
+ ">, expected <" |
|
408 |
+ toHexString(expected) |
|
409 |
+ ">"); |
|
410 |
} |
|
411 |
} |
|
412 |
||
413 |
private static String toHexString(int c) { |
|
414 |
return "0x" + Integer.toHexString(c); |
|
415 |
} |
|
416 |
||
417 |
private static String toHexString(String s) { |
|
418 |
StringBuilder sb = new StringBuilder(); |
|
419 |
for (int i = 0; i < s.length(); i++) { |
|
420 |
char c = s.charAt(i); |
|
421 |
||
422 |
sb.append(" 0x"); |
|
423 |
if (c < 0x10) sb.append('0'); |
|
424 |
if (c < 0x100) sb.append('0'); |
|
425 |
if (c < 0x1000) sb.append('0'); |
|
426 |
sb.append(Integer.toHexString(c)); |
|
427 |
} |
|
428 |
sb.append(' '); |
|
429 |
return sb.toString(); |
|
430 |
} |
|
431 |
} |