undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
@bug 4136620 4144590
@summary Make sure that Attribute & subclasses are serialized and deserialized correctly
@modules java.desktop
*/
import java.text.AttributedCharacterIterator.Attribute;
import java.awt.font.TextAttribute;
import java.io.*;
public class ReadResolve {
public static void main(String[] args) throws Exception {
testSerializationCycle(Attribute.LANGUAGE);
testSerializationCycle(TextAttribute.INPUT_METHOD_HIGHLIGHT);
boolean gotException = false;
Attribute result = null;
try {
result = doSerializationCycle(FakeAttribute.LANGUAGE);
} catch (Throwable e) {
gotException = true;
}
if (!gotException) {
throw new RuntimeException("Attribute should throw an exception when given a fake \"language\" attribute. Deserialized object: " + result);
}
}
static Attribute doSerializationCycle(Attribute attribute) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(attribute);
oos.flush();
byte[] data = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Attribute result = (Attribute) ois.readObject();
return result;
}
static void testSerializationCycle(Attribute attribute) throws Exception {
Attribute result = doSerializationCycle(attribute);
if (result != attribute) {
throw new RuntimeException("attribute changed identity during serialization/deserialization");
}
}
private static class FakeAttribute extends Attribute {
// This LANGUAGE attribute should never be confused with the
// Attribute.LANGUAGE attribute. However, we don't override
// readResolve here, so that deserialization goes
// to Attribute. Attribute has to catch this problem and reject
// the fake attribute.
static final FakeAttribute LANGUAGE = new FakeAttribute("language");
FakeAttribute(String name) {
super(name);
}
}
}

View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4139771
* @summary test all aspects of AttributedString class
*/
import java.text.Annotation;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.AttributedString;
import java.text.CharacterIterator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class AttributedStringTest {
private static final String text = "Hello, world!";
private static final Annotation hi = new Annotation("hi");
private static final int[] array5_13 = {5, 13};
private static final int[] array3_9_13 = {3, 9, 13};
private static final int[] array5_9_13 = {5, 9, 13};
private static final int[] array3_5_9_13 = {3, 5, 9, 13};
private static final Attribute[] arrayLanguage = {Attribute.LANGUAGE};
private static final Attribute[] arrayLanguageReading = {Attribute.LANGUAGE, Attribute.READING};
private static final Set setLanguageReading = new HashSet();
static {
setLanguageReading.add(Attribute.LANGUAGE);
setLanguageReading.add(Attribute.READING);
}
public static final void main(String argv[]) throws Exception {
AttributedString string;
AttributedCharacterIterator iterator;
// create a string with text, but no attributes
string = new AttributedString(text);
iterator = string.getIterator();
// make sure the text is there and attributes aren't
checkIteratorText(iterator, text);
if (!iterator.getAllAttributeKeys().isEmpty()) {
throwException(iterator, "iterator provides attributes where none are defined");
}
// add an attribute to a subrange
string.addAttribute(Attribute.LANGUAGE, Locale.ENGLISH, 3, 9);
iterator = string.getIterator();
// make sure the attribute is defined, and it's on the correct subrange
checkIteratorAttributeKeys(iterator, arrayLanguage);
checkIteratorSubranges(iterator, array3_9_13);
checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, null);
checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.ENGLISH);
checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
// add an attribute to a subrange
string.addAttribute(Attribute.READING, hi, 0, 5);
iterator = string.getIterator();
// make sure the attribute is defined, and it's on the correct subrange
checkIteratorAttributeKeys(iterator, arrayLanguageReading);
checkIteratorSubranges(iterator, array3_5_9_13);
checkIteratorAttribute(iterator, 0, Attribute.READING, hi);
checkIteratorAttribute(iterator, 3, Attribute.READING, hi);
checkIteratorAttribute(iterator, 5, Attribute.READING, null);
checkIteratorAttribute(iterator, 9, Attribute.READING, null);
// make sure the first attribute wasn't adversely affected
// in particular, we shouldn't see separate subranges (3,5) and (5,9).
checkIteratorSubranges(iterator, Attribute.LANGUAGE, array3_9_13);
checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, null);
checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.ENGLISH);
checkIteratorAttribute(iterator, 5, Attribute.LANGUAGE, Locale.ENGLISH);
checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
// for the entire set of attributes, we expect four subranges
checkIteratorSubranges(iterator, setLanguageReading, array3_5_9_13);
// redefine the language attribute so that both language and reading are continuous from 0 to 5
string.addAttribute(Attribute.LANGUAGE, Locale.US, 0, 5);
iterator = string.getIterator();
// make sure attributes got changed and merged correctly
checkIteratorAttributeKeys(iterator, arrayLanguageReading);
checkIteratorSubranges(iterator, array3_5_9_13);
checkIteratorSubranges(iterator, Attribute.LANGUAGE, array5_9_13);
checkIteratorSubranges(iterator, Attribute.READING, array5_13);
checkIteratorSubranges(iterator, setLanguageReading, array5_9_13);
checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, Locale.US);
checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.US);
checkIteratorAttribute(iterator, 5, Attribute.LANGUAGE, Locale.ENGLISH);
checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
// make sure an annotation is only returned if its range is contained in the iterator's range
iterator = string.getIterator(null, 3, 5);
checkIteratorAttribute(iterator, 3, Attribute.READING, null);
checkIteratorAttribute(iterator, 5, Attribute.READING, null);
iterator = string.getIterator(null, 0, 4);
checkIteratorAttribute(iterator, 0, Attribute.READING, null);
checkIteratorAttribute(iterator, 3, Attribute.READING, null);
iterator = string.getIterator(null, 0, 5);
checkIteratorAttribute(iterator, 0, Attribute.READING, hi);
checkIteratorAttribute(iterator, 4, Attribute.READING, hi);
checkIteratorAttribute(iterator, 5, Attribute.READING, null);
}
private static final void checkIteratorText(AttributedCharacterIterator iterator, String expectedText) throws Exception {
if (iterator.getEndIndex() - iterator.getBeginIndex() != expectedText.length()) {
throwException(iterator, "text length doesn't match between original text and iterator");
}
char c = iterator.first();
for (int i = 0; i < expectedText.length(); i++) {
if (c != expectedText.charAt(i)) {
throwException(iterator, "text content doesn't match between original text and iterator");
}
c = iterator.next();
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator text doesn't end with DONE");
}
}
private static final void checkIteratorAttributeKeys(AttributedCharacterIterator iterator, Attribute[] expectedKeys) throws Exception {
Set iteratorKeys = iterator.getAllAttributeKeys();
if (iteratorKeys.size() != expectedKeys.length) {
throwException(iterator, "number of keys returned by iterator doesn't match expectation");
}
for (int i = 0; i < expectedKeys.length; i++) {
if (!iteratorKeys.contains(expectedKeys[i])) {
throwException(iterator, "expected key wasn't found in iterator's key set");
}
}
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart() != previous || iterator.getRunLimit() != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart() + ", " + iterator.getRunLimit());
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, Attribute key, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart(key) != previous || iterator.getRunLimit(key) != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart(key) + ", " + iterator.getRunLimit(key) + " for key " + key);
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, Set keys, int[] expectedLimits) throws Exception {
int previous = 0;
char c = iterator.first();
for (int i = 0; i < expectedLimits.length; i++) {
if (iterator.getRunStart(keys) != previous || iterator.getRunLimit(keys) != expectedLimits[i]) {
throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart(keys) + ", " + iterator.getRunLimit(keys) + " for keys " + keys);
}
previous = expectedLimits[i];
c = iterator.setIndex(previous);
}
if (c != CharacterIterator.DONE) {
throwException(iterator, "iterator's run sequence doesn't end with DONE");
}
}
private static final void checkIteratorAttribute(AttributedCharacterIterator iterator, int index, Attribute key, Object expectedValue) throws Exception {
iterator.setIndex(index);
Object value = iterator.getAttribute(key);
if (!((expectedValue == null && value == null) || (expectedValue != null && expectedValue.equals(value)))) {
throwException(iterator, "iterator returns wrong attribute value - " + value + " instead of " + expectedValue);
}
value = iterator.getAttributes().get(key);
if (!((expectedValue == null && value == null) || (expectedValue != null && expectedValue.equals(value)))) {
throwException(iterator, "iterator's map returns wrong attribute value - " + value + " instead of " + expectedValue);
}
}
private static final void throwException(AttributedCharacterIterator iterator, String details) throws Exception {
dumpIterator(iterator);
throw new Exception(details);
}
private static final void dumpIterator(AttributedCharacterIterator iterator) {
Set attributeKeys = iterator.getAllAttributeKeys();
System.out.print("All attributes: ");
Iterator keyIterator = attributeKeys.iterator();
while (keyIterator.hasNext()) {
Attribute key = (Attribute) keyIterator.next();
System.out.print(key);
}
for(char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
if (iterator.getIndex() == iterator.getBeginIndex() ||
iterator.getIndex() == iterator.getRunStart()) {
System.out.println();
Map attributes = iterator.getAttributes();
Set entries = attributes.entrySet();
Iterator attributeIterator = entries.iterator();
while (attributeIterator.hasNext()) {
Map.Entry entry = (Map.Entry) attributeIterator.next();
System.out.print("<" + entry.getKey() + ": "
+ entry.getValue() + ">");
}
}
System.out.print(" ");
System.out.print(c);
}
System.out.println();
System.out.println("done");
System.out.println();
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4146853
* @summary Make sure we can construct an AttributedString from
* an AttributedCharacterIterator covering only a subrange
* @modules java.desktop
*/
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Hashtable;
public class TestAttributedStringCtor {
public static void main(String[] args) {
// Create a new AttributedString with one attribute.
Hashtable attributes = new Hashtable();
attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
AttributedString origString = new AttributedString("Hello world.", attributes);
// Create an iterator over part of the AttributedString.
AttributedCharacterIterator iter = origString.getIterator(null, 4, 6);
// Attempt to create a new AttributedString from the iterator.
// This will throw IllegalArgumentException.
AttributedString newString = new AttributedString(iter);
// Without the exception this would get executed.
System.out.println("DONE");
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4151160
* @summary Make sure to return correct run start and limit values
* when the iterator has been created with begin and end index values.
* @modules java.desktop
*/
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.Annotation;
public class getRunStartLimitTest {
public static void main(String[] args) throws Exception {
String text = "Hello world";
AttributedString as = new AttributedString(text);
// add non-Annotation attributes
as.addAttribute(TextAttribute.WEIGHT,
TextAttribute.WEIGHT_LIGHT,
0,
3);
as.addAttribute(TextAttribute.WEIGHT,
TextAttribute.WEIGHT_BOLD,
3,
5);
as.addAttribute(TextAttribute.WEIGHT,
TextAttribute.WEIGHT_EXTRABOLD,
5,
text.length());
// add Annotation attributes
as.addAttribute(TextAttribute.WIDTH,
new Annotation(TextAttribute.WIDTH_EXTENDED),
0,
3);
as.addAttribute(TextAttribute.WIDTH,
new Annotation(TextAttribute.WIDTH_CONDENSED),
3,
4);
AttributedCharacterIterator aci = as.getIterator(null, 2, 4);
aci.first();
int runStart = aci.getRunStart();
if (runStart != 2) {
throw new Exception("1st run start is wrong. ("+runStart+" should be 2.)");
}
int runLimit = aci.getRunLimit();
if (runLimit != 3) {
throw new Exception("1st run limit is wrong. ("+runLimit+" should be 3.)");
}
Object value = aci.getAttribute(TextAttribute.WEIGHT);
if (value != TextAttribute.WEIGHT_LIGHT) {
throw new Exception("1st run attribute is wrong. ("
+value+" should be "+TextAttribute.WEIGHT_LIGHT+".)");
}
value = aci.getAttribute(TextAttribute.WIDTH);
if (value != null) {
throw new Exception("1st run annotation is wrong. ("
+value+" should be null.)");
}
aci.setIndex(runLimit);
runStart = aci.getRunStart();
if (runStart != 3) {
throw new Exception("2nd run start is wrong. ("+runStart+" should be 3.)");
}
runLimit = aci.getRunLimit();
if (runLimit != 4) {
throw new Exception("2nd run limit is wrong. ("+runLimit+" should be 4.)");
}
value = aci.getAttribute(TextAttribute.WEIGHT);
if (value != TextAttribute.WEIGHT_BOLD) {
throw new Exception("2nd run attribute is wrong. ("
+value+" should be "+TextAttribute.WEIGHT_BOLD+".)");
}
value = aci.getAttribute(TextAttribute.WIDTH);
if (!(value instanceof Annotation)
|| (((Annotation)value).getValue() != TextAttribute.WIDTH_CONDENSED)) {
throw new Exception("2nd run annotation is wrong. (" + value + " should be "
+ new Annotation(TextAttribute.WIDTH_CONDENSED)+".)");
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4827312 6850113
* @summary verify that argument validity check is not fooled by overflow
*/
public class BidiBug {
public static void main(String[] args) {
try {
byte buff[] = new byte[3000];
java.text.Bidi bidi = new java.text.Bidi(new char[20],10,buff,Integer.MAX_VALUE-3,4,1);
}
catch (IllegalArgumentException e) {
System.out.println("Passed: " + e);
return; // success
}
throw new RuntimeException("Failed: Bidi didn't throw error, though we didn't crash either");
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4396492 4396496 4778510 6850113
* @summary verify that the embedding values processed by the bidi code use negative values to
* indicate overrides, rather than using bit 7. Also tests Bidi without loading awt classes to
* confirm that Bidi can be used without awt. Verify that embedding level 0 is properly mapped
* to the base embedding level.
* @modules java.desktop
*/
import java.awt.Color;
import java.awt.Frame;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
import java.text.Bidi;
public class BidiEmbeddingTest {
public static void main(String[] args) {
// to regress embedding test against old fix, call with an arg. A window will pop
// up causing awt lib to be loaded so the vm won't die with the unsatisfied link error.
if (args.length > 0) {
Frame f = new Frame();
f.setSize(300, 300);
f.setBackground(Color.white);
f.show();
}
test1();
test2();
}
static void test1() {
String target = "BACK WARDS";
String str = "If this text is >" + target + "< the test passed.";
int start = str.indexOf(target);
int limit = start + target.length();
System.out.println("start: " + start + " limit: " + limit);
AttributedString astr = new AttributedString(str);
astr.addAttribute(TextAttribute.BIDI_EMBEDDING,
new Integer(-1),
start,
limit);
Bidi bidi = new Bidi(astr.getIterator());
for (int i = 0; i < bidi.getRunCount(); ++i) {
System.out.println("run " + i +
" from " + bidi.getRunStart(i) +
" to " + bidi.getRunLimit(i) +
" at level " + bidi.getRunLevel(i));
}
System.out.println(bidi);
byte[] embs = new byte[str.length() + 3];
for (int i = start + 1; i < limit + 1; ++i) {
embs[i] = -1;
}
Bidi bidi2 = new Bidi(str.toCharArray(), 0, embs, 1, str.length(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
for (int i = 0; i < bidi2.getRunCount(); ++i) {
System.out.println("run " + i +
" from " + bidi2.getRunStart(i) +
" to " + bidi2.getRunLimit(i) +
" at level " + bidi2.getRunLevel(i));
}
System.out.println(bidi2 + "\n");
if (bidi.getRunCount() != 3 || bidi2.getRunCount() != 3) {
throw new Error("Bidi run count incorrect");
} else {
System.out.println("test1() passed.\n");
}
}
// make sure BIDI_EMBEDDING values of 0 are mapped to base run direction, instead of flagging an error.
static void test2() {
String target = "BACK WARDS";
String str = "If this text is >" + target + "< the test passed.";
int length = str.length();
int start = str.indexOf(target);
int limit = start + target.length();
System.out.println("start: " + start + " limit: " + limit);
AttributedString astr = new AttributedString(str);
astr.addAttribute(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL);
astr.addAttribute(TextAttribute.BIDI_EMBEDDING,
new Integer(-3),
start,
limit);
Bidi bidi = new Bidi(astr.getIterator());
for (int i = 0; i < bidi.getRunCount(); ++i) {
System.out.println("run " + i +
" from " + bidi.getRunStart(i) +
" to " + bidi.getRunLimit(i) +
" at level " + bidi.getRunLevel(i));
}
System.out.println(bidi + "\n");
if (bidi.getRunCount() != 6) { // runs of spaces and angles at embedding bound,s and final period, each get level 1
throw new Error("Bidi embedding processing failed");
} else {
System.out.println("test2() passed.\n");
}
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4888843
* @summary verify that surrogate pairs representing codepoints with R or AL directionality
* and correctly recognized and reordered.
*/
import java.text.Bidi;
public class BidiSurrogateTest {
private static final String RTLS = new String(Character.toChars(0x10800)); // surrogate code point with R directionality
private static final String LTRS = new String(Character.toChars(0x107ff)); // surrogate code point with L directionality
private static final String LRE = "\u202a";
private static final String RLE = "\u202b";
private static final String PDF = "\u202c";
public static void main(String[] args) {
new BidiSurrogateTest().test();
}
void test() {
test0();
test1();
}
void test0() {
// test unpaired surrogates - should have L directionality
testRequiresBidi("\ud800", false); // unpaired lead surrogate
testRequiresBidi("\udc00", false); // unpaired trail surrogate
testRequiresBidi("\udc00\ud800", false); // out of order surrogates
testRequiresBidi("a\udc00b\ud800c", false); // out of order surrogates split
testRequiresBidi(LTRS, false); // supplementary with L
testRequiresBidi(RTLS, true); // supplementary with R
testRequiresBidi("a" + RTLS + "b", true); // R supplementary in LTR text
testRequiresBidi(LTRS + RTLS, true); // R supplementary in LTR supplementary text
testRequiresBidi(LRE, false); // LRE lone embedding
testRequiresBidi(RLE, true); // RLE lone embedding
testRequiresBidi(PDF, false); // PDF lone pop embedding
}
void testRequiresBidi(String string, boolean requiresBidi) {
char[] text = string.toCharArray();
if (Bidi.requiresBidi(text, 0, text.length) != requiresBidi) {
throw new RuntimeException("testRequiresBidi failed with '" + string + "', " + requiresBidi);
}
}
void test1() {
// test that strings with surrogate runs process surrogate directionality ok
testBidi("This is a string with " + LTRS + " in it.", false);
testBidi("This is a string with \ud800 in it.", false);
testBidi("This is a string with \u0640 in it.", 22, 1);
testBidi(RTLS, true);
testBidi("This is a string with " + RTLS + RTLS + RTLS + " in it.", 22, 6);
}
void testBidi(String string, boolean directionIsRTL) {
Bidi bidi = new Bidi(string, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
if (bidi.isMixed()) {
throw new RuntimeException("bidi is mixed");
}
if (bidi.isRightToLeft() != directionIsRTL) {
throw new RuntimeException("bidi is not " + (directionIsRTL ? "rtl" : "ltr"));
}
}
void testBidi(String string, int rtlstart, int rtllength) {
Bidi bidi = new Bidi(string, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
for (int i = 0; i < bidi.getRunCount(); ++i) {
if ((bidi.getRunLevel(i) & 1) != 0) {
if (bidi.getRunStart(i) != rtlstart ||
bidi.getRunLimit(i) != rtlstart + rtllength) {
throw new RuntimeException("first rtl run didn't match " + rtlstart + ", " + rtllength);
}
break;
}
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6850113 8174270
* @summary Verify the return value of digit() for some digits.
* @modules java.base/jdk.internal.icu.lang
* @compile -XDignore.symbol.file=true Bug6850113.java
* @run main Bug6850113
*/
import jdk.internal.icu.lang.UCharacter;
public class Bug6850113 {
public static void main(String[] args) {
boolean err = false;
// Fullwidth Latin capital letters
for (int i = 0xff21, j = 10; i <= 0xff3a; i++, j++) {
if (UCharacter.digit(i, 36) != j) {
err = true;
System.out.println("Error: UCharacter.digit(0x" +
Integer.toHexString(i) + ", 36) returned " +
UCharacter.digit(i, 36) + ", expected=" + j);
}
}
// Fullwidth Latin small letters
for (int i = 0xff41, j = 10; i <= 0xff5a; i++, j++) {
if (UCharacter.digit(i, 36) != j) {
err = true;
System.out.println("Error: UCharacter.digit(0x" +
Integer.toHexString(i) + ", 36) returned " +
UCharacter.digit(i, 36) + ", expected=" + j);
}
}
if (err) {
throw new RuntimeException("UCharacter.digit(): Wrong return value");
}
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7002398
* @summary Verify that Corrigendum #8 for Unicode 6.0.0 has been applied.
*/
import java.text.*;
public class Bug7002398 {
private static final int[] directions = {
Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT,
Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT,
Bidi.DIRECTION_LEFT_TO_RIGHT,
Bidi.DIRECTION_RIGHT_TO_LEFT
};
/*
* Old Bidi class: AL AN AL AN AL
* New Bidi class: AL
*/
private static final String str = "\u0627\u0660\u0710\u070F\u070D";
private static final int[] expectedLevels = {1, 2, 1, 1, 1};
public static void main(String[] args) {
boolean err = false;
for (int dir = 0; dir < directions.length; dir ++) {
Bidi bidi = new Bidi(str, directions[dir]);
for (int index = 0; index < str.length(); index ++) {
int gotLevel = bidi.getLevelAt(index);
if (gotLevel != expectedLevels[index]) {
err = true;
System.err.println("Unexpected level for the character 0x" +
Integer.toHexString(str.charAt(index)).toUpperCase() +
": Expected level = " + expectedLevels[index] +
", actual level = " + bidi.getLevelAt(index) +
" in direction = " + directions[dir] + ".");
}
}
}
if (err) {
throw new RuntimeException("Failed.");
}
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7041232
* @summary verify that an unexpected exception isn't thrown for unnatural data to keep backward compatibility with JDK 6.
*/
import java.text.*;
public class Bug7041232 {
public static void main(String[] args) {
String UnicodeChars;
StringBuffer sb = new StringBuffer();
// Generates String which includes U+2028(line separator) and
// U+2029(paragraph separator)
for (int i = 0x2000; i < 0x2100; i++) {
sb.append((char)i);
}
UnicodeChars = sb.toString();
Bidi bidi = new Bidi(UnicodeChars, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
bidi.createLineBidi(0, UnicodeChars.length());
}
}

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7042148
* @summary verify that Bidi.baseIsLeftToRight() returns the correct value even if an incorrect position is set in the given AttributedCharacterIterator.
* @modules java.desktop
*/
import java.awt.font.*;
import java.text.*;
import java.util.*;
public class Bug7042148 {
private static boolean err = false;
public static void main(String[] args) {
testDirection();
if (err) {
throw new RuntimeException("Failed");
} else {
System.out.println("Passed.");
}
}
private static void testDirection() {
Map attrLTR = new HashMap();
attrLTR.put(TextAttribute.RUN_DIRECTION,
TextAttribute.RUN_DIRECTION_LTR);
Map attrRTL = new HashMap();
attrRTL.put(TextAttribute.RUN_DIRECTION,
TextAttribute.RUN_DIRECTION_RTL);
String str1 = "A\u05e0";
String str2 = "\u05e0B";
test(str1, attrLTR, Bidi.DIRECTION_LEFT_TO_RIGHT);
test(str1, attrRTL, Bidi.DIRECTION_RIGHT_TO_LEFT);
test(str2, attrLTR, Bidi.DIRECTION_LEFT_TO_RIGHT);
test(str2, attrRTL, Bidi.DIRECTION_RIGHT_TO_LEFT);
}
private static void test(String text, Map attr, int dirFlag) {
boolean expected = (dirFlag == Bidi.DIRECTION_LEFT_TO_RIGHT);
Bidi bidi = new Bidi(text, dirFlag);
boolean got = bidi.baseIsLeftToRight();
if (got != expected) {
err = true;
System.err.println("wrong Bidi(String, int).baseIsLeftToRight() value: " +
"\n\ttext=" + text +
"\n\tExpected=" + expected +
"\n\tGot=" + got);
}
AttributedString as = new AttributedString(text, attr);
AttributedCharacterIterator itr = as.getIterator();
itr.last();
itr.next();
bidi = new Bidi(itr);
got = bidi.baseIsLeftToRight();
if (got != expected) {
err = true;
System.err.println("Wrong Bidi(AttributedCharacterIterator).baseIsLeftToRight() value: " +
"\n\ttext=" + text +
"\n\tExpected=" + expected +
"\n\tGot=" + got);
}
}
}

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7051769 8038092 8174270
* @summary verify that Bidi.toString() returns the corect result.
* The second run is intended to test lazy SharedSectets init for 8038092
* @modules java.desktop
* @run main Bug7051769
* @run main/othervm -DpreloadBidi=true Bug7051769
*/
import java.awt.font.*;
import java.text.*;
import java.util.*;
public class Bug7051769 {
static {
if (System.getProperty("preloadBidi", "").equals("true")) {
// Make sure the SharedSecret is lazily initialized correctly
try {
Class.forName("jdk.internal.icu.text.BidiBase");
System.out.println("BidiBase class has been pre-loaded.");
} catch (ClassNotFoundException e) {
System.out.println("BidiBase class could not be pre-loaded.");
}
}
}
private static boolean err = false;
public static void main(String[] args) {
testNumericShaping();
if (err) {
throw new RuntimeException("Failed");
} else {
System.out.println("Passed.");
}
}
private static void testNumericShaping() {
Map attrNS = new HashMap();
attrNS.put(TextAttribute.NUMERIC_SHAPING,
NumericShaper.getContextualShaper(NumericShaper.ARABIC));
attrNS.put(TextAttribute.RUN_DIRECTION,
TextAttribute.RUN_DIRECTION_RTL);
String text = "\u0623\u0643\u062a\u0648\u0628\u0631 10";
String expected = "jdk.internal.icu.text.BidiBase[dir: 2 baselevel: 1 length: 9 runs: [1 1 1 1 1 1 1 2 2] text: [0x623 0x643 0x62a 0x648 0x628 0x631 0x20 0x661 0x660]]";
AttributedString as = new AttributedString(text, attrNS);
AttributedCharacterIterator itr = as.getIterator();
itr.last();
itr.next();
Bidi bidi = new Bidi(itr);
String got = bidi.toString();
if (!got.equals(expected)) {
err = true;
System.err.println("Wrong toString() output: " +
"\n\tExpected=" + expected +
"\n\tGot=" + got);
}
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8005277
* @summary verify that Bidi.getRunLevel() returns a corect level.
*/
import java.text.Bidi;
public class Bug8005277 {
public static void main(String[] args) {
boolean err = false;
String string = "\u05D0\u05D1\u05D2";
Bidi bidi = new Bidi(string, Bidi.DIRECTION_LEFT_TO_RIGHT);
int result = bidi.getRunCount();
if (result != 1) {
System.err.println("Incorrect run count: " + result);
err = true;
}
result = bidi.getRunStart(0);
if (result != 0) {
System.err.println("Incorrect run start: " + result);
err = true;
}
result = bidi.getRunLimit(0);
if (result != 3) {
System.err.println("Incorrect run limit: " + result);
err = true;
}
result = bidi.getRunLevel(0);
if (result != 1) {
System.err.println("Incorrect run level: " + result);
err = true;
}
if (err) {
throw new RuntimeException("Failed.");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,267 @@
/*
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4533872 4640853
* @summary Unit tests for supplementary character support (JSR-204) and Unicode 4.0 support
* @run junit Bug4533872
*/
import java.text.BreakIterator;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Bug4533872 {
static final String[] given = {
/* Lu Nd Lu Ll */
"XYZ12345 ABCDE abcde",
/* Nd Lo Nd Lu Po Lu Ll */
"123\uD800\uDC00345 ABC\uFF61XYZ abc",
/* Nd Lo Nd Lu Po Lu Ll */
"123\uD800\uDC00345 ABC\uD800\uDD00XYZ abc",
/* Lu Ll Cs Ll Cs Lu Lo Lu */
"ABCabc\uDC00xyz\uD800ABC\uD800\uDC00XYZ",
};
// Golden data for TestNext(), TestBoundar() and TestPrintEach*ward()
static final String[][] expected = {
{"XYZ12345", " ", "ABCDE", " ", "abcde"},
{"123\uD800\uDC00345", " ", "ABC", "\uFF61", "XYZ", " ", "abc"},
{"123\uD800\uDC00345", " ", "ABC", "\uD800\uDD00", "XYZ", " ", "abc"},
{"ABCabc", "\uDC00", "xyz", "\uD800", "ABC\uD800\uDC00XYZ"},
};
BreakIterator iter;
int start, end, current;
/*
* Test for next(int n)
*/
@Test
void TestNext() {
iter = BreakIterator.getWordInstance(Locale.US);
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
start = iter.first();
int j = expected[i].length - 1;
start = iter.next(j);
end = iter.next();
if (!expected[i][j].equals(given[i].substring(start, end))) {
fail("Word break failure: printEachForward() expected:<" +
expected[i][j] + ">, got:<" +
given[i].substring(start, end) +
"> start=" + start + " end=" + end);
}
}
}
/*
* Test for isBoundary(int n)
*/
@Test
void TestIsBoundary() {
iter = BreakIterator.getWordInstance(Locale.US);
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
start = iter.first();
end = iter.next();
while (end < given[i].length()) {
if (!iter.isBoundary(end)) {
fail("Word break failure: isBoundary() This should be a boundary. Index=" +
end + " for " + given[i]);
}
end = iter.next();
}
}
}
/*
* The followig test cases were made based on examples in BreakIterator's
* API Doc.
*/
/*
* Test mainly for next() and current()
*/
@Test
void TestPrintEachForward() {
iter = BreakIterator.getWordInstance(Locale.US);
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
start = iter.first();
// Check current()'s return value - should be same as first()'s.
current = iter.current();
if (start != current) {
fail("Word break failure: printEachForward() Unexpected current value: current()=" +
current + ", expected(=first())=" + start);
}
int j = 0;
for (end = iter.next();
end != BreakIterator.DONE;
start = end, end = iter.next(), j++) {
// Check current()'s return value - should be same as next()'s.
current = iter.current();
if (end != current) {
fail("Word break failure: printEachForward() Unexpected current value: current()=" +
current + ", expected(=next())=" + end);
}
if (!expected[i][j].equals(given[i].substring(start, end))) {
fail("Word break failure: printEachForward() expected:<" +
expected[i][j] + ">, got:<" +
given[i].substring(start, end) +
"> start=" + start + " end=" + end);
}
}
}
}
/*
* Test mainly for previous() and current()
*/
@Test
void TestPrintEachBackward() {
iter = BreakIterator.getWordInstance(Locale.US);
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
end = iter.last();
// Check current()'s return value - should be same as last()'s.
current = iter.current();
if (end != current) {
fail("Word break failure: printEachBackward() Unexpected current value: current()=" +
current + ", expected(=last())=" + end);
}
int j;
for (start = iter.previous(), j = expected[i].length-1;
start != BreakIterator.DONE;
end = start, start = iter.previous(), j--) {
// Check current()'s return value - should be same as previous()'s.
current = iter.current();
if (start != current) {
fail("Word break failure: printEachBackward() Unexpected current value: current()=" +
current + ", expected(=previous())=" + start);
}
if (!expected[i][j].equals(given[i].substring(start, end))) {
fail("Word break failure: printEachBackward() expected:<" +
expected[i][j] + ">, got:<" +
given[i].substring(start, end) +
"> start=" + start + " end=" + end);
}
}
}
}
/*
* Test mainly for following() and previous()
*/
@Test
void TestPrintAt_1() {
iter = BreakIterator.getWordInstance(Locale.US);
int[][] index = {
{2, 8, 10, 15, 17},
{1, 8, 10, 12, 15, 17, 20},
{3, 8, 10, 13, 16, 18, 20},
{4, 6, 9, 10, 16},
};
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
for (int j = index[i].length-1; j >= 0; j--) {
end = iter.following(index[i][j]);
start = iter.previous();
if (!expected[i][j].equals(given[i].substring(start, end))) {
fail("Word break failure: printAt_1() expected:<" +
expected[i][j] + ">, got:<" +
given[i].substring(start, end) +
"> start=" + start + " end=" + end);
}
}
}
}
/*
* Test mainly for preceding() and next()
*/
@Test
void TestPrintAt_2() {
iter = BreakIterator.getWordInstance(Locale.US);
int[][] index = {
{2, 9, 10, 15, 17},
{1, 9, 10, 13, 16, 18, 20},
{4, 9, 10, 13, 16, 18, 20},
{6, 7, 10, 11, 15},
};
for (int i = 0; i < given.length; i++) {
iter.setText(given[i]);
// Check preceding(0)'s return value - should equals BreakIterator.DONE.
if (iter.preceding(0) != BreakIterator.DONE) {
fail("Word break failure: printAt_2() expected:-1(BreakIterator.DONE), got:" +
iter.preceding(0));
}
for (int j = 0; j < index[i].length; j++) {
start = iter.preceding(index[i][j]);
end = iter.next();
if (!expected[i][j].equals(given[i].substring(start, end))) {
fail("Word break failure: printAt_2() expected:<" +
expected[i][j] + ">, got:<" +
given[i].substring(start, end) +
"> start=" + start + " end=" + end);
}
}
// Check next()'s return value - should equals BreakIterator.DONE.
end = iter.last();
start = iter.next();
if (start != BreakIterator.DONE) {
fail("Word break failure: printAt_2() expected:-1(BreakIterator.DONE), got:" + start);
}
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4740757
* @summary Confirm line-breaking behavior of Hangul
*/
import java.text.*;
import java.util.*;
public class Bug4740757 {
private static boolean err = false;
public static void main(String[] args) {
Locale defaultLocale = Locale.getDefault();
if (defaultLocale.getLanguage().equals("th")) {
Locale.setDefault(Locale.KOREA);
test4740757();
Locale.setDefault(defaultLocale);
} else {
test4740757();
}
if (err) {
throw new RuntimeException("Incorrect Line-breaking");
}
}
private static void test4740757() {
String source = "\uc548\ub155\ud558\uc138\uc694? \uc88b\uc740 \uc544\uce68, \uc5ec\ubcf4\uc138\uc694! \uc548\ub155. End.";
String expected = "\uc548/\ub155/\ud558/\uc138/\uc694? /\uc88b/\uc740 /\uc544/\uce68, /\uc5ec/\ubcf4/\uc138/\uc694! /\uc548/\ub155. /End./";
BreakIterator bi = BreakIterator.getLineInstance(Locale.KOREAN);
bi.setText(source);
int start = bi.first();
int end = bi.next();
StringBuilder sb = new StringBuilder();
for (; end != BreakIterator.DONE; start = end, end = bi.next()) {
sb.append(source.substring(start,end));
sb.append('/');
}
if (!expected.equals(sb.toString())) {
System.err.println("Failed: Hangul line-breaking failed." +
"\n\tExpected: " + expected +
"\n\tGot: " + sb +
"\nin " + Locale.getDefault() + " locale.");
err = true;
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4912404
* @summary Confirm that BreakIterator.equals(null) return false.
*/
import java.text.BreakIterator;
public class Bug4912404 {
public static void main(String[] args) {
BreakIterator b = BreakIterator.getWordInstance();
b.setText("abc");
if (b.equals(null)) {
throw new RuntimeException("BreakIterator.equals(null) should return false.");
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @run main/timeout=60 Bug4932583
* @bug 4932583
* @summary Confirm that BreakIterator doesn't get caught in an infinite loop.
*/
import java.text.*;
import java.util.*;
import java.io.*;
public class Bug4932583 {
public static void main(String[] args) {
BreakIterator iterator = BreakIterator.getCharacterInstance();
iterator.setText("\uDB40\uDFFF");
int boundary = iterator.next();
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6513074
* @summary Confirm that JIS X 0213 characters are processed in line-breaking properly.
*/
import java.text.*;
import java.util.*;
public class Bug6513074 {
private static final String[][] source = {
{"\ufa30\ufa31 \ufa69\ufa6a",
"JIS X 0213 compatibility additions (\\uFA30-\\uFA6A)"},
};
private static final String[] expected_line = {
"\ufa30/\ufa31 /\ufa69/\ufa6a/",
};
private static final String[] expected_word = {
"\ufa30\ufa31/ /\ufa69\ufa6a/",
};
private static final String[] expected_char = {
"\ufa30/\ufa31/ /\ufa69/\ufa6a/",
};
private static boolean err = false;
public static void main(String[] args) {
Locale defaultLocale = Locale.getDefault();
if (defaultLocale.getLanguage().equals("th")) {
Locale.setDefault(Locale.JAPAN);
test6513074();
Locale.setDefault(defaultLocale);
} else {
test6513074();
}
if (err) {
throw new RuntimeException("Failed: Incorrect Text-breaking.");
}
}
private static void test6513074() {
BreakIterator bi = BreakIterator.getLineInstance(Locale.JAPAN);
for (int i = 0; i < source.length; i++) {
testBreakIterator(bi, "Line", source[i][0], expected_line[i], source[i][1]);
}
bi = BreakIterator.getWordInstance(Locale.JAPAN);
for (int i = 0; i < source.length; i++) {
testBreakIterator(bi, "Word", source[i][0], expected_word[i], source[i][1]);
}
bi = BreakIterator.getCharacterInstance(Locale.JAPAN);
for (int i = 0; i < source.length; i++) {
testBreakIterator(bi, "Character", source[i][0], expected_char[i], source[i][1]);
}
}
private static void testBreakIterator(BreakIterator bi,
String type,
String source,
String expected,
String description) {
bi.setText(source);
int start = bi.first();
int end = bi.next();
StringBuilder sb = new StringBuilder();
for (; end != BreakIterator.DONE; start = end, end = bi.next()) {
sb.append(source.substring(start,end));
sb.append('/');
}
if (!expected.equals(sb.toString())) {
System.err.println("Failed: Incorrect " + type + "-breaking for " +
description +
"\n\tExpected: " + toString(expected) +
"\n\tGot: " + toString(sb.toString()));
err = true;
}
}
private static String toString(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
sb.append(" 0x" + Integer.toHexString(s.charAt(i)));
}
return sb.toString();
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7104012
* @summary Confirm that AIOBE is not thrown.
*/
import java.text.*;
import java.util.*;
public class Bug7104012 {
public static void main(String[] args) {
boolean err = false;
List<String> data = new ArrayList<>();
data.add("\udb40");
data.add(" \udb40");
data.add("\udc53");
data.add(" \udc53");
data.add(" \udb40\udc53");
data.add("\udb40\udc53");
data.add("ABC \udb40\udc53 123");
data.add("\udb40\udc53 ABC \udb40\udc53");
for (Locale locale : Locale.getAvailableLocales()) {
List<BreakIterator> breakIterators = new ArrayList<>();
breakIterators.add(BreakIterator.getCharacterInstance(locale));
breakIterators.add(BreakIterator.getLineInstance(locale));
breakIterators.add(BreakIterator.getSentenceInstance(locale));
breakIterators.add(BreakIterator.getWordInstance(locale));
for (BreakIterator bi : breakIterators) {
for (String str : data) {
try {
bi.setText(str);
bi.first();
while (bi.next() != BreakIterator.DONE) { }
bi.last();
while (bi.previous() != BreakIterator.DONE) { }
}
catch (ArrayIndexOutOfBoundsException ex) {
System.out.println(" " + data.indexOf(str)
+ ": BreakIterator(" + locale
+ ") threw AIOBE.");
err = true;
}
}
}
}
if (err) {
throw new RuntimeException("Unexpected exception.");
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8032446
* @summary Confirm that BreakIterator works as expected with new characters in Unicode 7.
*/
import java.text.*;
import java.util.*;
public class Bug8032446 {
public static void main(String[] args) {
boolean err = false;
StringBuilder sb = new StringBuilder();
for (int i = 0x10860; i <= 0x10876; i++) { // Palmyrene Letters
sb.append(Character.toChars(i));
}
sb.append(" ");
for (int i = 0x10879; i <= 0x1087D; i++) { // Palmyrene Numbers
sb.append(Character.toChars(i));
}
String s = sb.toString();
BreakIterator bi = BreakIterator.getWordInstance(Locale.ROOT);
bi.setText(s);
bi.first();
if (bi.next() != s.indexOf(' ')) {
throw new RuntimeException("Unexpected word breaking.");
}
}
}

View file

@ -0,0 +1,154 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6521742
* @summary test exceptions
*/
import java.text.*;
import java.util.*;
import static java.text.BreakIterator.DONE;
public class ExceptionTest {
private static final String text =
"An ordered collection (also known as a sequence). "
+ "The user of this interface has precise control over "
+ "where in the list each element is inserted. "
+ "The user can access elements by their integer index (position in the list), "
+ "and search for elements in the list.";
public static void main(String[] args) {
BreakIterator bi = BreakIterator.getWordInstance();
bi.setText(text);
MirroredBreakIterator mirror = new MirroredBreakIterator(bi);
final int first = bi.first();
if (first != 0) {
throw new RuntimeException("first != 0: " + first);
}
final int last = bi.last();
bi = BreakIterator.getWordInstance();
bi.setText(text);
int length = text.length();
/*
* following(int)
*/
for (int i = 0; i <= length; i++) {
if (i == length) {
check(bi.following(i), DONE);
}
check(bi.following(i), mirror.following(i));
check(bi.current(), mirror.current());
}
for (int i = -length; i < 0; i++) {
checkFollowingException(bi, i);
checkFollowingException(mirror, i);
check(bi.current(), mirror.current());
}
for (int i = 1; i < length; i++) {
checkFollowingException(bi, length + i);
checkFollowingException(mirror, length + i);
check(bi.current(), mirror.current());
}
/*
* preceding(int)
*/
for (int i = length; i >= 0; i--) {
if (i == 0) {
check(bi.preceding(i), DONE);
}
check(bi.preceding(i), mirror.preceding(i));
check(bi.current(), mirror.current());
}
for (int i = -length; i < 0; i++) {
checkPrecedingException(bi, i);
checkPrecedingException(mirror, i);
check(bi.current(), mirror.current());
}
for (int i = 1; i < length; i++) {
checkPrecedingException(bi, length + i);
checkPrecedingException(mirror, length + i);
check(bi.current(), mirror.current());
}
/*
* isBoundary(int)
*/
for (int i = 0; i <= length; i++) {
check(bi.isBoundary(i), mirror.isBoundary(i));
check(bi.current(), mirror.current());
}
for (int i = -length; i < 0; i++) {
checkIsBoundaryException(bi, i);
checkIsBoundaryException(mirror, i);
}
for (int i = 1; i < length; i++) {
checkIsBoundaryException(bi, length + i);
checkIsBoundaryException(mirror, length + i);
}
}
private static void check(int i1, int i2) {
if (i1 != i2) {
throw new RuntimeException(i1 + " != " + i2);
}
}
private static void check(boolean b1, boolean b2) {
if (b1 != b2) {
throw new RuntimeException(b1 + " != " + b2);
}
}
private static void checkFollowingException(BreakIterator bi, int offset) {
try {
bi.following(offset);
} catch (IllegalArgumentException e) {
return; // OK
}
throw new RuntimeException(bi + ": following() doesn't throw an IAE with offset "
+ offset);
}
private static void checkPrecedingException(BreakIterator bi, int offset) {
try {
bi.preceding(offset);
} catch (IllegalArgumentException e) {
return; // OK
}
throw new RuntimeException(bi + ": preceding() doesn't throw an IAE with offset "
+ offset);
}
private static void checkIsBoundaryException(BreakIterator bi, int offset) {
try {
bi.isBoundary(offset);
} catch (IllegalArgumentException e) {
return; // OK
}
throw new RuntimeException(bi + ": isBoundary() doesn't throw an IAE with offset "
+ offset);
}
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.text.BreakIterator;
import java.text.CharacterIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class MirroredBreakIterator extends BreakIterator {
private final List<Integer> boundaries;
private int charIndex;
private int boundaryIndex;
MirroredBreakIterator(BreakIterator bi) {
List<Integer> b = new ArrayList<Integer>();
int i = bi.first();
charIndex = i;
for (; i != DONE; i = bi.next()) {
b.add(i);
}
boundaries = Collections.unmodifiableList(b);
}
@Override
public Object clone() {
try {
return super.clone();
} catch (Exception e) {
throw new RuntimeException("clone failed", e);
}
}
@Override
public int first() {
return changeIndices(0);
}
@Override
public int last() {
return changeIndices(boundaries.size() - 1);
}
@Override
public int next(int n) {
if (n == 0) {
return current();
}
int newBoundary = boundaryIndex + n;
if (newBoundary < 0) {
first();
return DONE;
}
if (newBoundary > lastBoundary()) {
last();
return DONE;
}
return changeIndices(newBoundary);
}
@Override
public int next() {
if (boundaryIndex == lastBoundary()) {
return DONE;
}
return changeIndices(boundaryIndex + 1);
}
@Override
public int previous() {
if (boundaryIndex == 0) {
return DONE;
}
return changeIndices(boundaryIndex - 1);
}
@Override
public int following(int offset) {
validateOffset(offset);
for (int b = 0; b <= lastBoundary(); b++) {
int i = boundaries.get(b);
if (i > offset) {
return changeIndices(i, b);
}
}
return DONE;
}
@Override
public int preceding(int offset) {
validateOffset(offset);
for (int b = lastBoundary(); b >= 0; b--) {
int i = boundaries.get(b);
if (i < offset) {
return changeIndices(i, b);
}
}
return DONE;
}
@Override
public boolean isBoundary(int offset) {
// Call the default implementation in BreakIterator
return super.isBoundary(offset);
}
@Override
public int current() {
return charIndex;
}
@Override
public CharacterIterator getText() {
throw new UnsupportedOperationException();
}
@Override
public void setText(CharacterIterator newText) {
throw new UnsupportedOperationException();
}
private int lastBoundary() {
return boundaries.size() - 1;
}
private int changeIndices(int newCharIndex, int newBoundary) {
boundaryIndex = newBoundary;
return charIndex = newCharIndex;
}
private int changeIndices(int newBoundary) {
try {
return changeIndices(boundaries.get(newBoundary), newBoundary);
} catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException(e);
}
}
private void validateOffset(int offset) {
if (offset < boundaries.get(0) || offset > boundaries.get(lastBoundary())) {
throw new IllegalArgumentException();
}
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary test Comparison of New Collators against Old Collators in the en_US locale
* @modules jdk.localedata
*/
import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Locale;
import java.text.BreakIterator;
import java.lang.Math;
public class NewVSOld_th_TH {
public static void main(String args[]) throws FileNotFoundException,
UnsupportedEncodingException,
IOException {
final String ENCODING = "UTF-8";
final Locale THAI_LOCALE = Locale.of("th", "TH");
String rawFileName = "test_th_TH.txt";
String oldFileName = "broken_th_TH.txt";
StringBuilder rawText = new StringBuilder();
StringBuilder oldText = new StringBuilder();
StringBuilder cookedText = new StringBuilder();
File f;
f = new File(System.getProperty("test.src", "."), rawFileName);
try (InputStreamReader rawReader =
new InputStreamReader(new FileInputStream(f), ENCODING)) {
int c;
while ((c = rawReader.read()) != -1) {
rawText.append((char) c);
}
}
f = new File(System.getProperty("test.src", "."), oldFileName);
try (InputStreamReader oldReader =
new InputStreamReader(new FileInputStream(f), ENCODING)) {
int c;
while ((c = oldReader.read()) != -1) {
oldText.append((char) c);
}
}
BreakIterator breakIterator = BreakIterator.getWordInstance(THAI_LOCALE);
breakIterator.setText(rawText.toString());
int start = breakIterator.first();
for (int end = breakIterator.next();
end != BreakIterator.DONE;
start = end, end = breakIterator.next()) {
cookedText.append(rawText.substring(start, end));
cookedText.append("\n");
}
String cooked = cookedText.toString();
String old = oldText.toString();
if (cooked.compareTo(old) != 0) {
throw new RuntimeException("Text not broken the same as with the old BreakIterators");
}
}
}

View file

@ -0,0 +1,13 @@
การ
เก็บ
ภาษีประเทศ
ไทยและ
ประเทศ
เดนมาร์ค
อนุสัญญา
ระหว่าง
รัฐบาล
แห่ง
ประเทศ
ไทย
กับ

View file

@ -0,0 +1 @@
การเก็บภาษีประเทศไทยและประเทศเดนมาร์คอนุสัญญาระหว่างรัฐบาลแห่งประเทศไทยกับ

View file

@ -0,0 +1,293 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary test for Character Iterator
* @run junit CharacterIteratorTest
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
*
* Portions copyright (c) 2007 Sun Microsystems, Inc.
* All Rights Reserved.
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
import java.text.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class CharacterIteratorTest {
public CharacterIteratorTest() {
}
@Test
public void TestConstructionAndEquality() {
String testText = "Now is the time for all good men to come to the aid of their country.";
String testText2 = "Don't bother using this string.";
CharacterIterator test1 = new StringCharacterIterator(testText);
CharacterIterator test2 = new StringCharacterIterator(testText, 5);
CharacterIterator test3 = new StringCharacterIterator(testText, 2, 20, 5);
CharacterIterator test4 = new StringCharacterIterator(testText2);
CharacterIterator test5 = (CharacterIterator)test1.clone();
if (test1.equals(test2) || test1.equals(test3) || test1.equals(test4))
fail("Construation or equals() failed: Two unequal iterators tested equal");
if (!test1.equals(test5))
fail("clone() or equals() failed: Two clones tested unequal");
if (test1.hashCode() == test2.hashCode() || test1.hashCode() == test3.hashCode()
|| test1.hashCode() == test4.hashCode())
fail("hash() failed: different objects have same hash code");
if (test1.hashCode() != test5.hashCode())
fail("hash() failed: identical objects have different hash codes");
test1.setIndex(5);
if (!test1.equals(test2) || test1.equals(test5))
fail("setIndex() failed");
}
@Test
public void TestIteration() {
String text = "Now is the time for all good men to come to the aid of their country.";
CharacterIterator iter = new StringCharacterIterator(text, 5);
if (iter.current() != text.charAt(5))
fail("Iterator didn't start out in the right place.");
char c = iter.first();
int i = 0;
if (iter.getBeginIndex() != 0 || iter.getEndIndex() != text.length())
fail("getBeginIndex() or getEndIndex() failed");
System.out.println("Testing forward iteration...");
do {
if (c == CharacterIterator.DONE && i != text.length())
fail("Iterator reached end prematurely");
else if (c != text.charAt(i))
fail("Character mismatch at position " + i + ", iterator has " + c +
", string has " + text.charAt(c));
if (iter.current() != c)
fail("current() isn't working right");
if (iter.getIndex() != i)
fail("getIndex() isn't working right");
if (c != CharacterIterator.DONE) {
c = iter.next();
i++;
}
} while (c != CharacterIterator.DONE);
c = iter.last();
i = text.length() - 1;
System.out.println("Testing backward iteration...");
do {
if (c == CharacterIterator.DONE && i >= 0)
fail("Iterator reached end prematurely");
else if (c != text.charAt(i))
fail("Character mismatch at position " + i + ", iterator has " + c +
", string has " + text.charAt(c));
if (iter.current() != c)
fail("current() isn't working right");
if (iter.getIndex() != i)
fail("getIndex() isn't working right");
if (c != CharacterIterator.DONE) {
c = iter.previous();
i--;
}
} while (c != CharacterIterator.DONE);
iter = new StringCharacterIterator(text, 5, 15, 10);
if (iter.getBeginIndex() != 5 || iter.getEndIndex() != 15)
fail("creation of a restricted-range iterator failed");
if (iter.getIndex() != 10 || iter.current() != text.charAt(10))
fail("starting the iterator in the middle didn't work");
c = iter.first();
i = 5;
System.out.println("Testing forward iteration over a range...");
do {
if (c == CharacterIterator.DONE && i != 15)
fail("Iterator reached end prematurely");
else if (c != text.charAt(i))
fail("Character mismatch at position " + i + ", iterator has " + c +
", string has " + text.charAt(c));
if (iter.current() != c)
fail("current() isn't working right");
if (iter.getIndex() != i)
fail("getIndex() isn't working right");
if (c != CharacterIterator.DONE) {
c = iter.next();
i++;
}
} while (c != CharacterIterator.DONE);
c = iter.last();
i = 14;
System.out.println("Testing backward iteration over a range...");
do {
if (c == CharacterIterator.DONE && i >= 5)
fail("Iterator reached end prematurely");
else if (c != text.charAt(i))
fail("Character mismatch at position " + i + ", iterator has " + c +
", string has " + text.charAt(c));
if (iter.current() != c)
fail("current() isn't working right");
if (iter.getIndex() != i)
fail("getIndex() isn't working right");
if (c != CharacterIterator.DONE) {
c = iter.previous();
i--;
}
} while (c != CharacterIterator.DONE);
}
/**
* @bug 4082050 4078261 4078255
*/
@Test
public void TestPathologicalCases() {
String text = "This is only a test.";
/*
This test is commented out until API-change approval for bug #4082050 goes through.
// test for bug #4082050 (don't get an error if begin == end, even though all
// operations on the iterator will cause exceptions)
// [I actually fixed this so that you CAN create an iterator with begin == end,
// but all operations on it return DONE.]
CharacterIterator iter = new StringCharacterIterator(text, 5, 5, 5);
if (iter.first() != CharacterIterator.DONE
|| iter.next() != CharacterIterator.DONE
|| iter.last() != CharacterIterator.DONE
|| iter.previous() != CharacterIterator.DONE
|| iter.current() != CharacterIterator.DONE
|| iter.getIndex() != 5)
fail("Got something other than DONE when performing operations on an empty StringCharacterIterator");
*/
CharacterIterator iter = null;
// if we try to construct a StringCharacterIterator with an endIndex that's off
// the end of the String under iterator, we're supposed to get an
// IllegalArgumentException
boolean gotException = false;
try {
iter = new StringCharacterIterator(text, 5, 100, 5);
}
catch (IllegalArgumentException e) {
gotException = true;
}
if (!gotException)
fail("StringCharacterIterator didn't throw an exception when given an invalid substring range.");
// test for bug #4078255 (getting wrong value from next() when we're at the end
// of the string)
iter = new StringCharacterIterator(text);
int expectedIndex = iter.getEndIndex();
int actualIndex;
iter.last();
actualIndex = iter.getIndex();
if (actualIndex != expectedIndex - 1)
fail("last() failed: expected " + (expectedIndex - 1) + ", got " + actualIndex);
iter.next();
actualIndex = iter.getIndex();
if (actualIndex != expectedIndex)
fail("next() after last() failed: expected " + expectedIndex + ", got " + actualIndex);
iter.next();
actualIndex = iter.getIndex();
if (actualIndex != expectedIndex)
fail("second next() after last() failed: expected " + expectedIndex + ", got " + actualIndex);
}
/*
* @bug 4123771 4051073
* #4123771 is actually a duplicate of bug #4051073, which was fixed some time ago, but
* no one ever added a regression test for it.
*/
@Test
public void TestBug4123771() {
String text = "Some string for testing";
StringCharacterIterator iter = new StringCharacterIterator(text);
int index = iter.getEndIndex();
try {
char c = iter.setIndex(index);
}
catch (Exception e) {
System.out.println("method setIndex(int position) throws unexpected exception " + e);
System.out.println(" position: " + index);
System.out.println(" getEndIndex(): " + iter.getEndIndex());
System.out.println(" text.length(): " + text.length());
fail(""); // re-throw the exception through our test framework
}
}
}

View file

@ -0,0 +1,325 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Collation API
* @modules jdk.localedata
* @run junit APITest
*/
import java.util.Locale;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.text.CollationKey;
import java.text.CollationElementIterator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class APITest {
final void doAssert(boolean condition, String message)
{
if (!condition) {
fail("ERROR: " + message);
}
}
@Test
public final void TestProperty( )
{
Collator col = null;
try {
col = Collator.getInstance(Locale.ROOT);
System.out.println("The property tests begin : ");
System.out.println("Test ctors : ");
doAssert(col.compare("ab", "abc") < 0, "ab < abc comparison failed");
doAssert(col.compare("ab", "AB") < 0, "ab < AB comparison failed");
doAssert(col.compare("black-bird", "blackbird") > 0, "black-bird > blackbird comparison failed");
doAssert(col.compare("black bird", "black-bird") < 0, "black bird < black-bird comparison failed");
doAssert(col.compare("Hello", "hello") > 0, "Hello > hello comparison failed");
System.out.println("Test ctors ends.");
System.out.println("testing Collator.getStrength() method ...");
doAssert(col.getStrength() == Collator.TERTIARY, "collation object has the wrong strength");
doAssert(col.getStrength() != Collator.PRIMARY, "collation object's strength is primary difference");
System.out.println("testing Collator.setStrength() method ...");
col.setStrength(Collator.SECONDARY);
doAssert(col.getStrength() != Collator.TERTIARY, "collation object's strength is secondary difference");
doAssert(col.getStrength() != Collator.PRIMARY, "collation object's strength is primary difference");
doAssert(col.getStrength() == Collator.SECONDARY, "collation object has the wrong strength");
System.out.println("testing Collator.setDecomposition() method ...");
col.setDecomposition(Collator.NO_DECOMPOSITION);
doAssert(col.getDecomposition() != Collator.FULL_DECOMPOSITION, "collation object's strength is secondary difference");
doAssert(col.getDecomposition() != Collator.CANONICAL_DECOMPOSITION, "collation object's strength is primary difference");
doAssert(col.getDecomposition() == Collator.NO_DECOMPOSITION, "collation object has the wrong strength");
} catch (Exception foo) {
fail("Error : " + foo.getMessage()
+ "\n Default Collator creation failed.");
}
System.out.println("Default collation property test ended.");
System.out.println("Collator.getRules() testing ...");
doAssert(((RuleBasedCollator)col).getRules().length() != 0, "getRules() result incorrect" );
System.out.println("getRules tests end.");
try {
col = Collator.getInstance(Locale.FRENCH);
col.setStrength(Collator.PRIMARY);
System.out.println("testing Collator.getStrength() method again ...");
doAssert(col.getStrength() != Collator.TERTIARY, "collation object has the wrong strength");
doAssert(col.getStrength() == Collator.PRIMARY, "collation object's strength is not primary difference");
System.out.println("testing French Collator.setStrength() method ...");
col.setStrength(Collator.TERTIARY);
doAssert(col.getStrength() == Collator.TERTIARY, "collation object's strength is not tertiary difference");
doAssert(col.getStrength() != Collator.PRIMARY, "collation object's strength is primary difference");
doAssert(col.getStrength() != Collator.SECONDARY, "collation object's strength is secondary difference");
} catch (Exception bar) {
fail("Error : " + bar.getMessage()
+ "\n Creating French collation failed.");
}
System.out.println("Create junk collation: ");
Locale abcd = Locale.of("ab", "CD");
Collator junk = null;
try {
junk = Collator.getInstance(abcd);
} catch (Exception err) {
fail("Error : " + err.getMessage()
+ "\n Junk collation creation failed, should at least return the collator for the base bundle.");
}
try {
col = Collator.getInstance(Locale.ROOT);
doAssert(col.equals(junk), "The base bundle's collation should be returned.");
} catch (Exception exc) {
fail("Error : " + exc.getMessage()
+ "\n Default collation comparison, caching not working.");
}
System.out.println("Collator property test ended.");
}
@Test
public final void TestHashCode( )
{
System.out.println("hashCode tests begin.");
Collator col1 = null;
try {
col1 = Collator.getInstance(Locale.ROOT);
} catch (Exception foo) {
fail("Error : " + foo.getMessage()
+ "\n Default collation creation failed.");
}
Collator col2 = null;
Locale dk = Locale.of("da", "DK");
try {
col2 = Collator.getInstance(dk);
} catch (Exception bar) {
fail("Error : " + bar.getMessage()
+ "\n Danish collation creation failed.");
return;
}
Collator col3 = null;
try {
col3 = Collator.getInstance(Locale.ROOT);
} catch (Exception err) {
fail("Error : " + err.getMessage()
+ "\n 2nd default collation creation failed.");
}
System.out.println("Collator.hashCode() testing ...");
if (col1 != null) {
doAssert(col1.hashCode() != col2.hashCode(), "Hash test1 result incorrect");
if (col3 != null) {
doAssert(col1.hashCode() == col3.hashCode(), "Hash result not equal");
}
}
System.out.println("hashCode tests end.");
}
//----------------------------------------------------------------------------
// ctor -- Tests the constructor methods
//
@Test
public final void TestCollationKey( )
{
System.out.println("testing CollationKey begins...");
Collator col = null;
try {
col = Collator.getInstance(Locale.ROOT);
} catch (Exception foo) {
fail("Error : " + foo.getMessage()
+ "\n Default collation creation failed.");
}
if (col == null) {
return;
}
String test1 = "Abcda", test2 = "abcda";
System.out.println("Use tertiary comparison level testing ....");
CollationKey sortk1 = col.getCollationKey(test1);
CollationKey sortk2 = col.getCollationKey(test2);
doAssert(sortk1.compareTo(sortk2) > 0,
"Result should be \"Abcda\" >>> \"abcda\"");
CollationKey sortk3 = sortk2;
CollationKey sortkNew = sortk1;
doAssert(sortk1 != sortk2, "The sort keys should be different");
doAssert(sortk1.hashCode() != sortk2.hashCode(), "sort key hashCode() failed");
doAssert(sortk2.compareTo(sortk3) == 0, "The sort keys should be the same");
doAssert(sortk1 == sortkNew, "The sort keys assignment failed");
doAssert(sortk1.hashCode() == sortkNew.hashCode(), "sort key hashCode() failed");
doAssert(sortkNew != sortk3, "The sort keys should be different");
doAssert(sortk1.compareTo(sortk3) > 0, "Result should be \"Abcda\" >>> \"abcda\"");
doAssert(sortk2.compareTo(sortk3) == 0, "Result should be \"abcda\" == \"abcda\"");
long cnt1, cnt2;
byte byteArray1[] = sortk1.toByteArray();
byte byteArray2[] = sortk2.toByteArray();
doAssert(byteArray1 != null && byteArray2 != null, "CollationKey.toByteArray failed.");
System.out.println("testing sortkey ends...");
}
//----------------------------------------------------------------------------
// ctor -- Tests the constructor methods
//
@Test
public final void TestElemIter( )
{
System.out.println("testing sortkey begins...");
Collator col = null;
try {
col = Collator.getInstance();
} catch (Exception foo) {
fail("Error : " + foo.getMessage()
+ "\n Default collation creation failed.");
}
RuleBasedCollator rbCol;
if (col instanceof RuleBasedCollator) {
rbCol = (RuleBasedCollator) col;
} else {
return;
}
String testString1 = "XFILE What subset of all possible test cases has the highest probability of detecting the most errors?";
String testString2 = "Xf ile What subset of all possible test cases has the lowest probability of detecting the least errors?";
System.out.println("Constructors and comparison testing....");
CollationElementIterator iterator1 = rbCol.getCollationElementIterator(testString1);
CollationElementIterator iterator2 = rbCol.getCollationElementIterator(testString1);
CollationElementIterator iterator3 = rbCol.getCollationElementIterator(testString2);
int order1, order2, order3;
order1 = iterator1.next();
order2 = iterator2.next();
doAssert(order1 == order2, "The order result should be the same");
order3 = iterator3.next();
doAssert(CollationElementIterator.primaryOrder(order1)
== CollationElementIterator.primaryOrder(order3),
"The primary orders should be the same");
doAssert(CollationElementIterator.secondaryOrder(order1)
== CollationElementIterator.secondaryOrder(order3),
"The secondary orders should be the same");
doAssert(CollationElementIterator.tertiaryOrder(order1)
== CollationElementIterator.tertiaryOrder(order3),
"The tertiary orders should be the same");
order1 = iterator1.next();
order3 = iterator3.next();
doAssert(CollationElementIterator.primaryOrder(order1)
== CollationElementIterator.primaryOrder(order3),
"The primary orders should be identical");
doAssert(CollationElementIterator.tertiaryOrder(order1)
!= CollationElementIterator.tertiaryOrder(order3),
"The tertiary orders should be different");
order1 = iterator1.next();
order3 = iterator3.next();
doAssert(CollationElementIterator.secondaryOrder(order1)
!= CollationElementIterator.secondaryOrder(order3),
"The secondary orders should be different");
doAssert(order1 != CollationElementIterator.NULLORDER,
"Unexpected end of iterator reached");
iterator1.reset();
iterator2.reset();
iterator3.reset();
order1 = iterator1.next();
order2 = iterator2.next();
doAssert(order1 == order2, "The order result should be the same");
order3 = iterator3.next();
doAssert(CollationElementIterator.primaryOrder(order1)
== CollationElementIterator.primaryOrder(order3),
"The orders should be the same");
doAssert(CollationElementIterator.secondaryOrder(order1)
== CollationElementIterator.secondaryOrder(order3),
"The orders should be the same");
doAssert(CollationElementIterator.tertiaryOrder(order1)
== CollationElementIterator.tertiaryOrder(order3),
"The orders should be the same");
order1 = iterator1.next();
order2 = iterator2.next();
order3 = iterator3.next();
doAssert(CollationElementIterator.primaryOrder(order1)
== CollationElementIterator.primaryOrder(order3),
"The primary orders should be identical");
doAssert(CollationElementIterator.tertiaryOrder(order1)
!= CollationElementIterator.tertiaryOrder(order3),
"The tertiary orders should be different");
order1 = iterator1.next();
order3 = iterator3.next();
doAssert(CollationElementIterator.secondaryOrder(order1)
!= CollationElementIterator.secondaryOrder(order3),
"The secondary orders should be different");
doAssert(order1 != CollationElementIterator.NULLORDER, "Unexpected end of iterator reached");
System.out.println("testing CollationElementIterator ends...");
}
@Test
public final void TestGetAll()
{
Locale[] list = Collator.getAvailableLocales();
for (int i = 0; i < list.length; ++i) {
System.out.println("Locale name: ");
System.out.println(list[i].toString());
System.out.println(" , the display name is : ");
System.out.println(list[i].getDisplayName());
}
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 5047314
* @summary verify that compare() and getCollationKey() don't go into an infinite loop for unfinished Thai/Lao text.
* @run main/timeout=60 Bug5047314
*/
import java.text.Collator;
import java.util.Locale;
public class Bug5047314 {
private static Collator colLao = Collator.getInstance(Locale.of("lo"));
private static Collator colThai = Collator.getInstance(Locale.of("th"));
private static String[] textLao = {
"\u0ec0", "\u0ec1", "\u0ec2", "\u0ec3", "\u0ec4"
};
private static String[] textThai = {
"\u0e40", "\u0e41", "\u0e42", "\u0e43", "\u0e44"
};
public static void main(String[] args) {
testLao1();
testLao2();
testThai1();
testThai2();
}
private static void testLao1() {
System.out.print("Test(Lao 1) .... ");
for (int i = 0; i < textLao.length; i++) {
colLao.compare(textLao[i], textLao[i]);
}
System.out.println("Passed.");
}
private static void testLao2() {
System.out.print("Test(Lao 2) .... ");
for (int i = 0; i < textLao.length; i++) {
colLao.compare(textLao[i], textLao[i]);
}
System.out.println("Passed.");
}
private static void testThai1() {
System.out.print("Test(Thai 1) .... ");
for (int i = 0; i < textThai.length; i++) {
colThai.compare(textThai[i], textThai[i]);
}
System.out.println("Passed.");
}
private static void testThai2() {
System.out.print("Test(Thai 2) .... ");
for (int i = 0; i < textThai.length; i++) {
colThai.getCollationKey(textThai[i]);
}
System.out.println("Passed.");
}
}

View file

@ -0,0 +1,196 @@
/*
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6271411
* @summary Confirm that three JCK testcases for CollationElementIterator pass.
* @run junit Bug6271411
*/
import java.text.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/*
* Based on JCK-runtime-15/tests/api/java_text/CollationElementIterator/ColltnElmtIterTests.java.
*/
public class Bug6271411 {
/*
* Rule for RuleBasedCollator
*/
static final String rule = "< c, C < d; D";
/*
* Textdata
*/
static final String[] values = {
"", "c", "cH522Yd", "Hi, high school", "abcchCHidD"
};
/*
* Confirm that setOffset() throws IllegalArgumentException
* (not IndexOutOfBoundsException) if the given offset is invalid.
* Use CollationElementIterator.setText(String).
*/
@Test
public void Test_CollationElementIterator0007() throws Exception {
int[] offsets = {
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -10000, -2, -1,
100, 101, // These two are customized for every test data later.
12345, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
};
boolean err = false;
RuleBasedCollator rbc = new RuleBasedCollator(rule);
CollationElementIterator iterator = rbc.getCollationElementIterator("");
for (int i = 0; i < values.length; i++) {
String source = values[i];
iterator.setText(source);
int len = source.length();
offsets[5] = len + 1;
offsets[6] = len + 2;
for (int j = 0; j < offsets.length; j++) {
try {
iterator.setOffset(offsets[j]);
System.out.println("IllegalArgumentException should be thrown for setOffset(" +
offsets[j] + ") for <" + source + ">.");
err = true;
}
catch (IllegalArgumentException e) {
}
}
}
if (err) {
fail("CollationElementIterator.setOffset() didn't throw an expected IllegalArguemntException.");
}
}
/*
* Confirm that setText() doesn't throw an exception and setOffset() throws
* IllegalArgumentException if the given offset is invalid.
* Use CollationElementIterator.setText(CharacterIterator).
*/
@Test
public void Test_CollationElementIterator0010() throws Exception {
String prefix = "xyz abc";
String suffix = "1234567890";
int begin = prefix.length();
int[] offsets = {
Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -10000,
-2, -1, 0, 1, begin - 2, begin - 1, 9, 10, 11, 12, 13, 14,
15, 12345, Integer.MAX_VALUE - 1, Integer.MAX_VALUE
};
boolean err = false;
RuleBasedCollator rbc = new RuleBasedCollator(rule);
CollationElementIterator iterator = rbc.getCollationElementIterator("");
for (int i = 0; i < values.length; i++) {
String str = prefix + values[i] + suffix;
int len = str.length();
int end = len - suffix.length();
CharacterIterator source =
new StringCharacterIterator(str, begin, end, begin);
iterator.setText(source);
offsets[9] = end + 1;
offsets[10] = end + 2;
offsets[11] = (end + len) / 2;
offsets[12] = len - 1;
offsets[13] = len;
offsets[14] = len + 1;
offsets[15] = len + 2;
for (int j = 0; j < offsets.length; j++) {
try {
iterator.setOffset(offsets[j]);
System.out.println("IllegalArgumentException should be thrown for setOffset(" +
offsets[j] + ") for <" + str + ">.");
err = true;
}
catch (IllegalArgumentException e) {
}
}
}
if (err) {
fail("CollationElementIterator.setOffset() didn't throw an expected IllegalArguemntException.");
}
}
/*
* Confirm that setText() doesn't throw an exception and setOffset() sets
* an offset as expected.
* Use CollationElementIterator.setText(CharacterIterator).
*/
@Test
public void Test_CollationElementIterator0011() throws Exception {
String prefix = "xyz abc";
String suffix = "1234567890";
int begin = prefix.length();
int[] offsets = { begin, begin + 1, 2, 3, 4 };
RuleBasedCollator rbc = new RuleBasedCollator(rule);
CollationElementIterator iterator = rbc.getCollationElementIterator("");
for (int i = 0; i < values.length; i++) {
String str = prefix + values[i] + suffix;
int len = str.length();
int end = len - suffix.length();
CharacterIterator source =
new StringCharacterIterator(str, begin, end, begin);
iterator.setText(source);
offsets[2] = (end + len) / 2;
offsets[3] = len - 1;
offsets[4] = len;
for (int j = 0; j < offsets.length; j++) {
int offset = offsets[j];
if (offset < begin || offset > end) {
break;
}
iterator.setOffset(offset);
int newOffset = iterator.getOffset();
if (newOffset != offset) {
throw new RuntimeException("setOffset() didn't set a correct offset. Got: " +
newOffset + " Expected: " + offset + " for <" + str + ">.");
}
}
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6970930
* @summary verify that compare() throws NPE instead of IAE when an argument is null.
*/
import java.text.*;
public class Bug6970930 {
private static boolean err = false;
public static void main(String[] args) {
// Check if compare() throws NPE.
test1(null, null);
test1("\"foo\"", null);
test1(null, "\"bar\"");
if (err) {
throw new RuntimeException("Failed.");
} else {
System.out.println("Passed.");
}
}
private static void test1(String s1, String s2) {
RuleBasedCollator col = null;
try {
col = new RuleBasedCollator("< a < b");
}
catch (ParseException e) {
err = true;
System.err.println(e);
}
try {
col.compare("foo", "bar"); // This line is necessary to reproduce the bug.
col.compare(s1, s2);
err = true;
System.err.println("No exception was thrown for compare(" +
s1 + ", " + s2 + ").");
}
catch (NullPointerException e) {
System.out.println("NPE was thrown as expected for compare(" +
s1 + ", " + s2 + ").");
}
catch (Exception e) {
err = true;
System.err.println("Unexpected exception was thrown for compare(" +
s1 + ", " + s2 + "): " + e);
}
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 7200119
* @summary verify that getAvailableLocales() contains Locale.US
*/
import java.text.*;
import java.util.*;
public class Bug7200119 {
public static void main(String[] args) {
List<Locale> avail = Arrays.asList(Collator.getAvailableLocales());
if (!avail.contains(Locale.US)) {
throw new RuntimeException("Failed.");
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4106263
* @summary Tests on the bug 4106263 - CollationKey became non-final extendable class.
* The implementation of CollationKey is moved to the new private class,
* RuleBasedCollationKey. This test basically tests on the two features:
* 1. Existing code using CollationKey works (backward compatiblility)
* 2. CollationKey can be extended by its subclass.
* @modules jdk.localedata
*/
public class CollationKeyTest {
public static void main(String[] args) {
CollationKeyTestImpl ck = new CollationKeyTestImpl("Testing the CollationKey");
ck.run();
}
}

View file

@ -0,0 +1,243 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
* A part of tests on the bug 4106263. CollationKey became non-final extendable class.
* The implementation of CollationKey is moved to the new private class,
* RuleBasedCollationKey. This test basically tests on the two features:
* 1. Existing code using CollationKey works (backward compatiblility)
* 2. CollationKey can be extended by its subclass.
*/
import java.util.Locale;
import java.text.Collator;
import java.text.CollationKey;
import java.io.*;
import java.text.*;
public class CollationKeyTestImpl extends CollationKey {
private static String[] sourceData_ja = {
"\u3042\u3044\u3046\u3048\u3048",
"\u3041\u3043\u3045\u3047\u3049",
"\u3052\u3054\u3056\u3058\u3058",
"\u3051\u3053\u3055\u3057\u3059",
"\u3062\u3064\u3066\u3068\u3068",
"\u3061\u3063\u3065\u3067\u3069",
"\u3072\u3074\u3075\u3078\u3078",
"\u3071\u3073\u3075\u3077\u3079",
"\u3082\u3084\u3085\u3088\u3088",
"\u3081\u3083\u3085\u3087\u3089",
"\u30a2\u30a4\u30a6\u30a8\u30aa",
"\u30a1\u30a3\u30a5\u30a7\u30a9",
"\u30c2\u30c4\u30c6\u30c8\u30ca",
"\u30c1\u30c3\u30c5\u30c7\u30c9",
"\u30b2\u30b4\u30b6\u30b8\u30ba",
"\u30b1\u30b3\u30b5\u30b7\u30b9",
"\u30d2\u30d4\u30d6\u30d8\u30da",
"\u30d1\u30d3\u30d5\u30d7\u30d9",
"\u30e2\u30e4\u30e6\u30e8\u30ea",
"\u30e1\u30e3\u30e5\u30e7\u30e9"
};
private static final String[] targetData_ja = {
"\u3042\u3044\u3046\u3048\u3048",
"\u3041\u3043\u3045\u3047\u3049",
"\u30a2\u30a4\u30a6\u30a8\u30aa",
"\u30a1\u30a3\u30a5\u30a7\u30a9",
"\u3052\u3054\u3056\u3058\u3058",
"\u3051\u3053\u3055\u3057\u3059",
"\u30b1\u30b3\u30b5\u30b7\u30b9",
"\u30b2\u30b4\u30b6\u30b8\u30ba",
"\u3061\u3063\u3065\u3067\u3069",
"\u30c1\u30c3\u30c5\u30c7\u30c9",
"\u3062\u3064\u3066\u3068\u3068",
"\u30c2\u30c4\u30c6\u30c8\u30ca",
"\u3071\u3073\u3075\u3077\u3079",
"\u30d1\u30d3\u30d5\u30d7\u30d9",
"\u3072\u3074\u3075\u3078\u3078",
"\u30d2\u30d4\u30d6\u30d8\u30da",
"\u3081\u3083\u3085\u3087\u3089",
"\u30e1\u30e3\u30e5\u30e7\u30e9",
"\u3082\u3084\u3085\u3088\u3088",
"\u30e2\u30e4\u30e6\u30e8\u30ea"
};
public void run() {
/** debug: printout the test data
for (int i=0; i<sourceData_ja.length; i++){
System.out.println(i+": "+sourceData_ja[i]);
}
**/
/*
* 1. Test the backward compatibility
* note: targetData_ja.length is equal to sourceData_ja.length
*/
Collator myCollator = Collator.getInstance(Locale.JAPAN);
CollationKey[] keys = new CollationKey[sourceData_ja.length];
CollationKey[] target_keys = new CollationKey[targetData_ja.length];
for (int i=0; i<sourceData_ja.length; i++){
keys[i] = myCollator.getCollationKey(sourceData_ja[i]);
target_keys[i] = myCollator.getCollationKey(targetData_ja[i]); //used later
}
/* Sort the string using CollationKey */
InsertionSort(keys);
/** debug: printout the result after sort
System.out.println("--- After Sorting ---");
for (int i=0; i<sourceData_ja.length; i++){
System.out.println(i+" :"+keys[i].getSourceString());
}
**/
/*
* Compare the result using equals method and getSourceString method.
*/
boolean pass = true;
for (int i=0; i<sourceData_ja.length; i++){
/* Comparing using String.equals: in order to use getStringSource() */
if (! targetData_ja[i].equals(keys[i].getSourceString())){
throw new RuntimeException("FAILED: CollationKeyTest backward compatibility "
+"while comparing" +targetData_ja[i]+" vs "
+keys[i].getSourceString());
}
/* Comparing using CollaionKey.equals: in order to use equals() */
if (! target_keys[i].equals(keys[i])){
throw new RuntimeException("FAILED: CollationKeyTest backward compatibility."
+" Using CollationKey.equals " +targetData_ja[i]
+" vs " +keys[i].getSourceString());
}
/* Comparing using CollaionKey.hashCode(): in order to use hashCode() */
if (target_keys[i].hashCode() != keys[i].hashCode()){
throw new RuntimeException("FAILED: CollationKeyTest backward compatibility."
+" Using CollationKey.hashCode " +targetData_ja[i]
+" vs " +keys[i].getSourceString());
}
/* Comparing using CollaionKey.toByteArray(): in order to use toByteArray() */
byte[] target_bytes = target_keys[i].toByteArray();
byte[] source_bytes = keys[i].toByteArray();
for (int j=0; j<target_bytes.length; j++){
Byte targetByte = new Byte(target_bytes[j]);
Byte sourceByte = new Byte(source_bytes[j]);
if (targetByte.compareTo(sourceByte)!=0){
throw new RuntimeException("FAILED: CollationKeyTest backward "
+"compatibility. Using Byte.compareTo from CollationKey.toByteArray "
+targetData_ja[i]
+" vs " +keys[i].getSourceString());
}
}
}
testSubclassMethods();
testConstructor();
}
/*
* Sort the array of CollationKey using compareTo method in insertion sort.
*/
private void InsertionSort(CollationKey[] keys){
int f, i;
CollationKey tmp;
for (f=1; f < keys.length; f++){
if(keys[f].compareTo( keys[f-1]) > 0){
continue;
}
tmp = keys[f];
i = f-1;
while ( (i>=0) && (keys[i].compareTo(tmp) > 0) ) {
keys[i+1] = keys[i];
i--;
}
keys[i+1]=tmp;
}
}
/*
* From here is the bogus methods to test the subclass of
* the CollationKey class.
*/
public CollationKeyTestImpl(String str){
super (str);
// debug: System.out.println("CollationKeyTest extends CollationKey class: "+str);
}
/* abstract method: needs to be implemented */
public byte[] toByteArray(){
String foo= "Hello";
return foo.getBytes();
}
/* abstract method: needs to be implemented */
public int compareTo(CollationKey target){
return 0;
}
public boolean equals(Object target){
return true;
}
public String getSourceString(){
return "CollationKeyTestImpl";
}
/*
* This method tests the collection of bugus methods from the extended
* subclass of CollationKey class.
*/
private void testSubclassMethods() {
CollationKeyTestImpl clt1 = new CollationKeyTestImpl("testSubclassMethods-1");
CollationKeyTestImpl clt2 = new CollationKeyTestImpl("testSubclassMethods-2");
// extended method, equals always returns true
if (!clt1.equals(clt2)){
throw new RuntimeException("Failed: equals(CollationKeySubClass)");
}
// extended method, compareTo always returns 0
if (clt1.compareTo(clt2)!=0){
throw new RuntimeException("Failed: compareTo(CollationKeySubClass)");
}
// overriding extended method, getSourceString always returns "CollationKeyTestImpl"
if (! clt1.getSourceString().equals("CollationKeyTestImpl")){
throw new RuntimeException("Failed: CollationKey subclass overriding getSourceString()");
}
// extended method, toByteArray always returns bytes from "Hello"
String str2 = new String( clt2.toByteArray());
if (! clt2.equals("Hello")){
throw new RuntimeException("Failed: CollationKey subclass toByteArray()");
}
}
/*
* This method tests CollationKey constructor with null source string.
* It should throw NPE.
*/
private void testConstructor() {
boolean npe=false;
try{
CollationKeyTestImpl cltNull = new CollationKeyTestImpl(null);
} catch (NullPointerException npException){
npe=true;
// debug: System.out.println("--- NPE is thrown with NULL arguement: PASS ---");
}
if(!npe){
throw new RuntimeException("Failed: CollationKey Constructor with null source"+
" didn't throw NPE!");
}
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4114080 4150807
* @summary Test currency collation. For bug 4114080, make sure the collation
* of the euro sign behaves properly. For bug 4150807, make sure the collation
* order of ALL the current symbols is correct. This means they sort
* in English alphabetical order of their English names. This test can be
* easily extended to do simple spot checking. See other collation tests for
* more sophisticated testing.
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Locale;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.text.CollationKey;
/* Author: Alan Liu
* (C) Copyright IBM Corp. 1998 - All Rights Reserved
*/
public class CurrencyCollate {
static Collator myCollation = Collator.getInstance(Locale.US);
public static void main(String[] args) {
String[] DATA = {
"\u20AC", ">", "$", // euro > dollar
"\u20AC", "<", "\u00A3", // euro < pound
// additional tests for general currency sort order (bug #4150807)
"\u00a4", "<", "\u0e3f", // generic currency < baht
"\u0e3f", "<", "\u00a2", // baht < cent
"\u00a2", "<", "\u20a1", // cent < colon
"\u20a1", "<", "\u20a2", // colon < cruzeiro
"\u20a2", "<", "\u0024", // cruzeiro < dollar
"\u0024", "<", "\u20ab", // dollar < dong
"\u20ab", "<", "\u20a3", // dong < franc
"\u20a3", "<", "\u20a4", // franc < lira
"\u20a4", "<", "\u20a5", // lira < mill
"\u20a5", "<", "\u20a6", // mill < naira
"\u20a6", "<", "\u20a7", // naira < peseta
"\u20a7", "<", "\u00a3", // peseta < pound
"\u00a3", "<", "\u20a8", // pound < rupee
"\u20a8", "<", "\u20aa", // rupee < shekel
"\u20aa", "<", "\u20a9", // shekel < won
"\u20a9", "<", "\u00a5" // won < yen
};
for (int i=0; i<DATA.length; i+=3) {
int expected = DATA[i+1].equals(">") ? 1 : (DATA[i+1].equals("<") ? -1 : 0);
int actual = myCollation.compare(DATA[i], DATA[i+2]);
if (actual != expected) {
throw new RuntimeException("Collation of " +
DATA[i] + " vs. " +
DATA[i+2] + " yields " + actual +
"; expected " + expected);
}
}
System.out.println("Ok");
}
}
//eof

View file

@ -0,0 +1,219 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4930708 4174436 5008498
* @library /java/text/testlib
* @summary test Danish Collation
* @modules jdk.localedata
* @run junit DanishTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class DanishTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"Lvi",
"L\u00E4vi",
"L\u00FCbeck",
"ANDR\u00C9",
"ANDRE",
"ANNONCERER"
};
private static final String[] primaryTargetData = {
"Lwi",
"L\u00F6wi",
"Lybeck",
"ANDR\u00E9",
"ANDR\u00C9",
"ANN\u00D3NCERER"
};
private static final int[] primaryResults = {
-1, -1, 0, 0, 0, 0
};
/*
* Data for TestTertiary()
*/
private static final String[] tertiarySourceData = {
"Luc",
"luck",
"L\u00FCbeck",
"L\u00E4vi",
"L\u00F6ww"
};
private static final String[] tertiaryTargetData = {
"luck",
"L\u00FCbeck",
"lybeck",
"L\u00F6we",
"mast"
};
private static final int[] tertiaryResults = {
-1, -1, 1, -1, -1
};
/*
* Data for TestExtra()
*/
private static final String[] testData = {
"A/S",
"ANDRE",
"ANDR\u00C9", // E-acute
"ANDR\u00C8", // E-grave
"ANDR\u00E9", // e-acute
"ANDR\u00EA", // e-circ
"Andre",
"Andr\u00E9", // e-acute
"\u00C1NDRE", // A-acute
"\u00C0NDRE", // A-grave
"andre",
"\u00E1ndre", // a-acute
"\u00E0ndre", // a-grave
"ANDREAS",
"ANNONCERER",
"ANN\u00D3NCERER", // O-acute
"annoncerer",
"ann\u00F3ncerer", // o-acute
"AS",
"A\u00e6RO", // ae-ligature
"CA",
"\u00C7A", // C-cedilla
"CB",
"\u00C7C", // C-cedilla
"D.S.B.",
"DA",
"DB",
"\u00D0ORA", // capital eth
"DSB",
"\u00D0SB", // capital eth
"DSC",
"EKSTRA_ARBEJDE",
"EKSTRABUD",
"H\u00D8ST", // could the 0x00D8 be 0x2205?
"HAAG",
"H\u00C5NDBOG", // A-ring
"HAANDV\u00C6RKSBANKEN", // AE-ligature
"INTERNETFORBINDELSE",
"Internetforbindelse",
"\u00CDNTERNETFORBINDELSE", // I-acute
"internetforbindelse",
"\u00EDnternetforbindelse", // i-acute
"Karl",
"karl",
"NIELSEN",
"NIELS J\u00D8RGEN", // O-slash
"NIELS-J\u00D8RGEN", // O-slash
"OERVAL",
"\u0152RVAL", // OE-ligature
"\u0153RVAL", // oe-ligature
"R\u00C9E, A", // E-acute
"REE, B",
"R\u00C9E, L", // E-acute
"REE, V",
"SCHYTT, B",
"SCHYTT, H",
"SCH\u00DCTT, H", // U-diaeresis
"SCHYTT, L",
"SCH\u00DCTT, M", // U-diaeresis
"SS",
"ss",
"\u00DF", // sharp S
"SSA",
"\u00DFA", // sharp S
"STOREK\u00C6R", // AE-ligature
"STORE VILDMOSE",
"STORMLY",
"STORM PETERSEN",
"THORVALD",
"THORVARDUR",
"\u00DEORVAR\u0110UR", // capital thorn, capital d-stroke(like eth) (sami)
"THYGESEN",
"VESTERG\u00C5RD, A",
"VESTERGAARD, A",
"VESTERG\u00C5RD, B", // 50
"Westmalle",
"YALLE",
"Yderligere",
"\u00DDderligere", // Y-acute
"\u00DCderligere", // U-diaeresis
"\u00FDderligere", // y-acute
"\u00FCderligere", // u-diaeresis
"U\u0308ruk-hai",
"ZORO",
"\u00C6BLE", // AE-ligature
"\u00E6BLE", // ae-ligature
"\u00C4BLE", // A-diaeresis
"\u00E4BLE", // a-diaeresis
"\u00D8BERG", // O-stroke
"\u00F8BERG", // o-stroke
"\u00D6BERG", // O-diaeresis
"\u00F6BERG" // o-diaeresis
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
for (int i = 0; i < testData.length-1; i++) {
for (int j = i+1; j < testData.length; j++) {
TestUtils.doCollatorTest(myCollation, testData[i], testData[j], -1);
}
}
}
private final Collator myCollation = Collator.getInstance(Locale.of("da"));
}

View file

@ -0,0 +1,425 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Dummy Collation
* @run junit DummyTest
*/
import java.text.Collator;
import java.text.RuleBasedCollator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
public class DummyTest {
private static final String DEFAULTRULES =
"='\u200B'=\u200C=\u200D=\u200E=\u200F"
// Control Characters
+ "=\u0000 =\u0001 =\u0002 =\u0003 =\u0004" //null, .. eot
+ "=\u0005 =\u0006 =\u0007 =\u0008 ='\u0009'" //enq, ...
+ "='\u000b' =\u000e" //vt,, so
+ "=\u000f ='\u0010' =\u0011 =\u0012 =\u0013" //si, dle, dc1, dc2, dc3
+ "=\u0014 =\u0015 =\u0016 =\u0017 =\u0018" //dc4, nak, syn, etb, can
+ "=\u0019 =\u001a =\u001b =\u001c =\u001d" //em, sub, esc, fs, gs
+ "=\u001e =\u001f =\u007f" //rs, us, del
//....then the C1 Latin 1 reserved control codes
+ "=\u0080 =\u0081 =\u0082 =\u0083 =\u0084 =\u0085"
+ "=\u0086 =\u0087 =\u0088 =\u0089 =\u008a =\u008b"
+ "=\u008c =\u008d =\u008e =\u008f =\u0090 =\u0091"
+ "=\u0092 =\u0093 =\u0094 =\u0095 =\u0096 =\u0097"
+ "=\u0098 =\u0099 =\u009a =\u009b =\u009c =\u009d"
+ "=\u009e =\u009f"
// IGNORE except for secondary, tertiary difference
// Spaces
+ ";'\u0020';'\u00A0'" // spaces
+ ";'\u2000';'\u2001';'\u2002';'\u2003';'\u2004'" // spaces
+ ";'\u2005';'\u2006';'\u2007';'\u2008';'\u2009'" // spaces
+ ";'\u200A';'\u3000';'\uFEFF'" // spaces
+ ";'\r' ;'\t' ;'\n';'\f';'\u000b'" // whitespace
// Non-spacing accents
+ ";\u0301" // non-spacing acute accent
+ ";\u0300" // non-spacing grave accent
+ ";\u0306" // non-spacing breve accent
+ ";\u0302" // non-spacing circumflex accent
+ ";\u030c" // non-spacing caron/hacek accent
+ ";\u030a" // non-spacing ring above accent
+ ";\u030d" // non-spacing vertical line above
+ ";\u0308" // non-spacing diaeresis accent
+ ";\u030b" // non-spacing double acute accent
+ ";\u0303" // non-spacing tilde accent
+ ";\u0307" // non-spacing dot above/overdot accent
+ ";\u0304" // non-spacing macron accent
+ ";\u0337" // non-spacing short slash overlay (overstruck diacritic)
+ ";\u0327" // non-spacing cedilla accent
+ ";\u0328" // non-spacing ogonek accent
+ ";\u0323" // non-spacing dot-below/underdot accent
+ ";\u0332" // non-spacing underscore/underline accent
// with the rest of the general diacritical marks in binary order
+ ";\u0305" // non-spacing overscore/overline
+ ";\u0309" // non-spacing hook above
+ ";\u030e" // non-spacing double vertical line above
+ ";\u030f" // non-spacing double grave
+ ";\u0310" // non-spacing chandrabindu
+ ";\u0311" // non-spacing inverted breve
+ ";\u0312" // non-spacing turned comma above/cedilla above
+ ";\u0313" // non-spacing comma above
+ ";\u0314" // non-spacing reversed comma above
+ ";\u0315" // non-spacing comma above right
+ ";\u0316" // non-spacing grave below
+ ";\u0317" // non-spacing acute below
+ ";\u0318" // non-spacing left tack below
+ ";\u0319" // non-spacing tack below
+ ";\u031a" // non-spacing left angle above
+ ";\u031b" // non-spacing horn
+ ";\u031c" // non-spacing left half ring below
+ ";\u031d" // non-spacing up tack below
+ ";\u031e" // non-spacing down tack below
+ ";\u031f" // non-spacing plus sign below
+ ";\u0320" // non-spacing minus sign below
+ ";\u0321" // non-spacing palatalized hook below
+ ";\u0322" // non-spacing retroflex hook below
+ ";\u0324" // non-spacing double dot below
+ ";\u0325" // non-spacing ring below
+ ";\u0326" // non-spacing comma below
+ ";\u0329" // non-spacing vertical line below
+ ";\u032a" // non-spacing bridge below
+ ";\u032b" // non-spacing inverted double arch below
+ ";\u032c" // non-spacing hacek below
+ ";\u032d" // non-spacing circumflex below
+ ";\u032e" // non-spacing breve below
+ ";\u032f" // non-spacing inverted breve below
+ ";\u0330" // non-spacing tilde below
+ ";\u0331" // non-spacing macron below
+ ";\u0333" // non-spacing double underscore
+ ";\u0334" // non-spacing tilde overlay
+ ";\u0335" // non-spacing short bar overlay
+ ";\u0336" // non-spacing long bar overlay
+ ";\u0338" // non-spacing long slash overlay
+ ";\u0339" // non-spacing right half ring below
+ ";\u033a" // non-spacing inverted bridge below
+ ";\u033b" // non-spacing square below
+ ";\u033c" // non-spacing seagull below
+ ";\u033d" // non-spacing x above
+ ";\u033e" // non-spacing vertical tilde
+ ";\u033f" // non-spacing double overscore
+ ";\u0340" // non-spacing grave tone mark
+ ";\u0341" // non-spacing acute tone mark
+ ";\u0342;\u0343;\u0344;\u0345;\u0360;\u0361" // newer
+ ";\u0483;\u0484;\u0485;\u0486" // Cyrillic accents
+ ";\u20D0;\u20D1;\u20D2" // symbol accents
+ ";\u20D3;\u20D4;\u20D5" // symbol accents
+ ";\u20D6;\u20D7;\u20D8" // symbol accents
+ ";\u20D9;\u20DA;\u20DB" // symbol accents
+ ";\u20DC;\u20DD;\u20DE" // symbol accents
+ ";\u20DF;\u20E0;\u20E1" // symbol accents
+ ",'\u002D';\u00AD" // dashes
+ ";\u2010;\u2011;\u2012" // dashes
+ ";\u2013;\u2014;\u2015" // dashes
+ ";\u2212" // dashes
// other punctuation
+ "<'\u005f'" // underline/underscore (spacing)
+ "<\u00af" // overline or macron (spacing)
// + "<\u00ad" // syllable hyphen (SHY) or soft hyphen
+ "<'\u002c'" // comma (spacing)
+ "<'\u003b'" // semicolon
+ "<'\u003a'" // colon
+ "<'\u0021'" // exclamation point
+ "<\u00a1" // inverted exclamation point
+ "<'\u003f'" // question mark
+ "<\u00bf" // inverted question mark
+ "<'\u002f'" // slash
+ "<'\u002e'" // period/full stop
+ "<\u00b4" // acute accent (spacing)
+ "<'\u0060'" // grave accent (spacing)
+ "<'\u005e'" // circumflex accent (spacing)
+ "<\u00a8" // diaresis/umlaut accent (spacing)
+ "<'\u007e'" // tilde accent (spacing)
+ "<\u00b7" // middle dot (spacing)
+ "<\u00b8" // cedilla accent (spacing)
+ "<'\u0027'" // apostrophe
+ "<'\"'" // quotation marks
+ "<\u00ab" // left angle quotes
+ "<\u00bb" // right angle quotes
+ "<'\u0028'" // left parenthesis
+ "<'\u0029'" // right parenthesis
+ "<'\u005b'" // left bracket
+ "<'\u005d'" // right bracket
+ "<'\u007b'" // left brace
+ "<'\u007d'" // right brace
+ "<\u00a7" // section symbol
+ "<\u00b6" // paragraph symbol
+ "<\u00a9" // copyright symbol
+ "<\u00ae" // registered trademark symbol
+ "<'\u0040'" // at sign
+ "<\u00a4" // international currency symbol
+ "<\u00a2" // cent sign
+ "<'\u0024'" // dollar sign
+ "<\u00a3" // pound-sterling sign
+ "<\u00a5" // yen sign
+ "<'\u002a'" // asterisk
+ "<'\\u005c'" // backslash
+ "<'\u0026'" // ampersand
+ "<'\u0023'" // number sign
+ "<'\u0025'" // percent sign
+ "<'\u002b'" // plus sign
// + "<\u002d" // hyphen or minus sign
+ "<\u00b1" // plus-or-minus sign
+ "<\u00f7" // divide sign
+ "<\u00d7" // multiply sign
+ "<'\u003c'" // less-than sign
+ "<'\u003d'" // equal sign
+ "<'\u003e'" // greater-than sign
+ "<\u00ac" // end of line symbol/logical NOT symbol
+ "<'\u007c'" // vertical line/logical OR symbol
+ "<\u00a6" // broken vertical line
+ "<\u00b0" // degree symbol
+ "<\u00b5" // micro symbol
// NUMERICS
+ "<0<1<2<3<4<5<6<7<8<9"
+ "<\u00bc<\u00bd<\u00be" // 1/4,1/2,3/4 fractions
// NON-IGNORABLES
+ "<a,A"
+ "<b,B"
+ "<c,C"
+ "<d,D"
+ "<\u00F0,\u00D0" // eth
+ "<e,E"
+ "<f,F"
+ "<g,G"
+ "<h,H"
+ "<i,I"
+ "<j,J"
+ "<k,K"
+ "<l,L"
+ "<m,M"
+ "<n,N"
+ "<o,O"
+ "<p,P"
+ "<q,Q"
+ "<r,R"
+ "<s, S & SS,\u00DF" // s-zet
+ "<t,T"
+ "&th, \u00FE & TH, \u00DE" // thorn
+ "<u,U"
+ "<v,V"
+ "<w,W"
+ "<x,X"
+ "<y,Y"
+ "<z,Z"
+ "&AE,\u00C6" // ae & AE ligature
+ "&AE,\u00E6"
+ "&OE,\u0152" // oe & OE ligature
+ "&OE,\u0153";
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"p\u00EAche",
"abc",
"abc",
"abc",
"abc",
"abc",
"a\u00E6c",
"acHc",
"black"
};
private static final String[] primaryTargetData = {
"p\u00E9ch\u00E9",
"abc",
"aBC",
"abch",
"abd",
"\u00E4bc",
"a\u00C6c",
"aCHc",
"black-bird"
};
private static final int[] primaryResults = {
0, 0, 0, -1, -1, 0, 0, 0, -1
};
/*
* Data for TestSecondary()
*/
private static final String[] secondarySourceData = {
"four",
"five",
"1",
"abc",
"abc",
"abcH",
"abc",
"acHc"
};
private static final String[] secondaryTargetData = {
"4",
"5",
"one",
"abc",
"aBc",
"abch",
"abd",
"aCHc"
};
private static final int[] secondaryResults = {
0, 0, 0, 0, 0, 0, -1, 0
};
/*
* Data for TestTertiary()
*/
private static final String[] tertiarySourceData = {
"ab'c",
"co-op",
"ab",
"ampersad",
"all",
"four",
"five",
"1",
"1",
"1",
"2",
"2",
"Hello",
"a<b",
"a<b",
"acc",
"acHc"
};
private static final String[] tertiaryTargetData = {
"abc",
"COOP",
"abc",
"&",
"&",
"4",
"5",
"one",
"nne",
"pne",
"two",
"uwo",
"hellO",
"a<=b",
"abc",
"aCHc",
"aCHc"
};
private static final int[] tertiaryResults = {
-1, 1, -1, -1, -1, -1, -1, 1, 1, -1,
1, -1, 1, 1, -1, -1, -1
};
private static final String[] testData = {
"a",
"A",
"\u00e4",
"\u00c4",
"ae",
"aE",
"Ae",
"AE",
"\u00e6",
"\u00c6",
"b",
"c",
"z"
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(getCollator(), Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestSecondary() {
TestUtils.doCollatorTest(getCollator(), Collator.SECONDARY,
secondarySourceData, secondaryTargetData, secondaryResults);
}
@Test
public void TestTertiary() {
Collator col = getCollator();
TestUtils.doCollatorTest(col, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
for (int i = 0; i < testData.length-1; i++) {
for (int j = i+1; j < testData.length; j++) {
TestUtils.doCollatorTest(col, testData[i], testData[j], -1);
}
}
}
private RuleBasedCollator myCollation = null;
private Collator getCollator() {
if (myCollation == null) {
try {
myCollation = new RuleBasedCollator
(DEFAULTRULES + "& C < ch, cH, Ch, CH & Five, 5 & Four, 4 & one, 1 & Ampersand; '&' & Two, 2 ");
} catch (Exception foo) {
fail("Collator creation failed.");
myCollation = (RuleBasedCollator)Collator.getInstance();
}
}
return myCollation;
}
}

View file

@ -0,0 +1,230 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test English Collation
* @run junit EnglishTest
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
public class EnglishTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"p\u00EAche",
"abc",
"abc",
"abc",
"a\u00E6c"
};
private static final String[] primaryTargetData = {
"p\u00E9ch\u00E9",
"aBC",
"abd",
"\u00E4bc",
"a\u00C6c"
};
private static final int[] primaryResults = {
0, 0, -1, 0, 0,
};
/*
* Data for TestSecondary()
*/
private static final String[] secondarySourceData = {
"abc",
"abc",
"a\u00E6c",
"abc",
"abc",
"p\u00e9ch\u00e9"
};
private static final String[] secondaryTargetData = {
"aBd",
"\u00E4bc",
"a\u00C6c",
"aBd",
"\u00E4bc",
"p\u00eache"
};
private static final int[] secondaryResults = {
-1, -1, 0, -1, -1, -1
};
/*
* Data for TestTertiary() {
*/
private static final String[] tertiarySourceData = {
"ab",
"black-bird",
"black bird",
"black-bird",
"Hello",
"ABC",
"abc",
"blackbird",
"black-bird",
"black-bird",
"p\u00EAche",
"p\u00E9ch\u00E9",
"\u00C4B\u0308C\u0308",
"a\u0308bc",
"p\u00E9cher",
"roles",
"abc",
"A",
"A",
"ab",
"tcompareplain",
"ab",
"a#b",
"a#b",
"abc",
"Abcda",
"abcda",
"abcda",
"\u00E6bcda",
"\u00E4bcda",
"abc",
"abc",
"abc",
"abc",
"abc",
"acHc",
"a\u0308bc",
"thi\u0302s"
};
private static final String[] tertiaryTargetData = {
"abc",
"blackbird",
"black-bird",
"black",
"hello",
"ABC",
"ABC",
"blackbirds",
"blackbirds",
"blackbird",
"p\u00E9ch\u00E9",
"p\u00E9cher",
"\u00C4B\u0308C\u0308",
"A\u0308bc",
"p\u00E9che",
"ro\u0302le",
"A\u00E1cd",
"A\u00E1cd",
"abc",
"abc",
"TComparePlain",
"aBc",
"a#B",
"a&b",
"a#c",
"abcda",
"\u00C4bcda",
"\u00E4bcda",
"\u00C4bcda",
"\u00C4bcda",
"ab#c",
"abc",
"ab=c",
"abd",
"\u00E4bc",
"aCHc",
"\u00E4bc",
"th\u00EEs"
};
private static final int[] tertiaryResults = {
-1, 1, -1, 1, 1, 0, -1, -1, -1, 1,
1, -1, 0, -1, 1, 1, 1, -1, -1, -1,
-1, -1, -1, 1, 1, 1, -1, -1, 1, -1,
1, 0, 1, -1, -1, -1, 0, 0
};
private static final String testData[] = {
"a",
"A",
"e",
"E",
"\u00e9",
"\u00e8",
"\u00ea",
"\u00eb",
"ea",
"x"
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestSecondary() {
TestUtils.doCollatorTest(myCollation, Collator.SECONDARY,
secondarySourceData, secondaryTargetData, secondaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
for (int i = 0; i < testData.length-1; i++) {
for (int j = i+1; j < testData.length; j++) {
TestUtils.doCollatorTest(myCollation, testData[i], testData[j], -1);
}
}
}
private final Collator myCollation = Collator.getInstance(Locale.ENGLISH);
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Finnish Collation
* @modules jdk.localedata
* @run junit FinnishTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class FinnishTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"L\u00E5vi",
"wat"
};
private static final String[] primaryTargetData = {
"L\u00E4we",
"vat"
};
private static final int[] primaryResults = {
-1, 0
};
/*
* Data for TestTertiary()
*/
private static final String tertiarySourceData[] = {
"wat",
"vat",
"a\u00FCbeck"
};
private static final String tertiaryTargetData[] = {
"vat",
"way",
"axbeck"
};
private static final int[] tertiaryResults = {
1, -1, 1
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
}
private final Collator myCollation = Collator.getInstance(Locale.of("fi", "FI"));
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test French Collation
* @modules jdk.localedata
* @run junit FrenchTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class FrenchTest {
private static final String[] tertiarySourceData = {
"abc",
"COTE",
"p\u00EAche",
"p\u00EAcher",
"p\u00E9cher",
"p\u00E9cher",
"Hello"
};
private static final String[] tertiaryTargetData = {
"ABC",
"c\u00f4te",
"p\u00E9ch\u00E9",
"p\u00E9ch\u00E9",
"p\u00EAche",
"p\u00EAcher",
"hellO"
};
private static final int[] tertiaryResults = {
-1, -1, -1, 1, 1, -1, 1
};
private static final String[] testData = {
"a",
"A",
"e",
"E",
"\u00e9",
"\u00e8",
"\u00ea",
"\u00eb",
"ea",
"x"
};
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
for (int i = 0; i < testData.length-1; i++) {
for (int j = i+1; j < testData.length; j++) {
TestUtils.doCollatorTest(myCollation, testData[i], testData[j], -1);
}
}
}
private final Collator myCollation = Collator.getInstance(Locale.FRANCE);
}

View file

@ -0,0 +1,301 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test G7 Collation
* @modules jdk.localedata
* @run junit G7Test
*/
/*
*
*
* (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
* (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
*
* Portions copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
*
* The original version of this source code and documentation is copyrighted
* and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
* materials are provided under terms of a License Agreement between Taligent
* and Sun. This technology is protected by multiple US and International
* patents. This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
*/
/**
* G7 Test cases
*
* @author Helena Shih
*/
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// G7 test program for printing out test results
public class G7Test {
private static final String testCases[] = {
"black-birds", // 0
"Pat", // 1
"p\u00E9ch\u00E9", // 2
"p\u00EAche", // 3
"p\u00E9cher", // 4
"p\u00EAcher", // 5
"Tod", // 6
"T\u00F6ne", // 7
"Tofu", // 8
"blackbirds", // 9
"Ton", // 10
"PAT", // 11
"blackbird", // 12
"black-bird", // 13
"pat", // 14
// Additional tests
"czar", // 15
"churo", // 16
"cat", // 17
"darn", // 18
"?", // 19
"quick", // 20
"#", // 21
"&", // 22
"aardvark", // 23
"a-rdvark", // 24
"abbot", // 25
"coop", // 26
"co-p", // 27
"cop", // 28
"zebra" // 29
};
// loop to TOTALTESTSET
private static final int[][] G7Results = {
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // en_US
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // en_GB
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // en_CA
{ 12, 13, 9, 0, 14, 1, 11, 3, 2, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // fr_FR
{ 12, 13, 9, 0, 14, 1, 11, 3, 2, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // fr_CA
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // de_DE
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // it_IT
{ 12, 13, 9, 0, 14, 1, 11, 2, 3, 4,
5, 6, 8, 10, 7, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, // ja_JP
};
// new table collation with rules "& Z < p, P"
// loop to FIXEDTESTSET
private static final int[] Test1Results = {
12, 13, 9, 0, 6, 8, 10, 7, 14, 1,
11, 2, 3, 4, 5, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31
};
// new table collation with rules "& C < ch , cH, Ch, CH "
// loop to TOTALTESTSET
private static final int[] Test2Results = {
19, 22, 21, 23, 25, 24, 12, 13, 9, 0,
17, 26, 28, 27, 15, 16, 18, 14, 1, 11,
2, 3, 4, 5, 20, 6, 8, 10, 7, 29
};
// new table collation with rules
// "& Question-mark ; ? & Hash-mark ; # & Ampersand ; '&' "
// loop to TOTALTESTSET
private static final int[] Test3Results = {
23, 25, 22, 24, 12, 13, 9, 0, 17, 16,
26, 28, 27, 15, 18, 21, 14, 1, 11, 2,
3, 4, 5, 19, 20, 6, 8, 10, 7, 29
};
// analogous to Japanese rules
// " & aa ; a- & ee ; e- & ii ; i- & oo ; o- & uu ; u- "
// loop to TOTALTESTSET
private static final int[] Test4Results = {
19, 22, 21, 23, 24, 25, 12, 13, 9, 0,
17, 16, 26, 27, 28, 15, 18, 14, 1, 11,
2, 3, 4, 5, 20, 6, 8, 10, 7, 29
};
@Test
public void TestG7Data() {
for (int i = 0; i < locales.length; i++) {
Collator myCollation= null;
RuleBasedCollator tblColl1 = null;
try {
myCollation = Collator.getInstance(locales[i]);
tblColl1 = new RuleBasedCollator(((RuleBasedCollator)myCollation).getRules());
} catch (Exception foo) {
fail("Exception: " + foo.getMessage() +
" Locale : " + locales[i].getDisplayName() +
" getRules failed\n");
continue;
}
for (int j = 0; j < FIXEDTESTSET; j++) {
for (int n = j+1; n < FIXEDTESTSET; n++) {
TestUtils.doCollatorTest(tblColl1, testCases[G7Results[i][j]],
testCases[G7Results[i][n]], -1);
}
}
myCollation = null;
}
}
/*
* Demo Test 1 : Create a new table collation with rules "& Z < p, P"
*/
@Test
public void TestDemoTest1() {
int j = 0;
final Collator myCollation = Collator.getInstance(Locale.US);
final String defRules = ((RuleBasedCollator)myCollation).getRules();
RuleBasedCollator tblColl = null;
String newRules = defRules + " & Z < p, P";
try {
tblColl = new RuleBasedCollator(newRules);
for (j = 0; j < FIXEDTESTSET; j++) {
for (int n = j+1; n < FIXEDTESTSET; n++) {
TestUtils.doCollatorTest(tblColl, testCases[Test1Results[j]],
testCases[Test1Results[n]], -1);
}
}
tblColl = null;
} catch (Exception foo) {
fail("Exception: " + foo.getMessage() +
"\nDemo Test 1 Table Collation object creation failed.");
}
}
/*
* Demo Test 2 : Create a new table collation with rules
* "& C < ch , cH, Ch, CH"
*/
@Test
public void TestDemoTest2() {
final Collator myCollation = Collator.getInstance(Locale.US);
final String defRules = ((RuleBasedCollator)myCollation).getRules();
String newRules = defRules + "& C < ch , cH, Ch, CH";
try {
RuleBasedCollator tblColl = new RuleBasedCollator(newRules);
for (int j = 0; j < TOTALTESTSET; j++) {
for (int n = j+1; n < TOTALTESTSET; n++) {
TestUtils.doCollatorTest(tblColl, testCases[Test2Results[j]],
testCases[Test2Results[n]], -1);
}
}
} catch (Exception foo) {
fail("Exception: " + foo.getMessage() +
"\nDemo Test 2 Table Collation object creation failed.\n");
}
}
/*
* Demo Test 3 : Create a new table collation with rules
* "& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'"
*/
@Test
public void TestDemoTest3() {
final Collator myCollation = Collator.getInstance(Locale.US);
final String defRules = ((RuleBasedCollator)myCollation).getRules();
RuleBasedCollator tblColl = null;
String newRules = defRules + "& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&";
try {
tblColl = new RuleBasedCollator(newRules);
for (int j = 0; j < TOTALTESTSET; j++) {
for (int n = j+1; n < TOTALTESTSET; n++) {
TestUtils.doCollatorTest(tblColl, testCases[Test3Results[j]],
testCases[Test3Results[n]], -1);
}
}
} catch (Exception foo) {
fail("Exception: " + foo.getMessage() +
"\nDemo Test 3 Table Collation object creation failed.");
}
}
/*
* Demo Test 4 : Create a new table collation with rules
* " & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' "
*/
@Test
public void TestDemoTest4() {
final Collator myCollation = Collator.getInstance(Locale.US);
final String defRules = ((RuleBasedCollator)myCollation).getRules();
RuleBasedCollator tblColl = null;
String newRules = defRules + " & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' ";
try {
tblColl = new RuleBasedCollator(newRules);
for (int j = 0; j < TOTALTESTSET; j++) {
for (int n = j+1; n < TOTALTESTSET; n++) {
TestUtils.doCollatorTest(tblColl, testCases[Test4Results[j]],
testCases[Test4Results[n]], -1);
}
}
} catch (Exception foo) {
fail("Exception: " + foo.getMessage() +
"\nDemo Test 4 Table Collation object creation failed.");
}
tblColl = null;
}
private static final int FIXEDTESTSET = 15;
private static final int TOTALTESTSET = 30;
private static final Locale locales[] = {
Locale.US,
Locale.UK,
Locale.CANADA,
Locale.FRANCE,
Locale.CANADA_FRENCH,
Locale.GERMANY,
Locale.JAPAN,
Locale.ITALY
};
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test German Collation
* @run junit GermanTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class GermanTest {
/*
* Shared data for TestPrimary() and TestTertiary()
*/
private static final String testSourceData[] = {
"Gr\u00F6\u00DFe",
"abc",
"T\u00F6ne",
"T\u00F6ne",
"T\u00F6ne",
"a\u0308bc",
"\u00E4bc",
"\u00E4bc",
"Stra\u00DFe",
"efg",
"\u00E4bc",
"Stra\u00DFe"
};
private static final String testTargetData[] = {
"Grossist",
"a\u0308bc",
"Ton",
"Tod",
"Tofu",
"A\u0308bc",
"a\u0308bc",
"aebc",
"Strasse",
"efg",
"aebc",
"Strasse"
};
/*
* Data for TestPrimary()
*/
private static final int[] primaryResults = {
-1, 0, 1, 1, 1, 0, 0, -1, 0, 0,
-1, 0
};
/*
* Data for TestTertiary()
*/
private static final int[] tertiaryResults = {
-1, -1, 1, 1, 1, -1, 0, -1, 1, 0,
-1, 1
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
testSourceData, testTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
testSourceData, testTargetData, tertiaryResults);
}
private final Collator myCollation = Collator.getInstance(Locale.GERMAN);
}

View file

@ -0,0 +1,297 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4062985 4108758 4108762 4157299
* @library /java/text/testlib
* @summary Test CollationElementIterator, particularly the new methods in 1.2
* @run junit IteratorTest
*/
/*
* (C) Copyright IBM Corp. 1998 - All Rights Reserved
*
* The original version of this source code and documentation is copyrighted
* and owned by IBM, Inc. These materials are provided under terms of a
* License Agreement between IBM and Sun. This technology is protected by
* multiple US and International patents. This notice and attribution to IBM
* may not be removed.
*/
import java.util.Locale;
import java.text.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class IteratorTest {
// TODO:
// - Test previous() with contracting character sequences, which don't work
// at the moment.
// - Test edge cases on setOffset(), e.g. offset > length, etc.
//
/**
* Test for CollationElementIterator.previous()
*
* @bug 4108758 - Make sure it works with contracting characters
*
*/
@Test
public void TestPrevious() throws ParseException {
// A basic test to see if it's working at all
backAndForth(en_us.getCollationElementIterator(test1));
// Test with a contracting character sequence
RuleBasedCollator c1 = new RuleBasedCollator(
"< a,A < b,B < c,C, d,D < z,Z < ch,cH,Ch,CH" );
backAndForth(c1.getCollationElementIterator("abchdcba"));
// Test with an expanding character sequence
RuleBasedCollator c2 = new RuleBasedCollator(
"< a < b < c/abd < d" );
backAndForth(c2.getCollationElementIterator("abcd"));
// Now try both
RuleBasedCollator c3 = new RuleBasedCollator(
"< a < b < c/aba < d < z < ch" );
backAndForth(c3.getCollationElementIterator("abcdbchdc"));
}
/**
* Test for getOffset() and setOffset()
*/
@Test
public void TestOffset() {
CollationElementIterator iter = en_us.getCollationElementIterator(test1);
// Run all the way through the iterator, then get the offset
int orders[] = getOrders(iter);
int offset = iter.getOffset();
if (offset != test1.length()) {
System.out.println("offset at end != length: "
+ offset + " vs " + test1.length());
}
// Now set the offset back to the beginning and see if it works
iter.setOffset(0);
TestUtils.compareCollationElementIters(iter, en_us.getCollationElementIterator(test1));
// TODO: try iterating halfway through a messy string.
}
/**
* Test for setText()
*/
@Test
public void TestSetText() {
CollationElementIterator iter1 = en_us.getCollationElementIterator(test1);
CollationElementIterator iter2 = en_us.getCollationElementIterator(test2);
// Run through the second iterator just to exercise it
int c = iter2.next();
int i = 0;
while ( ++i < 10 && c != CollationElementIterator.NULLORDER) {
c = iter2.next();
}
// Now set it to point to the same string as the first iterator
iter2.setText(test1);
TestUtils.compareCollationElementIters(iter1, iter2);
}
/** @bug 4108762
* Test for getMaxExpansion()
*/
@Test
public void TestMaxExpansion() throws ParseException {
// Try a simple one first:
// The only expansion ends with 'e' and has length 2
String[][] test1 = {
{ "< a & ae = \u00e4 < b < e", "" },
{ "a", "1" },
{ "b", "1" },
{ "e", "2" },
};
verifyExpansion(test1);
// Now a more complicated one:
// "a1" --> "ae"
// "z" --> "aeef"
//
String[][] test2 = {
{ "< a & ae = a1 & aeef = z < b < e < f", "" },
{ "a", "1" },
{ "b", "1" },
{ "e", "2" },
{ "f", "4" },
};
verifyExpansion(test2);
}
/*
* @bug 4157299
*/
@Test
public void TestClearBuffers() throws ParseException {
RuleBasedCollator c = new RuleBasedCollator("< a < b < c & ab = d");
CollationElementIterator i = c.getCollationElementIterator("abcd");
int e0 = i.next(); // save the first collation element
i.setOffset(3); // go to the expanding character
i.next(); // but only use up half of it
i.setOffset(0); // go back to the beginning
int e = i.next(); // and get this one again
if (e != e0) {
fail("got " + Integer.toString(e, 16) + ", expected " +
Integer.toString(e0, 16));
}
}
//------------------------------------------------------------------------
// Internal utilities
//
private void backAndForth(CollationElementIterator iter) {
// Run through the iterator forwards and stick it into an array
int [] orders = getOrders(iter);
// Now go through it backwards and make sure we get the same values
int index = orders.length;
int o;
while ((o = iter.previous()) != CollationElementIterator.NULLORDER) {
if (o != orders[--index]) {
fail("Mismatch at index " + index + ": "
+ orders[index] + " vs " + o);
break;
}
}
if (index != 0) {
fail("Didn't get back to beginning - index is " + index);
iter.reset();
fail("next: ");
while ((o = iter.next()) != NULLORDER) {
fail( Integer.toHexString(o) + " ");
}
fail("");
fail("prev: ");
while ((o = iter.previous()) != NULLORDER) {
fail( Integer.toHexString(o) + " ");
}
fail("");
}
}
/**
* Verify that getMaxExpansion works on a given set of collation rules
*
* The first row of the "tests" array contains the collation rules
* at index 0, and the string at index 1 is ignored.
*
* Subsequent rows of the array contain a character and a number, both
* represented as strings. The character's collation order is determined,
* and getMaxExpansion is called for that character. If its value is
* not equal to the specified number, an error results.
*/
private void verifyExpansion(String[][] tests) throws ParseException
{
RuleBasedCollator coll = new RuleBasedCollator(tests[0][0]);
CollationElementIterator iter = coll.getCollationElementIterator("");
for (int i = 1; i < tests.length; i++) {
// First get the collation key that the test string expands to
iter.setText(tests[i][0]);
int order = iter.next();
if (order == NULLORDER || iter.next() != NULLORDER) {
iter.reset();
fail("verifyExpansion: '" + tests[i][0] +
"' has multiple orders:" + orderString(iter));
}
int expansion = iter.getMaxExpansion(order);
int expect = new Integer(tests[i][1]).intValue();
if (expansion != expect) {
fail("expansion for '" + tests[i][0] + "' is wrong: " +
"expected " + expect + ", got " + expansion);
}
}
}
/**
* Return an integer array containing all of the collation orders
* returned by calls to next on the specified iterator
*/
private int[] getOrders(CollationElementIterator iter)
{
int maxSize = 100;
int size = 0;
int[] orders = new int[maxSize];
int order;
while ((order = iter.next()) != NULLORDER) {
if (size == maxSize) {
maxSize *= 2;
int[] temp = new int[maxSize];
System.arraycopy(orders, 0, temp, 0, size);
orders = temp;
}
orders[size++] = order;
}
if (orders.length > size) {
int[] temp = new int[size];
System.arraycopy(orders, 0, temp, 0, size);
orders = temp;
}
return orders;
};
/**
* Return a string containing all of the collation orders
* returned by calls to next on the specified iterator
*/
private String orderString(CollationElementIterator iter) {
StringBuffer buf = new StringBuffer();
int order;
while ((order = iter.next()) != NULLORDER) {
buf.append( Integer.toHexString(order) + " ");
}
return buf.toString();
}
static final private int NULLORDER = CollationElementIterator.NULLORDER;
RuleBasedCollator en_us = (RuleBasedCollator)Collator.getInstance(Locale.US);
String test1 = "What subset of all possible test cases?";
String test2 = "has the highest probability of detecting";
}

View file

@ -0,0 +1,325 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test 1.1 02/09/11
* @bug 4176141 4655819
* @summary Regression tests for Japanese Collation
* @modules jdk.localedata
*/
import java.text.*;
import java.util.*;
public class JapaneseTest {
// NOTE:
// Golden data in this test case is locale data dependent and
// may need to be changed if the Japanese locale collation rules
// are changed.
/*
* | NO_DECOMP(default) | CANONICAL_DECOMP | FULL_DECOMP
* -------------------+--------------------+------------------+-------------
* PRIMARY | s1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
* SECONDARY | s1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
* TERTIARY(default) | S1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
*/
static final int[][] results1 = {
{ -1, -1, -1},
{ -1, -1, -1},
{ -1, -1, -1},
};
static final String[][] compData1 = {
/*
* Data to verify '<' relationship in LocaleElements_ja.java
*/
{"\u3084", "\u30E6",
"Hiragana \"YA\"(0x3084) <---> Katakana \"YU\"(0x30E6)"},
{"\u30E6", "\u3088",
"Katakana \"YU\"(0x30E6) <---> Hiragana \"YO\"(0x3088)"},
{"\u00B1", "\u2260",
"Plus-Minus Sign(0x00B1) <---> Not Equal To(0x2260)"},
{"\u3011", "\u2260",
"Right Black Lenticular Bracket(0x3011) <---> Not Equal To(0x2260)"},
{"\u2260", "\u2103",
"Not Equal To(0x2260) <---> Degree Celsius(0x2103)"},
{"\u2260", "\u2606",
"Not Equal To(0x2260) <---> White Star(0x2606)"},
{"\u30FD", "\u309E",
"Katakana Iteration Mark(0x30FD) <---> Hiragana Voiced Iteration Mark(0x309E)"},
{"\u3059\u309D", "\u3059\u309E",
"Hiragana \"SU\"(0x3059)Hiragana Iteration Mark(0x309D) <---> Hiragana \"SU\"(0x3059)Hiragana Voiced Iteration Mark(0x309E)"},
{"\u821E", "\u798F",
"CJK Unified Ideograph(0x821E) <---> CJK Unified Ideograph(0x798F)"},
/*
* Data to verify normalization
*/
{"\u2260", "\u225F",
"Not Equal To(0x2260) <---> Questioned Equal To(0x225F)"},
{"\u226E", "\u2260",
"Not Less-than(0x226E) <---> Not Equal To(0x2260)"},
{"\u226E", "\u226D",
"Not Less-than(0x226E) <---> Not Equivalent To(0x226D)"},
};
/*
* | NO_DECOMP(default) | CANONICAL_DECOMP | FULL_DECOMP
* -------------------+--------------------+------------------+-------------
* PRIMARY | s1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
* SECONDARY | s1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
* TERTIARY(default) | S1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
*/
static final int[][] results2 = {
{ 0, 0, 0},
{ -1, -1, -1},
{ -1, -1, -1},
};
static final String[][] compData2 = {
/*
* Data to verify ';' relationship in LocaleElements_ja.java
*/
{"\u3099", "\u309A",
"Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Combining Katakana-Hiragana Semi-voiced Sound Mark(0x309A)"},
{"\u3053\u3046\u3068\u3046", "\u3053\u3046\u3068\u3099\u3046",
"Hiragana \"KOUTOU\"(0x3053 0x3046 0x3068 0x3046) <---> Hiragana \"KOUTO\"(0x3053 0x3046 0x3068)Combining Katakana-Hiragana Voiced Sound Mark(0X3099)\"U\"(0x3046)"},
{"\u3053\u3046\u3068\u3046", "\u3053\u3046\u3069\u3046",
"Hiragana \"KOUTOU\"(0x3053 0x3046 0x3068 0x3046) <---> Hiragana \"KOUDOU\"(0x3053 0x3046 0x3069 0x3046)"},
{"\u3053\u3046\u3069\u3046", "\u3054\u3046\u3068\u3046",
"Hiragana \"KOUTOU\"(0x3053 0x3046 0x3069 0x3046) <---> Hiragana \"GOUTOU\"(0x3054 0x3046 0x3068 0x3046)"},
{"\u3054\u3046\u3068\u3046", "\u3054\u3046\u3069\u3046",
"Hiragana \"GOUTOU\"(0x3054 0x3046 0x3068 0x3046) <---> Hiragana \"GOUDOU\"(0x3054 0x3046 0x3069 0x3046)"},
};
/*
* | NO_DECOMP(default) | CANONICAL_DECOMP | FULL_DECOMP
* -------------------+--------------------+------------------+-------------
* PRIMARY | s1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
* SECONDARY | s1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
* TERTIARY(default) | S1 < s2 (-1) | s1 < s2 (-1) | s1 < s2 (-1)
*/
static final int[][] results3 = {
{ 0, 0, 0},
{ 0, 0, 0},
{ -1, -1, -1},
};
static final String[][] compData3 = {
/*
* Data to verify ',' relationship in LocaleElements_ja.java
*/
{"\u3042", "\u3041",
"Hiragana \"A\"(0x3042) <---> Hiragana \"a\"(0x3041)"},
{"\u3041", "\u30A2",
"Hiragana \"a\"(0x3041) <---> Katakana \"A\"(0x30A2)"},
{"\u30A2", "\u30A1",
"Katakana \"A\"(0x30A2) <---> Katakana \"a\"(0x30A1)"},
{"\u3094", "\u30F4",
"Hiragana \"VU\"(0x3094) <---> Katakana \"VU\"(0x30F4)"},
{"\u3094", "\u30A6\u3099",
"Hiragana \"VU\"(0x3094) <---> Katakana \"U\"(0x30A6)Combining Katakana-Hiragana Voiced Sound Mark(0x3099)"},
{"\u3046\u3099", "\u30F4",
"Hiragana \"U\"(0x3046)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VU\"(0x30F4)"},
{"\u3046\u3099", "\u30A6\u3099",
"Hiragana \"U\"(0x3046)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"U\"(0x30A6)Combining Katakana-Hiragana Voiced Sound Mark(0x3099)"},
{"\u30AB\u30A2", "\u30AB\u30FC",
"Katakana \"KAA\"(0x30AB 0x30A2) <---> Katakana \"KA-\"(0x30AB 0x30FC)"},
{"\u30CB\u30A1\u30A2", "\u30CB\u30A1\u30FC",
"Katakana \"NyaA\"(0x30CB 0x30A1 0x30A2) <---> Katakana \"Nya-\"(0x30CB 0x30A1 0x30FC)"},
{"\u30B3\u30AA\u30D2\u30A4", "\u30B3\u30FC\u30D2\u30FC",
"Katakana \"KOOHII\"(0x30B3 0x30AA 0x30D2 0x30A4) <---> Katakana \"KO-HI-\"(0x30B3 0x30FC 0x30D2 0x30FC)"},
{"\u308A\u3088\u3046", "\u308A\u3087\u3046",
"Hiragana \"RIYOU\"(0x308A 0x3088 0x3046) <---> Hiragana \"Ryou\"(0x308A 0x3087 0x3046)"},
{"\u3081\u3064\u304D", "\u3081\u3063\u304D",
"Hiragana \"METSUKI\"(0x3081 0x3064 0x304D) <---> Hiragana \"MEKKI\"(0x3081 0x3063 0x304D)"},
{"\u3075\u3042\u3093", "\u30D5\u30A1\u30F3",
"Hiragana \"FUAN\"(0x3075 0x3042 0x3093) <---> Katakana \"FUaN\"(0x30D5 0x30A1 0x30F3)"},
{"\u3075\u3041\u3093", "\u30D5\u30A2\u30F3",
"Hiragana \"FUaN\"(0x3075 0x3041 0x3093) <---> Katakana \"FUAN\"(0x30D5 0x30A2 0x30F3)"},
{"\u30D5\u30A2\u30F3", "\u30D5\u30A1\u30F3",
"Katakana \"FUAN\"(0x30D5 0x30A2 0x30F3) <---> Katakana \"FUaN\"(0x30D5 0x30A1 0x30F3)"},
};
/*
* | NO_DECOMP(default) | CANONICAL_DECOMP | FULL_DECOMP
* -------------------+--------------------+------------------+-------------
* PRIMARY | s1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
* SECONDARY | s1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
* TERTIARY(default) | S1 = s2 (0) | s1 = s2 (0) | s1 = s2 (0)
*/
static final int[][] results4 = {
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
};
static final String[][] compData4 = {
/*
* Data to verify Japanese normalization
*/
{"\u309E", "\u309D\u3099",
"Hiragana Voiced Iteration Mark(0x309E) <---> Hiragana Iteration Mark(0x309D)Combining Katakana-Hiragana Voiced Sound Mark(0x3099)"},
{"\u30FE", "\u30FD\u3099",
"Katakana Voiced Iteration Mark(0x30FE) <---> Katakana iteration mark(0x30FD)Combining Katakana-Hiragana Voiced Sound Mark(0x3099)"},
{"\u306F\u3099", "\u3070",
"Hiragana \"HA\"(0x306F)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Hiragana \"BA\"(0x3070)"},
{"\u306F\u309A", "\u3071",
"Hiragana \"HA\"(0x306F)Combining Katakana-Hiragana Semi-voiced Sound Mark(0x309A) <---> Hiragana \"PA\"(0x3071)"},
{"\u30EF\u3099", "\u30F7",
"Katakana \"WA\"(0x306F)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VA\"(0x30F7)"},
{"\u30F0\u3099", "\u30F8",
"Katakana \"WI\"(0x30F0)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VI\"(0x30F8)"},
{"\u30F1\u3099", "\u30F9",
"Katakana \"WE\"(0x30F1)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VE\"(0x30F9)"},
{"\u30F2\u3099", "\u30FA",
"Katakana \"WO\"(0x30F2)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VO\"(0x30FA)"},
{"\u3046\u3099", "\u3094",
"Hiragana \"U\"(0x3046)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Hiragana \"VU\"(0x3094)"},
{"\u30A6\u3099", "\u30F4",
"Katakana \"U\"(0x30A6)Combining Katakana-Hiragana Voiced Sound Mark(0x3099) <---> Katakana \"VU\"(0x30F4)"},
// verify normalization
{"\u2260", "\u003D\u0338",
"Not Equal To(0x2260) <---> Equal(0x003D)Combining Long Solidus Overlay(0x0338)"},
{"\u2262", "\u2261\u0338",
"Not Identical To(0x2262) <---> Identical To(0x2261)Combining Long Solidus Overlay(0x0338)"},
{"\u226E", "\u003C\u0338",
"Not Less-than(0x226E) <---> Less-than Sign(0x003C)Combining Long Solidus Overlay(0x0338)"},
// Verify a character which has been added since Unicode 2.1.X.
{"\u798F", "\uFA1B",
"CJK Unified Ideograph \"FUKU\"(0x798F) <---> CJK Compatibility Ideograph \"FUKU\"(0xFA1B)"},
};
/*
* | NO_DECOMP(default) | CANONICAL_DECOMP | FULL_DECOMP
* -------------------+--------------------+------------------+-------------
* PRIMARY | s1 > s2 (1) | s1 = s2 (0) | s1 = s2 (0)
* SECONDARY | s1 > s2 (1) | s1 = s2 (0) | s1 = s2 (0)
* TERTIARY(default) | S1 > s2 (1) | s1 = s2 (0) | s1 = s2 (0)
*/
static final int[][] results5 = {
{ 1, 0, 0},
{ 1, 0, 0},
{ 1, 0, 0},
};
static final String[][] compData5 = {
/*
* Data to verify normalization
*/
{"\u226D", "\u224D\u0338",
"Not Equivalent To(0x226D) <---> Equivalent To(0x224D)Combining Long Solidus Overlay(0x0338)"},
};
static final int[][] results6 = {
{ 1, -1, -1},
{ 1, -1, -1},
{ 1, -1, -1},
};
static final String[][] compData6 = {
/*
* Data to verify normalization
*/
{"\u226D", "\u226C",
"Not Equivalent To(0x226D) <---> Between(0x226C)"},
{"\u226D", "\u225F",
"Not Equivalent To(0x226D) <---> Questioned Equal To(0x225F)"},
};
/*
* The following data isn't used at the moment because iteration marks
* aren't supported now.
*/
static final String[][] compData0 = {
{"\u307F\u307F", "\u307F\u309D",
"Hiragana \"MIMI\"(0x307F 0x307F) <---> Hiragana \"MI\"(0x307F)Hiragana Iteration Mark(0x309D)"},
{"\u3044\u3059\u305A", "\u3044\u3059\u309E",
"Hiragana \"ISUZU\"(0x3044 0x3059 0x305A) <---> Hiragana \"ISU\"(0x3044 0x3059)Hiragana Voiced Iteration Mark(0x309E)"},
{"\u30DF\u30DF", "\u30DF\u30FD",
"Katakana \"MIMI\"(0x30DF 0x30DF) <---> Katakana \"MI\"(0x30DF)Katakana Iteration Mark(0x30FD)"},
{"\u30A4\u30B9\u30BA", "\u30A4\u30B9\u30FE",
"Katakana \"ISUZU\"(0x30A4 0x30B9 0x30BA) <---> Katakana \"ISU\"(0x30A4 0x30B9)Katakana Voiced Iteration Mark(0x30FE)"},
};
static final String[] decomp_name = {
"NO_DECOMP", "CANONICAL_DECOMP", "FULL_DECOMP"
};
static final String[] strength_name = {
"PRIMARY", "SECONDARY", "TERTIARY"
};
Collator col = Collator.getInstance(Locale.JAPAN);
int result = 0;
public static void main(String[] args) throws Exception {
new JapaneseTest().run();
}
public void run() {
// Use all available localse on the initial testing....
// Locale[] locales = Locale.getAvailableLocales();
Locale[] locales = { Locale.getDefault() };
for (int l = 0; l < locales.length; l++) {
Locale.setDefault(locales[l]);
for (int decomp = 0; decomp < 3; decomp++) {// See decomp_name.
col.setDecomposition(decomp);
for (int strength = 0; strength < 3; strength++) {// See strength_name.
// System.err.println("\n" + locales[l] + ": " + strength_name[strength] + " --- " + decomp_name[decomp]);
col.setStrength(strength);
doCompare(compData1, results1[strength][decomp], strength, decomp);
doCompare(compData2, results2[strength][decomp], strength, decomp);
doCompare(compData3, results3[strength][decomp], strength, decomp);
doCompare(compData4, results4[strength][decomp], strength, decomp);
doCompare(compData5, results5[strength][decomp], strength, decomp);
doCompare(compData6, results6[strength][decomp], strength, decomp);
}
}
}
/* Check result */
if (result !=0) {
throw new RuntimeException("Unexpected results on Japanese collation.");
}
}
void doCompare(String[][] s, int expectedValue, int strength, int decomp) {
int value;
for (int i=0; i < s.length; i++) {
if ((value = col.compare(s[i][0], s[i][1])) != expectedValue) {
result++;
System.err.println(strength_name[strength] +
": compare() returned unexpected value.(" +
value + ") on " + decomp_name[decomp] +
" Expected(" + expectedValue +
") for " + s[i][2]);
}
}
}
}

View file

@ -0,0 +1,143 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test 1.1 02/09/12
* @bug 4176141 4655819
* @summary Regression tests for Korean Collation
* @modules jdk.localedata
*/
import java.text.*;
import java.util.*;
public class KoreanTest {
// NOTE:
// Golden data in this test case is locale data dependent and
// may need to be changed if the Korean locale collation rules
// are changed.
// And, CollationDecomp has been set to 0(NO_DECOMPOSITION) in
// LocaleElements_ko.java.
// This is very important to consider what is correct behavior in
// Korean Collator. Sometimes different from other locales.
/*
* TERTIARY(default): s1 < s2, SECONDARY: s1 < s2, PRIMARY: s1 < s2
*/
static final String[][] compData1 = {
/*
* Data to verify '<' relationship in LocaleElements_ja.java
*/
{"\uACE0\uC591\uC774", "\u732B",
"Hangul \"Cat\"(0xACE0 0xC591 0xC774) <---> Chinese Kanji \"Cat\"(0x732B)"},
{"\u30FB", "\u2025",
"Katakana middle dot(0x30FB) <---> Two dot leader(0x2025)"},
{"\u00B1", "\u2260",
"Plus-Minus Sign(0x00B1) <---> Not Equal To(0x2260)"},
{"\u3011", "\u2260",
"Right Black Lenticular Bracket(0x3011) <---> Not Equal To(0x2260)"},
{"\u2260", "\u2103",
"Not Equal To(0x2260) <---> Degree Celsius(0x2103)"},
{"\u2260", "\u2606",
"Not Equal To(0x2260) <---> White Star(0x2606)"},
// Unlike other locales' Collator, compare() returns -1 because of
// NO_DECOMPOSITION.
/* above "assumption" is no longer true, now we do normalize ("decomposition")
for the pattern in ko locale, but exclude those hangul syllables, so the
test case below need to be excluded from tiger/1.5
{"\u003D\u0338", "\u2260",
"Equal(0x003D)Combining Long Solidus Overlay(0x0338) <---> Not Equal To(0x2260)"},
*/
};
/*
* TERTIARY(default): s1 = s2, SECONDARY: s1 = s2, PRIMARY: s1 = s2
*/
static final String[][] compData2 = {
// Verify a character which has been added since Unicode 2.1.X.
{"\u798F", "\uFA1B",
"CJK Unified Ideograph \"FUKU\"(0x798F) <---> CJK Compatibility Ideograph \"FUKU\"(0xFA1B)"},
};
Collator col = Collator.getInstance(Locale.KOREA);
int result = 0;
public static void main(String[] args) throws Exception {
new KoreanTest().run();
}
public void run() {
//
// Test for TERTIARY(default)
//
doCompare(compData1);
doEquals(compData2);
//
// Test for SECONDARY
//
col.setStrength(Collator.SECONDARY);
doCompare(compData1);
doEquals(compData2);
//
// Test for PRIMARY
//
col.setStrength(Collator.PRIMARY);
doCompare(compData1);
doEquals(compData2);
if (result !=0) {
throw new RuntimeException("Unexpected results on Korean collation.");
}
}
/* compare() should return -1 for each combination. */
void doCompare(String[][] s) {
int value;
for (int i=0; i < s.length; i++) {
if ((value = col.compare(s[i][0], s[i][1])) > -1) {
result++;
System.err.println("TERTIARY: The first string should be less than the second string: " +
s[i][2] + " compare() returned " + value + ".");
}
}
}
/* equals() should return true for each combination. */
void doEquals(String[][] s) {
for (int i=0; i < s.length; i++) {
if (!col.equals(s[i][0], s[i][1])) {
result++;
System.err.println("TERTIARY: The first string should be equals to the second string: " +
s[i][2] + " compare() returned " +
col.compare(s[i][0], s[i][1] + "."));
}
}
}
}

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Collation, Monkey style
* @run junit MonkeyTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.io.IOException;
import java.util.Random;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Locale;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.text.CollationKey;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class MonkeyTest
{
public void report(String s, String t, int result, int revResult)
{
if (result == -1)
{
if (revResult != 1)
fail(" --> Test Failed");
}
else if (result == 1)
{
if (revResult != -1)
fail(" --> Test Failed");
}
else if (result == 0)
{
if (revResult != 0)
fail(" --> Test Failed");
}
}
@Test
public void TestCollationKey()
{
String source = "-abcdefghijklmnopqrstuvwxyz#&^$@";
Random r = new Random(3);
int s = checkValue(r.nextInt() % source.length());
int t = checkValue(r.nextInt() % source.length());
int slen = checkValue((r.nextInt() - source.length()) % source.length());
int tlen = checkValue((r.nextInt() - source.length()) % source.length());
String subs = source.substring((s > slen ? slen : s), (s >= slen ? s : slen));
String subt = source.substring((t > tlen ? tlen : t), (t >= tlen ? t : tlen));
myCollator.setStrength(Collator.TERTIARY);
CollationKey CollationKey1 = myCollator.getCollationKey(subs);
CollationKey CollationKey2 = myCollator.getCollationKey(subt);
int result = CollationKey1.compareTo(CollationKey2); // Tertiary
int revResult = CollationKey2.compareTo(CollationKey1); // Tertiary
report(("CollationKey(" + subs + ")"), ("CollationKey(" + subt + ")"), result, revResult);
myCollator.setStrength(Collator.SECONDARY);
CollationKey1 = myCollator.getCollationKey(subs);
CollationKey2 = myCollator.getCollationKey(subt);
result = CollationKey1.compareTo(CollationKey2); // Secondary
revResult = CollationKey2.compareTo(CollationKey1); // Secondary
report(("CollationKey(" + subs + ")") , ("CollationKey(" + subt + ")"), result, revResult);
myCollator.setStrength(Collator.PRIMARY);
CollationKey1 = myCollator.getCollationKey(subs);
CollationKey2 = myCollator.getCollationKey(subt);
result = CollationKey1.compareTo(CollationKey2); // Primary
revResult = CollationKey2.compareTo(CollationKey1); // Primary
report(("CollationKey(" + subs + ")"), ("CollationKey(" + subt + ")"), result, revResult);
String addOne = subs + "\uE000";
CollationKey1 = myCollator.getCollationKey(subs);
CollationKey2 = myCollator.getCollationKey(addOne);
result = CollationKey1.compareTo(CollationKey2);
if (result != -1)
fail("CollationKey(" + subs + ")" + ".LT." + "CollationKey(" + addOne + ") Failed.");
result = CollationKey2.compareTo(CollationKey1);
if (result != 1)
fail("CollationKey(" + addOne + ")" + ".GT." + "CollationKey(" + subs + ") Failed.");
}
private static int checkValue(int value)
{
value *= (value > 0) ? 1 : -1;
return value;
}
@Test
public void TestCompare()
{
String source = "-abcdefghijklmnopqrstuvwxyz#&^$@";
Random r = new Random(3);
int s = checkValue(r.nextInt() % source.length());
int t = checkValue(r.nextInt() % source.length());
int slen = checkValue((r.nextInt() - source.length()) % source.length());
int tlen = checkValue((r.nextInt() - source.length()) % source.length());
String subs = source.substring((s > slen ? slen : s), (s >= slen ? s : slen));
String subt = source.substring((t > tlen ? tlen : t), (t >= tlen ? t : tlen));
myCollator.setStrength(Collator.TERTIARY);
int result = myCollator.compare(subs, subt); // Tertiary
int revResult = myCollator.compare(subt, subs); // Tertiary
report(subs, subt, result, revResult);
myCollator.setStrength(Collator.SECONDARY);
result = myCollator.compare(subs, subt); // Secondary
revResult = myCollator.compare(subt, subs); // Secondary
report(subs, subt, result, revResult);
myCollator.setStrength(Collator.PRIMARY);
result = myCollator.compare(subs, subt); // Primary
revResult = myCollator.compare(subt, subs); // Primary
report(subs, subt, result, revResult);
String addOne = subs + "\uE000";
result = myCollator.compare(subs, addOne);
if (result != -1)
fail("Test : " + subs + " .LT. " + addOne + " Failed.");
result = myCollator.compare(addOne, subs);
if (result != 1)
fail("Test : " + addOne + " .GE. " + subs + " Failed.");
}
private static Collator myCollator = Collator.getInstance();
}

View file

@ -0,0 +1,978 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4048446 4051866 4053636 4054238 4054734 4054736 4058613 4059820 4060154
* 4062418 4065540 4066189 4066696 4076676 4078588 4079231 4081866 4087241
* 4087243 4092260 4095316 4101940 4103436 4114076 4114077 4124632 4132736
* 4133509 4139572 4141640 4179126 4179686 4244884 4663220
* @library /java/text/testlib
* @summary Regression tests for Collation and associated classes
* @modules jdk.localedata
* @run junit Regression
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.text.*;
import java.util.Locale;
import java.util.Vector;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Regression {
// CollationElementIterator.reset() doesn't work
//
@Test
public void Test4048446() {
CollationElementIterator i1 = en_us.getCollationElementIterator(test1);
CollationElementIterator i2 = en_us.getCollationElementIterator(test1);
while ( i1.next() != CollationElementIterator.NULLORDER ) {
}
i1.reset();
TestUtils.compareCollationElementIters(i1, i2);
}
// Collator -> rules -> Collator round-trip broken for expanding characters
//
@Test
public void Test4051866() throws ParseException {
// Build a collator containing expanding characters
RuleBasedCollator c1 = new RuleBasedCollator("< o "
+"& oe ,o\u3080"
+"& oe ,\u1530 ,O"
+"& OE ,O\u3080"
+"& OE ,\u1520"
+"< p ,P");
// Build another using the rules from the first
RuleBasedCollator c2 = new RuleBasedCollator(c1.getRules());
// Make sure they're the same
if (!c1.getRules().equals(c2.getRules())) {
fail("Rules are not equal");
}
}
// Collator thinks "black-bird" == "black"
//
@Test
public void Test4053636() {
if (en_us.equals("black-bird","black")) {
fail("black-bird == black");
}
}
// CollationElementIterator will not work correctly if the associated
// Collator object's mode is changed
//
@Test
public void Test4054238() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
CollationElementIterator i1 = en_us.getCollationElementIterator(test3);
c.setDecomposition(Collator.NO_DECOMPOSITION);
CollationElementIterator i2 = en_us.getCollationElementIterator(test3);
// At this point, BOTH iterators should use NO_DECOMPOSITION, since the
// collator itself is in that mode
TestUtils.compareCollationElementIters(i1, i2);
}
// Collator.IDENTICAL documented but not implemented
//
@Test
public void Test4054734() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
try {
c.setStrength(Collator.IDENTICAL);
}
catch (Exception e) {
fail("Caught " + e.toString() + " setting Collator.IDENTICAL");
}
String[] decomp = {
"\u0001", "<", "\u0002",
"\u0001", "=", "\u0001",
"A\u0001", ">", "~\u0002", // Ensure A and ~ are not compared bitwise
"\u00C0", "=", "A\u0300" // Decomp should make these equal
};
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
compareArray(c, decomp);
String[] nodecomp = {
"\u00C0", ">", "A\u0300" // A-grave vs. A combining-grave
};
c.setDecomposition(Collator.NO_DECOMPOSITION);
compareArray(c, nodecomp);
}
// Full Decomposition mode not implemented
//
@Test
public void Test4054736() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setDecomposition(Collator.FULL_DECOMPOSITION);
String[] tests = {
"\uFB4f", "=", "\u05D0\u05DC", // Alef-Lamed vs. Alef, Lamed
};
compareArray(c, tests);
}
// Collator.getInstance() causes an ArrayIndexOutofBoundsException for Korean
//
@Test
public void Test4058613() {
// Creating a default collator doesn't work when Korean is the default
// locale
Locale oldDefault = Locale.getDefault();
Locale.setDefault( Locale.KOREAN );
try {
Collator c = Collator.getInstance();
// Since the fix to this bug was to turn of decomposition for Korean collators,
// ensure that's what we got
if (c.getDecomposition() != Collator.NO_DECOMPOSITION) {
fail("Decomposition is not set to NO_DECOMPOSITION");
}
}
finally {
Locale.setDefault(oldDefault);
}
}
// RuleBasedCollator.getRules does not return the exact pattern as input
// for expanding character sequences
//
@Test
public void Test4059820() {
RuleBasedCollator c = null;
try {
c = new RuleBasedCollator("< a < b , c/a < d < z");
} catch (ParseException e) {
fail("Exception building collator: " + e.toString());
return;
}
if ( c.getRules().indexOf("c/a") == -1) {
fail("returned rules do not contain 'c/a'");
}
}
// MergeCollation::fixEntry broken for "& H < \u0131, \u0130, i, I"
//
@Test
public void Test4060154() {
RuleBasedCollator c = null;
try {
c = new RuleBasedCollator("< g, G < h, H < i, I < j, J"
+ " & H < \u0131, \u0130, i, I" );
} catch (ParseException e) {
fail("Exception building collator: " + e.toString());
return;
}
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
String[] tertiary = {
"A", "<", "B",
"H", "<", "\u0131",
"H", "<", "I",
"\u0131", "<", "\u0130",
"\u0130", "<", "i",
"\u0130", ">", "H",
};
c.setStrength(Collator.TERTIARY);
compareArray(c, tertiary);
String[] secondary = {
"H", "<", "I",
"\u0131", "=", "\u0130",
};
c.setStrength(Collator.PRIMARY);
compareArray(c, secondary);
};
// Secondary/Tertiary comparison incorrect in French Secondary
//
@Test
public void Test4062418() throws ParseException {
RuleBasedCollator c = (RuleBasedCollator) Collator.getInstance(Locale.FRANCE);
c.setStrength(Collator.SECONDARY);
String[] tests = {
"p\u00eache", "<", "p\u00e9ch\u00e9", // Comparing accents from end, p\u00e9ch\u00e9 is greater
};
compareArray(c, tests);
}
// Collator.compare() method broken if either string contains spaces
//
@Test
public void Test4065540() {
if (en_us.compare("abcd e", "abcd f") == 0) {
fail("'abcd e' == 'abcd f'");
}
}
// Unicode characters need to be recursively decomposed to get the
// correct result. For example,
// u1EB1 -> \u0103 + \u0300 -> a + \u0306 + \u0300.
//
@Test
public void Test4066189() {
String test1 = "\u1EB1";
String test2 = "a\u0306\u0300";
RuleBasedCollator c1 = (RuleBasedCollator) en_us.clone();
c1.setDecomposition(Collator.FULL_DECOMPOSITION);
CollationElementIterator i1 = en_us.getCollationElementIterator(test1);
RuleBasedCollator c2 = (RuleBasedCollator) en_us.clone();
c2.setDecomposition(Collator.NO_DECOMPOSITION);
CollationElementIterator i2 = en_us.getCollationElementIterator(test2);
TestUtils.compareCollationElementIters(i1, i2);
}
// French secondary collation checking at the end of compare iteration fails
//
@Test
public void Test4066696() {
RuleBasedCollator c = (RuleBasedCollator) Collator.getInstance(Locale.FRANCE);
c.setStrength(Collator.SECONDARY);
String[] tests = {
"\u00e0", "<", "\u01fa", // a-grave < A-ring-acute
};
compareArray(c, tests);
}
// Bad canonicalization of same-class combining characters
//
@Test
public void Test4076676() {
// These combining characters are all in the same class, so they should not
// be reordered, and they should compare as unequal.
String s1 = "A\u0301\u0302\u0300";
String s2 = "A\u0302\u0300\u0301";
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
if (c.compare(s1,s2) == 0) {
fail("Same-class combining chars were reordered");
}
}
// RuleBasedCollator.equals(null) throws NullPointerException
//
@Test
public void Test4079231() {
try {
if (en_us.equals(null)) {
fail("en_us.equals(null) returned true");
}
}
catch (Exception e) {
fail("en_us.equals(null) threw " + e.toString());
}
}
// RuleBasedCollator breaks on "< a < bb" rule
//
@Test
public void Test4078588() throws ParseException {
RuleBasedCollator rbc=new RuleBasedCollator("< a < bb");
int result = rbc.compare("a","bb");
if (result != -1) {
fail("Compare(a,bb) returned " + result + "; expected -1");
}
}
// Combining characters in different classes not reordered properly.
//
@Test
public void Test4081866() throws ParseException {
// These combining characters are all in different classes,
// so they should be reordered and the strings should compare as equal.
String s1 = "A\u0300\u0316\u0327\u0315";
String s2 = "A\u0327\u0316\u0315\u0300";
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
// Now that the default collators are set to NO_DECOMPOSITION
// (as a result of fixing bug 4114077), we must set it explicitly
// when we're testing reordering behavior. -- lwerner, 5/5/98
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
if (c.compare(s1,s2) != 0) {
fail("Combining chars were not reordered");
}
}
// string comparison errors in Scandinavian collators
//
@Test
public void Test4087241() {
RuleBasedCollator c = (RuleBasedCollator) Collator.getInstance(
Locale.of("da", "DK"));
c.setStrength(Collator.SECONDARY);
String[] tests = {
"\u007a", "<", "\u00e6", // z < ae
"a\u0308", "<", "a\u030a", // a-unlaut < a-ring
"Y", "<", "u\u0308", // Y < u-umlaut
};
compareArray(c, tests);
}
// CollationKey takes ignorable strings into account when it shouldn't
//
@Test
public void Test4087243() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
String[] tests = {
"123", "=", "123\u0001", // 1 2 3 = 1 2 3 ctrl-A
};
compareArray(c, tests);
}
// Mu/micro conflict
// Micro symbol and greek lowercase letter Mu should sort identically
//
@Test
public void Test4092260() {
Collator c = Collator.getInstance(Locale.of("el"));
// will only be equal when FULL_DECOMPOSITION is used
c.setDecomposition(Collator.FULL_DECOMPOSITION);
String[] tests = {
"\u00B5", "=", "\u03BC",
};
compareArray(c, tests);
}
void Test4095316() {
Collator c = Collator.getInstance(Locale.of("el", "GR"));
c.setStrength(Collator.TERTIARY);
// javadocs for RuleBasedCollator clearly specify that characters containing compatability
// chars MUST use FULL_DECOMPOSITION to get accurate comparisons.
c.setDecomposition(Collator.FULL_DECOMPOSITION);
String[] tests = {
"\u03D4", "=", "\u03AB",
};
compareArray(c, tests);
}
@Test
public void Test4101940() {
try {
RuleBasedCollator c = new RuleBasedCollator("< a < b");
CollationElementIterator i = c.getCollationElementIterator("");
i.reset();
if (i.next() != i.NULLORDER) {
fail("next did not return NULLORDER");
}
}
catch (Exception e) {
fail("Caught " + e );
}
}
// Collator.compare not handling spaces properly
//
@Test
public void Test4103436() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
String[] tests = {
"file", "<", "file access",
"file", "<", "fileaccess",
};
compareArray(c, tests);
}
// Collation not Unicode conformant with Hangul syllables
//
@Test
public void Test4114076() {
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
//
// With Canonical decomposition, Hangul syllables should get decomposed
// into Jamo, but Jamo characters should not be decomposed into
// conjoining Jamo
//
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
String[] test1 = {
"\ud4db", "=", "\u1111\u1171\u11b6",
};
compareArray(c, test1);
// Full decomposition result should be the same as canonical decomposition
// for all hangul.
c.setDecomposition(Collator.FULL_DECOMPOSITION);
compareArray(c, test1);
}
// Collator.getCollationKey was hanging on certain character sequences
//
@Test
public void Test4124632() throws Exception {
Collator coll = Collator.getInstance(Locale.JAPAN);
try {
coll.getCollationKey("A\u0308bc");
} catch (OutOfMemoryError e) {
fail("Ran out of memory -- probably an infinite loop");
}
}
// sort order of french words with multiple accents has errors
//
@Test
public void Test4132736() {
Collator c = Collator.getInstance(Locale.FRANCE);
String[] test1 = {
"e\u0300e\u0301", "<", "e\u0301e\u0300",
"e\u0300\u0301", ">", "e\u0301\u0300",
};
compareArray(c, test1);
}
// The sorting using java.text.CollationKey is not in the exact order
//
@Test
public void Test4133509() {
String[] test1 = {
"Exception", "<", "ExceptionInInitializerError",
"Graphics", "<", "GraphicsEnvironment",
"String", "<", "StringBuffer",
};
compareArray(en_us, test1);
}
// Collation with decomposition off doesn't work for Europe
//
@Test
public void Test4114077() {
// Ensure that we get the same results with decomposition off
// as we do with it on....
RuleBasedCollator c = (RuleBasedCollator) en_us.clone();
c.setStrength(Collator.TERTIARY);
String[] test1 = {
"\u00C0", "=", "A\u0300", // Should be equivalent
"p\u00eache", ">", "p\u00e9ch\u00e9",
"\u0204", "=", "E\u030F",
"\u01fa", "=", "A\u030a\u0301", // a-ring-acute -> a-ring, acute
// -> a, ring, acute
"A\u0300\u0316", "<", "A\u0316\u0300", // No reordering --> unequal
};
c.setDecomposition(Collator.NO_DECOMPOSITION);
compareArray(c, test1);
String[] test2 = {
"A\u0300\u0316", "=", "A\u0316\u0300", // Reordering --> equal
};
c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
compareArray(c, test2);
}
// Support for Swedish gone in 1.1.6 (Can't create Swedish collator)
//
@Test
public void Test4141640() {
//
// Rather than just creating a Swedish collator, we might as well
// try to instantiate one for every locale available on the system
// in order to prevent this sort of bug from cropping up in the future
//
Locale[] locales = Collator.getAvailableLocales();
for (int i = 0; i < locales.length; i++) {
try {
Collator c = Collator.getInstance(locales[i]);
} catch (Exception e) {
fail("Caught " + e + " creating collator for " + locales[i]);
}
}
}
// getCollationKey throws exception for spanish text
// Cannot reproduce this bug on 1.2, however it DOES fail on 1.1.6
//
@Test
public void Test4139572() {
//
// Code pasted straight from the bug report
//
// create spanish locale and collator
Locale l = Locale.of("es", "es");
Collator col = Collator.getInstance(l);
// this spanish phrase kills it!
col.getCollationKey("Nombre De Objeto");
}
// RuleBasedCollator doesn't use getCollationElementIterator internally
//
@Test
public void Test4146160() throws ParseException {
//
// Use a custom collator class whose getCollationElementIterator
// methods increment a count....
//
My4146160Collator.count = 0;
new My4146160Collator().getCollationKey("1");
if (My4146160Collator.count < 1) {
fail("getCollationElementIterator not called");
}
My4146160Collator.count = 0;
new My4146160Collator().compare("1", "2");
if (My4146160Collator.count < 1) {
fail("getCollationElementIterator not called");
}
}
static class My4146160Collator extends RuleBasedCollator {
public My4146160Collator() throws ParseException {
super(Regression.en_us.getRules());
}
public CollationElementIterator getCollationElementIterator(
String text) {
count++;
return super.getCollationElementIterator(text);
}
public CollationElementIterator getCollationElementIterator(
CharacterIterator text) {
count++;
return super.getCollationElementIterator(text);
}
public static int count = 0;
};
// CollationElementIterator.previous broken for expanding char sequences
//
@Test
public void Test4179686() throws ParseException {
// Create a collator with a few expanding character sequences in it....
RuleBasedCollator coll = new RuleBasedCollator(en_us.getRules()
+ " & ae ; \u00e4 & AE ; \u00c4"
+ " & oe ; \u00f6 & OE ; \u00d6"
+ " & ue ; \u00fc & UE ; \u00dc");
String text = "T\u00f6ne"; // o-umlaut
CollationElementIterator iter = coll.getCollationElementIterator(text);
Vector elements = new Vector();
int elem;
// Iterate forward and collect all of the elements into a Vector
while ((elem = iter.next()) != iter.NULLORDER) {
elements.addElement(new Integer(elem));
}
// Now iterate backward and make sure they're the same
int index = elements.size() - 1;
while ((elem = iter.previous()) != iter.NULLORDER) {
int expect = ((Integer)elements.elementAt(index)).intValue();
if (elem != expect) {
fail("Mismatch at index " + index
+ ": got " + Integer.toString(elem,16)
+ ", expected " + Integer.toString(expect,16));
}
index--;
}
}
@Test
public void Test4244884() throws ParseException {
RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(Locale.US);
coll = new RuleBasedCollator(coll.getRules()
+ " & C < ch , cH , Ch , CH < cat < crunchy");
String[] testStrings = new String[] {
"car",
"cave",
"clamp",
"cramp",
"czar",
"church",
"catalogue",
"crunchy",
"dog"
};
for (int i = 1; i < testStrings.length; i++) {
if (coll.compare(testStrings[i - 1], testStrings[i]) >= 0) {
fail("error: \"" + testStrings[i - 1]
+ "\" is greater than or equal to \"" + testStrings[i]
+ "\".");
}
}
}
@Test
public void Test4179216() throws ParseException {
// you can position a CollationElementIterator in the middle of
// a contracting character sequence, yielding a bogus collation
// element
RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(Locale.US);
coll = new RuleBasedCollator(coll.getRules()
+ " & C < ch , cH , Ch , CH < cat < crunchy");
String testText = "church church catcatcher runcrunchynchy";
CollationElementIterator iter = coll.getCollationElementIterator(
testText);
// test that the "ch" combination works properly
iter.setOffset(4);
int elt4 = CollationElementIterator.primaryOrder(iter.next());
iter.reset();
int elt0 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(5);
int elt5 = CollationElementIterator.primaryOrder(iter.next());
if (elt4 != elt0 || elt5 != elt0)
fail("The collation elements at positions 0 (" + elt0 + "), 4 ("
+ elt4 + "), and 5 (" + elt5 + ") don't match.");
// test that the "cat" combination works properly
iter.setOffset(14);
int elt14 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(15);
int elt15 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(16);
int elt16 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(17);
int elt17 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(18);
int elt18 = CollationElementIterator.primaryOrder(iter.next());
iter.setOffset(19);
int elt19 = CollationElementIterator.primaryOrder(iter.next());
if (elt14 != elt15 || elt14 != elt16 || elt14 != elt17
|| elt14 != elt18 || elt14 != elt19)
fail("\"cat\" elements don't match: elt14 = " + elt14 + ", elt15 = "
+ elt15 + ", elt16 = " + elt16 + ", elt17 = " + elt17
+ ", elt18 = " + elt18 + ", elt19 = " + elt19);
// now generate a complete list of the collation elements,
// first using next() and then using setOffset(), and
// make sure both interfaces return the same set of elements
iter.reset();
int elt = iter.next();
int count = 0;
while (elt != CollationElementIterator.NULLORDER) {
++count;
elt = iter.next();
}
String[] nextElements = new String[count];
String[] setOffsetElements = new String[count];
int lastPos = 0;
iter.reset();
elt = iter.next();
count = 0;
while (elt != CollationElementIterator.NULLORDER) {
nextElements[count++] = testText.substring(lastPos, iter.getOffset());
lastPos = iter.getOffset();
elt = iter.next();
}
count = 0;
for (int i = 0; i < testText.length(); ) {
iter.setOffset(i);
lastPos = iter.getOffset();
elt = iter.next();
setOffsetElements[count++] = testText.substring(lastPos, iter.getOffset());
i = iter.getOffset();
}
for (int i = 0; i < nextElements.length; i++) {
if (nextElements[i].equals(setOffsetElements[i])) {
System.out.println(nextElements[i]);
} else {
fail("Error: next() yielded " + nextElements[i] + ", but setOffset() yielded "
+ setOffsetElements[i]);
}
}
}
@Test
public void Test4216006() throws Exception {
// rule parser barfs on "<\u00e0=a\u0300", and on other cases
// where the same token (after normalization) appears twice in a row
boolean caughtException = false;
try {
RuleBasedCollator dummy = new RuleBasedCollator("\u00e0<a\u0300");
}
catch (ParseException e) {
caughtException = true;
}
if (!caughtException) {
throw new Exception("\"a<a\" collation sequence didn't cause parse error!");
}
RuleBasedCollator collator = new RuleBasedCollator("<\u00e0=a\u0300");
collator.setDecomposition(Collator.FULL_DECOMPOSITION);
collator.setStrength(Collator.IDENTICAL);
String[] tests = {
"a\u0300", "=", "\u00e0",
"\u00e0", "=", "a\u0300"
};
compareArray(collator, tests);
}
@Test
public void Test4171974() {
// test French accent ordering more thoroughly
String[] frenchList = {
"\u0075\u0075", // u u
"\u00fc\u0075", // u-umlaut u
"\u01d6\u0075", // u-umlaut-macron u
"\u016b\u0075", // u-macron u
"\u1e7b\u0075", // u-macron-umlaut u
"\u0075\u00fc", // u u-umlaut
"\u00fc\u00fc", // u-umlaut u-umlaut
"\u01d6\u00fc", // u-umlaut-macron u-umlaut
"\u016b\u00fc", // u-macron u-umlaut
"\u1e7b\u00fc", // u-macron-umlaut u-umlaut
"\u0075\u01d6", // u u-umlaut-macron
"\u00fc\u01d6", // u-umlaut u-umlaut-macron
"\u01d6\u01d6", // u-umlaut-macron u-umlaut-macron
"\u016b\u01d6", // u-macron u-umlaut-macron
"\u1e7b\u01d6", // u-macron-umlaut u-umlaut-macron
"\u0075\u016b", // u u-macron
"\u00fc\u016b", // u-umlaut u-macron
"\u01d6\u016b", // u-umlaut-macron u-macron
"\u016b\u016b", // u-macron u-macron
"\u1e7b\u016b", // u-macron-umlaut u-macron
"\u0075\u1e7b", // u u-macron-umlaut
"\u00fc\u1e7b", // u-umlaut u-macron-umlaut
"\u01d6\u1e7b", // u-umlaut-macron u-macron-umlaut
"\u016b\u1e7b", // u-macron u-macron-umlaut
"\u1e7b\u1e7b" // u-macron-umlaut u-macron-umlaut
};
Collator french = Collator.getInstance(Locale.FRENCH);
System.out.println("Testing French order...");
checkListOrder(frenchList, french);
System.out.println("Testing French order without decomposition...");
french.setDecomposition(Collator.NO_DECOMPOSITION);
checkListOrder(frenchList, french);
String[] englishList = {
"\u0075\u0075", // u u
"\u0075\u00fc", // u u-umlaut
"\u0075\u01d6", // u u-umlaut-macron
"\u0075\u016b", // u u-macron
"\u0075\u1e7b", // u u-macron-umlaut
"\u00fc\u0075", // u-umlaut u
"\u00fc\u00fc", // u-umlaut u-umlaut
"\u00fc\u01d6", // u-umlaut u-umlaut-macron
"\u00fc\u016b", // u-umlaut u-macron
"\u00fc\u1e7b", // u-umlaut u-macron-umlaut
"\u01d6\u0075", // u-umlaut-macron u
"\u01d6\u00fc", // u-umlaut-macron u-umlaut
"\u01d6\u01d6", // u-umlaut-macron u-umlaut-macron
"\u01d6\u016b", // u-umlaut-macron u-macron
"\u01d6\u1e7b", // u-umlaut-macron u-macron-umlaut
"\u016b\u0075", // u-macron u
"\u016b\u00fc", // u-macron u-umlaut
"\u016b\u01d6", // u-macron u-umlaut-macron
"\u016b\u016b", // u-macron u-macron
"\u016b\u1e7b", // u-macron u-macron-umlaut
"\u1e7b\u0075", // u-macron-umlaut u
"\u1e7b\u00fc", // u-macron-umlaut u-umlaut
"\u1e7b\u01d6", // u-macron-umlaut u-umlaut-macron
"\u1e7b\u016b", // u-macron-umlaut u-macron
"\u1e7b\u1e7b" // u-macron-umlaut u-macron-umlaut
};
Collator english = Collator.getInstance(Locale.ENGLISH);
System.out.println("Testing English order...");
checkListOrder(englishList, english);
System.out.println("Testing English order without decomposition...");
english.setDecomposition(Collator.NO_DECOMPOSITION);
checkListOrder(englishList, english);
}
private void checkListOrder(String[] sortedList, Collator c) {
// this function uses the specified Collator to make sure the
// passed-in list is already sorted into ascending order
for (int i = 0; i < sortedList.length - 1; i++) {
if (c.compare(sortedList[i], sortedList[i + 1]) >= 0) {
fail("List out of order at element #" + i + ": "
+ TestUtils.prettify(sortedList[i]) + " >= "
+ TestUtils.prettify(sortedList[i + 1]));
}
}
}
// CollationElementIterator set doesn't work propertly with next/prev
@Test
public void Test4663220() {
RuleBasedCollator collator = (RuleBasedCollator)Collator.getInstance(Locale.US);
CharacterIterator stringIter = new StringCharacterIterator("fox");
CollationElementIterator iter = collator.getCollationElementIterator(stringIter);
int[] elements_next = new int[3];
System.out.println("calling next:");
for (int i = 0; i < 3; ++i) {
System.out.println("[" + i + "] " + (elements_next[i] = iter.next()));
}
int[] elements_fwd = new int[3];
System.out.println("calling set/next:");
for (int i = 0; i < 3; ++i) {
iter.setOffset(i);
System.out.println("[" + i + "] " + (elements_fwd[i] = iter.next()));
}
for (int i = 0; i < 3; ++i) {
if (elements_next[i] != elements_fwd[i]) {
fail("mismatch at position " + i +
": " + elements_next[i] +
" != " + elements_fwd[i]);
}
}
}
//------------------------------------------------------------------------
// Internal utilities
//
private void compareArray(Collator c, String[] tests) {
for (int i = 0; i < tests.length; i += 3) {
int expect = 0;
if (tests[i+1].equals("<")) {
expect = -1;
} else if (tests[i+1].equals(">")) {
expect = 1;
} else if (tests[i+1].equals("=")) {
expect = 0;
} else {
expect = Integer.decode(tests[i+1]).intValue();
}
int result = c.compare(tests[i], tests[i+2]);
if (sign(result) != sign(expect))
{
fail( i/3 + ": compare(" + TestUtils.prettify(tests[i])
+ " , " + TestUtils.prettify(tests[i+2])
+ ") got " + result + "; expected " + expect);
}
else
{
// Collator.compare worked OK; now try the collation keys
CollationKey k1 = c.getCollationKey(tests[i]);
CollationKey k2 = c.getCollationKey(tests[i+2]);
result = k1.compareTo(k2);
if (sign(result) != sign(expect)) {
fail( i/3 + ": key(" + TestUtils.prettify(tests[i])
+ ").compareTo(key(" + TestUtils.prettify(tests[i+2])
+ ")) got " + result + "; expected " + expect);
fail(" " + TestUtils.prettifyCKey(k1) + " vs. " + TestUtils.prettifyCKey(k2));
}
}
}
}
private static final int sign(int i) {
if (i < 0) return -1;
if (i > 0) return 1;
return 0;
}
static RuleBasedCollator en_us = (RuleBasedCollator)Collator.getInstance(Locale.US);
String test1 = "XFILE What subset of all possible test cases has the highest probability of detecting the most errors?";
String test2 = "Xf ile What subset of all possible test cases has the lowest probability of detecting the least errors?";
String test3 = "a\u00FCbeck Gr\u00F6\u00DFe L\u00FCbeck";
}

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4406815 8222969 8266784
* @summary RuleBasedCollatorTest uses very limited but selected test data
* to test basic functionalities provided by RuleBasedCollator.
* @run junit/othervm RuleBasedCollatorTest
*/
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.CollationElementIterator;
import java.text.CollationKey;
import java.text.Collator;
import java.text.ParseException;
import java.text.RuleBasedCollator;
import java.util.Arrays;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class RuleBasedCollatorTest {
private static RuleBasedCollator USC;
private static String US_RULES;
@BeforeAll
void setup() {
Collator c = Collator.getInstance(Locale.US);
assumeFalse(!(c instanceof RuleBasedCollator), "skip tests.");
USC = (RuleBasedCollator) c;
US_RULES = USC.getRules();
}
Object[][] rulesData() {
//Basic Tailor
String BASIC_TAILOR_RULES = "< b=c<\u00e6;A,a";
String[] BASIC_TAILOR_DATA = {"\u00e6", "b", "a", "c", "A"};
String[] BASIC_TAILOR_EXPECTED = {"b", "c", "\u00e6", "A", "a"};
//Contraction
String CONTRACTION_RULES = US_RULES + "& b < ch ,cH, Ch, CH < c ";
String[] CONTRACTION_DATA = {"b", "c", "ch", "CH", "Ch", "cH"};
String[] CONTRACTION_EXPECTED = {"b", "ch", "cH", "Ch", "CH", "c"};
//Expansion
String EXPANSION_RULES = US_RULES + "& ae = \u00e4 < b";
String[] EXPANSION_DATA = {"ad", "af", "\u00e4"};
String[] EXPANSION_EXPECTED = {"ad", "\u00e4", "af"};
//Punctuation
String PUNCTUATION_RULES = US_RULES + "< ' ' < '-'";
String[] PUNCTUATION_DATA = {"b-w", "b-W", "B-w", "B-W", "bW", "bw",
"Bw", "BW", "b w", "b W", "B w", "B W"};
String[] PUNCTUATION_EXPECTED = {"bw", "bW", "Bw", "BW", "b w", "b W",
"B w", "B W", "b-w", "b-W", "B-w", "B-W"};
return new Object[][] {
{BASIC_TAILOR_RULES, BASIC_TAILOR_DATA, BASIC_TAILOR_EXPECTED},
{CONTRACTION_RULES, CONTRACTION_DATA, CONTRACTION_EXPECTED},
{EXPANSION_RULES, EXPANSION_DATA, EXPANSION_EXPECTED},
{PUNCTUATION_RULES, PUNCTUATION_DATA, PUNCTUATION_EXPECTED}
};
}
@ParameterizedTest
@MethodSource("rulesData")
void testRules(String rules, String[] testData, String[] expected)
throws ParseException {
Arrays.sort(testData, new RuleBasedCollator(rules));
assertArrayEquals(expected, testData);
}
Object[][] FrenchSecondarySort() {
return new Object[][] {
{ "\u0061\u00e1\u0061", "\u00e1\u0061\u0061", 1 },
//{"\u0061\u00e1", "\u00e1\u0041", 1}, //JDK-4406815
//{"\u00e1\u0041", "\u0061\u00e1", -1}, //JDK-4406815
{"\u1ea0a", "\u1ea2A", -1}, //case ignore
{ "\u1ea0b", "\u1ea2A", 1 }, //primary overwrite
{ "\u1e15", "\u1e1d", -1 }, //ignore sec diacritic
{ "a", "\u1ea1", -1 } };
}
@ParameterizedTest
@MethodSource("FrenchSecondarySort")
void testFrenchSecondarySort(String sData, String tData,
int expected) throws ParseException {
String french_rule = "@";
String rules = US_RULES + french_rule;
RuleBasedCollator rc = new RuleBasedCollator(rules);
int result = rc.compare(sData, tData);
assertEquals(expected, result);
}
Object[][] ThaiLaoVowelConsonantSwapping() {
return new Object[][] {{"\u0e44\u0e01", "\u0e40\u0e2e", -1},//swap
{"\u0e2e\u0e40", "\u0e01\u0e44", 1},//no swap
{"\u0e44\u0061", "\u0e40\u0081", 1}//no swap
};
}
@ParameterizedTest
@MethodSource("ThaiLaoVowelConsonantSwapping")
void testThaiLaoVowelConsonantSwapping(String sData, String tData,
int expected) throws ParseException {
String thai_rule = "& Z < \u0e01 < \u0e2e <\u0e40 < \u0e44!";
String rules = US_RULES + thai_rule;
RuleBasedCollator rc = new RuleBasedCollator(rules);
int result = rc.compare(sData, tData);
assertEquals(expected, result);
}
@Test
void testIgnorableCharacter() throws ParseException {
String rule = "=f<a<c";
RuleBasedCollator rc = new RuleBasedCollator(rule);
CollationElementIterator iter = rc.getCollationElementIterator("f");
int element = iter.next();
int primary = iter.primaryOrder(element);
assertEquals(0, primary);
}
Object[][] Normalization() {
return new Object[][] {
//micro sign has no canonical decomp mapping
// 0:NO_Decomposition;
// 1:CANONICAL_Decomposition;
// 2:FULL_Decomposition
{"\u00b5", "\u03BC", 0, -1},
{"\u00b5", "\u03BC", 1, -1},
{"\u00b5", "\u03BC", 2, 0}
};
}
@ParameterizedTest
@MethodSource("Normalization")
void testNormalization(String sData, String tData, int decomp,
int result) {
RuleBasedCollator rc = (RuleBasedCollator)USC.clone();
rc.setDecomposition(decomp);
assertEquals(result, rc.compare(sData, tData));
}
@Test
void testEquality() throws ParseException {
String rule1 = "<a=b";
RuleBasedCollator rc1= new RuleBasedCollator(rule1);
//test equals()
assertTrue(rc1.equals(new RuleBasedCollator(rule1)));
//test semantic equality
String[] array1 = {"b", "c", "a"};
String[] array2 = Arrays.copyOf(array1, array1.length);
String[] expected = {"b", "a", "c"};
String rule2 = "<b=a";
RuleBasedCollator rc2= new RuleBasedCollator(rule2);
Arrays.sort(array1, rc1);
Arrays.sort(array2, rc2);
assertArrayEquals(array2, array1);
assertArrayEquals(expected, array1);
}
@Test
void testBasicParsingOrder() throws ParseException {
String rule1 = "< a < b & a < c";
String rule2 = "< a < c & a < b";
String rule3 = "< a < b < c";
String s = "abc";
RuleBasedCollator c1 = new RuleBasedCollator(rule1);
RuleBasedCollator c2 = new RuleBasedCollator(rule2);
RuleBasedCollator c3 = new RuleBasedCollator(rule3);
CollationKey k1 = c1.getCollationKey(s);
CollationKey k2 = c2.getCollationKey(s);
CollationKey k3 = c3.getCollationKey(s);
//rule1 should not equals to rule2
assertNotEquals(0, k1.compareTo(k2));
//rule2 should equals to rule3
assertEquals(0, k2.compareTo(k3));
}
Object[][] ParseData() {
return new Object[][] {
{""},
{"a < b"},
{"< a-b < c"},
{"< ,a"},
{"< a < b & c < d"}
};
}
@ParameterizedTest
@MethodSource("ParseData")
void testParseException(String rule) {
assertThrows(ParseException.class, () -> new RuleBasedCollator(rule));
}
@Test
void testNullParseException() {
assertThrows(NullPointerException.class, () -> new RuleBasedCollator(null));
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Spanish Collation
* @run junit SpanishTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class SpanishTest {
/*
* TestPrimary()
*/
private static final String[] primarySourceData = {
"alias",
"acHc",
"acc",
"Hello"
};
private static final String[] primaryTargetData = {
"allias",
"aCHc",
"aCHc",
"hellO"
};
private static final int[] primaryResults = {
-1, 0, -1, 0
};
/*
* TestTertiary()
*/
private static final String[] tertiarySourceData = {
"alias",
"Elliot",
"Hello",
"acHc",
"acc"
};
private static final String[] tertiaryTargetData = {
"allias",
"Emiot",
"hellO",
"aCHc",
"aCHc"
};
private static final int[] tertiaryResults = {
-1, -1, 1, -1, -1
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
}
private final Collator myCollation = Collator.getInstance(Locale.of("es", "ES"));
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Supplementary Character Collation
* @run junit SurrogatesTest
*/
import java.text.Collator;
import java.text.RuleBasedCollator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class SurrogatesTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"A\ud800\udc04BCD"
};
private static final String[] primaryTargetData = {
"A\ud800\udc05BCD"
};
private static final int[] primaryResults = {
0
};
/*
* Data for TestTertiary()
*/
private static final String[] tertiarySourceData = {
"ABCD",
"ABCD",
"A\ud800\udc00CD",
"WXYZ",
"WXYZ",
"AFEM",
"FGM",
"BB",
"BB"
};
private static final String[] tertiaryTargetData = {
"A\ud800\udc00CD",
"AB\ud800\udc00D",
"A\ud800\udc01CD",
"W\ud800\udc0aYZ",
"W\ud800\udc0bYZ",
"A\ud800\udc08M",
"\ud800\udc08M",
"\ud800\udc04\ud800\udc02",
"\ud800\udc04\ud800\udc05"
};
private static final int[] tertiaryResults = {
-1, 1, 1, 1, -1, -1, -1, -1, 1
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
}
private Collator getCollator() {
RuleBasedCollator base = (RuleBasedCollator)Collator.getInstance();
String rule = base.getRules();
try {
return new RuleBasedCollator(rule
+ "&B < \ud800\udc01 < \ud800\udc00"
+ ", \ud800\udc02, \ud800\udc03"
+ "; \ud800\udc04, \ud800\udc05"
+ "< \ud800\udc06 < \ud800\udc07"
+ "&FE < \ud800\udc08"
+ "&PE, \ud800\udc09"
+ "&Z < \ud800\udc0a < \ud800\udc0b < \ud800\udc0c"
+ "&\ud800\udc0a < x, X"
+ "&A < \ud800\udc04\ud800\udc05");
} catch (Exception e) {
fail("Failed to create new RulebasedCollator object");
return null;
}
}
private Collator myCollation = getCollator();
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4401726
* @author John O'Conner
* @library /java/text/testlib
* @summary Regression tests for Collation and associated classes
* @run junit Test4401726
*/
import java.text.*;
import java.util.Locale;
import java.util.Vector;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Test4401726 {
@Test
public void TestSetOffSet() {
int[] expected = {0, -1, 65536};
int[] actual = new int[expected.length];
try {
String rule = "< a, A < d; D";
RuleBasedCollator rbc = new RuleBasedCollator(rule);
String str = "aD";
CollationElementIterator iterator =
rbc.getCollationElementIterator(str);
iterator.setOffset(0);
actual[0] = iterator.getOffset();
actual[1] = iterator.previous();
iterator.setOffset(0);
actual[2] = iterator.next();
if (compareArray(expected, actual) == false) {
fail("Failed.");
}
str = "a";
iterator = rbc.getCollationElementIterator(str);
iterator.setOffset(0);
actual[0] = iterator.getOffset();
actual[1] = iterator.previous();
iterator.setOffset(0);
actual[2] = iterator.next();
if (compareArray(expected, actual) == false) {
fail("Failed.");
}
} catch (ParseException e) {
fail("Unexpected ParseException: " + e);
}
}
boolean compareArray(int[] expected, int[] actual) {
boolean retVal = false;
if (expected.length == actual.length) {
int errors = 0;
for(int x=0; x< expected.length; ++x) {
if (expected[x] != actual[x]) {
++errors;
}
}
if (errors == 0) retVal = true;
}
return retVal;
}
}

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Thai Collation
* @modules jdk.localedata
* @run junit ThaiTest
*/
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
*
* This software is the proprietary information of Oracle.
* Use is subject to license terms.
*
*/
import java.util.Locale;
import java.text.Collator;
import java.text.RuleBasedCollator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class ThaiTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"\u0e01\u0e01",
"\u0e07\u0e42\u0e01\u0e49",
"\u0e10\u0e34\u0e19",
"\u0e16\u0e32\u0e21\u0e23\u0e23\u0e04\u0e40\u0e17\u0e28\u0e19\u0e32",
"\u0e23\u0e21\u0e18\u0e23\u0e23\u0e21\u0e4c\u0e1b\u0e23\u0e30\u0e01\u0e31\u0e19\u0e20\u0e31\u0e22",
"\u0e23\u0e23\u0e21\u0e2a\u0e34\u0e17\u0e18\u0e34\u0e4c\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e2b\u0e21\u0e32\u0e22\u0e41\u0e25\u0e30\u0e22\u0e35\u0e48\u0e2b\u0e49\u0e2d\u0e01\u0e32\u0e23\u0e04\u0e49\u0e32\u0e02\u0e32\u0e22",
"\u0e23\u0e23\u0e25\u0e38\u0e19\u0e34\u0e15\u0e34\u0e20\u0e32\u0e27\u0e30",
"\u0e01\u0e25\u0e37\u0e2d\u0e41\u0e01\u0e07",
"\u0e21\u0e17\u0e34\u0e25\u0e41\u0e2d\u0e25\u0e01\u0e2d\u0e2e\u0e2d\u0e25\u0e4c",
"\u0e40\u0e2d\u0e35\u0e48\u0e22\u0e21\u0e2d\u0e48\u0e2d\u0e07",
"\u0e2a\u0e14\u0e32\u0e1b\u0e31\u0e15\u0e15\u0e34\u0e1c\u0e25",
"\u0e2d\u0e19\u0e01\u0e23\u0e23\u0e21\u0e2a\u0e34\u0e17\u0e18\u0e34\u0e4c",
"\u0e21\u0e49\u0e40\u0e17\u0e49\u0e32\u0e22\u0e32\u0e22\u0e21\u0e48\u0e2d\u0e21",
"\u0e2a\u0e49\u0e25\u0e30\u0e21\u0e32\u0e19",
"\u0e2a\u0e49\u0e28\u0e36\u0e01",
"\u0e2a\u0e49\u0e2d\u0e31\u0e48\u0e27",
"\u0e2a\u0e49\u0e40\u0e14\u0e37\u0e2d\u0e19",
"\u0e2a\u0e49\u0e40\u0e25\u0e37\u0e48\u0e2d\u0e19",
"\u0e2a\u0e49\u0e41\u0e02\u0e27\u0e19",
"\u0e2a\u0e49\u0e41\u0e2b\u0e49\u0e07",
"\u0e2a\u0e49\u0e44\u0e01\u0e48",
"\u0e2b",
"\u0e2b\u0e0b\u0e2d\u0e07",
"\u0e2b\u0e19",
"\u0e2b\u0e1b\u0e25\u0e32\u0e23\u0e49\u0e32",
"\u0e2b\u0e21",
"\u0e2b\u0e21\u0e17\u0e2d\u0e07",
"\u0e2b\u0e21\u0e2a\u0e31\u0e1a\u0e1b\u0e30\u0e23\u0e14",
"\u0e2b\u0e21\u0e49",
"\u0e2b\u0e23\u0e13\u0e22\u0e4c",
"\u0e2b\u0e25",
"\u0e2b\u0e25\u0e19\u0e49\u0e33",
"\u0e2b\u0e25\u0e48",
"\u0e2b\u0e25\u0e48\u0e16\u0e19\u0e19",
"\u0e2b\u0e25\u0e48\u0e17\u0e27\u0e35\u0e1b",
"\u0e2b\u0e25\u0e48\u0e17\u0e32\u0e07",
"\u0e2b\u0e25\u0e48\u0e23\u0e27\u0e1a",
"\u0e2b\u0e49",
"\u0e2d",
"\u0e2d\u0e49",
"\u0e2e\u0e42\u0e25",
"\u0e2e\u0e44\u0e1f",
"\u0e2e\u0e49"
};
private static final String[] primaryTargetData = {
"\u0e01\u0e01",
"\u0e07\u0e42\u0e01\u0e49",
"\u0e10\u0e34\u0e19",
"\u0e16\u0e32\u0e21\u0e23\u0e23\u0e04\u0e40\u0e17\u0e28\u0e19\u0e32",
"\u0e23\u0e21\u0e18\u0e23\u0e23\u0e21\u0e4c\u0e1b\u0e23\u0e30\u0e01\u0e31\u0e19\u0e20\u0e31\u0e22",
"\u0e23\u0e23\u0e21\u0e2a\u0e34\u0e17\u0e18\u0e34\u0e4c\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e2b\u0e21\u0e32\u0e22\u0e41\u0e25\u0e30\u0e22\u0e35\u0e48\u0e2b\u0e49\u0e2d\u0e01\u0e32\u0e23\u0e04\u0e49\u0e32\u0e02\u0e32\u0e22",
"\u0e23\u0e23\u0e25\u0e38\u0e19\u0e34\u0e15\u0e34\u0e20\u0e32\u0e27\u0e30",
"\u0e01\u0e25\u0e37\u0e2d\u0e41\u0e01\u0e07",
"\u0e21\u0e17\u0e34\u0e25\u0e41\u0e2d\u0e25\u0e01\u0e2d\u0e2e\u0e2d\u0e25\u0e4c",
"\u0e40\u0e2d\u0e35\u0e48\u0e22\u0e21\u0e2d\u0e48\u0e2d\u0e07",
"\u0e2a\u0e14\u0e32\u0e1b\u0e31\u0e15\u0e15\u0e34\u0e1c\u0e25",
"\u0e2d\u0e19\u0e01\u0e23\u0e23\u0e21\u0e2a\u0e34\u0e17\u0e18\u0e34\u0e4c",
"\u0e21\u0e49\u0e40\u0e17\u0e49\u0e32\u0e22\u0e32\u0e22\u0e21\u0e48\u0e2d\u0e21",
"\u0e2a\u0e49\u0e25\u0e30\u0e21\u0e32\u0e19",
"\u0e2a\u0e49\u0e28\u0e36\u0e01",
"\u0e2a\u0e49\u0e2d\u0e31\u0e48\u0e27",
"\u0e2a\u0e49\u0e40\u0e14\u0e37\u0e2d\u0e19",
"\u0e2a\u0e49\u0e40\u0e25\u0e37\u0e48\u0e2d\u0e19",
"\u0e2a\u0e49\u0e41\u0e02\u0e27\u0e19",
"\u0e2a\u0e49\u0e41\u0e2b\u0e49\u0e07",
"\u0e2a\u0e49\u0e44\u0e01\u0e48",
"\u0e2b",
"\u0e2b\u0e0b\u0e2d\u0e07",
"\u0e2b\u0e19",
"\u0e2b\u0e1b\u0e25\u0e32\u0e23\u0e49\u0e32",
"\u0e2b\u0e21",
"\u0e2b\u0e21\u0e17\u0e2d\u0e07",
"\u0e2b\u0e21\u0e2a\u0e31\u0e1a\u0e1b\u0e30\u0e23\u0e14",
"\u0e2b\u0e21\u0e49",
"\u0e2b\u0e23\u0e13\u0e22\u0e4c",
"\u0e2b\u0e25",
"\u0e2b\u0e25\u0e19\u0e49\u0e33",
"\u0e2b\u0e25\u0e48",
"\u0e2b\u0e25\u0e48\u0e16\u0e19\u0e19",
"\u0e2b\u0e25\u0e48\u0e17\u0e27\u0e35\u0e1b",
"\u0e2b\u0e25\u0e48\u0e17\u0e32\u0e07",
"\u0e2b\u0e25\u0e48\u0e23\u0e27\u0e1a",
"\u0e2b\u0e49",
"\u0e2d",
"\u0e2d\u0e49",
"\u0e2e\u0e42\u0e25",
"\u0e2e\u0e44\u0e1f",
"\u0e2e\u0e49"
};
private static final int[] primaryResults = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
private final Collator myCollation = Collator.getInstance(Locale.of("th"));
}

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /java/text/testlib
* @summary test Turkish Collation
* @modules jdk.localedata
* @run junit TurkishTest
*/
/*
(C) Copyright Taligent, Inc. 1996 - All Rights Reserved
(C) Copyright IBM Corp. 1996 - All Rights Reserved
The original version of this source code and documentation is copyrighted and
owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
provided under terms of a License Agreement between Taligent and Sun. This
technology is protected by multiple US and International patents. This notice and
attribution to Taligent may not be removed.
Taligent is a registered trademark of Taligent, Inc.
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class TurkishTest {
/*
* Data for TestPrimary()
*/
private static final String[] primarySourceData = {
"\u00FCoid",
"vo\u0131d",
"idea",
"Idea",
"\u0130dea"
};
private static final String[] primaryTargetData = {
"void",
"void",
"Idea",
"\u0130dea",
"\u0131dea"
};
private static final int[] primaryResults = {
-1, -1, 1, -1, 1
};
/*
* Data for TestTertiary()
*/
private static final String[] tertiarySourceData = {
"s\u0327",
"v\u00E4t",
"old",
"\u00FCoid",
"h\u011Ealt",
"stres\u015E",
"vo\u0131d",
"idea",
"idea",
"\u0131dea"
};
private static final String tertiaryTargetData[] = {
"u\u0308",
"vbt",
"\u00D6ay",
"void",
"halt",
"\u015Etre\u015Es",
"void",
"Idea",
"\u0130dea",
"Idea"
};
private static final int[] tertiaryResults = {
-1, -1, -1, -1, 1, -1, -1, 1, -1, -1
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY,
primarySourceData, primaryTargetData, primaryResults);
}
@Test
public void TestTertiary() {
TestUtils.doCollatorTest(myCollation, Collator.TERTIARY,
tertiarySourceData, tertiaryTargetData, tertiaryResults);
}
private final Collator myCollation = Collator.getInstance(Locale.of("tr", "TR"));
}

View file

@ -0,0 +1,368 @@
/*
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4932968 5015215
* @library /java/text/testlib
* @summary test Vietnamese Collation
* @modules jdk.localedata
* @run junit VietnameseTest
*/
/*
*******************************************************************************
* (C) Copyright IBM Corp. 1996-2003 - All Rights Reserved *
* *
* The original version of this source code and documentation is copyrighted *
* and owned by IBM, These materials are provided under terms of a License *
* Agreement between IBM and Sun. This technology is protected by multiple *
* US and International patents. This notice and attribution to IBM may not *
* to removed. *
*******************************************************************************
*/
import java.util.Locale;
import java.text.Collator;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
// Quick dummy program for printing out test results
public class VietnameseTest {
private final static String testPS[] = {
"a",
"a",
"\u00c2",
"Cz",
"d",
"e",
"e",
"\u1ec7",
"gz",
"i",
"kz",
"nz",
"nh",
"o",
"o",
"\u01a0",
"pz",
"tz",
"tr",
"u",
"u",
"y"
};
private final static String testPT[] = {
"\u00e0",
"\u0102",
"\u0102",
"Ch",
"\u0110",
"\u0111",
"\u1eb9",
"\u1eb9",
"gi",
"\u0128",
"kh",
"ng",
"ng",
"\u00f2",
"\u00f4",
"\u00f4",
"ph",
"th",
"th",
"\u1ee5",
"\u01b0",
"\u1ef4"
};
private final static int testPR[] = {
0,
-1,
1,
1,
-1,
1,
0,
1,
1,
0,
1,
1,
1,
0,
-1,
1,
1,
1,
1,
0,
-1,
0
};
private final static String testT[] = {
"a",
"A",
"\u00e0",
"\u00c0",
"\u1ea3",
"\u1ea2",
"\u00e3",
"\u00c3",
"\u00e1",
"\u00c1",
"\u1ea1",
"\u1ea0",
"\u0103",
"\u0102",
"\u1eb1",
"\u1eb0",
"\u1eb3",
"\u1eb2",
"\u1eb5",
"\u1eb4",
"\u1eaf",
"\u1eae",
"\u1eb7",
"\u1eb6",
"\u00e2",
"\u00c2",
"\u1ea7",
"\u1ea6",
"\u1ea9",
"\u1ea8",
"\u1eab",
"\u1eaa",
"\u1ea5",
"\u1ea4",
"\u1ead",
"\u1eac",
"b",
"B",
"c",
"C",
"ch",
"Ch",
"CH",
"d",
"D",
"\u0111",
"\u0110",
"e",
"E",
"\u00e8",
"\u00c8",
"\u1ebb",
"\u1eba",
"\u1ebd",
"\u1ebc",
"\u00e9",
"\u00c9",
"\u1eb9",
"\u1eb8",
"\u00ea",
"\u00ca",
"\u1ec1",
"\u1ec0",
"\u1ec3",
"\u1ec2",
"\u1ec5",
"\u1ec4",
"\u1ebf",
"\u1ebe",
"\u1ec7",
"\u1ec6",
"f",
"F",
"g",
"G",
"gi",
"Gi",
"GI",
"gz",
"h",
"H",
"i",
"I",
"\u00ec",
"\u00cc",
"\u1ec9",
"\u1ec8",
"\u0129",
"\u0128",
"\u00ed",
"\u00cd",
"\u1ecb",
"\u1eca",
"j",
"J",
"k",
"K",
"kh",
"Kh",
"KH",
"kz",
"l",
"L",
"m",
"M",
"n",
"N",
"ng",
"Ng",
"NG",
"ngz",
"nh",
"Nh",
"NH",
"nz",
"o",
"O",
"\u00f2",
"\u00d2",
"\u1ecf",
"\u1ece",
"\u00f5",
"\u00d5",
"\u00f3",
"\u00d3",
"\u1ecd",
"\u1ecc",
"\u00f4",
"\u00d4",
"\u1ed3",
"\u1ed2",
"\u1ed5",
"\u1ed4",
"\u1ed7",
"\u1ed6",
"\u1ed1",
"\u1ed0",
"\u1ed9",
"\u1ed8",
"\u01a1",
"\u01a0",
"\u1edd",
"\u1edc",
"\u1edf",
"\u1ede",
"\u1ee1",
"\u1ee0",
"\u1edb",
"\u1eda",
"\u1ee3",
"\u1ee2",
"p",
"P",
"ph",
"Ph",
"PH",
"pz",
"q",
"Q",
"r",
"R",
"s",
"S",
"t",
"T",
"th",
"Th",
"TH",
"thz",
"tr",
"Tr",
"TR",
"tz",
"u",
"U",
"\u00f9",
"\u00d9",
"\u1ee7",
"\u1ee6",
"\u0169",
"\u0168",
"\u00fa",
"\u00da",
"\u1ee5",
"\u1ee4",
"\u01b0",
"\u01af",
"\u1eeb",
"\u1eea",
"\u1eed",
"\u1eec",
"\u1eef",
"\u1eee",
"\u1ee9",
"\u1ee8",
"\u1ef1",
"\u1ef0",
"v",
"V",
"w",
"W",
"x",
"X",
"y",
"Y",
"\u1ef3",
"\u1ef2",
"\u1ef7",
"\u1ef6",
"\u1ef9",
"\u1ef8",
"\u00fd",
"\u00dd",
"\u1ef5",
"\u1ef4",
"z",
"Z"
};
@Test
public void TestPrimary() {
TestUtils.doCollatorTest(myCollation, Collator.PRIMARY, testPS, testPT, testPR);
}
@Test
public void TestTertiary() {
int testLength = testT.length;
myCollation.setStrength(Collator.TERTIARY);
for (int i = 0; i < testLength - 1; i++) {
for (int j = i+1; j < testLength; j++) {
TestUtils.doCollatorTest(myCollation, testT[i], testT[j], -1);
}
}
}
private final Collator myCollation = Collator.getInstance(Locale.of("vi", "VN"));
}

View file

@ -0,0 +1,44 @@
#
# Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Hex dump of a serialized ChiceFormat for Bug4185732Test.
aced0005737200166a6176612e746578742e43686f696365466f726d617418e9
c6bee365b6040200025b000d63686f696365466f726d6174737400135b4c6a61
76612f6c616e672f537472696e673b5b000c63686f6963654c696d6974737400
025b44787200166a6176612e746578742e4e756d626572466f726d6174dff6b3
bf137d07e803000b5a000c67726f7570696e67557365644200116d6178467261
6374696f6e4469676974734200106d6178496e74656765724469676974734900
156d6178696d756d4672616374696f6e4469676974734900146d6178696d756d
496e74656765724469676974734200116d696e4672616374696f6e4469676974
734200106d696e496e74656765724469676974734900156d696e696d756d4672
616374696f6e4469676974734900146d696e696d756d496e7465676572446967
6974735a00107061727365496e74656765724f6e6c7949001573657269616c56
657273696f6e4f6e53747265616d787200106a6176612e746578742e466f726d
6174fbd8bc12e90f184302000078700103280000000300000028000100000000
00000001000000000178757200135b4c6a6176612e6c616e672e537472696e67
3badd256e7e91d7b470200007870000000067400034d6f6e7400035475657400
0357656474000454687572740003467269740003536174757200025b443ea68c
14ab635a1e0200007870000000073ff000000000000040000000000000004008
000000000000401000000000000040140000000000004018000000000000401c
000000000000

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*
* (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
*
* Portions copyright (c) 2007 Sun Microsystems, Inc.
* All Rights Reserved.
*
* The original version of this source code and documentation
* is copyrighted and owned by Taligent, Inc., a wholly-owned
* subsidiary of IBM. These materials are provided under terms
* of a License Agreement between Taligent and Sun. This technology
* is protected by multiple US and International patents.
*
* This notice and attribution to Taligent may not be removed.
* Taligent is a registered trademark of Taligent, Inc.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
/*
* @test
* @bug 4185732
* @library /java/text/testlib
* @build HexDumpReader
* @summary Test that ChoiceFormat invariants are preserved across serialization.
* This test depends on Bug4185732.ser.txt and will fail otherwise.
* @run junit Bug4185732Test
*/
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.text.ChoiceFormat;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Bug4185732Test {
/*
* The ChoiceFormat class requires that its choiceFormats and choiceLimits
* arrays have the same length. This test ensures that the invariant is enforced
* during the readObject() call.
*/
@Test
public void choiceFormatSerializationInvariantsTest() {
try {
// A serialized ChoiceFormat with unequal formats and limits
final ObjectInputStream in
= new ObjectInputStream(HexDumpReader.getStreamFromHexDump("Bug4185732.ser.txt"));
final ChoiceFormat loc = (ChoiceFormat)in.readObject();
if (loc.getFormats().length != loc.getLimits().length) {
fail("ChoiceFormat did not properly check stream");
} else {
// for some reason, the data file was VALID. This test
// requires a corrupt data file the format and limit
// arrays are of different length.
fail("Test data file was not properly created");
}
} catch (InvalidObjectException expectedException) {
// Expecting an IOE
} catch (Exception wrongException) {
fail("Expected an InvalidObjectException, instead got: " + wrongException);
}
}
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4387255
* @summary Verifies that ChoiceFormat can handle large numbers of choices
* (previously capped at 30).
* @run junit Bug4387255
*/
import java.text.ChoiceFormat;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class Bug4387255 {
private static final double[] doubles = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35};
private static final String[] strings = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z"};
private static final String pattern =
"0#0|1#1|2#2|3#3|4#4|5#5|6#6|7#7|8#8|9#9" +
"|10#A|11#B|12#C|13#D|14#E|15#F|16#G|17#H|18#I|19#J" +
"|20#K|21#L|22#M|23#N|24#O|25#P|26#Q|27#R|28#S|29#T" +
"|30#U|31#V|32#W|33#X|34#Y|35#Z";
private static final ChoiceFormat choiceFormat1 = new ChoiceFormat(doubles, strings);
private static final ChoiceFormat choiceFormat2 = new ChoiceFormat(pattern);
// Ensure that both the large ChoiceFormats format each value properly
@ParameterizedTest
@MethodSource
public void largeChoicesTest(double db, String expectedString) {
String result = choiceFormat2.format(db);
assertEquals(expectedString, result,
"Wrong format result with: " + choiceFormat2);
}
/*
* Create arguments in form of : (double, string)
* Each string is the expected result of ChoiceFormat.format(double)
*/
private static Arguments[] largeChoicesTest() {
Arguments[] doublesAndStrings = new Arguments[doubles.length];
for (int i = 0; i < doubles.length; i++) {
doublesAndStrings[i] = arguments(doubles[i], strings[i]);
}
return doublesAndStrings;
}
/*
* Check that creating a ChoiceFormat with limits and formats arrays
* equivalent to a string pattern are equal. (Checks that both constructors
* allow for a large number of choices and formats)
*/
@Test
public void patternEqualsArraysTest() {
assertEquals(choiceFormat1, choiceFormat2, "Pattern is equivalent to " +
"formats and limits, but ChoiceFormats are not equal");
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8001209
* @summary Confirm that the values set by setChoices() are not mutable.
* @run junit Bug8001209
*/
import java.text.ChoiceFormat;
import java.text.ParsePosition;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class Bug8001209 {
// Represents the expected output of formatting the ChoiceFormat
private static String expectedFormattedOutput;
private static ChoiceFormat cFmt;
private static ParsePosition status;
private static String[] originalSetterArray;
// Build the original ChoiceFormat to test if it can be mutated
@BeforeAll
static void setUpChoiceFormatAndOutput() {
double[] limits = {1, 2, 3, 4, 5, 6, 7};
originalSetterArray = new String[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
// Constructor calls setChoices
cFmt = new ChoiceFormat(limits, originalSetterArray);
status = new ParsePosition(0);
// Build the expected results of formatting with the original ChoiceFormat
StringBuilder before = new StringBuilder();
for (double i = 1.0; i <= 7.0; ++i) {
status.setIndex(0);
String s = cFmt.format(i);
before.append(" ");
before.append(s);
before.append(cFmt.parse(cFmt.format(i), status));
}
expectedFormattedOutput = before.toString();
}
/*
* Ensure that mutating the arrays returned by getChoices and getLimits does
* not affect the internal representation of the ChoiceFormat.
*/
@Test
public void immutableArraysFromGetters() {
// Modify the array returned by getFormats() -> newFormats
String[] newFormats = (String[]) cFmt.getFormats();
newFormats[6] = "Doyoubi";
StringBuilder after = new StringBuilder();
for (double i = 1.0; i <= 7.0; ++i) {
status.setIndex(0);
String s = cFmt.format(i);
after.append(" ");
after.append(s);
after.append(cFmt.parse(cFmt.format(i), status));
}
// Compare the expected results with the new formatted results
assertEquals(after.toString(), expectedFormattedOutput,
"Mutating array returned from getter changed internals of ChoiceFormat");
}
/*
* Ensure that mutating the arrays passed to setChoices/constructor does
* not affect the internal representation of the ChoiceFormat.
*/
@Test
public void immutableArraysFromSetter() {
// Modify the array passed to setFormats() -> dayOfWeekNames
originalSetterArray[6] = "Saturday";
StringBuilder after = new StringBuilder();
for (double i = 1.0; i <= 7.0; ++i) {
status.setIndex(0);
String s = cFmt.format(i);
after.append(" ");
after.append(s);
after.append(cFmt.parse(cFmt.format(i), status));
}
// Compare the expected results with the new formatted results
assertEquals(after.toString(), expectedFormattedOutput,
"Mutating array passed to setter changed internals of ChoiceFormat");
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8353585
* @summary Basic parse tests. Enforce regular behavior, no match, and multi match.
* @run junit ParseTest
*/
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.ChoiceFormat;
import java.text.ParsePosition;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ParseTest {
// Ensure that the parsed text produces the expected number
// i.e. return limit corresponding to format matched
@ParameterizedTest
@MethodSource
void parseTest(String pattern, String text, Double expected, int index) {
var pp = new ParsePosition(index);
var fmt = new ChoiceFormat(pattern);
assertEquals(expected, fmt.parse(text, pp), "Incorrect limit returned");
if (expected.equals(Double.NaN)) { // AKA failed parse
assertEquals(index, pp.getErrorIndex(),
"Failed parse produced incorrect error index");
} else {
assertEquals(-1, pp.getErrorIndex(),
"Error index should remain -1 on match");
}
}
private static Stream<Arguments> parseTest() {
return Stream.of(
Arguments.of("1#foo", "foo", Double.NaN, -1),
Arguments.of("1#baz", "foo bar baz", Double.NaN, 20),
Arguments.of("1#baz", "foo bar baz", 1d, 8),
Arguments.of("1#baz", "foo baz quux", Double.NaN, 8),
Arguments.of("1#a", "", Double.NaN, 0),
Arguments.of("1#a", "a", 1d, 0),
Arguments.of("1# ", " ", 1d, 0),
Arguments.of("1#a|2#a", "a", 1d, 0),
Arguments.of("1#a|2#aa", "aa", 2d, 0),
Arguments.of("1#a|2#aa", "aabb", 2d, 0),
Arguments.of("1#a|2#aa", "bbaa", Double.NaN, 0),
Arguments.of("1#aa|2#aaa", "a", Double.NaN, 0)
);
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6285888 6801704 8325898
* @summary Test the expected behavior for a wide range of patterns (both
* correct and incorrect). This test documents the behavior of incorrect
* ChoiceFormat patterns either throwing an exception, or discarding
* the incorrect portion of a pattern.
* @run junit PatternsTest
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.ChoiceFormat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class PatternsTest {
private static final String ERR1 =
"Each interval must contain a number before a format";
private static final String ERR2 =
"Incorrect order of intervals, must be in ascending order";
// Check that some valid patterns do not throw an exception. Check
// them against the expected values they should be formatted as.
@ParameterizedTest
@MethodSource
public void validPatternsTest(String pattern, String[] expectedValues) {
var fmt = new ChoiceFormat(pattern);
for (int i=1; i<=expectedValues.length; i++) {
assertEquals(expectedValues[i-1], fmt.format(i),
String.format("ChoiceFormat formatted %s incorrectly:", i));
}
}
// Valid patterns ranging from normal appearing to odd. These should not
// throw an exception or discard any portions of the pattern.
private static Arguments[] validPatternsTest() {
return new Arguments[] {
// Multi pattern with trailing empty string Format
arguments("1#foo|2#bar|3#", new String[]{"foo", "bar", ""}),
// Multi patten with trailing '|'
arguments("1#foo|2#bar|", new String[]{"foo", "bar"}),
// Using a '>' (not a Relation) within a Format
arguments("1#foo|2#bar>", new String[]{"foo", "bar>"}),
// Standard Multi Pattern
arguments("1#foo|2#bar", new String[]{"foo", "bar"}),
// Same numerical value Limits, different Relations
arguments("1#foo|1<baz", new String[]{"foo", "baz"}),
// Standard Single Pattern
arguments("1#foo", new String[]{"foo"}),
// Single pattern with empty string Format
arguments("1#", new String[]{""})
};
}
// Check that the incorrect pattern throws an IAE with the desired error msg
// This also tests applyPattern, as the ChoiceFormat constructor calls applyPattern
@ParameterizedTest
@MethodSource
public void invalidPatternsThrowsTest(String pattern, String errMsg) {
var ex = assertThrows(IllegalArgumentException.class,
() -> new ChoiceFormat(pattern));
assertEquals(errMsg, ex.getMessage());
}
// Variety of patterns that break the ChoiceFormat pattern syntax and throw
// an exception.
private static Arguments[] invalidPatternsThrowsTest() {
return new Arguments[] {
arguments("#", ERR1), // Only relation
arguments("#foo", ERR1), // No Limit
arguments("0#foo|#|1#bar", ERR1), // Missing Relation in SubPattern
arguments("#|", ERR1), // Missing Limit
arguments("##|", ERR1), // Double Relations
arguments("0#test|#", ERR1), // SubPattern missing Limit
arguments("0#foo|3#bar|1#baz", ERR2), // Non-ascending Limits
// No longer throw IAE after 6285888, as relational symbols
// can now be used within the Format segment.
// arguments("0#foo1#", ERR1), // SubPattern not separated by '|'
// arguments("0#foo#", ERR1), // Using a Relation in a format
};
}
// Check that the incorrect pattern discards the trailing incorrect portion.
// These incorrect patterns should ideally throw an exception, but for
// behavioral compatibility reasons do not.
@ParameterizedTest
@MethodSource
public void invalidPatternsDiscardedTest(String brokenPattern, String actualPattern) {
var cf1 = new ChoiceFormat(brokenPattern);
var cf2 = new ChoiceFormat(actualPattern);
assertEquals(cf2, cf1,
String.format("Expected %s, but got %s", cf2.toPattern(), cf1.toPattern()));
}
// Variety of incorrect patterns with the actual expected pattern
// after discarding occurs.
private static Arguments[] invalidPatternsDiscardedTest() {
return new Arguments[] {
// Incomplete SubPattern (limit only) at end of Pattern
arguments("1#bar|2", "1#bar"),
// Incomplete SubPattern at the end of the Pattern
arguments("0#foo|1#bar|baz", "0#foo|1#bar"),
// Incomplete SubPattern with trailing | at the end of the Pattern
// Prior to 6801704, it created the broken "0#foo|1#bar|1#"
// which caused formatting 1 to return an empty string
arguments("0#foo|1#bar|baz|", "0#foo|1#bar"),
// Same as previous, with additional incomplete subPatterns
arguments("0#foo|1#bar|baz|quux", "0#foo|1#bar"),
// --- These throw an ArrayIndexOutOfBoundsException
// when attempting to format with them as the incomplete patterns
// are discarded, initializing the cFmt with empty limits and formats ---
// SubPattern with only a Limit (which is interpreted as a Format)
arguments("0", ""),
// SubPattern with only a Format
arguments("foo", ""),
// empty string
arguments("", "")
};
}
// Calling format() with empty limits and formats
// throws an ArrayIndexOutOfBoundsException
@Test
public void emptyLimitsAndFormatsTest() {
var cf1 = new ChoiceFormat("");
assertThrows(ArrayIndexOutOfBoundsException.class,
() -> cf1.format(1));
var cf2 = new ChoiceFormat(new double[]{}, new String[]{});
assertThrows(ArrayIndexOutOfBoundsException.class,
() -> cf2.format(2));
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6285888
* @summary Ensure ChoiceFormat supports "#", "<", "≤" within
* the format segment of a ChoiceFormat String pattern
* @run junit SymbolsInFormatSegment
*/
import java.text.ChoiceFormat;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*
* These tests would previously throw IAEs on all input as ChoiceFormat would parse
* the relational symbol syntactically (when not needed). With the associated change
* set, ChoiceFormat knows to not treat any subsequent relational symbols as
* syntactically significant unless a '|' has been parsed.
*/
public class SymbolsInFormatSegment {
// Test a variety of patterns with relational symbols in the Format segment
@ParameterizedTest
@MethodSource("patternsWithSymbols")
public void allowInConstructor(String pattern, String expected, int limit) {
var cf = new ChoiceFormat(pattern);
assertEquals(expected, cf.format(limit));
}
// Same as previous test, but check the applyPattern method
@ParameterizedTest
@MethodSource("patternsWithSymbols")
public void allowInApplyPattern(String pattern, String expected, int limit) {
var cf = new ChoiceFormat("");
cf.applyPattern(pattern);
assertEquals(expected, cf.format(limit));
}
private static Stream<Arguments> patternsWithSymbols() {
return Stream.of(
// CSR example
Arguments.of("1#The code is #7281", "The code is #7281", 1),
// Other examples
Arguments.of("1#<", "<", 1),
Arguments.of("1#foo<", "foo<", 1),
Arguments.of("1<foo\u2264", "foo\u2264", 1),
Arguments.of("1\u2264foo#", "foo#", 1),
Arguments.of("1#foo<#\u2264|2\u2264baz<#\u2264", "baz<#\u2264", 100),
Arguments.of("1#foo<#\u2264|2#baz<#\u2264|3<bar##\u2264", "bar##\u2264", 100),
Arguments.of("1#foo<#\u2264|2#baz<#\u2264|3\u2264bar##\u2264", "bar##\u2264", 100)
);
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8321545
* @summary Ensure value returned by overridden toString method is as expected
* @run junit ToStringTest
*/
import java.text.ChoiceFormat;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ToStringTest {
// Check a normal expected value. There is no null locale test as
// ChoiceFormat is not localized.
@Test
public void normalValueTest() {
String expectedStr = "ChoiceFormat [pattern: \"1.0#foo\"]\n";
var c = new ChoiceFormat("1.0#foo");
assertEquals(expectedStr, c.toString());
}
// Ensure toString throws no exception when ChoiceFormat is created
// with empty arrays
@Test
public void oddValueTest() {
var c2 = new ChoiceFormat(new double[]{}, new String[]{});
System.out.println(c2);
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CompactFormatAndParseHelper {
static void testFormat(NumberFormat cnf, Object number,
String expected) {
String result = cnf.format(number);
assertEquals(expected, result, "Incorrect formatting of the number '"
+ number + "'");
}
static void testParse(NumberFormat cnf, String parseString,
Number expected, ParsePosition position, Class<? extends Number> returnType) throws ParseException {
Number number;
if (position == null) {
number = cnf.parse(parseString);
} else {
number = cnf.parse(parseString, position);
}
if (returnType != null) {
assertEquals(returnType, number.getClass(),
"Incorrect return type for string '" + parseString + "'");
}
assertEquals(expected, number, "Incorrect parsing of the string '"
+ parseString + "'");
}
}

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8222756
* @summary Checks the plurals work with SPI provider
* @modules jdk.localedata
* @library provider
* @build provider/module-info provider/test.NumberFormatProviderImpl
* @run main/othervm -Djava.locale.providers=SPI,CLDR SPIProviderTest
*/
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Locale;
public class SPIProviderTest {
private static final Locale QAA = Locale.forLanguageTag("qaa");
private static final Locale QAB = Locale.forLanguageTag("qab");
public static void main(String... args) {
new SPIProviderTest();
}
SPIProviderTest() {
Arrays.stream(testData())
.forEach(SPIProviderTest::testSPIProvider);
}
Object[][] testData() {
return new Object[][]{
// Locale, Number, expected
{QAA, 1_000, "1K"},
{QAA, -1_000, "-1K"},
{QAA, 2_000, "2K"},
{QAA, -2_000, "-2K"},
{QAA, 1_000_000, "1M"},
{QAA, -1_000_000, "-1M"},
{QAA, 2_000_000, "2M"},
{QAA, -2_000_000, "-2M"},
{QAB, 1_000, "1K"},
{QAB, -1_000, "(1K)"},
{QAB, 2_000, "2KK"},
{QAB, -2_000, "-2KK"},
{QAB, 3_000, "3KKK"},
{QAB, -3_000, "-3KKK"},
{QAB, 5_000, "5KKKK"},
{QAB, -5_000, "-5KKKK"},
{QAB, 10_000, "10000"},
{QAB, -10_000, "-10000"},
{QAB, 1_000_000, "1 M"},
{QAB, -1_000_000, "(1 M)"},
{QAB, 2_000_000, "2 MM"},
{QAB, -2_000_000, "(2 MM)"},
{QAB, 3_000_000, "3 MMM"},
{QAB, -3_000_000, "-3 MMM"},
{QAB, 5_000_000, "5 MMMM"},
{QAB, -5_000_000, "-5 MMMM"},
};
}
public static void testSPIProvider(Object... args) {
Locale loc = (Locale)args[0];
Number number = (Number)args[1];
String expected = (String)args[2];
System.out.printf("Testing locale: %s, number: %d, expected: %s\n", loc, number, expected);
NumberFormat nf =
NumberFormat.getCompactNumberInstance(loc, NumberFormat.Style.SHORT);
String formatted = nf.format(number);
System.out.printf(" formatted: %s\n", formatted);
if (!formatted.equals(expected)) {
throw new RuntimeException("formatted and expected strings do not match.");
}
try {
Number parsed = nf.parse(formatted);
System.out.printf(" parsed: %s\n", parsed);
if (parsed.intValue() != number.intValue()) {
throw new RuntimeException("parsed and input numbers do not match.");
}
} catch (ParseException pe) {
throw new RuntimeException(pe);
}
}
}

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552
* @summary Checks the rounding of formatted number in compact number formatting
* @run junit/othervm TestCNFRounding
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestCNFRounding {
private static final List<RoundingMode> MODES = List.of(
RoundingMode.HALF_EVEN,
RoundingMode.HALF_UP,
RoundingMode.HALF_DOWN,
RoundingMode.UP,
RoundingMode.DOWN,
RoundingMode.CEILING,
RoundingMode.FLOOR);
Object[][] roundingData() {
return new Object[][]{
// Number, half_even, half_up, half_down, up, down, ceiling, floor
{5500, new String[]{"6K", "6K", "5K", "6K", "5K", "6K", "5K"}},
{2500, new String[]{"2K", "3K", "2K", "3K", "2K", "3K", "2K"}},
{1600, new String[]{"2K", "2K", "2K", "2K", "1K", "2K", "1K"}},
{1100, new String[]{"1K", "1K", "1K", "2K", "1K", "2K", "1K"}},
{1000, new String[]{"1K", "1K", "1K", "1K", "1K", "1K", "1K"}},
{-1000, new String[]{"-1K", "-1K", "-1K", "-1K", "-1K", "-1K", "-1K"}},
{-1100, new String[]{"-1K", "-1K", "-1K", "-2K", "-1K", "-1K", "-2K"}},
{-1600, new String[]{"-2K", "-2K", "-2K", "-2K", "-1K", "-1K", "-2K"}},
{-2500, new String[]{"-2K", "-3K", "-2K", "-3K", "-2K", "-2K", "-3K"}},
{-5500, new String[]{"-6K", "-6K", "-5K", "-6K", "-5K", "-5K", "-6K"}},
{5501, new String[]{"6K", "6K", "6K", "6K", "5K", "6K", "5K"}},
{-5501, new String[]{"-6K", "-6K", "-6K", "-6K", "-5K", "-5K", "-6K"}},
{1001, new String[]{"1K", "1K", "1K", "2K", "1K", "2K", "1K"}},
{-1001, new String[]{"-1K", "-1K", "-1K", "-2K", "-1K", "-1K", "-2K"}},
{4501, new String[]{"5K", "5K", "5K", "5K", "4K", "5K", "4K"}},
{-4501, new String[]{"-5K", "-5K", "-5K", "-5K", "-4K", "-4K", "-5K"}},
{4500, new String[]{"4K", "5K", "4K", "5K", "4K", "5K", "4K"}},
{-4500, new String[]{"-4K", "-5K", "-4K", "-5K", "-4K", "-4K", "-5K"}},};
}
Object[][] roundingFract() {
return new Object[][]{
// Number, half_even, half_up, half_down, up, down, ceiling, floor
{5550, new String[]{"5.5K", "5.5K", "5.5K", "5.6K", "5.5K", "5.6K", "5.5K"}},
{2550, new String[]{"2.5K", "2.5K", "2.5K", "2.6K", "2.5K", "2.6K", "2.5K"}},
{1660, new String[]{"1.7K", "1.7K", "1.7K", "1.7K", "1.6K", "1.7K", "1.6K"}},
{1110, new String[]{"1.1K", "1.1K", "1.1K", "1.2K", "1.1K", "1.2K", "1.1K"}},
{1000, new String[]{"1.0K", "1.0K", "1.0K", "1.0K", "1.0K", "1.0K", "1.0K"}},
{-1000, new String[]{"-1.0K", "-1.0K", "-1.0K", "-1.0K", "-1.0K", "-1.0K", "-1.0K"}},
{-1110, new String[]{"-1.1K", "-1.1K", "-1.1K", "-1.2K", "-1.1K", "-1.1K", "-1.2K"}},
{-1660, new String[]{"-1.7K", "-1.7K", "-1.7K", "-1.7K", "-1.6K", "-1.6K", "-1.7K"}},
{-2550, new String[]{"-2.5K", "-2.5K", "-2.5K", "-2.6K", "-2.5K", "-2.5K", "-2.6K"}},
{-5550, new String[]{"-5.5K", "-5.5K", "-5.5K", "-5.6K", "-5.5K", "-5.5K", "-5.6K"}},
{5551, new String[]{"5.6K", "5.6K", "5.6K", "5.6K", "5.5K", "5.6K", "5.5K"}},
{-5551, new String[]{"-5.6K", "-5.6K", "-5.6K", "-5.6K", "-5.5K", "-5.5K", "-5.6K"}},
{1001, new String[]{"1.0K", "1.0K", "1.0K", "1.1K", "1.0K", "1.1K", "1.0K"}},
{-1001, new String[]{"-1.0K", "-1.0K", "-1.0K", "-1.1K", "-1.0K", "-1.0K", "-1.1K"}},
{4551, new String[]{"4.6K", "4.6K", "4.6K", "4.6K", "4.5K", "4.6K", "4.5K"}},
{-4551, new String[]{"-4.6K", "-4.6K", "-4.6K", "-4.6K", "-4.5K", "-4.5K", "-4.6K"}},
{4500, new String[]{"4.5K", "4.5K", "4.5K", "4.5K", "4.5K", "4.5K", "4.5K"}},
{-4500, new String[]{"-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K"}},};
}
Object[][] rounding2Fract() {
return new Object[][]{
// Number, half_even, half_up, half_down
{1115, new String[]{"1.11K", "1.11K", "1.11K"}},
{1125, new String[]{"1.12K", "1.13K", "1.12K"}},
{1135, new String[]{"1.14K", "1.14K", "1.14K"}},
{3115, new String[]{"3.12K", "3.12K", "3.12K"}},
{3125, new String[]{"3.12K", "3.13K", "3.12K"}},
{3135, new String[]{"3.13K", "3.13K", "3.13K"}},
{6865, new String[]{"6.87K", "6.87K", "6.87K"}},
{6875, new String[]{"6.88K", "6.88K", "6.87K"}},
{6885, new String[]{"6.88K", "6.88K", "6.88K"}},
{3124, new String[]{"3.12K", "3.12K", "3.12K"}},
{3126, new String[]{"3.13K", "3.13K", "3.13K"}},
{3128, new String[]{"3.13K", "3.13K", "3.13K"}},
{6864, new String[]{"6.86K", "6.86K", "6.86K"}},
{6865, new String[]{"6.87K", "6.87K", "6.87K"}},
{6868, new String[]{"6.87K", "6.87K", "6.87K"}},
{4685, new String[]{"4.68K", "4.68K", "4.68K"}},
{4687, new String[]{"4.69K", "4.69K", "4.69K"}},
{4686, new String[]{"4.69K", "4.69K", "4.69K"}},};
}
@Test
void testNullMode() {
assertThrows(NullPointerException.class, () -> {
NumberFormat fmt = NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
fmt.setRoundingMode(null);
});
}
@Test
void testDefaultRoundingMode() {
NumberFormat fmt = NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
assertEquals(RoundingMode.HALF_EVEN, fmt.getRoundingMode(),
"Default RoundingMode should be " + RoundingMode.HALF_EVEN);
}
@ParameterizedTest
@MethodSource("roundingData")
void testRounding(Object number, String[] expected) {
for (int index = 0; index < MODES.size(); index++) {
testRoundingMode(number, expected[index], 0, MODES.get(index));
}
}
@ParameterizedTest
@MethodSource("roundingFract")
void testRoundingFract(Object number, String[] expected) {
for (int index = 0; index < MODES.size(); index++) {
testRoundingMode(number, expected[index], 1, MODES.get(index));
}
}
@ParameterizedTest
@MethodSource("rounding2Fract")
void testRounding2Fract(Object number, String[] expected) {
List<RoundingMode> rModes = List.of(RoundingMode.HALF_EVEN,
RoundingMode.HALF_UP, RoundingMode.HALF_DOWN);
for (int index = 0; index < rModes.size(); index++) {
testRoundingMode(number, expected[index], 2, rModes.get(index));
}
}
private void testRoundingMode(Object number, String expected,
int fraction, RoundingMode rounding) {
NumberFormat fmt = NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
fmt.setRoundingMode(rounding);
assertEquals(rounding, fmt.getRoundingMode(),
"RoundingMode set is not returned by getRoundingMode");
fmt.setMinimumFractionDigits(fraction);
String result = fmt.format(number);
assertEquals(expected, result, "Incorrect formatting of number "
+ number + " using rounding mode: " + rounding);
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8368328
* @summary Tests if CompactNumberFormat.clone() creates an independent object
* @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED TestClone
*/
import java.lang.invoke.MethodHandles;
import java.text.CompactNumberFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
public class TestClone {
// Concurrently parse numbers using cloned instances as originally
// reported in the bug. This test could produce false negative results,
// depending on the testing environment
@Test
void randomAccessTest() {
var original =
NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
var threads = IntStream.range(0, 10)
.mapToObj(num -> new Thread(() -> {
var clone = (NumberFormat) original.clone();
for (int i = 0; i < 1000; i++) {
assertDoesNotThrow(() ->
assertEquals(num, clone.parse(String.valueOf(num)).intValue()));
}
})).toList();
threads.forEach(Thread::start);
threads.forEach(t -> {
try {
t.join();
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
});
}
private static Stream<Arguments> referenceFields() throws ClassNotFoundException {
return Stream.of(
Arguments.of("compactPatterns", String[].class),
Arguments.of("symbols", DecimalFormatSymbols.class),
Arguments.of("decimalFormat", DecimalFormat.class),
Arguments.of("defaultDecimalFormat", DecimalFormat.class),
Arguments.of("digitList", Class.forName("java.text.DigitList"))
);
}
// Explicitly checks if the cloned object has its own references for
// "compactPatterns", "symbols", "decimalFormat", "defaultDecimalFormat",
// and "digitList"
@ParameterizedTest
@MethodSource("referenceFields")
void whiteBoxTest(String fieldName, Class<?> type) throws Throwable {
var original = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
var clone = original.clone();
var lookup = MethodHandles.privateLookupIn(CompactNumberFormat.class, MethodHandles.lookup());
assertNotSame(lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(original),
lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(clone));
}
}

View file

@ -0,0 +1,700 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 8363972
* 8354548
* @summary Checks the functioning of compact number format
* @modules jdk.localedata
* @run junit/othervm TestCompactNumber
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.FieldPosition;
import java.text.Format;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestCompactNumber {
private static final NumberFormat FORMAT_DZ_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("dz"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_EN_US_SHORT = NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_EN_LONG = NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_HI_IN_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_JA_JP_SHORT = NumberFormat
.getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_IT_SHORT = NumberFormat
.getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_IT_LONG = NumberFormat
.getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_CA_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("ca"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_AS_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("as"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_BRX_SHORT = NumberFormat
.getCompactNumberInstance(Locale.of("brx"), NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_SW_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("sw"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_SE_SHORT = NumberFormat
.getCompactNumberInstance(Locale.of("se"), NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_DE_LONG = NumberFormat
.getCompactNumberInstance(Locale.GERMAN, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_SL_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("sl"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_ES_LONG_FD1 = NumberFormat
.getCompactNumberInstance(Locale.of("es"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_DE_LONG_FD2 = NumberFormat
.getCompactNumberInstance(Locale.GERMAN, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_IT_LONG_FD3 = NumberFormat
.getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_PT_LONG_FD4 = NumberFormat
.getCompactNumberInstance(Locale.of("pt"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_PL_LONG = NumberFormat
.getCompactNumberInstance(Locale.of("pl"), NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_FR_LONG = NumberFormat
.getCompactNumberInstance(Locale.FRENCH, NumberFormat.Style.LONG);
static {
FORMAT_ES_LONG_FD1.setMaximumFractionDigits(1);
FORMAT_DE_LONG_FD2.setMaximumFractionDigits(2);
FORMAT_IT_LONG_FD3.setMaximumFractionDigits(3);
FORMAT_PT_LONG_FD4.setMaximumFractionDigits(4);
}
Object[][] compactFormatData() {
return new Object[][]{
// compact number format instance, number to format, formatted output
{FORMAT_DZ_LONG, 1000.09, "སྟོང་ཕ"
+ "ྲག ༡"},
{FORMAT_DZ_LONG, -999.99, "-སྟོང་ཕ"
+ "ྲག ༡"},
{FORMAT_DZ_LONG, -0.0, "-༠"},
{FORMAT_DZ_LONG, 3000L, "སྟོང་ཕ"
+ "ྲག ༣"},
{FORMAT_DZ_LONG, new BigInteger("12345678901234567890"), "ད"
+ "ུང་ཕྱུར་ས"
+ "་ཡ་ ༡༢༣༤༥༧"},
// negative
{FORMAT_DZ_LONG, new BigInteger("-12345678901234567890"), "-ད"
+ "ུང་ཕྱུར་ས"
+ "་ཡ་ ༡༢༣༤༥༧"},
{FORMAT_DZ_LONG, new BigDecimal("12345678901234567890.89"), "ད"
+ "ུང་ཕྱུར་ས"
+ "་ཡ་ ༡༢༣༤༥༧"},
{FORMAT_DZ_LONG, new BigDecimal("-12345678901234567890.89"), "-ད"
+ "ུང་ཕྱུར་ས"
+ "་ཡ་ ༡༢༣༤༥༧"},
// Zeros
{FORMAT_EN_US_SHORT, 0, "0"},
{FORMAT_EN_US_SHORT, 0.0, "0"},
{FORMAT_EN_US_SHORT, -0.0, "-0"},
// Less than 1000 no suffix
{FORMAT_EN_US_SHORT, 499, "499"},
// Boundary number
{FORMAT_EN_US_SHORT, 1000.0, "1K"},
// Long
{FORMAT_EN_US_SHORT, 3000L, "3K"},
{FORMAT_EN_US_SHORT, 30000L, "30K"},
{FORMAT_EN_US_SHORT, 300000L, "300K"},
{FORMAT_EN_US_SHORT, 3000000L, "3M"},
{FORMAT_EN_US_SHORT, 30000000L, "30M"},
{FORMAT_EN_US_SHORT, 300000000L, "300M"},
{FORMAT_EN_US_SHORT, 3000000000L, "3B"},
{FORMAT_EN_US_SHORT, 30000000000L, "30B"},
{FORMAT_EN_US_SHORT, 300000000000L, "300B"},
{FORMAT_EN_US_SHORT, 3000000000000L, "3T"},
{FORMAT_EN_US_SHORT, 30000000000000L, "30T"},
{FORMAT_EN_US_SHORT, 300000000000000L, "300T"},
{FORMAT_EN_US_SHORT, 3000000000000000L, "3000T"},
// Negatives
{FORMAT_EN_US_SHORT, -3000L, "-3K"},
{FORMAT_EN_US_SHORT, -30000L, "-30K"},
{FORMAT_EN_US_SHORT, -300000L, "-300K"},
{FORMAT_EN_US_SHORT, -3000000L, "-3M"},
{FORMAT_EN_US_SHORT, -30000000L, "-30M"},
{FORMAT_EN_US_SHORT, -300000000L, "-300M"},
{FORMAT_EN_US_SHORT, -3000000000L, "-3B"},
{FORMAT_EN_US_SHORT, -30000000000L, "-30B"},
{FORMAT_EN_US_SHORT, -300000000000L, "-300B"},
{FORMAT_EN_US_SHORT, -3000000000000L, "-3T"},
{FORMAT_EN_US_SHORT, -30000000000000L, "-30T"},
{FORMAT_EN_US_SHORT, -300000000000000L, "-300T"},
{FORMAT_EN_US_SHORT, -3000000000000000L, "-3000T"},
// Double
{FORMAT_EN_US_SHORT, 3000.0, "3K"},
{FORMAT_EN_US_SHORT, 30000.0, "30K"},
{FORMAT_EN_US_SHORT, 300000.0, "300K"},
{FORMAT_EN_US_SHORT, 3000000.0, "3M"},
{FORMAT_EN_US_SHORT, 30000000.0, "30M"},
{FORMAT_EN_US_SHORT, 300000000.0, "300M"},
{FORMAT_EN_US_SHORT, 3000000000.0, "3B"},
{FORMAT_EN_US_SHORT, 30000000000.0, "30B"},
{FORMAT_EN_US_SHORT, 300000000000.0, "300B"},
{FORMAT_EN_US_SHORT, 3000000000000.0, "3T"},
{FORMAT_EN_US_SHORT, 30000000000000.0, "30T"},
{FORMAT_EN_US_SHORT, 300000000000000.0, "300T"},
{FORMAT_EN_US_SHORT, 3000000000000000.0, "3000T"},
// Negatives
{FORMAT_EN_US_SHORT, -3000.0, "-3K"},
{FORMAT_EN_US_SHORT, -30000.0, "-30K"},
{FORMAT_EN_US_SHORT, -300000.0, "-300K"},
{FORMAT_EN_US_SHORT, -3000000.0, "-3M"},
{FORMAT_EN_US_SHORT, -30000000.0, "-30M"},
{FORMAT_EN_US_SHORT, -300000000.0, "-300M"},
{FORMAT_EN_US_SHORT, -3000000000.0, "-3B"},
{FORMAT_EN_US_SHORT, -30000000000.0, "-30B"},
{FORMAT_EN_US_SHORT, -300000000000.0, "-300B"},
{FORMAT_EN_US_SHORT, -3000000000000.0, "-3T"},
{FORMAT_EN_US_SHORT, -30000000000000.0, "-30T"},
{FORMAT_EN_US_SHORT, -300000000000000.0, "-300T"},
{FORMAT_EN_US_SHORT, -3000000000000000.0, "-3000T"},
// BigInteger
{FORMAT_EN_US_SHORT, new BigInteger("12345678901234567890"),
"12345679T"},
{FORMAT_EN_US_SHORT, new BigInteger("-12345678901234567890"),
"-12345679T"},
//BigDecimal
{FORMAT_EN_US_SHORT, new BigDecimal("12345678901234567890.89"),
"12345679T"},
{FORMAT_EN_US_SHORT, new BigDecimal("-12345678901234567890.89"),
"-12345679T"},
{FORMAT_EN_US_SHORT, new BigDecimal("12345678901234567890123466767.89"),
"12345678901234568T"},
{FORMAT_EN_US_SHORT, new BigDecimal(
"12345678901234567890878732267863209.89"),
"12345678901234567890879T"},
// number as exponent
{FORMAT_EN_US_SHORT, 9.78313E+3, "10K"},
// Less than 1000 no suffix
{FORMAT_EN_LONG, 999, "999"},
// Round the value and then format
{FORMAT_EN_LONG, 999.99, "1 thousand"},
// 10 thousand
{FORMAT_EN_LONG, 99000, "99 thousand"},
// Long path
{FORMAT_EN_LONG, 330000, "330 thousand"},
// Double path
{FORMAT_EN_LONG, 3000.90, "3 thousand"},
// BigInteger path
{FORMAT_EN_LONG, new BigInteger("12345678901234567890"),
"12345679 trillion"},
//BigDecimal path
{FORMAT_EN_LONG, new BigDecimal("12345678901234567890.89"),
"12345679 trillion"},
// Less than 1000 no suffix
{FORMAT_HI_IN_LONG, -999, "-999"},
// Round the value with 0 fraction digits and format it
{FORMAT_HI_IN_LONG, -999.99, "-1 हज़ार"},
// 10 thousand
{FORMAT_HI_IN_LONG, 99000, "99 हज़ार"},
// Long path
{FORMAT_HI_IN_LONG, 330000, "3 लाख"},
// Double path
{FORMAT_HI_IN_LONG, 3000.90, "3 हज़ार"},
// BigInteger path
{FORMAT_HI_IN_LONG, new BigInteger("12345678901234567890"),
"123456789 खरब"},
// BigDecimal path
{FORMAT_HI_IN_LONG, new BigDecimal("12345678901234567890.89"),
"123456789 खरब"},
// 1000 does not have any suffix in "ja" locale
{FORMAT_JA_JP_SHORT, -999.99, "-1,000"},
// 0-9999 does not have any suffix
{FORMAT_JA_JP_SHORT, 9999, "9,999"},
// 99000/10000 => 9.9万 rounded to 10万
{FORMAT_JA_JP_SHORT, 99000, "10万"},
// Negative
{FORMAT_JA_JP_SHORT, -99000, "-10万"},
// Long path
{FORMAT_JA_JP_SHORT, 330000, "33万"},
// Double path
{FORMAT_JA_JP_SHORT, 3000.90, "3,001"},
// BigInteger path
{FORMAT_JA_JP_SHORT, new BigInteger("12345678901234567890"),
"1235京"},
// BigDecimal path
{FORMAT_JA_JP_SHORT, new BigDecimal("12345678901234567890.89"),
"1235京"},
// less than 1000 no suffix
{FORMAT_IT_SHORT, 499, "499"},
// Boundary number
{FORMAT_IT_SHORT, 1000, "1K"},
// Long path
{FORMAT_IT_SHORT, 3000000L, "3 Mln"},
// Double path
{FORMAT_IT_SHORT, 3000000.0, "3 Mln"},
// BigInteger path
{FORMAT_IT_SHORT, new BigInteger("12345678901234567890"),
"12345679 Bln"},
// BigDecimal path
{FORMAT_IT_SHORT, new BigDecimal("12345678901234567890.89"),
"12345679 Bln"},
{FORMAT_CA_LONG, 999, "999"},
{FORMAT_CA_LONG, 999.99, "1 miler"},
{FORMAT_CA_LONG, 99000, "99 milers"},
{FORMAT_CA_LONG, 330000, "330 milers"},
{FORMAT_CA_LONG, 3000.90, "3 milers"},
{FORMAT_CA_LONG, 1000000, "1 milió"},
{FORMAT_CA_LONG, new BigInteger("12345678901234567890"),
"12345679 bilions"},
{FORMAT_CA_LONG, new BigDecimal("12345678901234567890.89"),
"12345679 bilions"},
{FORMAT_AS_LONG, 5000.0, "৫ হাজাৰ"},
{FORMAT_AS_LONG, 50000.0, "৫০ হাজাৰ"},
{FORMAT_AS_LONG, 500000.0, "৫ লাখ"},
{FORMAT_AS_LONG, 5000000.0, "৫ নিযুত"},
{FORMAT_AS_LONG, 50000000.0, "৫০ নিযুত"},
{FORMAT_AS_LONG, 500000000.0, "৫০০ নিযুত"},
{FORMAT_AS_LONG, 5000000000.0, "৫ শত কোটি"},
{FORMAT_AS_LONG, 50000000000.0, "৫০ শত কোটি"},
{FORMAT_AS_LONG, 500000000000.0, "৫০০ শত কোটি"},
{FORMAT_AS_LONG, 5000000000000.0, "৫ শত পৰাৰ্দ্ধ"},
{FORMAT_AS_LONG, 50000000000000.0, "৫০ শত পৰাৰ্দ্ধ"},
{FORMAT_AS_LONG, 500000000000000.0, "৫০০ শত পৰাৰ্দ্ধ"},
{FORMAT_AS_LONG, 5000000000000000.0, "৫০০০ শত পৰাৰ্দ্ধ"},
{FORMAT_AS_LONG, new BigInteger("12345678901234567890"),
"১২৩৪৫৬৭৯ শত পৰাৰ্দ্ধ"},
{FORMAT_AS_LONG, new BigDecimal("12345678901234567890123466767.89"),
"১২৩৪৫৬৭৮৯০১২৩৪৫৬৮ শত পৰাৰ্দ্ধ"},
{FORMAT_BRX_SHORT, 999, "999"},
{FORMAT_BRX_SHORT, 999.99, "1के"},
{FORMAT_BRX_SHORT, 99000, "99के"},
{FORMAT_BRX_SHORT, 330000, "330के"},
{FORMAT_BRX_SHORT, 3000.90, "3के"},
{FORMAT_BRX_SHORT, 1000000, "1एम"},
{FORMAT_BRX_SHORT, new BigInteger("12345678901234567890"),
"12345679ति"},
{FORMAT_BRX_SHORT, new BigDecimal("12345678901234567890.89"),
"12345679ति"},
// Less than 1000 no suffix
{FORMAT_SW_LONG, 499, "499"},
// Boundary number
{FORMAT_SW_LONG, 1000, "elfu 1"},
// Long path
{FORMAT_SW_LONG, 3000000L, "milioni 3"},
// Long path, negative
{FORMAT_SW_LONG, -3000000L, "milioni -3"},
// Double path
{FORMAT_SW_LONG, 3000000.0, "milioni 3"},
// Double path, negative
{FORMAT_SW_LONG, -3000000.0, "milioni -3"},
// BigInteger path
{FORMAT_SW_LONG, new BigInteger("12345678901234567890"),
"trilioni 12345679"},
// BigDecimal path
{FORMAT_SW_LONG, new BigDecimal("12345678901234567890.89"),
"trilioni 12345679"},
// Positives
// No compact form
{FORMAT_SE_SHORT, 999, "999"},
// Long
{FORMAT_SE_SHORT, 8000000L, "8 mn"},
// Double
{FORMAT_SE_SHORT, 8000.98, "8 dt"},
// Big integer
{FORMAT_SE_SHORT, new BigInteger("12345678901234567890"), "12345679 bn"},
// Big decimal
{FORMAT_SE_SHORT, new BigDecimal("12345678901234567890.98"), "12345679 bn"},
// Negatives
// No compact form
{FORMAT_SE_SHORT, -999, "−999"},
// Long
{FORMAT_SE_SHORT, -8000000L, "−8 mn"},
// Double
{FORMAT_SE_SHORT, -8000.98, "−8 dt"},
// BigInteger
{FORMAT_SE_SHORT, new BigInteger("-12345678901234567890"), "−12345679 bn"},
// BigDecimal
{FORMAT_SE_SHORT, new BigDecimal("-12345678901234567890.98"), "−12345679 bn"},
// Plurals
// DE: one:i = 1 and v = 0
{FORMAT_DE_LONG, 1_000_000, "1 Million"},
{FORMAT_DE_LONG, 2_000_000, "2 Millionen"},
// SL: one:v = 0 and i % 100 = 1
// two:v = 0 and i % 100 = 2
// few:v = 0 and i % 100 = 3..4 or v != 0
{FORMAT_SL_LONG, 1_000_000, "1 milijon"},
{FORMAT_SL_LONG, 2_000_000, "2 milijona"},
{FORMAT_SL_LONG, 3_000_000, "3 milijoni"},
{FORMAT_SL_LONG, 5_000_000, "5 milijonov"},
// Fractional plurals
{FORMAT_ES_LONG_FD1, 1_234_500, "1,2 millones"},
{FORMAT_DE_LONG_FD2, 1_234_500, "1,23 Millionen"},
{FORMAT_IT_LONG_FD3, 1_234_500, "1,234 milioni"},
{FORMAT_PT_LONG_FD4, 1_234_500, "1,2345 milhões"},
// 8338690
{FORMAT_PL_LONG, 5_000, "5 tysięcy"},
{FORMAT_PL_LONG, 4_949, "5 tysięcy"},
{FORMAT_FR_LONG, 1_949, "2 mille"},
{FORMAT_IT_LONG, 1_949, "2 mila"},
};
}
Object[][] compactParseData() {
return new Object[][]{
// compact number format instance, string to parse, parsed number, return type
{FORMAT_DZ_LONG, "སྟོང་ཕྲ"
+ "ག ༡", 1000L, Long.class},
{FORMAT_DZ_LONG, "-སྟོང་ཕྲ"
+ "ག ༣", -3000L, Long.class},
{FORMAT_DZ_LONG, "དུང་ཕྱུར"
+ "་ས་ཡ་ ༡"
+ "༢༣༤༥༧", 1.23457E19, Double.class},
{FORMAT_DZ_LONG, "-དུང་ཕྱུར"
+ "་ས་ཡ་ ༡"
+ "༢༣༤༥༧", -1.23457E19, Double.class},
{FORMAT_EN_US_SHORT, "-0.0", -0.0, Double.class},
{FORMAT_EN_US_SHORT, "-0", -0.0, Double.class},
{FORMAT_EN_US_SHORT, "0", 0L, Long.class},
{FORMAT_EN_US_SHORT, "499", 499L, Long.class},
{FORMAT_EN_US_SHORT, "-499", -499L, Long.class},
{FORMAT_EN_US_SHORT, "499.89", 499.89, Double.class},
{FORMAT_EN_US_SHORT, "-499.89", -499.89, Double.class},
{FORMAT_EN_US_SHORT, "1K", 1000L, Long.class},
{FORMAT_EN_US_SHORT, "-1K", -1000L, Long.class},
{FORMAT_EN_US_SHORT, "3K", 3000L, Long.class},
{FORMAT_EN_US_SHORT, "17K", 17000L, Long.class},
{FORMAT_EN_US_SHORT, "-17K", -17000L, Long.class},
{FORMAT_EN_US_SHORT, "-3K", -3000L, Long.class},
{FORMAT_EN_US_SHORT, "12345678901234567890", 1.2345678901234567E19, Double.class},
{FORMAT_EN_US_SHORT, "12345679T", 1.2345679E19, Double.class},
{FORMAT_EN_US_SHORT, "-12345679T", -1.2345679E19, Double.class},
{FORMAT_EN_US_SHORT, "599.01K", 599010L, Long.class},
{FORMAT_EN_US_SHORT, "-599.01K", -599010L, Long.class},
{FORMAT_EN_US_SHORT, "599444444.90T", 5.994444449E20, Double.class},
{FORMAT_EN_US_SHORT, "-599444444.90T", -5.994444449E20, Double.class},
{FORMAT_EN_US_SHORT, "123456789012345.5678K", 123456789012345568L, Long.class},
{FORMAT_EN_US_SHORT, "17.000K", 17000L, Long.class},
{FORMAT_EN_US_SHORT, "123.56678K", 123566.78000, Double.class},
{FORMAT_EN_US_SHORT, "-123.56678K", -123566.78000, Double.class},
{FORMAT_EN_LONG, "999", 999L, Long.class},
{FORMAT_EN_LONG, "1 thousand", 1000L, Long.class},
{FORMAT_EN_LONG, "3 thousand", 3000L, Long.class},
{FORMAT_EN_LONG, "12345679 trillion", 1.2345679E19, Double.class},
{FORMAT_HI_IN_LONG, "999", 999L, Long.class},
{FORMAT_HI_IN_LONG, "-999", -999L, Long.class},
{FORMAT_HI_IN_LONG, "1 हज़ार", 1000L, Long.class},
{FORMAT_HI_IN_LONG, "-1 हज़ार", -1000L, Long.class},
{FORMAT_HI_IN_LONG, "3 हज़ार", 3000L, Long.class},
{FORMAT_HI_IN_LONG, "12345679 खरब", 1234567900000000000L, Long.class},
{FORMAT_HI_IN_LONG, "-12345679 खरब", -1234567900000000000L, Long.class},
{FORMAT_JA_JP_SHORT, "-99", -99L, Long.class},
{FORMAT_JA_JP_SHORT, "1万", 10000L, Long.class},
{FORMAT_JA_JP_SHORT, "30万", 300000L, Long.class},
{FORMAT_JA_JP_SHORT, "-30万", -300000L, Long.class},
{FORMAT_JA_JP_SHORT, "12345679兆", 1.2345679E19, Double.class},
{FORMAT_JA_JP_SHORT, "-12345679兆", -1.2345679E19, Double.class},
{FORMAT_IT_SHORT, "-99", -99L, Long.class},
{FORMAT_IT_SHORT, "1 Mln", 1000000L, Long.class},
{FORMAT_IT_SHORT, "30 Mln", 30000000L, Long.class},
{FORMAT_IT_SHORT, "-30 Mln", -30000000L, Long.class},
{FORMAT_IT_SHORT, "12345679 Bln", 1.2345679E19, Double.class},
{FORMAT_IT_SHORT, "-12345679 Bln", -1.2345679E19, Double.class},
{FORMAT_SW_LONG, "-0.0", -0.0, Double.class},
{FORMAT_SW_LONG, "499", 499L, Long.class},
{FORMAT_SW_LONG, "elfu 1", 1000L, Long.class},
{FORMAT_SW_LONG, "elfu 3", 3000L, Long.class},
{FORMAT_SW_LONG, "elfu 17", 17000L, Long.class},
{FORMAT_SW_LONG, "elfu -3", -3000L, Long.class},
{FORMAT_SW_LONG, "499", 499L, Long.class},
{FORMAT_SW_LONG, "-499", -499L, Long.class},
{FORMAT_SW_LONG, "elfu 1", 1000L, Long.class},
{FORMAT_SW_LONG, "elfu 3", 3000L, Long.class},
{FORMAT_SW_LONG, "elfu -3", -3000L, Long.class},
{FORMAT_SW_LONG, "elfu 17", 17000L, Long.class},
{FORMAT_SW_LONG, "trilioni 12345679", 1.2345679E19, Double.class},
{FORMAT_SW_LONG, "trilioni -12345679", -1.2345679E19, Double.class},
{FORMAT_SW_LONG, "elfu 599.01", 599010L, Long.class},
{FORMAT_SW_LONG, "elfu -599.01", -599010L, Long.class},
{FORMAT_SE_SHORT, "999", 999L, Long.class},
{FORMAT_SE_SHORT, "8 mn", 8000000L, Long.class},
{FORMAT_SE_SHORT, "8 dt", 8000L, Long.class},
{FORMAT_SE_SHORT, "12345679 bn", 1.2345679E19, Double.class},
{FORMAT_SE_SHORT, "12345679,89 bn", 1.2345679890000001E19, Double.class},
{FORMAT_SE_SHORT, "\u2212999", -999L, Long.class},
{FORMAT_SE_SHORT, "\u22128\u00a0mn", -8000000L, Long.class},
// lenient parsing. Hyphen-minus should match the localized minus sign
{FORMAT_SE_SHORT, "−8 mn", -8000000L, Long.class},
{FORMAT_SE_SHORT, "\u22128 dt", -8000L, Long.class},
{FORMAT_SE_SHORT, "\u221212345679 bn", -1.2345679E19, Double.class},
{FORMAT_SE_SHORT, "\u221212345679,89 bn", -1.2345679890000001E19, Double.class},
// Plurals
// DE: one:i = 1 and v = 0
{FORMAT_DE_LONG, "1 Million", 1_000_000L, Long.class},
{FORMAT_DE_LONG, "2 Millionen", 2_000_000L, Long.class},
// SL: one:v = 0 and i % 100 = 1
// two:v = 0 and i % 100 = 2
// few:v = 0 and i % 100 = 3..4 or v != 0
{FORMAT_SL_LONG, "1 milijon", 1_000_000L, Long.class},
{FORMAT_SL_LONG, "2 milijona", 2_000_000L, Long.class},
{FORMAT_SL_LONG, "3 milijoni", 3_000_000L, Long.class},
{FORMAT_SL_LONG, "5 milijonov", 5_000_000L, Long.class},
// Fractional plurals
{FORMAT_ES_LONG_FD1, "1,2 millones", 1_200_000L, Long.class},
{FORMAT_DE_LONG_FD2, "1,23 Millionen", 1_230_000L, Long.class},
{FORMAT_IT_LONG_FD3, "1,234 milioni", 1_234_000L, Long.class},
{FORMAT_PT_LONG_FD4, "1,2345 milhões", 1_234_500L, Long.class},
// 8338690
{FORMAT_PL_LONG, "5 tysięcy", 5_000L, Long.class},
{FORMAT_FR_LONG, "2 mille", 2_000L, Long.class},
{FORMAT_IT_LONG, "2 mila", 2_000L, Long.class},
};
}
Object[][] exceptionParseData() {
return new Object[][]{
// compact number instance, string to parse, null (no o/p; must throw exception)
// no number
{FORMAT_DZ_LONG, "སྟོང་ཕྲ"
+ "ག", null},
// Invalid prefix
{FORMAT_DZ_LONG, "-སྟོང,་ཕྲ"
+ "ག ༣", null},
// Invalid prefix for en_US
{FORMAT_EN_US_SHORT, "K12,347", null},
// Invalid prefix for ja_JP
{FORMAT_JA_JP_SHORT, "万1", null},
};
}
Object[][] invalidParseData() {
return new Object[][]{
// compact number instance, string to parse, parsed number
// Prefix and suffix do not match
{FORMAT_DZ_LONG, "སྟོང་ཕྲ"
+ "ག ༡ KM", 1000L},
// Exponents are unparseable
{FORMAT_EN_US_SHORT, "-1.05E4K", -1.05},
// Default instance does not allow grouping
{FORMAT_EN_US_SHORT, "12,347", 12L},
// Take partial suffix "K" as 1000 for en_US_SHORT patterns
{FORMAT_EN_US_SHORT, "12KM", 12000L},
// Invalid suffix
{FORMAT_HI_IN_LONG, "-1  क.", -1L},
// invalid plurals
{FORMAT_DE_LONG, "2 Million", 2L},
{FORMAT_SL_LONG, "2 milijon", 2L},
{FORMAT_SL_LONG, "2 milijone", 2L},
{FORMAT_SL_LONG, "2 milijonv", 2L},
{FORMAT_SL_LONG, "5 milijona", 5L},
{FORMAT_SL_LONG, "3 milijon", 3L},
{FORMAT_SL_LONG, "3 milijonv", 3L},
{FORMAT_SL_LONG, "5 milijon", 5L},
{FORMAT_SL_LONG, "5 milijona", 5L},
{FORMAT_SL_LONG, "5 milijone", 5L},
// 8338690
{FORMAT_PL_LONG, "5 tysiące", 5L},
{FORMAT_FR_LONG, "2 millier", 2L},
{FORMAT_IT_LONG, "2 mille", 2L},
};
}
Object[][] formatFieldPositionData() {
return new Object[][]{
//compact number instance, number to format, field, start position, end position, formatted string
{FORMAT_DZ_LONG, -3500, NumberFormat.Field.SIGN, 0, 1, "-སྟོང་ཕྲག ༤"},
{FORMAT_DZ_LONG, 3500, NumberFormat.Field.INTEGER, 9, 10, "སྟོང་ཕྲག ༤"},
{FORMAT_DZ_LONG, -3500, NumberFormat.Field.INTEGER, 10, 11, "-སྟོང་ཕྲག ༤"},
{FORMAT_DZ_LONG, 999, NumberFormat.Field.INTEGER, 0, 3, "༩༩༩"},
{FORMAT_DZ_LONG, -999, NumberFormat.Field.INTEGER, 1, 4, "-༩༩༩"},
{FORMAT_DZ_LONG, 3500, NumberFormat.Field.PREFIX, 0, 9, "སྟོང་ཕྲག ༤"},
{FORMAT_DZ_LONG, -3500, NumberFormat.Field.PREFIX, 0, 10, "-སྟོང་ཕྲག ༤"},
{FORMAT_DZ_LONG, 999, NumberFormat.Field.PREFIX, 0, 0, "༩༩༩"},
{FORMAT_EN_US_SHORT, -3500, NumberFormat.Field.SIGN, 0, 1, "-4K"},
{FORMAT_EN_US_SHORT, 3500, NumberFormat.Field.INTEGER, 0, 1, "4K"},
{FORMAT_EN_US_SHORT, 14900000067L, NumberFormat.Field.INTEGER, 0, 2, "15B"},
{FORMAT_EN_US_SHORT, -1000, NumberFormat.Field.PREFIX, 0, 1, "-1K"},
{FORMAT_EN_US_SHORT, 3500, NumberFormat.Field.SUFFIX, 1, 2, "4K"},
{FORMAT_EN_US_SHORT, 14900000067L, NumberFormat.Field.SUFFIX, 2, 3, "15B"},
{FORMAT_EN_LONG, 3500, NumberFormat.Field.INTEGER, 0, 1, "4 thousand"},
{FORMAT_EN_LONG, 14900000067L, NumberFormat.Field.INTEGER, 0, 2, "15 billion"},
{FORMAT_EN_LONG, 3500, NumberFormat.Field.SUFFIX, 1, 10, "4 thousand"},
{FORMAT_EN_LONG, 14900000067L, NumberFormat.Field.SUFFIX, 2, 10, "15 billion"},
{FORMAT_JA_JP_SHORT, 14900000067L, NumberFormat.Field.INTEGER, 0, 3, "149億"},
{FORMAT_JA_JP_SHORT, -999.99, NumberFormat.Field.INTEGER, 1, 6, "-1,000"},
{FORMAT_JA_JP_SHORT, 14900000067L, NumberFormat.Field.SUFFIX, 3, 4, "149億"},
{FORMAT_JA_JP_SHORT, -999.99, NumberFormat.Field.SUFFIX, 0, 0, "-1,000"},
{FORMAT_JA_JP_SHORT, -999.99, NumberFormat.Field.SIGN, 0, 1, "-1,000"},
{FORMAT_HI_IN_LONG, -14900000067L, NumberFormat.Field.SIGN, 0, 1,
"-15 अरब"},
{FORMAT_HI_IN_LONG, 3500, NumberFormat.Field.INTEGER, 0, 1,
"4 हज़ार"},
{FORMAT_HI_IN_LONG, 14900000067L, NumberFormat.Field.INTEGER, 0, 2,
"15 अरब"},
{FORMAT_HI_IN_LONG, 3500, NumberFormat.Field.SUFFIX, 1, 7,
"4 हज़ार"},
{FORMAT_HI_IN_LONG, 14900000067L, NumberFormat.Field.SUFFIX, 2, 6,
"15 अरब"},
{FORMAT_SE_SHORT, 8000000L, NumberFormat.Field.SUFFIX, 1, 4, "8 mn"},
{FORMAT_SE_SHORT, 8000.98, NumberFormat.Field.SUFFIX, 1, 4, "8 dt"},
{FORMAT_SE_SHORT, new BigInteger("12345678901234567890"), NumberFormat.Field.SUFFIX, 8, 11, "12345679 bn"},
{FORMAT_SE_SHORT, new BigDecimal("12345678901234567890.98"), NumberFormat.Field.SUFFIX, 8, 11, "12345679 bn"},
{FORMAT_SE_SHORT, -8000000L, NumberFormat.Field.INTEGER, 1, 2, "−8 mn"},
{FORMAT_SE_SHORT, -8000.98, NumberFormat.Field.SIGN, 0, 1, "−8 dt"},
{FORMAT_SE_SHORT, new BigDecimal("-48982865901234567890.98"), NumberFormat.Field.INTEGER, 1, 9, "−48982866 bn"},};
}
Object[][] varParsePosition() {
return new Object[][]{
// compact number instance, parse string, parsed number,
// start position, end position, error index
{FORMAT_DZ_LONG, "སྟོང་ཕྲ"
+ "ག ༡ KM", 1000L, 0, 10, -1},
// Invalid prefix returns null
{FORMAT_DZ_LONG, "Number is: -སྟོང,་ཕྲ"
+ "ག ༣", null, 11, 11, 11},
// Returns null
{FORMAT_DZ_LONG, "སྟོང་ཕྲ"
+ "ག", null, 0, 0, 0},
{FORMAT_EN_US_SHORT, "Exponent: -1.05E4K", -1.05, 10, 15, -1},
// Default instance does not allow grouping
{FORMAT_EN_US_SHORT, "12,347", 12L, 0, 2, -1},
// Invalid suffix "KM" for en_US_SHORT patterns
{FORMAT_EN_US_SHORT, "12KM", 12000L, 0, 3, -1},
// Invalid suffix
{FORMAT_HI_IN_LONG, "-1  क.", -1L, 0, 2, -1},
{FORMAT_EN_LONG, "Number is: 12345679 trillion",
1.2345679E19, 11, 28, -1},
{FORMAT_EN_LONG, "Number is: -12345679 trillion",
-1.2345679E19, 11, 29, -1},
{FORMAT_EN_LONG, "parse 12 thousand and four", 12000L, 6, 17, -1},};
}
@Test
void testInstanceCreation() {
Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat
.getCompactNumberInstance(l, NumberFormat.Style.SHORT).format(10000));
Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat
.getCompactNumberInstance(l, NumberFormat.Style.LONG).format(10000));
}
@Test
void testFormatWithNullParam() {
assertThrows(IllegalArgumentException.class, () -> {
FORMAT_EN_US_SHORT.format(null);
});
}
@ParameterizedTest
@MethodSource("compactFormatData")
void testFormat(NumberFormat cnf, Object number,
String expected) {
CompactFormatAndParseHelper.testFormat(cnf, number, expected);
}
@ParameterizedTest
@MethodSource("compactParseData")
void testParse(NumberFormat cnf, String parseString,
Number expected, Class<? extends Number> returnType) throws ParseException {
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, returnType);
}
@ParameterizedTest
@MethodSource("compactParseData")
void testParsePosition(NumberFormat cnf, String parseString,
Number expected, Class<? extends Number> returnType) throws ParseException {
ParsePosition pos = new ParsePosition(0);
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, returnType);
assertEquals(parseString.length(), pos.getIndex());
assertEquals(-1, pos.getErrorIndex());
}
@ParameterizedTest
@MethodSource("varParsePosition")
void testVarParsePosition(NumberFormat cnf, String parseString,
Number expected, int startPosition, int indexPosition,
int errPosition) throws ParseException {
ParsePosition pos = new ParsePosition(startPosition);
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, null);
assertEquals(indexPosition, pos.getIndex());
assertEquals(errPosition, pos.getErrorIndex());
}
@ParameterizedTest
@MethodSource("exceptionParseData")
void throwsParseException(NumberFormat cnf, String parseString,
Number expected) {
assertThrows(ParseException.class, () -> CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null));
}
@ParameterizedTest
@MethodSource("invalidParseData")
void testInvalidParse(NumberFormat cnf, String parseString,
Number expected) throws ParseException {
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null);
}
@ParameterizedTest
@MethodSource("formatFieldPositionData")
void testFormatWithFieldPosition(NumberFormat nf,
Object number, Format.Field field, int posStartExpected,
int posEndExpected, String expected) {
FieldPosition pos = new FieldPosition(field);
StringBuffer buf = new StringBuffer();
StringBuffer result = nf.format(number, buf, pos);
assertEquals(expected, result.toString(), "Incorrect formatting of the number '"
+ number + "'");
assertEquals(posStartExpected, pos.getBeginIndex(), "Incorrect start position"
+ " while formatting the number '" + number + "', for the field " + field);
assertEquals(posEndExpected, pos.getEndIndex(), "Incorrect end position"
+ " while formatting the number '" + number + "', for the field " + field);
}
}

View file

@ -0,0 +1,211 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8217254 8251499 8281317
* @summary Checks the validity of compact number patterns specified through
* CompactNumberFormat constructor
* @run junit/othervm TestCompactPatternsValidity
*/
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.List;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertThrows;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestCompactPatternsValidity {
// Max range 10^4
private static final String[] COMPACT_PATTERN1 = new String[]{"0", "0", "0", "0K", "00K"};
// Quoted special character '.' as prefix
private static final String[] COMPACT_PATTERN2 = new String[]{"0", "'.'K0"};
// Quoted special character '.' as suffix
private static final String[] COMPACT_PATTERN3 = new String[]{"0", "0", "0", "0K", "00K'.'"};
// Containing both prefix and suffix
private static final String[] COMPACT_PATTERN4 = new String[]{"", "", "H0H", "0K", "00K", "H0G"};
// Differing while specifying prefix and suffix
private static final String[] COMPACT_PATTERN5 = new String[]{"", "", "", "0K", "K0"};
// Containing both prefix ('.') and suffix (K)
private static final String[] COMPACT_PATTERN6 = new String[]{"0", "", "", "'.'0K"};
// Quoted special character ',' as suffix
private static final String[] COMPACT_PATTERN7 = new String[]{"", "0", "0", "0K','"};
// Most commonly used type of compact patterns with 15 elements
private static final String[] COMPACT_PATTERN8 = new String[]{"", "", "", "0K", "00K", "000K", "0M",
"00M", "000M", "0B", "00B", "000B", "0T", "00T", "000T"};
// All empty or special patterns; checking the default formatting behaviour
private static final String[] COMPACT_PATTERN9 = new String[]{"", "", "", "0", "0", "", "", "", "", "", "", "", "", "", ""};
// Patterns beyond 10^19; divisors beyond long range
private static final String[] COMPACT_PATTERN10 = new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M",
"000M", "0B", "00B", "000B", "0T", "00T", "000T", "0L", "00L", "000L", "0XL", "00XL"};
// Containing positive;negative subpatterns
private static final String[] COMPACT_PATTERN11 = new String[]{"", "", "", "elfu 0;elfu -0", "elfu 00;elfu -00",
"elfu 000;elfu -000", "milioni 0;milioni -0", "milioni 00;milioni -00", "milioni 000;milioni -000"};
// Containing both prefix and suffix and positive;negative subpatern
private static final String[] COMPACT_PATTERN12 = new String[]{"", "", "H0H;H-0H", "0K;0K-", "00K;-00K", "H0G;-H0G"};
// A non empty pattern containing no 0s (min integer digits)
private static final String[] COMPACT_PATTERN13 =
new String[]{"", "", "", "Thousand", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "BeyondLong"};
// A non empty pattern containing no 0s (min integer digits), with plural rules
private static final String[] COMPACT_PATTERN14 =
new String[]{"", "", "", "{one:Kun other:0' 'Kun}"}; // from Somali in CLDR 38
Object[][] invalidCompactPatterns() {
return new Object[][] {
// compact patterns
// Pattern containing unquoted special character '.'
{new String[]{"", "", "", "0K", "00K."}},
// Pattern containing invalid single quote
{new String[]{"", "", "", "0 'do", "00K"}},
{new String[]{"", "", "", "0K", "00 don't"}},
// 0s (min integer digits) exceeding for the range at index 3
{new String[]{"", "", "0K", "00000K"}},
// null as a compact pattern
{new String[]{"", "", null, "00K"}},
};
}
Object[][] validPatternsFormat() {
return new Object[][] {
// compact patterns, numbers, expected output
{COMPACT_PATTERN1, List.of(200, 1000, 3000, 500000), List.of("200", "1K", "3K", "500K")},
{COMPACT_PATTERN2, List.of(1, 20, 3000), List.of("1", ".K2", ".K300")},
{COMPACT_PATTERN3, List.of(100.99, 1000, 30000), List.of("101", "1K", "30K.")},
{COMPACT_PATTERN4, List.of(0.0, 500, -500, 30000, 5000000), List.of("0", "H5H", "-H5H", "30K", "H50G")},
{COMPACT_PATTERN5, List.of(100, 1000, 30000), List.of("100", "1K", "K3")},
{COMPACT_PATTERN6, List.of(20.99, 1000, 30000), List.of("21", ".1K", ".30K")},
{COMPACT_PATTERN7, List.of(100, 1000, new BigInteger("12345678987654321")), List.of("100", "1K,", "12345678987654K,")},
{COMPACT_PATTERN8, List.of(new BigInteger("223565686837667632"), new BigDecimal("12322456774334.89766"), 30000, 3456.78,
new BigInteger("999999999999"), new BigDecimal("999999999999.0"), 999_999, 999_999_999),
List.of("223566T", "12T", "30K", "3K", "1T", "1T", "1M", "1B")},
{COMPACT_PATTERN9, List.of(new BigInteger("223566000000000000"), new BigDecimal("12345678987654567"), 30000, 3000),
List.of("223,566,000,000,000,000", "12,345,678,987,654,567", "30,000", "3,000")},
{COMPACT_PATTERN10, List.of(new BigInteger("100000000000000000"), new BigInteger("10000000000000000000"), new BigDecimal("555555555555555555555.89766"), 30000),
List.of("100L", "10XL", "556XL", "30K")},
{COMPACT_PATTERN11, List.of(20.99, -20.99, 1000, -1000, 30000, -30000, new BigInteger("12345678987654321"), new BigInteger("-12345678987654321")),
List.of("21", "-21", "elfu 1", "elfu -1", "elfu 30", "elfu -30", "milioni 12345678988", "milioni -12345678988")},
{COMPACT_PATTERN12, List.of(0, 500, -500, 30000, -3000, 5000000), List.of("0", "H5H", "H-5H", "30K", "3K-", "H50G")},
{COMPACT_PATTERN13, List.of(1000, new BigInteger("10000000000000000000"), new BigDecimal("9999999999999999999.9")),
List.of("Thousand", "BeyondLong", "BeyondLong")},
};
}
Object[][] validPatternsParse() {
return new Object[][] {
// compact patterns, parse string, expected output
{COMPACT_PATTERN1, List.of(".56", "200", ".1K", "3K", "500K"), List.of(0.56, 200L, 100L, 3000L, 500000L)},
{COMPACT_PATTERN2, List.of("1", ".K2", ".K300"), List.of(1L, 20L, 3000L)},
{COMPACT_PATTERN3, List.of("101", "1K", "30K."), List.of(101L, 1000L, 30000L)},
{COMPACT_PATTERN4, List.of("0", "H5H", "-H5H", "30K", "H50G"), List.of(0L, 500L, -500L, 30000L, 5000000L)},
{COMPACT_PATTERN5, List.of("100", "1K", "K3"), List.of(100L, 1000L, 30000L)},
{COMPACT_PATTERN6, List.of("21", ".1K", ".30K"), List.of(21L, 1000L, 30000L)},
{COMPACT_PATTERN7, List.of("100", "1K,", "12345678987654K,"), List.of(100L, 1000L, 12345678987654000L)},
{COMPACT_PATTERN8, List.of("223566T", "12T", "30K", "3K"), List.of(223566000000000000L, 12000000000000L, 30000L, 3000L)},
{COMPACT_PATTERN10, List.of("1L", "100L", "10XL", "556XL", "30K"), List.of(1000000000000000L, 100000000000000000L, 1.0E19, 5.56E20, 30000L)},
{COMPACT_PATTERN11, List.of("21", "-21", "100.90", "-100.90", "elfu 1", "elfu -1", "elfu 30", "elfu -30", "milioni 12345678988", "milioni -12345678988"),
List.of(21L, -21L, 100.90, -100.90, 1000L, -1000L, 30000L, -30000L, 12345678988000000L, -12345678988000000L)},
{COMPACT_PATTERN12, List.of("0", "H5H", "H-5H", "30K", "30K-", "H50G"), List.of(0L, 500L, -500L, 30000L, -30000L, 5000000L)},
{COMPACT_PATTERN13, List.of("Thousand", "BeyondLong"), List.of(1000L, new BigInteger("10000000000000000000"))},
};
}
Object[][] validPatternsFormatWithPluralRules() {
return new Object[][] {
// compact patterns, plural rules, numbers, expected output
{COMPACT_PATTERN14, "one:n = 1", List.of(1000, 2345), List.of("Kun", "2 Kun")},
};
}
Object[][] validPatternsParseWithPluralRules() {
return new Object[][] {
// compact patterns, plural rules, parse string, expected output
{COMPACT_PATTERN14, "one:n = 1", List.of("Kun", "2 Kun"), List.of(1000L, 2000L)},
};
}
@ParameterizedTest
@MethodSource("invalidCompactPatterns")
void testInvalidCompactPatterns(String[] compactPatterns) {
assertThrows(IllegalArgumentException.class, () -> {
new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols
.getInstance(Locale.US), compactPatterns);
});
}
@ParameterizedTest
@MethodSource("validPatternsFormat")
void testValidPatternsFormat(String[] compactPatterns,
List<Object> numbers, List<String> expected) {
CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
DecimalFormatSymbols.getInstance(Locale.US), compactPatterns);
for (int index = 0; index < numbers.size(); index++) {
CompactFormatAndParseHelper.testFormat(fmt, numbers.get(index),
expected.get(index));
}
}
@ParameterizedTest
@MethodSource("validPatternsParse")
void testValidPatternsParse(String[] compactPatterns,
List<String> parseString, List<Number> numbers) throws ParseException {
CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
DecimalFormatSymbols.getInstance(Locale.US), compactPatterns);
for (int index = 0; index < parseString.size(); index++) {
CompactFormatAndParseHelper.testParse(fmt, parseString.get(index),
numbers.get(index), null, null);
}
}
@ParameterizedTest
@MethodSource("validPatternsFormatWithPluralRules")
void testValidPatternsFormatWithPluralRules(String[] compactPatterns, String pluralRules,
List<Object> numbers, List<String> expected) {
CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules);
for (int index = 0; index < numbers.size(); index++) {
CompactFormatAndParseHelper.testFormat(fmt, numbers.get(index),
expected.get(index));
}
}
@ParameterizedTest
@MethodSource("validPatternsParseWithPluralRules")
void testValidPatternsParsewithPluralRules(String[] compactPatterns, String pluralRules,
List<String> parseString, List<Number> numbers) throws ParseException {
CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#",
DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules);
for (int index = 0; index < parseString.size(); index++) {
CompactFormatAndParseHelper.testParse(fmt, parseString.get(index),
numbers.get(index), null, null);
}
}
}

View file

@ -0,0 +1,197 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8222756 8327640
* @summary Checks the equals and hashCode method of CompactNumberFormat
* @modules jdk.localedata
* @run junit/othervm TestEquality
*/
import org.junit.jupiter.api.Test;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
public class TestEquality {
@Test
void testEquality() {
CompactNumberFormat cnf1 = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
CompactNumberFormat cnf2 = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
// A custom compact instance with the same state as
// compact number instance of "en_US" locale with SHORT style
String decimalPattern = "#,##0.###";
String[] compactPatterns = new String[]{
"",
"",
"",
"{one:0K other:0K}",
"{one:00K other:00K}",
"{one:000K other:000K}",
"{one:0M other:0M}",
"{one:00M other:00M}",
"{one:000M other:000M}",
"{one:0B other:0B}",
"{one:00B other:00B}",
"{one:000B other:000B}",
"{one:0T other:0T}",
"{one:00T other:00T}",
"{one:000T other:000T}"
};
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.US);
CompactNumberFormat cnf3 =
new CompactNumberFormat(decimalPattern, symbols, compactPatterns, "one:i = 1 and v = 0");
// A compact instance created with different decimalPattern than cnf3
CompactNumberFormat cnf4 = new CompactNumberFormat("#,#0.0#", symbols, compactPatterns);
// A compact instance created with different format symbols than cnf3
CompactNumberFormat cnf5 = new CompactNumberFormat(decimalPattern,
DecimalFormatSymbols.getInstance(Locale.JAPAN), compactPatterns);
// A compact instance created with different compact patterns than cnf3
CompactNumberFormat cnf6 = new CompactNumberFormat(decimalPattern,
symbols, new String[]{"", "", "", "0K", "00K", "000K"});
// Checking reflexivity
if (!cnf1.equals(cnf1)) {
throw new RuntimeException("[testEquality() reflexivity FAILED: The compared"
+ " objects must be equal]");
}
// Checking symmetry, checking equality of two same objects
if (!cnf1.equals(cnf2) || !cnf2.equals(cnf1)) {
throw new RuntimeException("[testEquality() symmetry FAILED: The compared"
+ " objects must be equal]");
}
// Checking transitivity, three objects must be equal
if (!cnf1.equals(cnf2) || !cnf2.equals(cnf3) || !cnf1.equals(cnf3)) {
throw new RuntimeException("[testEquality() transitivity FAILED: The compared"
+ " objects must be equal]");
}
// Objects must not be equal as the decimalPattern is different
checkEquals(cnf3, cnf4, false, "1st", "different decimal pattern");
// Objects must not be equal as the format symbols instance is different
checkEquals(cnf3, cnf5, false, "2nd", "different format symbols");
// Objects must not be equal as the compact patters are different
checkEquals(cnf3, cnf6, false, "3rd", "different compact patterns");
// Changing the min integer digits of first object; objects must not
// be equal
cnf1.setMinimumIntegerDigits(5);
checkEquals(cnf1, cnf2, false, "4th", "different min integer digits");
// Changing the min integer digits of second object; objects must
// be equal
cnf2.setMinimumIntegerDigits(5);
checkEquals(cnf1, cnf2, true, "5th", "");
// Changing the grouping size of first object; objects must not
// be equal
cnf1.setGroupingSize(4);
checkEquals(cnf1, cnf2, false, "6th", "different grouping size");
// Changing the grouping size if second object; objects must be equal
cnf2.setGroupingSize(4);
checkEquals(cnf1, cnf2, true, "7th", "");
// Changing the parseBigDecimal of first object; objects must not
// be equal
cnf1.setParseBigDecimal(true);
checkEquals(cnf1, cnf2, false, "8th", "different parse big decimal");
// Changing the parseBigDecimal of second object; objects must be equal
cnf2.setParseBigDecimal(true);
checkEquals(cnf1, cnf2, true, "9th", "");
// Changing the strict parsing value of first object; objects must not be equal
cnf1.setStrict(true);
checkEquals(cnf1, cnf2, false, "10th", "different strict parsing");
// Changing the strict parsing value of second object; objects must be equal
cnf2.setStrict(true);
checkEquals(cnf1, cnf2, true, "11th", "");
}
private void checkEquals(CompactNumberFormat cnf1, CompactNumberFormat cnf2,
boolean mustEqual, String nthComparison, String message) {
if (cnf1.equals(cnf2) != mustEqual) {
if (mustEqual) {
throw new RuntimeException("[testEquality() " + nthComparison
+ " comparison FAILED: The compared objects must be equal]");
} else {
throw new RuntimeException("[testEquality() " + nthComparison
+ " comparison FAILED: The compared objects must"
+ " not be equal because of " + message + "]");
}
}
}
@Test
void testHashCode() {
NumberFormat cnf1 = NumberFormat
.getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT);
NumberFormat cnf2 = NumberFormat
.getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT);
if (cnf1.hashCode() != cnf2.hashCode()) {
throw new RuntimeException("[testHashCode() FAILED: hashCode of the"
+ " compared objects must match]");
}
}
// Test the property of equals and hashCode i.e. two equal object must
// always have the same hashCode
@Test
void testEqualsAndHashCode() {
NumberFormat cnf1 = NumberFormat
.getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.SHORT);
cnf1.setMinimumIntegerDigits(5);
NumberFormat cnf2 = NumberFormat
.getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.SHORT);
cnf2.setMinimumIntegerDigits(5);
if (cnf1.equals(cnf2)) {
if (cnf1.hashCode() != cnf2.hashCode()) {
throw new RuntimeException("[testEqualsAndHashCode() FAILED: two"
+ " equal objects must have same hashCode]");
}
} else {
throw new RuntimeException("[testEqualsAndHashCode() FAILED: The"
+ " compared objects must be equal]");
}
}
}

View file

@ -0,0 +1,203 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552
* @summary Checks the functioning of
* CompactNumberFormat.formatToCharacterIterator method
* @modules jdk.localedata
* @run junit/othervm TestFormatToCharacterIterator
*/
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import java.text.Format;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestFormatToCharacterIterator {
private static final NumberFormat FORMAT_DZ = NumberFormat
.getCompactNumberInstance(Locale.of("dz"),
NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_EN_US = NumberFormat
.getCompactNumberInstance(Locale.US,
NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_EN_LONG = NumberFormat
.getCompactNumberInstance(Locale.ENGLISH,
NumberFormat.Style.LONG);
Object[][] compactFieldPositionData() {
return new Object[][]{
// compact format instance, number, resulted string, attributes/fields, attribute positions
{FORMAT_DZ, 1000.09, "\u0F66\u0F9F\u0F7C\u0F44\u0F0B\u0F55\u0FB2\u0F42 \u0F21",
new Format.Field[]{NumberFormat.Field.PREFIX, NumberFormat.Field.INTEGER}, new int[]{0, 9, 9, 10}},
{FORMAT_DZ, -999.99, "-\u0F66\u0F9F\u0F7C\u0F44\u0F0B\u0F55\u0FB2\u0F42 \u0F21",
new Format.Field[]{NumberFormat.Field.SIGN, NumberFormat.Field.PREFIX, NumberFormat.Field.INTEGER},
new int[]{0, 1, 1, 10, 10, 11}},
{FORMAT_DZ, -0.0, "-\u0F20", new Format.Field[]{NumberFormat.Field.SIGN, NumberFormat.Field.INTEGER}, new int[]{0, 1, 1, 2}},
{FORMAT_DZ, 3000L, "\u0F66\u0F9F\u0F7C\u0F44\u0F0B\u0F55\u0FB2\u0F42 \u0F23",
new Format.Field[]{NumberFormat.Field.PREFIX, NumberFormat.Field.INTEGER}, new int[]{0, 9, 9, 10}},
{FORMAT_DZ, new BigInteger("12345678901234567890"),
"\u0F51\u0F74\u0F44\u0F0B\u0F55\u0FB1\u0F74\u0F62\u0F0B\u0F66\u0F0B\u0F61\u0F0B \u0F21\u0F22\u0F23\u0F24\u0F25\u0F27",
new Format.Field[]{NumberFormat.Field.PREFIX, NumberFormat.Field.INTEGER}, new int[]{0, 14, 14, 20}},
{FORMAT_DZ, new BigDecimal("12345678901234567890.89"),
"\u0F51\u0F74\u0F44\u0F0B\u0F55\u0FB1\u0F74\u0F62\u0F0B\u0F66\u0F0B\u0F61\u0F0B \u0F21\u0F22\u0F23\u0F24\u0F25\u0F27",
new Format.Field[]{NumberFormat.Field.PREFIX, NumberFormat.Field.INTEGER}, new int[]{0, 14, 14, 20}},
// Zeros
{FORMAT_EN_US, 0, "0", new Format.Field[]{NumberFormat.Field.INTEGER}, new int[]{0, 1}},
{FORMAT_EN_US, 0.0, "0", new Format.Field[]{NumberFormat.Field.INTEGER}, new int[]{0, 1}},
{FORMAT_EN_US, -0.0, "-0", new Format.Field[]{NumberFormat.Field.SIGN, NumberFormat.Field.INTEGER}, new int[]{0, 1, 1, 2}},
// Less than 1000 no suffix
{FORMAT_EN_US, 499, "499", new Format.Field[]{NumberFormat.Field.INTEGER}, new int[]{0, 3}},
// Boundary number
{FORMAT_EN_US, 1000.0, "1K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
// Long
{FORMAT_EN_US, 3000L, "3K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
{FORMAT_EN_US, 30000L, "30K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
{FORMAT_EN_US, 300000L, "300K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 4}},
{FORMAT_EN_US, 3000000L, "3M",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
{FORMAT_EN_US, 30000000L, "30M",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
{FORMAT_EN_US, 300000000L, "300M",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 4}},
{FORMAT_EN_US, 3000000000L, "3B",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
{FORMAT_EN_US, 30000000000L, "30B",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
{FORMAT_EN_US, 300000000000L, "300B",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 4}},
{FORMAT_EN_US, 3000000000000L, "3T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
{FORMAT_EN_US, 30000000000000L, "30T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
{FORMAT_EN_US, 300000000000000L, "300T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 4}},
{FORMAT_EN_US, 3000000000000000L, "3000T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 4, 4, 5}},
// Double
{FORMAT_EN_US, 3000.0, "3K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 2}},
{FORMAT_EN_US, 30000.0, "30K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
{FORMAT_EN_US, 300000.0, "300K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 4}},
{FORMAT_EN_US, 3000000000000000.0, "3000T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 4, 4, 5}},
// BigInteger
{FORMAT_EN_US, new BigInteger("12345678901234567890"), "12345679T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 8, 8, 9}},
// BigDecimal
{FORMAT_EN_US, new BigDecimal("12345678901234567890.89"), "12345679T",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 8, 8, 9}},
// Number as exponent
{FORMAT_EN_US, 9.78313E+3, "10K",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 3}},
// Less than 1000 no suffix
{FORMAT_EN_LONG, 999, "999", new Format.Field[]{NumberFormat.Field.INTEGER}, new int[]{0, 3}},
// Round the value and then format
{FORMAT_EN_LONG, 999.99, "1 thousand",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 10}},
// 10 thousand
{FORMAT_EN_LONG, 99000, "99 thousand",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 2, 2, 11}},
// Long path
{FORMAT_EN_LONG, 330000, "330 thousand",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 3, 3, 12}},
// Double path
{FORMAT_EN_LONG, 3000.90, "3 thousand",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 1, 1, 10}},
// BigInteger path
{FORMAT_EN_LONG, new BigInteger("12345678901234567890"), "12345679 trillion",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 8, 8, 17}},
// BigDecimal path
{FORMAT_EN_LONG, new BigDecimal("12345678901234567890.89"), "12345679 trillion",
new Format.Field[]{NumberFormat.Field.INTEGER, NumberFormat.Field.SUFFIX}, new int[]{0, 8, 8, 17}}
};
}
@ParameterizedTest
@MethodSource("compactFieldPositionData")
void testFormatToCharacterIterator(NumberFormat fmt, Object number,
String expected, Format.Field[] expectedFields, int[] positions) {
AttributedCharacterIterator iterator = fmt.formatToCharacterIterator(number);
assertEquals(expected, getText(iterator), "Incorrect formatting of the number '"
+ number + "'");
iterator.first();
// Check start and end index of the formatted string
assertEquals(0, iterator.getBeginIndex(), "Incorrect start index: "
+ iterator.getBeginIndex() + " of the formatted string: " + expected);
assertEquals(expected.length(), iterator.getEndIndex(), "Incorrect end index: "
+ iterator.getEndIndex() + " of the formatted string: " + expected);
// Check the attributes returned by the formatToCharacterIterator
assertEquals(Set.of(expectedFields), iterator.getAllAttributeKeys(),
"Attributes do not match while formatting number: " + number);
// Check the begin and end index for attributes
iterator.first();
int currentPosition = 0;
do {
int start = iterator.getRunStart();
int end = iterator.getRunLimit();
assertEquals(positions[currentPosition], start,
"Incorrect start position for the attribute(s): "
+ iterator.getAttributes().keySet());
assertEquals(positions[currentPosition + 1], end,
"Incorrect end position for the attribute(s): "
+ iterator.getAttributes().keySet());
currentPosition = currentPosition + 2;
iterator.setIndex(end);
} while (iterator.current() != CharacterIterator.DONE);
}
// Create the formatted string from returned AttributedCharacterIterator
private String getText(AttributedCharacterIterator iterator) {
StringBuffer buffer = new StringBuffer();
for (char c = iterator.first(); c != CharacterIterator.DONE;
c = iterator.next()) {
buffer.append(c);
}
return buffer.toString();
}
}

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552
* @summary Checks the functioning of compact number format by changing the
* formatting parameters. For example, min fraction digits, grouping
* size etc.
* @modules jdk.localedata
* @run junit/othervm TestMutatingInstance
*/
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestMutatingInstance {
private static final NumberFormat FORMAT_FRACTION = NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
private static final CompactNumberFormat FORMAT_GROUPING = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_MININTEGER = NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_PARSEINTONLY = NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
// No compact patterns are specified for this instance except at index 4.
// This is to test how the behaviour differs between compact number formatting
// and general number formatting
private static final NumberFormat FORMAT_NO_PATTERNS = new CompactNumberFormat(
"#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US),
new String[]{"", "", "", "", "00K", "", "", "", "", "", "", "", "", "", ""});
@BeforeAll
void mutateInstances() {
FORMAT_FRACTION.setMinimumFractionDigits(2);
FORMAT_GROUPING.setGroupingSize(3);
FORMAT_GROUPING.setGroupingUsed(true);
FORMAT_MININTEGER.setMinimumIntegerDigits(5);
FORMAT_PARSEINTONLY.setParseIntegerOnly(true);
FORMAT_PARSEINTONLY.setGroupingUsed(true);
// Setting min fraction digits and other fields does not effect
// the general number formatting behaviour, when no compact number
// patterns are specified
FORMAT_NO_PATTERNS.setMinimumFractionDigits(2);
}
Object[][] compactFormatData() {
return new Object[][]{
{FORMAT_FRACTION, 1900, "1.90 thousand"},
{FORMAT_FRACTION, 1000, "1.00 thousand"},
{FORMAT_FRACTION, 9090.99, "9.09 thousand"},
{FORMAT_FRACTION, new BigDecimal(12346567890987654.32),
"12346.57 trillion"},
{FORMAT_FRACTION, new BigInteger("12346567890987654"),
"12346.57 trillion"},
{FORMAT_GROUPING, new BigDecimal(12346567890987654.32),
"12,347 trillion"},
{FORMAT_GROUPING, 100000, "100 thousand"},
{FORMAT_MININTEGER, 10000, "00010 thousand"},
{FORMAT_NO_PATTERNS, 100000, "100,000"},
{FORMAT_NO_PATTERNS, 1000.998, "1,001"},
{FORMAT_NO_PATTERNS, 10900, "10.90K"},
{FORMAT_NO_PATTERNS, new BigDecimal(12346567890987654.32), "12,346,567,890,987,654"},};
}
Object[][] compactParseData() {
return new Object[][]{
{FORMAT_FRACTION, "190 thousand", 190000L},
{FORMAT_FRACTION, "19.9 thousand", 19900L},
{FORMAT_GROUPING, "12,346 thousand", 12346000L},
{FORMAT_PARSEINTONLY, "12345 thousand", 12345000L},
{FORMAT_PARSEINTONLY, "12,345 thousand", 12345000L},
{FORMAT_PARSEINTONLY, "12.345 thousand", 12000L},};
}
@ParameterizedTest
@MethodSource("compactFormatData")
void formatCompactNumber(NumberFormat nf,
Object number, String expected) {
CompactFormatAndParseHelper.testFormat(nf, number, expected);
}
@ParameterizedTest
@MethodSource("compactParseData")
void parseCompactNumber(NumberFormat nf,
String parseString, Number expected) throws ParseException {
CompactFormatAndParseHelper.testParse(nf, parseString, expected, null, null);
}
}

View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8306116 8319990
* @summary Checks CNF.parse() when parseBigDecimal is set to true
* @modules jdk.localedata
* @run junit/othervm TestParseBigDecimal
*/
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigDecimal;
import java.text.CompactNumberFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestParseBigDecimal {
private static final CompactNumberFormat FORMAT_DZ_LONG = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.of("dz"), NumberFormat.Style.LONG);
private static final CompactNumberFormat FORMAT_EN_US_SHORT = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
private static final CompactNumberFormat FORMAT_EN_LONG = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG);
private static final CompactNumberFormat FORMAT_HI_IN_LONG = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.LONG);
private static final CompactNumberFormat FORMAT_JA_JP_SHORT = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT);
private static final CompactNumberFormat FORMAT_IT_SHORT = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.SHORT);
private static final CompactNumberFormat FORMAT_SW_LONG = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.of("sw"), NumberFormat.Style.LONG);
private static final CompactNumberFormat FORMAT_SE_SHORT = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.of("se"), NumberFormat.Style.SHORT);
@BeforeAll
void mutateInstances() {
FORMAT_DZ_LONG.setParseBigDecimal(true);
FORMAT_EN_US_SHORT.setParseBigDecimal(true);
FORMAT_EN_LONG.setParseBigDecimal(true);
FORMAT_HI_IN_LONG.setParseBigDecimal(true);
FORMAT_JA_JP_SHORT.setParseBigDecimal(true);
FORMAT_IT_SHORT.setParseBigDecimal(true);
FORMAT_SW_LONG.setParseBigDecimal(true);
FORMAT_SE_SHORT.setParseBigDecimal(true);
}
Object[][] compactParseData() {
return new Object[][]{
// compact number format instance, string to parse, parsed number
{FORMAT_DZ_LONG, "\u0F66\u0F9F\u0F7C\u0F44\u0F0B\u0F55\u0FB2"
+ "\u0F42 \u0F21", new BigDecimal("1000")},
{FORMAT_DZ_LONG, "-\u0F66\u0F9F\u0F7C\u0F44\u0F0B\u0F55\u0FB2"
+ "\u0F42 \u0F23", new BigDecimal("-3000")},
{FORMAT_DZ_LONG, "\u0F51\u0F74\u0F44\u0F0B\u0F55\u0FB1\u0F74\u0F62"
+ "\u0F0B\u0F66\u0F0B\u0F61\u0F0B \u0F21"
+ "\u0F22\u0F23\u0F24\u0F25\u0F27", new BigDecimal("12345700000000000000")},
{FORMAT_DZ_LONG, "-\u0F51\u0F74\u0F44\u0F0B\u0F55\u0FB1\u0F74\u0F62"
+ "\u0F0B\u0F66\u0F0B\u0F61\u0F0B \u0F21"
+ "\u0F22\u0F23\u0F24\u0F25\u0F27", new BigDecimal("-12345700000000000000")},
{FORMAT_EN_US_SHORT, "-0.0", new BigDecimal("-0.0")},
{FORMAT_EN_US_SHORT, "0", new BigDecimal("0")},
{FORMAT_EN_US_SHORT, "499", new BigDecimal("499")},
{FORMAT_EN_US_SHORT, "-499", new BigDecimal("-499")},
{FORMAT_EN_US_SHORT, "499.89", new BigDecimal("499.89")},
{FORMAT_EN_US_SHORT, "-499.89", new BigDecimal("-499.89")},
{FORMAT_EN_US_SHORT, "1K", new BigDecimal("1000")},
{FORMAT_EN_US_SHORT, "-1K", new BigDecimal("-1000")},
{FORMAT_EN_US_SHORT, "3K", new BigDecimal("3000")},
{FORMAT_EN_US_SHORT, "-3K", new BigDecimal("-3000")},
{FORMAT_EN_US_SHORT, "17K", new BigDecimal("17000")},
{FORMAT_EN_US_SHORT, "-17K", new BigDecimal("-17000")},
{FORMAT_EN_US_SHORT, "12345678901234567890",
new BigDecimal("12345678901234567890")},
{FORMAT_EN_US_SHORT, "12345679T", new BigDecimal("12345679000000000000")},
{FORMAT_EN_US_SHORT, "-12345679T", new BigDecimal("-12345679000000000000")},
{FORMAT_EN_US_SHORT, "599.01K", new BigDecimal("599010.00")},
{FORMAT_EN_US_SHORT, "-599.01K", new BigDecimal("-599010.00")},
{FORMAT_EN_US_SHORT, "599444444.90T", new BigDecimal("599444444900000000000.00")},
{FORMAT_EN_US_SHORT, "-599444444.90T", new BigDecimal("-599444444900000000000.00")},
{FORMAT_EN_US_SHORT, "123456789012345.5678K",
new BigDecimal("123456789012345567.8000")},
{FORMAT_EN_US_SHORT, "17.000K", new BigDecimal("17000.000")},
{FORMAT_EN_US_SHORT, "123.56678K", new BigDecimal("123566.78000")},
{FORMAT_EN_US_SHORT, "-123.56678K", new BigDecimal("-123566.78000")},
{FORMAT_EN_LONG, "999", new BigDecimal("999")},
{FORMAT_EN_LONG, "1 thousand", new BigDecimal("1000")},
{FORMAT_EN_LONG, "3 thousand", new BigDecimal("3000")},
{FORMAT_EN_LONG, "12345679 trillion", new BigDecimal("12345679000000000000")},
{FORMAT_HI_IN_LONG, "999", new BigDecimal("999")},
{FORMAT_HI_IN_LONG, "-999", new BigDecimal("-999")},
{FORMAT_HI_IN_LONG, "1 \u0939\u091C\u093C\u093E\u0930", new BigDecimal("1000")},
{FORMAT_HI_IN_LONG, "-1 \u0939\u091C\u093C\u093E\u0930", new BigDecimal("-1000")},
{FORMAT_HI_IN_LONG, "3 \u0939\u091C\u093C\u093E\u0930", new BigDecimal("3000")},
{FORMAT_HI_IN_LONG, "12345679 \u0916\u0930\u092C", new BigDecimal("1234567900000000000")},
{FORMAT_HI_IN_LONG, "-12345679 \u0916\u0930\u092C", new BigDecimal("-1234567900000000000")},
{FORMAT_JA_JP_SHORT, "-99", new BigDecimal("-99")},
{FORMAT_JA_JP_SHORT, "1\u4E07", new BigDecimal("10000")},
{FORMAT_JA_JP_SHORT, "30\u4E07", new BigDecimal("300000")},
{FORMAT_JA_JP_SHORT, "-30\u4E07", new BigDecimal("-300000")},
{FORMAT_JA_JP_SHORT, "12345679\u5146", new BigDecimal("12345679000000000000")},
{FORMAT_JA_JP_SHORT, "-12345679\u5146", new BigDecimal("-12345679000000000000")},
{FORMAT_IT_SHORT, "-99", new BigDecimal("-99")},
{FORMAT_IT_SHORT, "1\u00a0Mln", new BigDecimal("1000000")},
{FORMAT_IT_SHORT, "30\u00a0Mln", new BigDecimal("30000000")},
{FORMAT_IT_SHORT, "-30\u00a0Mln", new BigDecimal("-30000000")},
{FORMAT_IT_SHORT, "12345679\u00a0Bln", new BigDecimal("12345679000000000000")},
{FORMAT_IT_SHORT, "-12345679\u00a0Bln", new BigDecimal("-12345679000000000000")},
{FORMAT_SW_LONG, "-0.0", new BigDecimal("-0.0")},
{FORMAT_SW_LONG, "499", new BigDecimal("499")},
{FORMAT_SW_LONG, "elfu 1", new BigDecimal("1000")},
{FORMAT_SW_LONG, "elfu 3", new BigDecimal("3000")},
{FORMAT_SW_LONG, "elfu 17", new BigDecimal("17000")},
{FORMAT_SW_LONG, "elfu -3", new BigDecimal("-3000")},
{FORMAT_SW_LONG, "-499", new BigDecimal("-499")},
{FORMAT_SW_LONG, "elfu 1", new BigDecimal("1000")},
{FORMAT_SW_LONG, "elfu 3", new BigDecimal("3000")},
{FORMAT_SW_LONG, "elfu -3", new BigDecimal("-3000")},
{FORMAT_SW_LONG, "elfu 17", new BigDecimal("17000")},
{FORMAT_SW_LONG, "trilioni 12345679", new BigDecimal("12345679000000000000")},
{FORMAT_SW_LONG, "trilioni -12345679", new BigDecimal("-12345679000000000000")},
{FORMAT_SW_LONG, "elfu 599.01", new BigDecimal("599010.00")},
{FORMAT_SW_LONG, "elfu -599.01", new BigDecimal("-599010.00")},
{FORMAT_SE_SHORT, "999", new BigDecimal("999")},
{FORMAT_SE_SHORT, "8\u00a0mn", new BigDecimal("8000000")},
{FORMAT_SE_SHORT, "8\u00a0dt", new BigDecimal("8000")},
{FORMAT_SE_SHORT, "12345679\u00a0bn", new BigDecimal("12345679000000000000")},
{FORMAT_SE_SHORT, "12345679,89\u00a0bn", new BigDecimal("12345679890000000000.00")},
{FORMAT_SE_SHORT, "\u2212999", new BigDecimal("-999")},
{FORMAT_SE_SHORT, "\u22128\u00a0mn", new BigDecimal("-8000000")},
{FORMAT_SE_SHORT, "\u22128\u00a0dt", new BigDecimal("-8000")},
{FORMAT_SE_SHORT, "\u221212345679\u00a0bn", new BigDecimal("-12345679000000000000")},
{FORMAT_SE_SHORT, "\u221212345679,89\u00a0bn", new BigDecimal("-12345679890000000000.00")},};
}
@ParameterizedTest
@MethodSource("compactParseData")
void testParse(NumberFormat cnf, String parseString,
Number expected) throws ParseException {
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, BigDecimal.class);
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8222756
* @summary Tests plurals support in CompactNumberFormat
* @run junit/othervm TestPlurals
*/
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestPlurals {
private final static DecimalFormatSymbols DFS = DecimalFormatSymbols.getInstance(Locale.ROOT);
private final static String[] PATTERN = {
"{zero:0->zero one:0->one two:0->two few:0->few many:0->many other:0->other}"};
private final static String RULE_1 = "zero:n = 0; one:n = 1; two:n = 2; few:n = 3..4; many:n = 5..6,8";
private final static String RULE_2 = "one:n % 2 = 1 or n / 3 = 2;";
private final static String RULE_3 = "one:n%2=0andn/3=2;";
Object[][] pluralRules() {
return new Object[][]{
// rules, number, expected
{RULE_1, 0, "0->zero"},
{RULE_1, 1, "1->one"},
{RULE_1, 2, "2->two"},
{RULE_1, 3, "3->few"},
{RULE_1, 4, "4->few"},
{RULE_1, 5, "5->many"},
{RULE_1, 6, "6->many"},
{RULE_1, 7, "7->other"},
{RULE_1, 8, "8->many"},
{RULE_1, 9, "9->other"},
{RULE_2, 0, "0->other"},
{RULE_2, 1, "1->one"},
{RULE_2, 2, "2->other"},
{RULE_2, 3, "3->one"},
{RULE_2, 4, "4->other"},
{RULE_2, 5, "5->one"},
{RULE_2, 6, "6->one"},
{RULE_3, 0, "0->other"},
{RULE_3, 1, "1->other"},
{RULE_3, 2, "2->other"},
{RULE_3, 3, "3->other"},
{RULE_3, 4, "4->other"},
{RULE_3, 5, "5->other"},
{RULE_3, 6, "6->one"},
};
}
Object[][] invalidRules() {
return new Object [][] {
{"one:a = 1"},
{"on:n = 1"},
{"one:n = 1...2"},
{"one:n = 1.2"},
{"one:n = 1..2,"},
{"one:n = 1;one:n = 2"},
{"foo:n = 1"},
{"one:n = 1..2 andor v % 10 != 0"},
};
}
@Test
void testNullPluralRules() {
assertThrows(NullPointerException.class, () -> {
String[] pattern = {""};
new CompactNumberFormat("#", DFS, PATTERN, null);
});
}
@ParameterizedTest
@MethodSource("pluralRules")
void testPluralRules(String rules, Number n, String expected) {
var cnp = new CompactNumberFormat("#", DFS, PATTERN, rules);
assertEquals(expected, cnp.format(n));
}
@ParameterizedTest
@MethodSource("invalidRules")
void testInvalidRules(String rules) {
assertThrows(IllegalArgumentException.class,
() -> new CompactNumberFormat("#", DFS, PATTERN, rules));
}
@Test
void testLimitExceedingRules() {
assertThrows(IllegalArgumentException.class, () -> {
String andCond = " and n = 1";
String invalid = "one: n = 1" + andCond.repeat(2_048 / andCond.length());
new CompactNumberFormat("#", DFS, PATTERN, invalid);
});
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552
* @summary Checks the formatting and parsing of special values
* @modules jdk.localedata
* @run junit/othervm TestSpecialValues
*/
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestSpecialValues {
private static final NumberFormat FORMAT = NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
Object[][] formatSpecialValues() {
return new Object[][]{
// number , formatted ouput
{+0.0, "0"},
{-0.0, "-0"},
{Double.MIN_VALUE, "0"},
{Double.MIN_NORMAL, "0"},
{Double.NaN, "NaN"},
{Double.POSITIVE_INFINITY, "\u221E"},
{Double.NEGATIVE_INFINITY, "-\u221E"},
{Long.MIN_VALUE, "-9223372T"},
{Long.MAX_VALUE, "9223372T"},};
}
Object[][] parseSpecialValues() {
return new Object[][]{
// parse string, parsed number
{"-0.0", -0.0},
{"" + Long.MIN_VALUE, Long.MIN_VALUE},
{"" + Long.MAX_VALUE, Long.MAX_VALUE},
{"NaN", Double.NaN},
{"\u221E", Double.POSITIVE_INFINITY},
{"-\u221E", Double.NEGATIVE_INFINITY},};
}
@ParameterizedTest
@MethodSource("formatSpecialValues")
void testFormatSpecialValues(Object number, String expected) {
CompactFormatAndParseHelper.testFormat(FORMAT, number, expected);
}
@ParameterizedTest
@MethodSource("parseSpecialValues")
void testParseSpecialValues(String parseString, Number expected)
throws ParseException {
CompactFormatAndParseHelper.testParse(FORMAT, parseString, expected, null, null);
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8221432
* @summary Checks the behaviour of Unicode BCP 47 U Extension with
* compact number format
* @modules jdk.localedata
* @run junit/othervm TestUExtensionOverride
*/
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestUExtensionOverride {
Object[][] compactFormatData() {
return new Object[][]{
// locale, number, formatted string
// -nu
{Locale.forLanguageTag("en-US-u-nu-deva"), 12345, "\u0967\u0968K"},
{Locale.forLanguageTag("en-US-u-nu-sinh"), 12345, "\u0de7\u0de8K"},
{Locale.forLanguageTag("en-US-u-nu-zzzz"), 12345, "12K"},
// -rg
{Locale.forLanguageTag("fr-FR-u-rg-cazzzz"), 1234567,
"1\u00a0M"},
{Locale.forLanguageTag("fr-FR-u-rg-cazzzz"), 1234567890,
"1\u00a0G"},
// -nu and -rg
{Locale.forLanguageTag("en-US-u-nu-deva-rg-dezzzz"), 12345,
"\u0967\u0968K"},
{Locale.forLanguageTag("fr-FR-u-nu-zzzz-rg-cazzzz"), 1234567890,
"1\u00a0Md"},
{Locale.forLanguageTag("fr-FR-u-nu-zzzz-rg-zzzz"), 12345,
"12\u00a0k"},
{Locale.forLanguageTag("fr-FR-u-rg-cazzzz-nu-deva"), 12345,
"\u0967\u0968\u00a0k"},};
}
Object[][] compactParseData() {
return new Object[][]{
// locale, parse string, parsed number
// -nu
{Locale.forLanguageTag("en-US-u-nu-deva"),
"\u0967\u0968K", 12000L},
{Locale.forLanguageTag("en-US-u-nu-sinh"),
"\u0de7\u0de8K", 12000L},
{Locale.forLanguageTag("en-US-u-nu-zzzz"),
"12K", 12000L},
// -rg
{Locale.forLanguageTag("fr-FR-u-rg-cazzzz"),
"1\u00a0G", 1000000000L},
// -nu and -rg
{Locale.forLanguageTag("en-US-u-nu-deva-rg-dezzzz"),
"\u0967\u0968K", 12000L},
{Locale.forLanguageTag("fr-FR-u-nu-zzzz-rg-cazzzz"),
"1\u00a0Md", 1000000000L},
{Locale.forLanguageTag("fr-FR-u-nu-zzzz-rg-zzzz"),
"12\u00a0k", 12000L},
{Locale.forLanguageTag("fr-FR-u-rg-cazzzz-nu-deva"),
"\u0967\u0968\u00a0k", 12000L},};
}
@ParameterizedTest
@MethodSource("compactFormatData")
void testFormat(Locale locale, double num,
String expected) {
NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale,
NumberFormat.Style.SHORT);
CompactFormatAndParseHelper.testFormat(cnf, num, expected);
}
@ParameterizedTest
@MethodSource("compactParseData")
void testParse(Locale locale, String parseString,
Number expected) throws ParseException {
NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale,
NumberFormat.Style.SHORT);
CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null);
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8321545
* @summary Ensure value returned by overridden toString method is as expected
* @run junit ToStringTest
*/
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ToStringTest {
// Check a normal expected value. There is no null test as the getInstance
// methods and constructor (which takes DFS) throw NPE if the locale param is null.
@Test
public void expectedValueTest() {
String expectedStr = "CompactNumberFormat [locale: \"English (Canada)\", decimal pattern: \"#,##0.###\", compact patterns: \"[, , , {one:0' 'thousand other:0' 'thousand}, {one:00' 'thousand other:00' 'thousand}, {one:000' 'thousand other:000' 'thousand}, {one:0' 'million other:0' 'million}, {one:00' 'million other:00' 'million}, {one:000' 'million other:000' 'million}, {one:0' 'billion other:0' 'billion}, {one:00' 'billion other:00' 'billion}, {one:000' 'billion other:000' 'billion}, {one:0' 'trillion other:0' 'trillion}, {one:00' 'trillion other:00' 'trillion}, {one:000' 'trillion other:000' 'trillion}]\"]\n";
var c = NumberFormat.getCompactNumberInstance(Locale.CANADA, NumberFormat.Style.LONG);
assertEquals(expectedStr, c.toString());
}
// Check an odd value with empty decimal pattern and compact patterns.
@Test
public void oddValueTest() {
String expectedStr = "CompactNumberFormat [locale: \"English (Canada)\", decimal pattern: \"\", compact patterns: \"[]\"]\n";
var c = new CompactNumberFormat("", new DecimalFormatSymbols(Locale.CANADA), new String[]{});
assertEquals(expectedStr, c.toString());
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
module provider {
exports test;
provides java.text.spi.NumberFormatProvider with test.NumberFormatProviderImpl;
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package test;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.spi.NumberFormatProvider;
import java.util.Locale;
public class NumberFormatProviderImpl extends NumberFormatProvider {
private static final Locale QAA = Locale.forLanguageTag("qaa");
private static final Locale QAB = Locale.forLanguageTag("qab");
private static final Locale[] locales = {QAA, QAB};
private static final String[] oldPattern = {
// old US short compact format
"",
"",
"",
"0K",
"00K",
"000K",
"0M",
"00M",
"000M",
"0B",
"00B",
"000B",
"0T",
"00T",
"000T"
};
private static final String[] newPattern = {
"",
"",
"",
"{one:0K;(0K) two:0KK few:0KKK other:0KKKK}",
"",
"",
"{one:0' 'M;(0' 'M) two:0' 'MM;(0' 'MM) few:0' 'MMM other:0' 'MMMM}"
};
@Override
public NumberFormat getCurrencyInstance(Locale locale) {
return null;
}
@Override
public NumberFormat getIntegerInstance(Locale locale) {
return null;
}
@Override
public NumberFormat getNumberInstance(Locale locale) {
return null;
}
@Override
public NumberFormat getPercentInstance(Locale locale) {
return null;
}
@Override
public NumberFormat getCompactNumberInstance(Locale locale,
NumberFormat.Style style) {
if (locale.equals(QAB)) {
return new CompactNumberFormat(
"#",
DecimalFormatSymbols.getInstance(locale),
newPattern,
"one:v = 0 and i % 100 = 1;" +
"two:v = 0 and i % 100 = 2;" +
"few:v = 0 and i % 100 = 3..4 or v != 0;" +
"other:");
} else if (locale.equals(QAA)) {
return new CompactNumberFormat(
"#",
DecimalFormatSymbols.getInstance(locale),
oldPattern);
} else {
throw new RuntimeException("unsupported locale");
}
}
@Override
public Locale[] getAvailableLocales() {
return locales;
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552
* @modules jdk.localedata
* @summary Checks deserialization of compact number format
* @library /java/text/testlib
* @build TestDeserializeCNF HexDumpReader
* @run junit/othervm TestDeserializeCNF
*/
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.math.RoundingMode;
import java.text.CompactNumberFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestDeserializeCNF {
// This object is serialized in cnf1.ser.txt with HALF_UP
// rounding mode, groupingsize = 3 and parseBigDecimal = true
private static final CompactNumberFormat COMPACT_FORMAT1 = new CompactNumberFormat("#,##0.###",
DecimalFormatSymbols.getInstance(Locale.US),
new String[]{"", "", "", "0K", "00K", "000K", "0M", "00M", "000M", "0B", "00B", "000B", "0T", "00T", "000T"});
// This object is serialized in cnf2.ser.txt with min integer digits = 20
// and min fraction digits = 5
private static final CompactNumberFormat COMPACT_FORMAT2 = new CompactNumberFormat("#,##0.###",
DecimalFormatSymbols.getInstance(Locale.JAPAN),
new String[]{"", "", "", "0", "0\u4e07", "00\u4e07", "000\u4e07", "0000\u4e07", "0\u5104", "00\u5104", "000\u5104", "0000\u5104", "0\u5146", "00\u5146", "000\u5146"});
private static final String FILE_COMPACT_FORMAT1 = "cnf1.ser.txt";
private static final String FILE_COMPACT_FORMAT2 = "cnf2.ser.txt";
@BeforeAll
void mutateInstances() {
COMPACT_FORMAT1.setRoundingMode(RoundingMode.HALF_UP);
COMPACT_FORMAT1.setGroupingSize(3);
COMPACT_FORMAT1.setParseBigDecimal(true);
COMPACT_FORMAT2.setMinimumIntegerDigits(20);
COMPACT_FORMAT2.setMinimumFractionDigits(5);
}
@Test
void testDeserialization() throws IOException, ClassNotFoundException {
try (InputStream istream1 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT1);
ObjectInputStream ois1 = new ObjectInputStream(istream1);
InputStream istream2 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT2);
ObjectInputStream ois2 = new ObjectInputStream(istream2);) {
CompactNumberFormat obj1 = (CompactNumberFormat) ois1.readObject();
assertEquals(COMPACT_FORMAT1, obj1, "Deserialized instance is not"
+ " equal to the instance serialized in " + FILE_COMPACT_FORMAT1);
CompactNumberFormat obj2 = (CompactNumberFormat) ois2.readObject();
assertEquals(COMPACT_FORMAT2, obj2, "Deserialized instance is not"
+ " equal to the instance serialized in " + FILE_COMPACT_FORMAT2);
}
}
// The objects are serialized using the serialize() method, the hex
// dump printed is copied to respective object files
// void serialize(CompactNumberFormat cnf) {
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
// oos.writeObject(cnf);
// } catch (IOException ioe) {
// throw new RuntimeException(ioe);
// }
// byte[] ser = baos.toByteArray();
// for (byte b : ser) {
// System.out.print("" + String.format("%02x", b));
// }
// }
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8177552 8327640
* @modules jdk.localedata
* @summary Checks the serialization feature of CompactNumberFormat
* @run junit/othervm TestSerialization
*/
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.RoundingMode;
import java.text.CompactNumberFormat;
import java.text.NumberFormat;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestSerialization {
private static final NumberFormat FORMAT_HI = NumberFormat.getCompactNumberInstance(
Locale.of("hi"), NumberFormat.Style.SHORT);
private static final CompactNumberFormat FORMAT_EN_US = (CompactNumberFormat) NumberFormat
.getCompactNumberInstance(Locale.US, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_JA_JP = NumberFormat.getCompactNumberInstance(
Locale.JAPAN, NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_FR_FR = NumberFormat.getCompactNumberInstance(
Locale.FRANCE, NumberFormat.Style.LONG);
private static final NumberFormat FORMAT_DE_DE = NumberFormat.getCompactNumberInstance(
Locale.GERMANY, NumberFormat.Style.SHORT);
private static final NumberFormat FORMAT_KO_KR = NumberFormat.getCompactNumberInstance(
Locale.KOREA, NumberFormat.Style.SHORT);
@BeforeAll
void mutateInstances() {
FORMAT_HI.setMinimumFractionDigits(2);
FORMAT_HI.setMinimumIntegerDigits(5);
FORMAT_EN_US.setRoundingMode(RoundingMode.HALF_UP);
FORMAT_EN_US.setGroupingSize(3);
FORMAT_EN_US.setParseBigDecimal(true);
FORMAT_JA_JP.setMaximumFractionDigits(30);
FORMAT_JA_JP.setMaximumIntegerDigits(30);
FORMAT_FR_FR.setParseIntegerOnly(true);
FORMAT_FR_FR.setGroupingUsed(true);
FORMAT_FR_FR.setStrict(true);
// Setting minimum integer digits beyond the allowed range
FORMAT_DE_DE.setMinimumIntegerDigits(320);
// Setting minimum fraction digits beyond the allowed range
FORMAT_KO_KR.setMinimumFractionDigits(350);
}
@Test
void testSerialization() throws IOException, ClassNotFoundException {
// Serialize
serialize("cdf.ser", FORMAT_HI, FORMAT_EN_US, FORMAT_JA_JP, FORMAT_FR_FR, FORMAT_DE_DE, FORMAT_KO_KR);
// Deserialize
deserialize("cdf.ser", FORMAT_HI, FORMAT_EN_US, FORMAT_JA_JP, FORMAT_FR_FR, FORMAT_DE_DE, FORMAT_KO_KR);
}
private void serialize(String fileName, NumberFormat... formats)
throws IOException {
try (ObjectOutputStream os = new ObjectOutputStream(
new FileOutputStream(fileName))) {
for (NumberFormat fmt : formats) {
os.writeObject(fmt);
}
}
}
private static void deserialize(String fileName, NumberFormat... formats)
throws IOException, ClassNotFoundException {
try (ObjectInputStream os = new ObjectInputStream(
new FileInputStream(fileName))) {
for (NumberFormat fmt : formats) {
NumberFormat obj = (NumberFormat) os.readObject();
assertEquals(obj, fmt, "Serialized and deserialized"
+ " objects do not match");
long number = 123456789789L;
String expected = fmt.format(number);
String actual = obj.format(number);
assertEquals(expected, actual, "Serialized and deserialized"
+ " objects are expected to return same formatted"
+ " output for number: " + number);
}
}
}
}

View file

@ -0,0 +1,64 @@
#
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Hex dump of a serialized CompactNumberFormat for TestDeserializeCNF.
aced00057372001d6a6176612e746578742e436f6d706163744e756d626572466f726d
617462ed0c37b8207cf602000642000c67726f7570696e6753697a655a000f70617273
65426967446563696d616c5b000f636f6d706163745061747465726e737400135b4c6a
6176612f6c616e672f537472696e673b4c000e646563696d616c5061747465726e7400
124c6a6176612f6c616e672f537472696e673b4c000c726f756e64696e674d6f646574
00184c6a6176612f6d6174682f526f756e64696e674d6f64653b4c000773796d626f6c
737400204c6a6176612f746578742f446563696d616c466f726d617453796d626f6c73
3b787200166a6176612e746578742e4e756d626572466f726d6174dff6b3bf137d07e8
03000b5a000c67726f7570696e67557365644200116d61784672616374696f6e446967
6974734200106d6178496e74656765724469676974734900156d6178696d756d467261
6374696f6e4469676974734900146d6178696d756d496e746567657244696769747342
00116d696e4672616374696f6e4469676974734200106d696e496e7465676572446967
6974734900156d696e696d756d4672616374696f6e4469676974734900146d696e696d
756d496e74656765724469676974735a00107061727365496e74656765724f6e6c7949
001573657269616c56657273696f6e4f6e53747265616d787200106a6176612e746578
742e466f726d6174fbd8bc12e90f1843020000787000007f0000000000000135000100
000000000000010000000001780301757200135b4c6a6176612e6c616e672e53747269
6e673badd256e7e91d7b4702000078700000000f74000071007e000a71007e000a7400
02304b74000330304b7400043030304b740002304d74000330304d7400043030304d74
0002304274000330304274000430303042740002305474000330305474000430303054
740009232c2323302e2323237e7200166a6176612e6d6174682e526f756e64696e674d
6f646500000000000000001200007872000e6a6176612e6c616e672e456e756d000000
0000000000120000787074000748414c465f55507372001e6a6176612e746578742e44
6563696d616c466f726d617453796d626f6c73501d17990868939c0200114300106465
63696d616c536570617261746f72430005646967697443000b6578706f6e656e746961
6c43001167726f7570696e67536570617261746f724300096d696e75735369676e4300
116d6f6e6574617279536570617261746f724300107061747465726e53657061726174
6f724300077065724d696c6c43000770657263656e7449001573657269616c56657273
696f6e4f6e53747265616d4300097a65726f44696769744c00034e614e71007e00024c
000e63757272656e637953796d626f6c71007e00024c00146578706f6e656e7469616c
536570617261746f7271007e00024c0008696e66696e69747971007e00024c0012696e
746c43757272656e637953796d626f6c71007e00024c00066c6f63616c657400124c6a
6176612f7574696c2f4c6f63616c653b7870002e00230045002c002d002e003b203000
250000000300307400034e614e7074000145740003e2889e70737200106a6176612e75
74696c2e4c6f63616c657ef811609c30f9ec03000649000868617368636f64654c0007
636f756e74727971007e00024c000a657874656e73696f6e7371007e00024c00086c61
6e677561676571007e00024c000673637269707471007e00024c000776617269616e74
71007e00027870ffffffff740002555371007e000a740002656e71007e000a71007e00
0a78

View file

@ -0,0 +1,64 @@
#
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Hex dump of a serialized CompactNumberFormat for TestDeserializeCNF.
aced00057372001d6a6176612e746578742e436f6d706163744e756d626572466f726d
617462ed0c37b8207cf602000642000c67726f7570696e6753697a655a000f70617273
65426967446563696d616c5b000f636f6d706163745061747465726e737400135b4c6a
6176612f6c616e672f537472696e673b4c000e646563696d616c5061747465726e7400
124c6a6176612f6c616e672f537472696e673b4c000c726f756e64696e674d6f646574
00184c6a6176612f6d6174682f526f756e64696e674d6f64653b4c000773796d626f6c
737400204c6a6176612f746578742f446563696d616c466f726d617453796d626f6c73
3b787200166a6176612e746578742e4e756d626572466f726d6174dff6b3bf137d07e8
03000b5a000c67726f7570696e67557365644200116d61784672616374696f6e446967
6974734200106d6178496e74656765724469676974734900156d6178696d756d467261
6374696f6e4469676974734900146d6178696d756d496e746567657244696769747342
00116d696e4672616374696f6e4469676974734200106d696e496e7465676572446967
6974734900156d696e696d756d4672616374696f6e4469676974734900146d696e696d
756d496e74656765724469676974735a00107061727365496e74656765724f6e6c7949
001573657269616c56657273696f6e4f6e53747265616d787200106a6176612e746578
742e466f726d6174fbd8bc12e90f1843020000787000057f0000000500000135051400
000005000000140000000001780000757200135b4c6a6176612e6c616e672e53747269
6e673badd256e7e91d7b4702000078700000000f74000071007e000a71007e000a7400
013074000430e4b8877400053030e4b887740006303030e4b88774000730303030e4b8
8774000430e584847400053030e58484740006303030e5848474000730303030e58484
74000430e585867400053030e58586740006303030e58586740009232c2323302e2323
237e7200166a6176612e6d6174682e526f756e64696e674d6f64650000000000000000
1200007872000e6a6176612e6c616e672e456e756d0000000000000000120000787074
000948414c465f4556454e7372001e6a6176612e746578742e446563696d616c466f72
6d617453796d626f6c73501d17990868939c020011430010646563696d616c53657061
7261746f72430005646967697443000b6578706f6e656e7469616c43001167726f7570
696e67536570617261746f724300096d696e75735369676e4300116d6f6e6574617279
536570617261746f724300107061747465726e536570617261746f724300077065724d
696c6c43000770657263656e7449001573657269616c56657273696f6e4f6e53747265
616d4300097a65726f44696769744c00034e614e71007e00024c000e63757272656e63
7953796d626f6c71007e00024c00146578706f6e656e7469616c536570617261746f72
71007e00024c0008696e66696e69747971007e00024c0012696e746c43757272656e63
7953796d626f6c71007e00024c00066c6f63616c657400124c6a6176612f7574696c2f
4c6f63616c653b7870002e00230045002c002d002e003b203000250000000300307400
034e614e7074000145740003e2889e70737200106a6176612e7574696c2e4c6f63616c
657ef811609c30f9ec03000649000868617368636f64654c0007636f756e7472797100
7e00024c000a657874656e73696f6e7371007e00024c00086c616e677561676571007e
00024c000673637269707471007e00024c000776617269616e7471007e00027870ffff
ffff7400024a5071007e000a7400026a6171007e000a71007e000a78

View file

@ -0,0 +1,367 @@
/*
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4322313 4833268 6302990 6304305
* @summary Make sure that new implementation for
* SimpleDateFormat.parse('z' or 'Z') and format('z' or 'Z') work correctly.
* @run junit Bug4322313
*/
import java.io.*;
import java.text.*;
import java.util.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Bug4322313 {
@Test
public void Test4322313() {
Locale savedLocale = Locale.getDefault();
TimeZone savedTimeZone = TimeZone.getDefault();
boolean err = false;
long mpm = 60 * 1000; /* Milliseconds per a minute */
Locale[] locs = {Locale.US, Locale.JAPAN, Locale.UK, Locale.of("ar")};
String[] formats = {
"z",
"Z",
};
Object[][] valids = {
/* given ID offset format('z'), ('Z') index */
{"GMT+03:04", -184L * mpm, "GMT+03:04", "+0304", 9},
{"GMT+13:42", -822L * mpm, "GMT+13:42", "+1342", 9},
{"GMT+00:00", 0L, "GMT+00:00", "+0000", 9},
{"GMT+1:11", -71L * mpm, "GMT+01:11", "+0111", 8},
{"GMT +13:42", 0L, "GMT", "+0000", 3},
{" GMT", 0L, "GMT", "+0000", 4},
{"+0304", -184L * mpm, "GMT+03:04", "+0304", 5},
{"+1342", -822L * mpm, "GMT+13:42", "+1342", 5},
{"+0000", 0L, "GMT+00:00", "+0000", 5},
{" +1342", -822L * mpm, "GMT+13:42", "+1342", 6},
/* ISO-LATIN-1 digits */
{"GMT+\u0030\u0031:\u0032\u0033", -83L * mpm, "GMT+01:23", "+0123", 9},
/* In fact, this test case is skipped because TimeZone class can't
* recognize TimeZone IDs like "+00234" or "-00234".
*/
{"+00234", -23L * mpm, "GMT+00:23", "+0023", 5},
{"GMT-03:04", 184L * mpm, "GMT-03:04", "-0304", 9},
{"GMT-13:42", 822L * mpm, "GMT-13:42", "-1342", 9},
{"GMT-00:00", 0L, "GMT+00:00", "+0000", 9},
{"GMT-1:11", 71L * mpm, "GMT-01:11", "-0111", 8},
{"GMT -13:42", 0L, "GMT", "+0000", 3},
{"-0304", 184L * mpm, "GMT-03:04", "-0304", 5},
{"-1342", 822L * mpm, "GMT-13:42", "-1342", 5},
{" -1342", 822L * mpm, "GMT-13:42", "-1342", 6},
/* ISO-LATIN-1 digits */
{"GMT-\u0030\u0031:\u0032\u0033", 83L * mpm, "GMT-01:23", "-0123", 9},
/* In fact, this test case is skipped because TimeZone class can't
* recognize TimeZone IDs like "+00234" or "-00234".
*/
{"-00234", 23L * mpm, "GMT+00:23", "-0023", 5},
};
Object[][] invalids = {
/* given ID error index */
{"GMT+8", 5},
{"GMT+18", 6},
{"GMT+208", 6},
{"GMT+0304", 6},
{"GMT+42195", 5},
{"GMT+5:8", 7},
{"GMT+23:60", 8},
{"GMT+11:1", 8},
{"GMT+24:13", 5},
{"GMT+421:950", 5},
{"GMT+0a:0A", 5},
{"GMT+ 13:42", 4},
{"GMT+13 :42", 6},
{"GMT+13: 42", 7},
{"GMT+-13:42", 4},
{"G M T", 0},
{"+8", 2},
{"+18", 3},
{"+208", 4},
{"+2360", 4},
{"+2413", 2},
{"+42195", 2},
{"+0AbC", 2},
{"+ 1342", 1},
{"+-1342", 1},
{"1342", 0},
/* Arabic-Indic digits */
{"GMT+\u0660\u0661:\u0662\u0663", 4},
/* Extended Arabic-Indic digits */
{"GMT+\u06f0\u06f1:\u06f2\u06f3", 4},
/* Devanagari digits */
{"GMT+\u0966\u0967:\u0968\u0969", 4},
/* Fullwidth digits */
{"GMT+\uFF10\uFF11:\uFF12\uFF13", 4},
{"GMT-8", 5},
{"GMT-18", 6},
{"GMT-208", 6},
{"GMT-0304", 6},
{"GMT-42195", 5},
{"GMT-5:8", 7},
{"GMT-23:60", 8},
{"GMT-11:1", 8},
{"GMT-24:13", 5},
{"GMT-421:950", 5},
{"GMT-0a:0A", 5},
{"GMT- 13:42", 4},
{"GMT-13 :42", 6},
{"GMT-13: 42", 7},
{"GMT-+13:42", 4},
{"-8", 2},
{"-18", 3},
{"-208", 4},
{"-2360", 4},
{"-2413", 2},
{"-42195", 2},
{"-0AbC", 2},
{"- 1342", 1},
{"--1342", 1},
{"-802", 2},
/* Arabic-Indic digits */
{"GMT-\u0660\u0661:\u0662\u0663", 4},
/* Extended Arabic-Indic digits */
{"GMT-\u06f0\u06f1:\u06f2\u06f3", 4},
/* Devanagari digits */
{"GMT-\u0966\u0967:\u0968\u0969", 4},
/* Fullwidth digits */
{"GMT-\uFF10\uFF11:\uFF12\uFF13", 4},
};
try {
for (int i=0; i < locs.length; i++) {
Locale locale = locs[i];
Locale.setDefault(locale);
for (int j=0; j < formats.length; j++) {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
SimpleDateFormat sdf = new SimpleDateFormat(formats[j]);
Date date;
/* Okay case */
for (int k=0; k < valids.length; k++) {
ParsePosition pos = new ParsePosition(0);
try {
date = sdf.parse((String)valids[k][0], pos);
}
catch (Exception e) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + valids[k][0] +
"\"] Unexpected Exception occurred: " + e);
continue;
}
int offset = pos.getIndex();
if (offset != ((Integer)valids[k][4]).intValue()) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + valids[k][0] +
"\"] invalid index: expected:" + valids[k][4] +
", got:" + offset);
}
if (date.getTime() != ((Long)valids[k][1]).longValue()) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + valids[k][0] +
"\"] expected:" + valids[k][1] +
", got:" + date.getTime() + ", " + date);
} else {
/*
System.out.println("\tParse Okay [Locale=" +
locale) + ", " + formats[j] +
"/\"" + valids[k][0] +
"\"] expected:" + valids[k][1] +
", got:" + date.getTime() + ", " + date);
*/
try {
date = sdf.parse((String)valids[k][0]);
}
catch (Exception e) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + valids[k][0] +
"\"] Unexpected Exception occurred: " + e);
continue;
}
/* Since TimeZone.getTimeZone() don't treat
* "+00234" or "-00234" as a valid ID, skips.
*/
if (((String)valids[k][0]).length() == 6) {
continue;
}
/* Since TimeZone.getTimeZone() don't recognize
* +hhmm/-hhmm format, add "GMT" as prefix.
*/
sdf.setTimeZone(TimeZone.getTimeZone(
(((((String)valids[k][0]).charAt(0) != 'G') ?
"GMT" : "") + valids[k][0])));
StringBuffer s = new StringBuffer();
sdf.format(date, s, new FieldPosition(0));
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String got = s.toString();
String expected = (String)valids[k][2+j];
if (!got.equals(expected) &&
// special case to allow the difference between
// DateFormatSymbols.getZoneStrings() and
// TimeZone.getDisplayName() for "GMT+-00:00"
!(got.equals("GMT-00:00") &&
expected.equals("GMT+00:00"))) {
err = true;
System.err.println("\tFormat Error [Locale=" +
locale + ", " +
formats[j] + "/\"" + valids[k][0] +
"\"] expected:" + valids[k][2+j] +
", got:" + s + ", " + date);
} else {
/*
System.out.println("\tFormat Okay [Locale=" +
locale + ", " +
formats[j] + "/\"" + valids[k][0] +
"\"] expected:" + valids[k][2+j] +
", got:" + s + ", " + date);
*/
}
}
}
/* Error case 1
* using SimpleDateFormat.parse(String, ParsePosition)
*/
for (int k=0; k < invalids.length; k++) {
ParsePosition pos = new ParsePosition(0);
try {
date = sdf.parse((String)invalids[k][0], pos);
if (date != null) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] expected:null , got:" + date);
}
int offset = pos.getErrorIndex();
if (offset != ((Integer)invalids[k][1]).intValue()) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] incorrect offset. expected:" +
invalids[k][1] + ", got: " + offset);
} else {
/*
System.out.println("\tParse Okay [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] correct offset: " + offset);
*/
}
}
catch (Exception e) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] Unexpected Exception occurred: " + e);
}
}
/* Error case 2
* using DateFormat.parse(String)
*/
boolean correctParseException = false;
for (int k=0; k < invalids.length; k++) {
try {
date = sdf.parse((String)invalids[k][0]);
}
catch (ParseException e) {
correctParseException = true;
int offset = e.getErrorOffset();
if (offset != ((Integer)invalids[k][1]).intValue()) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] Expected exception occurred with an incorrect offset. expected:" +
invalids[k][1] + ", got: " + offset);
} else {
/*
System.out.println("\tParse Okay [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] Expected exception occurred with an correct offset: "
+ offset);
*/
}
}
catch (Exception e) {
err = true;
System.err.println("\tParse Error [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] Invalid exception occurred: " + e);
}
finally {
if (!correctParseException) {
err = true;
System.err.println("\tParse Error: [Locale=" +
locale + ", " + formats[j] +
"/\"" + invalids[k][0] +
"\"] Expected exception didn't occur.");
}
}
}
}
}
}
finally {
Locale.setDefault(savedLocale);
TimeZone.setDefault(savedTimeZone);
if (err) {
fail("SimpleDateFormat.parse()/format() test failed");
}
}
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4396385
* @summary Make sure to detect invalid values for 1-based hour formats.
*/
import java.text.*;
import java.util.*;
public class Bug4396385 {
private static int errorCount = 0;
private static String[][] data = {
{ "hh:mma", "-1:30AM" },
{ "hh:mma", "00:30AM" },
{ "hh:mma", "13:30AM" },
{ "kk:mm", "-1:12" },
{ "kk:mm", "00:12" },
{ "kk:mm", "25:12" },
};
public static void main(String[] args) {
TimeZone tz = TimeZone.getDefault();
// Use "GMT" to avoid any surprises related to offset
// transitions.
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
try {
for (String[] item : data) {
test(item[0], item[1]);
}
} finally {
// Restore the default time zone
TimeZone.setDefault(tz);
}
if (errorCount > 0) {
throw new RuntimeException("Failed with " + errorCount + " error(s).");
}
}
private static void test(String pattern, String src) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);
sdf.setLenient(false);
ParsePosition pos = new ParsePosition(0);
System.out.printf("parse: \"%s\" with \"%s\"", src, pattern);
Date date = sdf.parse(src, pos);
System.out.printf(": date = %s, errorIndex = %d", date, pos.getErrorIndex());
if (date != null || pos.getErrorIndex() == -1) {
System.out.println(": failed");
errorCount++;
} else {
System.out.println(": passed");
}
}
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4407042
* @summary Make sure that cloned SimpleDateFormat objects work
* independently in multiple threads.
* @library /java/text/testlib
* @run junit Bug4407042
*/
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import java.io.*;
import java.text.*;
import java.util.*;
public class Bug4407042 {
static final String TIME_STRING = "2000/11/18 00:01:00";
static final long UTC_LONG = 974534460000L;
static SimpleDateFormat masterFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
static boolean runrun = true;
static int duration = 10;
@Test
void test() {
Locale locale = Locale.getDefault();
Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale),
locale + " does not use ASCII digits");
Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale),
locale + " does not use a Gregorian calendar");
masterFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
DateParseThread d1 = new DateParseThread();
DateFormatThread d2 = new DateFormatThread();
d1.start();
d2.start();
int n = Thread.activeCount();
boolean failed = false;
for (int i = 0; i < duration; i++) {
try {
Thread.sleep(1000);
if (Thread.activeCount() != n) {
failed = true;
break;
}
} catch (InterruptedException e) {
}
}
runrun = false;
try {
d1.join();
d2.join();
} catch (InterruptedException e) {
}
if (failed) {
throw new RuntimeException("Failed");
}
}
synchronized static SimpleDateFormat getFormatter() {
return (SimpleDateFormat) masterFormat.clone();
}
static class DateParseThread extends Thread {
public void run() {
SimpleDateFormat sdf = getFormatter();
Calendar cal = null;
try {
int i = 0;
while (runrun) {
Date date =sdf.parse(TIME_STRING);
long t = date.getTime();
i++;
if (t != UTC_LONG) {
throw new RuntimeException("Parse Error: " + i +
" (" + sdf.format(date) + ") " + t +
" != " + UTC_LONG);
}
}
} catch (ParseException e) {
e.printStackTrace();
throw new RuntimeException("Parse Error");
}
}
}
static class DateFormatThread extends Thread {
public void run () {
SimpleDateFormat sdf = getFormatter();
Calendar cal = null;
int i = 0;
while (runrun) {
i++;
String s = sdf.format(new Date(UTC_LONG));
if (!s.equals(TIME_STRING)) {
throw new RuntimeException("Format Error: " + i + " " +
s + " != " + TIME_STRING);
}
}
}
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4736959
* @summary Make sure to parse "PM" (only) and produce the correct value.
*/
import java.text.*;
import java.util.*;
@SuppressWarnings("deprecation")
public class Bug4736959 {
/**
* 4736959: JSpinner won't work for AM/PM field
*/
public static void main(String[] args) {
SimpleDateFormat f = new SimpleDateFormat("a", Locale.US);
Date d1 = f.parse("AM", new ParsePosition(0));
System.out.println("d1: " + d1);
if (d1.getHours() != 0) {
throw new RuntimeException("Parsing \"AM\": expected 0 (midnight), got " +
d1.getHours());
}
Date d2 = f.parse("PM", new ParsePosition(0));
System.out.println("d2: " + d2);
if (d2.getHours() != 12) {
throw new RuntimeException("Parsing \"PM\": expected 12 (noon), got " +
d2.getHours());
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4845901
* @summary Make sure that SimpleDateFormat.parse() can distinguish
* the same time zone abbreviation for standard and daylight saving
* time.
* @library /java/text/testlib
* @run junit/othervm Bug4845901
*/
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import java.util.*;
import java.text.SimpleDateFormat;
public class Bug4845901 {
@Test
void test() {
Locale locale = Locale.getDefault();
Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale),
locale + " does not use a Gregorian calendar");
TimeZone savedTZ = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("Australia/Sydney"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS z");
try {
testParse(sdf, "2003.01.13 11:10:00.802 AEDT", 11);
testParse(sdf, "2003.06.12 11:10:00.802 AEST", 11);
testParse(sdf, "2004.12.24 10:10:00.002 AEDT", 10);
testParse(sdf, "2004.08.10 10:10:00.002 AEST", 10);
} finally {
TimeZone.setDefault(savedTZ);
}
}
@SuppressWarnings("deprecation")
static void testParse(SimpleDateFormat sdf, String str, int expectedHour) {
try {
Date parsedDate = sdf.parse(str);
if (parsedDate.getHours() != expectedHour) {
throw new RuntimeException(
"parsed date has wrong hour: " + parsedDate.getHours()
+ ", expected: " + expectedHour
+ "\ngiven string: " + str
+ "\nparsedDate = " + parsedDate);
}
} catch (java.text.ParseException e) {
throw new RuntimeException("parse exception", e);
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6251817
* @summary Confirm that a typo was corrected.
*/
import java.text.*;
import java.util.*;
public class Bug6251817 {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("zzzz", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("Australia/Lord_Howe"));
String got = sdf.format(new Date());
if (!got.equals("Lord Howe Standard Time") &&
!got.equals("Lord Howe Daylight Time")) {
throw new RuntimeException("Timezone display name for Australia/Lord_Howe is incorrect. Got:" + got);
}
}
}

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test 1.1 06/01/24
* @bug 6335238
* @summary Make sure that both the original and cloned SimpleDateFormat coexistindependently and don't cut off each other.
* @run main Bug6335238 10
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
// Usage: java Bug6335238 [duration]
public class Bug6335238 {
static final long UTC_LONG = 974534460000L;
static final String TIME_STRING = "2000/11/18 00:01:00";
static SimpleDateFormat masterSdf;
static int duration = 180;
static boolean stopped = false;
static boolean err = false;
public static void main(String[] args) {
if (args.length == 1) {
duration = Math.max(10, Integer.parseInt(args[0]));
}
Locale savedLocale = Locale.getDefault();
TimeZone savedTimeZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("US/Pacific"));
Locale.setDefault(Locale.US);
masterSdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
try {
// Once it is used, DecimalFormat becomes not thread-safe.
Date d = masterSdf.parse(TIME_STRING);
new Bug6335238();
} catch (Exception e) {
System.err.println(e);
err = true;
} finally {
TimeZone.setDefault(savedTimeZone);
Locale.setDefault(savedLocale);
if (err) {
throw new RuntimeException("Failed: Multiple DateFormat instances didn't work correctly.");
} else {
System.out.println("Passed.");
}
}
}
public Bug6335238() {
stopped = false;
DateParseThread d1 = new DateParseThread();
DateFormatThread d2 = new DateFormatThread();
DateParseThread d3 = new DateParseThread();
DateFormatThread d4 = new DateFormatThread();
d1.start();
d2.start();
d3.start();
d4.start();
try {
Thread.sleep(duration * 1000);
}
catch (Exception e) {
System.err.println(e);
err = true;
}
stopped = true;
}
class DateFormatThread extends Thread {
public void run() {
int i = 0;
while (!stopped) {
SimpleDateFormat sdf;
synchronized (masterSdf) {
sdf = (SimpleDateFormat)masterSdf.clone();
}
i++;
String s = sdf.format(new Date(UTC_LONG));
if (!s.equals(TIME_STRING)) {
stopped = true;
err = true;
throw new RuntimeException("Formatting Date Error: counter=" +
i + ", Got<" + s + "> != Expected<" + TIME_STRING + ">");
}
}
}
}
class DateParseThread extends Thread {
public void run() {
int i = 0;
while (!stopped) {
SimpleDateFormat sdf;
synchronized (masterSdf) {
sdf = (SimpleDateFormat)masterSdf.clone();
}
i++;
Date date;
try {
date = sdf.parse(TIME_STRING);
long t = date.getTime();
if (t != UTC_LONG) {
stopped = true;
err = true;
throw new RuntimeException("Parsing Date Error: counter=" +
i + " Got:" + t + "<" + sdf.format(date) +
"> != " + UTC_LONG);
}
}
catch (ParseException e) {
stopped = true;
err = true;
throw new RuntimeException(e);
}
}
}
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6530336 6537997 8008577 8174269 8333582
* @library /java/text/testlib
* @run junit/othervm Bug6530336
*/
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.FieldSource;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class Bug6530336 {
private static final Locale[] locales = Locale.getAvailableLocales();
private static final TimeZone[] timezones = {
TimeZone.getTimeZone("America/New_York"),
TimeZone.getTimeZone("America/Denver"),
};
private static final TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles");
private static final String[] expected = {
"Sun Jul 15 12:00:00 PDT 2007",
"Sun Jul 15 14:00:00 PDT 2007",
};
private static final Date[] dates = new Date[2];
@BeforeAll
static void setup() {
TimeZone.setDefault(timezone_LA);
}
@ParameterizedTest
@FieldSource("locales")
void test(Locale locale) {
Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale),
locale + " does not use a Gregorian calendar");
Locale.setDefault(locale);
for (int j = 0; j < timezones.length; j++) {
Calendar cal = Calendar.getInstance(timezones[j]);
cal.set(2007, 6, 15, 15, 0, 0);
dates[j] = cal.getTime();
}
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
for (int j = 0; j < timezones.length; j++) {
sdf.setTimeZone(timezones[j]);
String date = sdf.format(dates[j]);
// CLDR localizes GMT format into for some locales. Ignore those cases
if (date.matches(".*GMT[\\s+-]\\D.*") ||
date.contains("UTC") ||
date.contains("TMG") || // Interlingue
date.contains("ߜ߭ߕߖ") || // N’Ko
date.contains("ꋧꃅꎕꏦꄮꈉ") || // Sichuan Yi, Nuosu
date.contains("گرینیچ")) { // Central Kurdish
continue;
}
sdf.setTimeZone(timezone_LA);
String date_LA = assertDoesNotThrow(() -> sdf.parse(date).toString());
assertEquals(expected[j], date_LA,
"Got wrong Pacific time (%s) for (%s) in %s in %s.".formatted(date_LA, date, locale, timezones[j]));
}
}
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6609750
* @summary Make sure that SimpleDateFormat.format() formats years correctly.
*/
import java.text.*;
import java.util.*;
public class Bug6609750 {
public static void main(String[] args) {
boolean error = false;
Locale defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.US);
@SuppressWarnings("deprecation")
Date[] dates = {
new Date(9-1900, Calendar.JUNE, 12),
new Date(99-1900, Calendar.JUNE, 12),
new Date(999-1900, Calendar.JUNE, 12),
new Date(2009-1900, Calendar.JUNE, 12),
new Date(30009-1900, Calendar.JUNE, 12),
};
String[] patterns = {
"y", "yy", "yyy", "yyyy", "yyyyy", "yyyyyy"
};
String[][] expectedResults = {
{"9", "09", "009", "0009", "00009", "000009"},
{"99", "99", "099", "0099", "00099", "000099"},
{"999", "99", "999", "0999", "00999", "000999"},
{"2009", "09", "2009", "2009", "02009", "002009"},
{"30009", "09", "30009", "30009", "30009", "030009"},
};
SimpleDateFormat sdf = new SimpleDateFormat();
for (int dateNo = 0; dateNo < dates.length; dateNo++) {
Date date = dates[dateNo];
for (int patternNo = 0; patternNo < patterns.length; patternNo++) {
sdf.applyPattern(patterns[patternNo]);
String got = sdf.format(date);
if (!expectedResults[dateNo][patternNo].equals(got)) {
error = true;
System.err.println("Failed: Unexpected format result: " +
"Expected: \"" + expectedResults[dateNo][patternNo] +
"\", Got: \"" + got + "\" for date " + date +
" with pattern \"" + patterns[patternNo] + "\"");
}
}
}
Locale.setDefault(defaultLocale);
if (error) {
throw new RuntimeException("SimpleDateFormat.format() error.");
};
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6645292
* @summary Make sure to parse a DST time zone name with which the
* last DST rule doesn't observe DST.
*/
import java.text.*;
import java.util.*;
import static java.util.Calendar.*;
public class Bug6645292 {
public static void main(String[] args) {
Locale loc = Locale.getDefault();
TimeZone zone = TimeZone.getDefault();
try {
Locale.setDefault(Locale.US);
// Use "Asia/Shanghai" with an old time stamp rather than
// "Australia/Perth" because if Perth decides to obserb DST
// permanently, that decision will make this test case
// useless. There's the same risk with China, though.
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(1986, JUNE, 1);
Date d1 = cal.getTime();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzz");
String s = df.format(d1);
Date d2 = null;
try {
d2 = df.parse(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (!d1.equals(d2)) {
throw new RuntimeException("d1 (" + d1 + ") != d2 (" + d2 + ")");
}
} finally {
Locale.setDefault(loc);
TimeZone.setDefault(zone);
}
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6683975 8008577 8174269
* @summary Make sure that date is formatted correctly in th locale.
* @modules jdk.localedata
* @run main Bug6683975
*/
import java.text.*;
import java.util.*;
public class Bug6683975 {
private static boolean err = false;
private static Locale th = Locale.of("th");
private static Locale th_TH = Locale.of("th", "TH");
private static String expected_th[] = {
"\u0e27\u0e31\u0e19\u0e2d\u0e31\u0e07\u0e04\u0e32\u0e23\u0e17\u0e35\u0e48 30 \u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19 \u0e04.\u0e28. 2008 8 \u0e19\u0e32\u0e2c\u0e34\u0e01\u0e32 00 \u0e19\u0e32\u0e17\u0e35 00 \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35 \u0e40\u0e27\u0e25\u0e32\u0e2d\u0e2d\u0e21\u0e41\u0e2a\u0e07\u0e41\u0e1b\u0e0b\u0e34\u0e1f\u0e34\u0e01\u0e43\u0e19\u0e2d\u0e40\u0e21\u0e23\u0e34\u0e01\u0e32\u0e40\u0e2b\u0e19\u0e37\u0e2d", // 0: FULL
"30 \u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19 \u0e04.\u0e28. 2008 8 \u0e19\u0e32\u0e2c\u0e34\u0e01\u0e32 00 \u0e19\u0e32\u0e17\u0e35 00 \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35 PDT", // 1: LONG
"30 \u0e01.\u0e22. 2008 08:00:00", // 2: MEDIUM
"30/9/08 08:00", // 3: SHORT
};
private static String expected_th_TH[] = {
"\u0e27\u0e31\u0e19\u0e2d\u0e31\u0e07\u0e04\u0e32\u0e23\u0e17\u0e35\u0e48 30 \u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19 \u0e1e\u0e38\u0e17\u0e18\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a 2551 8 \u0e19\u0e32\u0e2c\u0e34\u0e01\u0e32 00 \u0e19\u0e32\u0e17\u0e35 00 \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35 \u0e40\u0e27\u0e25\u0e32\u0e2d\u0e2d\u0e21\u0e41\u0e2a\u0e07\u0e41\u0e1b\u0e0b\u0e34\u0e1f\u0e34\u0e01\u0e43\u0e19\u0e2d\u0e40\u0e21\u0e23\u0e34\u0e01\u0e32\u0e40\u0e2b\u0e19\u0e37\u0e2d", // 0: FULL
"30 \u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19 2551 8 \u0e19\u0e32\u0e2c\u0e34\u0e01\u0e32 00 \u0e19\u0e32\u0e17\u0e35 00 \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35 PDT", // 1: LONG
"30 \u0e01.\u0e22. 2551 08:00:00", // 2: MEDIUM
"30/9/51 08:00" // 3: SHORT
};
private static String stylePattern[] = {
"FULL", "LONG", "MEDIUM", "SHORT"
};
private static void test(int style) {
DateFormat df_th = DateFormat.getDateTimeInstance(style, style, th);
DateFormat df_th_TH = DateFormat.getDateTimeInstance(style, style, th_TH);
String str_th = ((SimpleDateFormat)df_th).toPattern();
String str_th_TH = ((SimpleDateFormat)df_th_TH).toPattern();
// CLDR has different patterns for Gregorian and Buddhist calendars, thus they don't match
// if (!str_th.equals(str_th_TH)) {
// err = true;
// System.err.println("Error: Pattern for th locale should be the same as pattern for th_TH locale. (" + stylePattern[style] + ")");
// System.err.println("\tth: " + str_th);
// System.err.println("\tth_TH: " + str_th_TH);
// }
@SuppressWarnings("deprecation")
Date date = new Date(2008-1900, Calendar.SEPTEMBER, 30, 8, 0, 0);
str_th = df_th.format(date);
if (!expected_th[style].equals(str_th)) {
err = true;
System.err.println("Error: Formatted date in th locale is incorrect in " + stylePattern[style] + " pattern.");
System.err.println("\tExpected: " + expected_th[style]);
System.err.println("\tGot: " + str_th);
}
str_th_TH = df_th_TH.format(date);
if (!expected_th_TH[style].equals(str_th_TH)) {
err = true;
System.err.println("Error: Formatted date in th_TH locale is incorrect in " + stylePattern[style] + " pattern.");
System.err.println("\tExpected: " + expected_th_TH[style]);
System.err.println("\tGot: " + str_th_TH);
}
}
public static void main(String[] args) {
TimeZone timezone = TimeZone.getDefault();
Locale locale = Locale.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("US/Pacific"));
Locale.setDefault(Locale.US);
try {
test(DateFormat.FULL);
test(DateFormat.LONG);
test(DateFormat.MEDIUM);
test(DateFormat.SHORT);
}
catch (Exception e) {
err = true;
System.err.println("Unexpected exception was thrown: " + e);
}
finally {
TimeZone.setDefault(timezone);
Locale.setDefault(locale);
if (err) {
throw new RuntimeException("Failed.");
} else {
System.out.println("Passed.");
}
}
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 7130335 7130335
* @summary Make sure that round-trip conversion (format/parse) works
* with old timestamps in Europe/Moscow and with multiple time zone letters.
*/
import java.text.*;
import java.util.*;
import static java.util.GregorianCalendar.*;
public class Bug7130335 {
private static final TimeZone MOSCOW = TimeZone.getTimeZone("Europe/Moscow");
private static final TimeZone LONDON = TimeZone.getTimeZone("Europe/London");
private static final TimeZone LA = TimeZone.getTimeZone("America/Los_Angeles");
private static final TimeZone[] ZONES = {
MOSCOW, LONDON, LA
};
public static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z", Locale.US);
sdf.setTimeZone(MOSCOW);
Calendar cal = new GregorianCalendar(MOSCOW, Locale.US);
cal.clear();
// Try both +03:00 and +02:00
cal.set(1922, SEPTEMBER, 30);
test(sdf, cal);
cal.add(DAY_OF_YEAR, 1);
test(sdf, cal);
cal.set(1991, MARCH, 31);
// in daylight saving time
test(sdf, cal);
cal.add(DAY_OF_YEAR, 1);
test(sdf, cal);
// Try the current timestamp
cal.setTimeInMillis(System.currentTimeMillis());
test(sdf, cal);
// tests for multiple time zone letters (8000529)
test8000529("yyyy-MM-dd HH:mm:ss.SSS Z (z)");
test8000529("yyyy-MM-dd HH:mm:ss.SSS Z (zzzz)");
test8000529("yyyy-MM-dd HH:mm:ss.SSS z (Z)");
test8000529("yyyy-MM-dd HH:mm:ss.SSS zzzz (Z)");
}
private static void test(SimpleDateFormat sdf, Calendar cal) throws Exception {
Date d = cal.getTime();
String f = sdf.format(d);
System.out.println(f);
Date pd = sdf.parse(f);
String p = sdf.format(pd);
if (!d.equals(pd) || !f.equals(p)) {
throw new RuntimeException("format: " + f + ", parse: " + p);
}
}
private static void test8000529(String fmt) throws Exception {
for (TimeZone tz : ZONES) {
SimpleDateFormat sdf = new SimpleDateFormat(fmt, Locale.US);
sdf.setTimeZone(tz);
Calendar cal = new GregorianCalendar(tz, Locale.US);
cal.clear();
cal.set(2012, JUNE, 22);
test(sdf, cal);
cal.set(2012, DECEMBER, 22);
test(sdf, cal);
cal.setTimeInMillis(System.currentTimeMillis());
test(sdf, cal);
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 7177315
* @summary Make sure that space characters are properly skipped when
* parsing 2-digit year values.
*/
import java.text.*;
import java.util.*;
public class Bug7177315 {
private static final String EXPECTED = "01/01/2012";
private static final String[] DATA = {
"01/01/12",
"01/01/ 12",
"01/01/ 12",
"1/1/12",
"1/1/ 12"
};
public static void main (String[] args) throws ParseException {
SimpleDateFormat parseFormat = new SimpleDateFormat("MM/dd/yy", Locale.US);
Calendar cal = new GregorianCalendar(2012-80, Calendar.JANUARY, 1);
parseFormat.set2DigitYearStart(cal.getTime());
SimpleDateFormat fmtFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
for (String text : DATA) {
Date date = parseFormat.parse(text);
String got = fmtFormat.format(date);
if (!EXPECTED.equals(got)) {
throw new RuntimeException("got: " + got + ", expected: " + EXPECTED);
}
}
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8072099
* @summary check the date time pattern for <NUMERIC_FIELD> which should
* not throw ParseException
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class Bug8072099 {
private static String[][] shouldPass = {
{"ha", "11AM"},
{"hma", "33AM"},
{"ka", "24AM"},
{"yyyMMM", "2016May"},
{"yyyyDDEEE", "2016366Sat"},
{"ddmyyyyz", "22111980GMT+5:30"}
};
public static void main(String[] args) {
Locale defaultLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.US);
// check the date time pattern which should pass
for (String[] pattern : shouldPass) {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat(pattern[0]);
parseDateTimeInput(dateTimeFormat, pattern[1]);
}
} finally {
Locale.setDefault(defaultLocale);
}
}
private static void parseDateTimeInput(SimpleDateFormat format,
String inputString) {
try {
format.parse(inputString);
} catch (ParseException ex) {
throw new RuntimeException("[FAILED: Unable to parse date time"
+ " string " + inputString + "]");
}
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8081794
* @summary ParsePosition getErrorIndex should return correct index
*/
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Bug8081794 {
public static void main(String[] args) {
String date = "13 Jan 2005 21:45:34 ABC";
String format = "dd MMM yyyy HH:mm:ss z";
ParsePosition pp = new ParsePosition(0);
pp.setIndex(0);
SimpleDateFormat sd = new SimpleDateFormat(format, Locale.ENGLISH);
Date d = sd.parse(date, pp);
int errorIndex = pp.getErrorIndex();
if (errorIndex == 21) {
System.out.println(": passed");
} else {
System.out.println(": failed");
throw new RuntimeException("Failed with wrong index: " + errorIndex);
}
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8139572
* @summary SimpleDateFormat parse month stand-alone format bug
* @compile -encoding utf-8 Bug8139572.java
* @modules jdk.localedata
* @run main Bug8139572
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class Bug8139572 {
private static final Locale RUSSIAN = Locale.of("ru");
private static final Date SEPT12 = new GregorianCalendar(2015, Calendar.SEPTEMBER, 12).getTime();
private static final String[] PATTERNS = {
"L",
"dd L",
"dd L yy",
"dd L yyyy",
"LL",
"dd LL",
"dd LL yy",
"dd LL yyyy",
"LLL",
"dd LLL",
"dd LLL yy",
"dd LLL yyyy",
"LLLL",
"dd LLLL",
"dd LLLL yy",
"dd LLLL yyyy"
};
private static final String[] APPLIED = {
"9",
"12 09",
"12 09 15",
"12 09 2015",
"09",
"12 09",
"12 09 15",
"12 09 2015",
"сентября",
"12 сентября",
"12 сентября 15",
"12 сентября 2015",
"сентября",
"12 сентября",
"12 сентября 15",
"12 сентября 2015"
};
private static final String[] EXPECTED = {
"9",
"12 9",
"12 9 15",
"12 9 2015",
"09",
"12 09",
"12 09 15",
"12 09 2015",
"сент.",
"12 сент.",
"12 сент. 15",
"12 сент. 2015",
"сентябрь",
"12 сентябрь",
"12 сентябрь 15",
"12 сентябрь 2015"
};
public static void main(String[] args) throws ParseException {
for (int i = 0; i < PATTERNS.length; i++) {
SimpleDateFormat fmt = new SimpleDateFormat(PATTERNS[i], RUSSIAN);
Date standAloneDate = fmt.parse(APPLIED[i]);
String str = fmt.format(standAloneDate);
if (!EXPECTED[i].equals(str)) {
throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[i] + "'");
}
}
SimpleDateFormat fmt = new SimpleDateFormat("", RUSSIAN);
for (int j = 0; j < PATTERNS.length; j++) {
fmt.applyPattern(PATTERNS[j]);
String str = fmt.format(SEPT12);
if (!EXPECTED[j].equals(str)) {
throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[j] + "'");
}
}
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8141243 8174269
* @summary Make sure that SimpleDateFormat parses "UTC" as the UTC time zone.
* @run main Bug8141243
*/
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import static java.util.TimeZone.*;
public class Bug8141243 {
public static void main(String[] args) {
TimeZone UTC = TimeZone.getTimeZone("UTC");
TimeZone initTz = TimeZone.getDefault();
List<String> errors = new ArrayList<>();
try {
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
for (Locale locale : DateFormat.getAvailableLocales()) {
// exclude any locales which localize "UTC".
String utc = UTC.getDisplayName(false, SHORT, locale);
if (!"UTC".equals(utc)) {
System.out.println("Skipping " + locale + " due to localized UTC name: " + utc);
continue;
}
SimpleDateFormat fmt = new SimpleDateFormat("z", locale);
try {
Date date = fmt.parse("UTC");
// Parsed one may not exactly be UTC. Universal, UCT, etc. are equivalents.
if (!fmt.getTimeZone().getID().matches("(Etc/)?(UTC|Universal|UCT|Zulu)")) {
errors.add("timezone: " + fmt.getTimeZone().getID()
+ ", locale: " + locale);
}
} catch (ParseException e) {
errors.add("parse exception: " + e + ", locale: " + locale);
}
}
} finally {
// Restore the default time zone
TimeZone.setDefault(initTz);
}
if (!errors.isEmpty()) {
System.out.println("Got unexpected results:");
for (String s : errors) {
System.out.println(" " + s);
}
throw new RuntimeException("Test failed.");
} else {
System.out.println("Test passed.");
}
}
}

Some files were not shown because too many files have changed in this diff Show more