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:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
58
test/jdk/java/text/Format/MessageFormat/Bug4185816.ser.txt
Normal file
58
test/jdk/java/text/Format/MessageFormat/Bug4185816.ser.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# 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 MessageFormat for Bug4185816Test.
|
||||
|
||||
aced0005737200176a6176612e746578742e4d657373616765466f726d617459
|
||||
ea973e12bd01a80200064900096d61784f66667365745b000f617267756d656e
|
||||
744e756d626572737400025b495b0007666f726d6174737400135b4c6a617661
|
||||
2f746578742f466f726d61743b4c00066c6f63616c657400124c6a6176612f75
|
||||
74696c2f4c6f63616c653b5b00076f66667365747371007e00014c0007706174
|
||||
7465726e7400124c6a6176612f6c616e672f537472696e673b787200106a6176
|
||||
612e746578742e466f726d6174fbd8bc12e90f18430200007870000000017572
|
||||
00025b494dba602676eab2a502000078700000000a0000000100000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000757200
|
||||
135b4c6a6176612e746578742e466f726d61743b5eacf7515deec1f802000078
|
||||
700000000a70737200166a6176612e746578742e43686f696365466f726d6174
|
||||
18e9c6bee365b6040200025b000d63686f696365466f726d6174737400135b4c
|
||||
6a6176612f6c616e672f537472696e673b5b000c63686f6963654c696d697473
|
||||
7400025b44787200166a6176612e746578742e4e756d626572466f726d6174df
|
||||
f6b3bf137d07e803000b5a000c67726f7570696e67557365644200116d617846
|
||||
72616374696f6e4469676974734200106d6178496e7465676572446967697473
|
||||
4900156d6178696d756d4672616374696f6e4469676974734900146d6178696d
|
||||
756d496e74656765724469676974734200116d696e4672616374696f6e446967
|
||||
6974734200106d696e496e74656765724469676974734900156d696e696d756d
|
||||
4672616374696f6e4469676974734900146d696e696d756d496e746567657244
|
||||
69676974735a00107061727365496e74656765724f6e6c794900157365726961
|
||||
6c56657273696f6e4f6e53747265616d7871007e000501032800000003000000
|
||||
2800010000000000000001000000000178757200135b4c6a6176612e6c616e67
|
||||
2e537472696e673badd256e7e91d7b470200007870000000037400086e6f2066
|
||||
696c65737400086f6e652066696c657400107b302c6e756d6265727d2066696c
|
||||
6573757200025b443ea68c14ab635a1e02000078700000000300000000000000
|
||||
003ff000000000000040000000000000007070707070707070737200106a6176
|
||||
612e7574696c2e4c6f63616c657ef811609c30f9ec0300044900086861736863
|
||||
6f64654c0007636f756e74727971007e00044c00086c616e677561676571007e
|
||||
00044c000776617269616e7471007e00047870ffffffff740002555374000265
|
||||
6e740000787571007e00070000000a0000000a00000015000000000000000000
|
||||
0000000000000000000000000000000000000000000000740016546865206469
|
||||
736b20222220636f6e7461696e73202e
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# 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 corrupted serialized MessageFormat for Bug4185732Test.
|
||||
|
||||
aced0005737200176a6176612e746578742e4d657373616765466f726d617459
|
||||
ea973e12bd01a80200064900096d61784f66667365745b000f617267756d656e
|
||||
744e756d626572737400025b495b0007666f726d6174737400135b4c6a617661
|
||||
2f746578742f466f726d61743b4c00066c6f63616c657400124c6a6176612f75
|
||||
74696c2f4c6f63616c653b5b00076f66667365747371007e00014c0007706174
|
||||
7465726e7400124c6a6176612f6c616e672f537472696e673b787200106a6176
|
||||
612e746578742e466f726d6174fbd8bc12e90f18430200007870000000017572
|
||||
00025b494dba602676eab2a502000078700000000a0000000100000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000757200
|
||||
135b4c6a6176612e746578742e466f726d61743b5eacf7515deec1f802000078
|
||||
700000000a70737200166a6176612e746578742e43686f696365466f726d6174
|
||||
18e9c6bee365b6040200025b000d63686f696365466f726d6174737400135b4c
|
||||
6a6176612f6c616e672f537472696e673b5b000c63686f6963654c696d697473
|
||||
7400025b44787200166a6176612e746578742e4e756d626572466f726d6174df
|
||||
f6b3bf137d07e803000b5a000c67726f7570696e67557365644200116d617846
|
||||
72616374696f6e4469676974734200106d6178496e7465676572446967697473
|
||||
4900156d6178696d756d4672616374696f6e4469676974734900146d6178696d
|
||||
756d496e74656765724469676974734200116d696e4672616374696f6e446967
|
||||
6974734200106d696e496e74656765724469676974734900156d696e696d756d
|
||||
4672616374696f6e4469676974734900146d696e696d756d496e746567657244
|
||||
69676974735a00107061727365496e74656765724f6e6c794900157365726961
|
||||
6c56657273696f6e4f6e53747265616d7871007e000501032800000003000000
|
||||
2800010000000000000001000000000178757200135b4c6a6176612e6c616e67
|
||||
2e537472696e673badd256e7e91d7b470200007870000000037400086e6f2066
|
||||
696c65737400086f6e652066696c657400107b302c6e756d6265727d2066696c
|
||||
6573757200025b443ea68c14ab635a1e02000078700000000300000000000000
|
||||
003ff000000000000040000000000000007070707070707070737200106a6176
|
||||
612e7574696c2e4c6f63616c657ef811609c30f9ec0300044900086861736863
|
||||
6f64654c0007636f756e74727971007e00044c00086c616e677561676571007e
|
||||
00044c000776617269616e7471007e00047870ffffffff740002555374000265
|
||||
6e740000787571007e00070000000a0000000a00000015000000000000000000
|
||||
0000000000000000000000000000000000000000000000740010546865206469
|
||||
736b20222220636f6e74
|
||||
110
test/jdk/java/text/Format/MessageFormat/Bug4185816Test.java
Normal file
110
test/jdk/java/text/Format/MessageFormat/Bug4185816Test.java
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4185816
|
||||
* @library /java/text/testlib
|
||||
* @build Bug4185816Test HexDumpReader
|
||||
* @run junit Bug4185816Test
|
||||
* @summary test that MessageFormat invariants are preserved across serialization.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.text.ChoiceFormat;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* A Locale can never contain language codes of he, yi or id.
|
||||
*/
|
||||
public class Bug4185816Test {
|
||||
private static final String FILE_NAME = "Bug4185816.ser";
|
||||
private static final String CORRUPT_FILE_NAME = "Bug4185816Corrupt.ser";
|
||||
|
||||
@Test
|
||||
public void testIt() throws Exception {
|
||||
Exception e = checkStreaming(FILE_NAME);
|
||||
if (e != null) {
|
||||
fail("MessageFormat did not stream in valid stream: "+e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
e = checkStreaming(CORRUPT_FILE_NAME);
|
||||
if (!(e instanceof InvalidObjectException)) {
|
||||
fail("MessageFormat did NOT detect corrupt stream: "+e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Exception checkStreaming(final String fileName) {
|
||||
try {
|
||||
final InputStream is = HexDumpReader.getStreamFromHexDump(fileName + ".txt");
|
||||
final ObjectInputStream in = new ObjectInputStream(is);
|
||||
final MessageFormat form = (MessageFormat)in.readObject();
|
||||
final Object[] testArgs = {12373L, "MyDisk"};
|
||||
final String result = form.format(testArgs);
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
74
test/jdk/java/text/Format/MessageFormat/Bug7003643.java
Normal file
74
test/jdk/java/text/Format/MessageFormat/Bug7003643.java
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 7003643
|
||||
* @summary Make sure MessageFormat.toPattern produces correct quoting. (SPI part is tested in PluggableLocale tests.)
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
public class Bug7003643 {
|
||||
private static final int N = 5;
|
||||
|
||||
private static final String[] elements = {
|
||||
"'{'", "'{", "{", "''", "}", "a", "'",
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
Random rand = new Random();
|
||||
int count = 0;
|
||||
int max = (int) (Math.pow((double)elements.length, (double)N)/0.52);
|
||||
while (count < max) {
|
||||
// Create a random pattern. If the produced pattern is
|
||||
// valid, then proceed with the round-trip testing.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < N; i++) {
|
||||
sb.append(elements[rand.nextInt(elements.length)]);
|
||||
}
|
||||
String pattern = sb.toString();
|
||||
MessageFormat mf = null;
|
||||
try {
|
||||
mf = new MessageFormat(pattern);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// bad pattern data
|
||||
}
|
||||
if (mf == null) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
String res1 = MessageFormat.format(pattern, 123);
|
||||
String toPattern = mf.toPattern();
|
||||
String res2 = MessageFormat.format(toPattern, 123);
|
||||
if (!res1.equals(res2)) {
|
||||
String s = String.format("Failed%n pattern=\"%s\" => result=\"%s\"%n"
|
||||
+ " toPattern()=\"%s\" => result=\"%s\"%n",
|
||||
pattern, res1, toPattern, res2);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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 8318761 8329118
|
||||
* @summary Test MessageFormatPattern ability to recognize and produce
|
||||
* appropriate FormatType and FormatStyle for CompactNumberFormat.
|
||||
* @run junit CompactSubFormats
|
||||
*/
|
||||
|
||||
import java.text.CompactNumberFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
// This test expects an US locale, as this locale provides distinct instances
|
||||
// for different styles.
|
||||
public class CompactSubFormats {
|
||||
|
||||
// Ensure the built-in FormatType and FormatStyles for cnFmt are as expected
|
||||
@Test
|
||||
public void applyPatternTest() {
|
||||
var mFmt = new MessageFormat(
|
||||
"{0,number,compact_short}{1,number,compact_long}", Locale.US);
|
||||
var compactShort = NumberFormat.getCompactNumberInstance(
|
||||
mFmt.getLocale(), NumberFormat.Style.SHORT);
|
||||
var compactLong = NumberFormat.getCompactNumberInstance(
|
||||
mFmt.getLocale(), NumberFormat.Style.LONG);
|
||||
assertEquals(mFmt.getFormatsByArgumentIndex()[0], compactShort);
|
||||
assertEquals(mFmt.getFormatsByArgumentIndex()[1], compactLong);
|
||||
}
|
||||
|
||||
// Ensure that only 'compact_short' and 'compact_long' are recognized as
|
||||
// compact number modifiers. All other compact_XX should be interpreted as
|
||||
// a subformatPattern for a DecimalFormat
|
||||
@Test
|
||||
public void recognizedCompactStylesTest() {
|
||||
// An exception won't be thrown since 'compact_regular' will be interpreted as a
|
||||
// subformatPattern.
|
||||
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
|
||||
assertEquals(new DecimalFormat("compact_regular", symbols),
|
||||
new MessageFormat("{0,number,compact_regular}", Locale.US).getFormatsByArgumentIndex()[0]);
|
||||
}
|
||||
|
||||
// SHORT and LONG CompactNumberFormats should produce correct patterns
|
||||
@Test
|
||||
public void toPatternTest() {
|
||||
var mFmt = new MessageFormat("{0}{1}", Locale.US);
|
||||
mFmt.setFormatByArgumentIndex(0, NumberFormat.getCompactNumberInstance(
|
||||
mFmt.getLocale(), NumberFormat.Style.SHORT));
|
||||
mFmt.setFormatByArgumentIndex(1, NumberFormat.getCompactNumberInstance(
|
||||
mFmt.getLocale(), NumberFormat.Style.LONG));
|
||||
assertEquals("{0,number,compact_short}{1,number,compact_long}", mFmt.toPattern());
|
||||
}
|
||||
|
||||
// A custom cnFmt cannot be recognized, thus does not produce any built-in pattern
|
||||
@Test
|
||||
public void badToPatternTest() {
|
||||
var mFmt = new MessageFormat("{0}", Locale.US);
|
||||
// Non-recognizable compactNumberFormat
|
||||
mFmt.setFormatByArgumentIndex(0, new CompactNumberFormat("",
|
||||
DecimalFormatSymbols.getInstance(Locale.US), new String[]{""}));
|
||||
// Default behavior of unrecognizable Formats is a FormatElement
|
||||
// in the form of { ArgumentIndex }
|
||||
assertEquals("{0}", mFmt.toPattern());
|
||||
}
|
||||
}
|
||||
123
test/jdk/java/text/Format/MessageFormat/LargeMessageFormat.java
Normal file
123
test/jdk/java/text/Format/MessageFormat/LargeMessageFormat.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 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 4112090 8008577 8174269
|
||||
* @summary verify that MessageFormat can handle large numbers of arguments
|
||||
* @modules jdk.localedata
|
||||
* @run main LargeMessageFormat
|
||||
*/
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class LargeMessageFormat {
|
||||
|
||||
public static void main(String[] args) throws ParseException {
|
||||
Locale reservedLocale = Locale.getDefault();
|
||||
TimeZone reservedTimeZone = TimeZone.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.GERMANY);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
|
||||
testFormat();
|
||||
testParse();
|
||||
} finally {
|
||||
// restore the reserved locale and time zone
|
||||
Locale.setDefault(reservedLocale);
|
||||
TimeZone.setDefault(reservedTimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int REPEATS = 89;
|
||||
|
||||
private static void testFormat() {
|
||||
// construct large argument array
|
||||
@SuppressWarnings("deprecation")
|
||||
Object[] sample = {
|
||||
0, // replace with running count below
|
||||
"hello",
|
||||
new Date(89, 10, 9),
|
||||
567890,
|
||||
1234.50
|
||||
};
|
||||
int samples = sample.length;
|
||||
Object[] arguments = new Object[REPEATS * (samples + 1)];
|
||||
for (int i = 0; i < REPEATS; i++) {
|
||||
System.arraycopy(sample, 0, arguments, i * samples, samples);
|
||||
arguments[i * samples] = i;
|
||||
}
|
||||
|
||||
// construct large template
|
||||
StringBuffer template = new StringBuffer();
|
||||
for (int i = 0; i < REPEATS; i++) {
|
||||
template.append("section {" + (i * samples) + ", number} - ");
|
||||
template.append("string: {" + (i * samples + 1) + "}; ");
|
||||
template.append("date: {" + (i * samples + 2) + ", date}; ");
|
||||
template.append("integer: {" + (i * samples + 3) + ", number}; ");
|
||||
template.append("currency: {" + (i * samples + 4) + ", number, currency};\n");
|
||||
}
|
||||
|
||||
// construct expected result string
|
||||
StringBuffer expected = new StringBuffer();
|
||||
for (int i = 0; i < REPEATS; i++) {
|
||||
expected.append("section " + i + " - ");
|
||||
expected.append("string: hello; ");
|
||||
expected.append("date: 09.11.1989; ");
|
||||
expected.append("integer: 567.890; ");
|
||||
expected.append("currency: 1.234,50\u00a0\u20AC;\n");
|
||||
}
|
||||
|
||||
// create message format
|
||||
MessageFormat format = new MessageFormat(template.toString());
|
||||
String result = format.format(arguments);
|
||||
if (!result.equals(expected.toString())) {
|
||||
System.out.println("Template:");
|
||||
System.out.println(template);
|
||||
System.out.println("Expected result: ");
|
||||
System.out.println(expected);
|
||||
System.out.println("Actual result: ");
|
||||
System.out.println(result);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testParse() throws ParseException {
|
||||
StringBuffer parseTemplate = new StringBuffer();
|
||||
StringBuffer parseInput = new StringBuffer();
|
||||
for (int i = 0; i < REPEATS; i++) {
|
||||
parseTemplate.append("{" + i + ", number} ");
|
||||
parseInput.append(i + " ");
|
||||
}
|
||||
MessageFormat parseFormat = new MessageFormat(parseTemplate.toString());
|
||||
Object[] parseResult = parseFormat.parse(parseInput.toString());
|
||||
for (int i = 0; i < REPEATS; i++) {
|
||||
if (((Number) parseResult[i]).intValue() != i) {
|
||||
throw new RuntimeException("got wrong parse result");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
test/jdk/java/text/Format/MessageFormat/ListSubFormats.java
Normal file
102
test/jdk/java/text/Format/MessageFormat/ListSubFormats.java
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 8318761 8329118
|
||||
* @summary Test MessageFormatPattern ability to recognize and produce the
|
||||
* appropriate FormatType and FormatStyle for ListFormat. ListFormat's
|
||||
* STANDARD, OR, and UNIT types are supported as built-in patterns for
|
||||
* MessageFormat. All types use the FULL style.
|
||||
* @run junit ListSubFormats
|
||||
*/
|
||||
|
||||
import java.text.ListFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
// This test expects an US locale, as this locale provides distinct instances
|
||||
// for different styles.
|
||||
public class ListSubFormats {
|
||||
|
||||
// Recognize the 'list' FormatType as well as '', 'or', and
|
||||
// 'unit' associated FormatStyles
|
||||
@Test
|
||||
public void applyPatternTest() {
|
||||
var mFmt = new MessageFormat("{0,list}{1,list,or}{2,list,unit}", Locale.US);
|
||||
var listStandard = ListFormat.getInstance(mFmt.getLocale(),
|
||||
ListFormat.Type.STANDARD, ListFormat.Style.FULL);
|
||||
var listOr = ListFormat.getInstance(mFmt.getLocale(),
|
||||
ListFormat.Type.OR, ListFormat.Style.FULL);
|
||||
var listUnit = ListFormat.getInstance(mFmt.getLocale(),
|
||||
ListFormat.Type.UNIT, ListFormat.Style.FULL);
|
||||
assertEquals(mFmt.getFormatsByArgumentIndex()[0], listStandard);
|
||||
assertEquals(mFmt.getFormatsByArgumentIndex()[1], listOr);
|
||||
assertEquals(mFmt.getFormatsByArgumentIndex()[2], listUnit);
|
||||
}
|
||||
|
||||
// Ensure incorrect FormatElement pattern throws IAE
|
||||
// java.text.ListFormat does not support String subformatPatterns
|
||||
@Test
|
||||
public void badApplyPatternTest() {
|
||||
// Wrong FormatStyle
|
||||
IllegalArgumentException exc = assertThrows(IllegalArgumentException.class, () ->
|
||||
new MessageFormat("{0,list,standard}", Locale.US));
|
||||
assertEquals("Unexpected modifier for List: standard", exc.getMessage());
|
||||
|
||||
// Wrong FormatType
|
||||
exc = assertThrows(IllegalArgumentException.class, () ->
|
||||
new MessageFormat("{0,listt,or}", Locale.US));
|
||||
assertEquals("unknown format type: listt", exc.getMessage());
|
||||
|
||||
}
|
||||
|
||||
// STANDARD, OR, UNIT ListFormats (with FULL style) should
|
||||
// produce correct patterns.
|
||||
@Test
|
||||
public void toPatternTest() {
|
||||
var mFmt = new MessageFormat("{0}{1}{2}", Locale.US);
|
||||
mFmt.setFormatByArgumentIndex(0,
|
||||
ListFormat.getInstance(mFmt.getLocale(), ListFormat.Type.STANDARD, ListFormat.Style.FULL));
|
||||
mFmt.setFormatByArgumentIndex(1,
|
||||
ListFormat.getInstance(mFmt.getLocale(), ListFormat.Type.OR, ListFormat.Style.FULL));
|
||||
mFmt.setFormatByArgumentIndex(2,
|
||||
ListFormat.getInstance(mFmt.getLocale(), ListFormat.Type.UNIT, ListFormat.Style.FULL));
|
||||
assertEquals("{0,list}{1,list,or}{2,list,unit}", mFmt.toPattern());
|
||||
}
|
||||
|
||||
// A custom ListFormat cannot be recognized, thus does not produce any built-in pattern
|
||||
@Test
|
||||
public void badToPatternTest() {
|
||||
var mFmt = new MessageFormat("{0}", Locale.US);
|
||||
mFmt.setFormatByArgumentIndex(0,
|
||||
ListFormat.getInstance(mFmt.getLocale(),
|
||||
ListFormat.Type.UNIT, ListFormat.Style.NARROW));
|
||||
assertEquals("{0}", mFmt.toPattern());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 8331446
|
||||
* @summary Enforce the MAX_ARGUMENT_INDEX(10,000) implementation limit for the
|
||||
* ArgumentIndex element in the MessageFormat pattern syntax. This
|
||||
* should be checked during construction/applyPattern/readObject and should effectively
|
||||
* prevent parse/format from being invoked with values over the limit.
|
||||
* @run junit MaxArgumentIndexTest
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class MaxArgumentIndexTest {
|
||||
|
||||
// A MessageFormat pattern that contains an ArgumentIndex value
|
||||
// which violates this implementation's limit: MAX_ARGUMENT_INDEX(10,000)
|
||||
// As this check is exclusive, 10,000 will violate the limit
|
||||
private static final String VIOLATES_MAX_ARGUMENT_INDEX = "{10000}";
|
||||
|
||||
// Check String constructor enforces the limit
|
||||
@Test
|
||||
public void constructorTest() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX));
|
||||
}
|
||||
|
||||
// Check String, Locale constructor enforces the limit
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void constructorWithLocaleTest(Locale locale) {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX, locale));
|
||||
}
|
||||
|
||||
// Provide some basic common locale values
|
||||
private static Stream<Locale> constructorWithLocaleTest() {
|
||||
return Stream.of(null, Locale.US, Locale.ROOT);
|
||||
}
|
||||
|
||||
// Edge case: Test a locale dependent subformat (with null locale) with a
|
||||
// violating ArgumentIndex. In this instance, the violating ArgumentIndex
|
||||
// will be caught and IAE thrown instead of the NPE
|
||||
@Test
|
||||
public void localeDependentSubFormatTest() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new MessageFormat("{10000,number,short}", null));
|
||||
// For reference
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new MessageFormat("{999,number,short}", null));
|
||||
}
|
||||
|
||||
// Check that the static format method enforces the limit
|
||||
@Test
|
||||
public void staticFormatTest() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> MessageFormat.format(VIOLATES_MAX_ARGUMENT_INDEX, new Object[]{1}));
|
||||
}
|
||||
|
||||
// Check that applyPattern(String) enforces the limit
|
||||
@Test
|
||||
public void applyPatternTest() {
|
||||
MessageFormat mf = new MessageFormat("");
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> mf.applyPattern(VIOLATES_MAX_ARGUMENT_INDEX));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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
|
||||
* @summary Validate some exceptions in MessageFormat
|
||||
* @bug 6481179 8039165 8318761
|
||||
* @run junit MessageFormatExceptions
|
||||
*/
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class MessageFormatExceptions {
|
||||
|
||||
// Any exception for a Subformat should be re-thrown as propagated as an IAE
|
||||
// to the MessageFormat
|
||||
@Test
|
||||
public void rethrowAsIAE() {
|
||||
// Same Subformat pattern for ChoiceFormat throws NumberFormatException
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new MessageFormat("{0,choice,0foo#foo}"));
|
||||
}
|
||||
|
||||
// MessageFormat should throw NPE when constructed with a null pattern
|
||||
@Test
|
||||
public void nullPatternTest() {
|
||||
assertThrows(NullPointerException.class, () -> new MessageFormat(null));
|
||||
assertThrows(NullPointerException.class, () -> new MessageFormat(null, Locale.US));
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> MessageFormat.format(null, new Object[] { "val0", "val1" }));
|
||||
}
|
||||
|
||||
// 8039165: When MessageFormat is constructed with a null locale a NPE
|
||||
// can potentially be thrown depending on the subformat created. Either
|
||||
// during the creation of the object itself, or later when format() is called.
|
||||
// The following are some examples.
|
||||
@Test
|
||||
public void nullLocaleTest() {
|
||||
// Fails when constructor invokes applyPattern()
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new MessageFormat("{0, date}", null));
|
||||
// Same as above, but with Subformat pattern
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new MessageFormat("{0, date,dd}", null));
|
||||
// Fail when constructor invokes applyPattern()
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new MessageFormat("{0, number}", null));
|
||||
// Fail when object calls format()
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> new MessageFormat("{0}", null).format(new Object[]{42}));
|
||||
// Fail when object calls format(), but locale is set via .setLocale()
|
||||
MessageFormat msgFmt = new MessageFormat("{0}");
|
||||
msgFmt.setLocale(null);
|
||||
assertThrows(NullPointerException.class, () -> msgFmt.format(new Object[]{42}));
|
||||
// Does not always fail if locale is null
|
||||
assertDoesNotThrow(() ->
|
||||
new MessageFormat("{0}", null).format(new Object[]{"hello"}));
|
||||
|
||||
}
|
||||
|
||||
// 6481179: Invalid format type should be provided in error message of IAE
|
||||
@Test
|
||||
public void formatMsgTest() {
|
||||
IllegalArgumentException iae = assertThrows(IllegalArgumentException.class,
|
||||
() -> MessageFormat.format("Testdata {1,invalid_format_type}", new Object[] { "val0", "val1" }));
|
||||
assertEquals("unknown format type: invalid_format_type", iae.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* 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
|
||||
* @summary Verify that MessageFormat.toPattern() properly escapes special curly braces
|
||||
* @bug 8323699
|
||||
* @run junit MessageFormatToPatternTest
|
||||
*/
|
||||
|
||||
import java.text.ChoiceFormat;
|
||||
import java.text.DateFormat;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
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;
|
||||
|
||||
public class MessageFormatToPatternTest {
|
||||
|
||||
private static final int NUM_RANDOM_TEST_CASES = 1000;
|
||||
|
||||
// Max levels of nesting of ChoiceFormats inside MessageFormats
|
||||
private static final int MAX_FORMAT_NESTING = 3;
|
||||
|
||||
private static Locale savedLocale;
|
||||
private static long randomSeed; // set this to a non-zero value for reproducibility
|
||||
private static Random random;
|
||||
private static boolean spitSeed;
|
||||
private static int textCount;
|
||||
|
||||
// Setup & Teardown
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
savedLocale = Locale.getDefault();
|
||||
Locale.setDefault(Locale.US);
|
||||
if (randomSeed == 0)
|
||||
randomSeed = new Random().nextLong();
|
||||
random = new Random(randomSeed);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown() {
|
||||
Locale.setDefault(savedLocale);
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
// Test expected output when given a MessageFormat pattern string and value 1.23
|
||||
@ParameterizedTest
|
||||
@MethodSource("generateOutputTestCases")
|
||||
public void testOutput(String pattern, String expected) {
|
||||
|
||||
// Test we get the expected output
|
||||
MessageFormat format = new MessageFormat(pattern);
|
||||
String actual = format.format(new Object[] { 1.23 });
|
||||
assertEquals(expected, actual);
|
||||
|
||||
// Test round trip as well
|
||||
testRoundTrip(format);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> generateOutputTestCases() {
|
||||
return Stream.of(
|
||||
|
||||
// This is the test case from JDK-8323699
|
||||
Arguments.of("{0,choice,0.0#option A: {0}|1.0#option B: {0}'}'}", "option B: 1.23}"),
|
||||
Arguments.of("{0,choice,0.0#option A: {0}|2.0#option B: {0}'}'}", "option A: 1.23"),
|
||||
|
||||
// A few more test cases from the PR#17416 discussion
|
||||
Arguments.of("Test: {0,number,foo'{'#.00}", "Test: foo{1.23"),
|
||||
Arguments.of("Test: {0,number,foo'}'#.00}", "Test: foo}1.23"),
|
||||
Arguments.of("{0,number,' abc }'' ' 0.00}", " abc }' 1.23"),
|
||||
Arguments.of("Wayne ''The Great One'' Gretsky", "Wayne 'The Great One' Gretsky"),
|
||||
Arguments.of("'Wayne ''The Great One'' Gretsky'", "Wayne 'The Great One' Gretsky"),
|
||||
Arguments.of("{0,choice,0.0#'''{''curly''}'' braces'}", "{curly} braces"),
|
||||
Arguments.of("{0,choice,0.0#''{''curly''}'' braces}", "{curly} braces"),
|
||||
Arguments.of("{0,choice,0.0#'{0,choice,0.0#''{0,choice,0.0#''''{0,choice,0.0#foo}''''}''}'}", "foo"),
|
||||
|
||||
// Absurd double quote examples
|
||||
Arguments.of("Foo '}''''''''}' {0,number,bar'}' '}' } baz ", "Foo }''''} bar} } 1 baz "),
|
||||
Arguments.of("'''}''{'''}''''}'", "'}'{'}''}"),
|
||||
|
||||
// An absurdly complicated example
|
||||
Arguments.of("{0,choice,0.0#text2887 [] '{'1,date,YYYY-MM-DD'}' text2888 [''*'']|1.0#found|2.0#'text2901 [oog'')!''] {2,choice,0.0#''text2897 ['''']''''wq1Q] {2,choice,0.0#''''text2891 [s''''''''&''''''''] {0,number,#0.##} text2892 [8''''''''|$'''''''''''''''''''''''']''''|1.0#''''text2893 [] {0,number,#0.##} text2894 [S'''''''']'''''''']''''|2.0#text2895 [''''''''.''''''''eB] {1,date,YYYY-MM-DD} text2896 [9Y]} text2898 []''|1.0#''text2899 [xk7] {0,number,#0.##} text2900 []''} text2902 [7'':$)''O]'}{0,choice,0.0#'text2903 [] {0,number,#0.##} text2904 [S'':'']'|1.0#'me'}", "foundme")
|
||||
);
|
||||
}
|
||||
|
||||
// Go roundrip from MessageFormat -> pattern string -> MessageFormat and verify equivalence
|
||||
@ParameterizedTest
|
||||
@MethodSource("generateRoundTripTestCases")
|
||||
public void testRoundTrip(MessageFormat format1) {
|
||||
|
||||
// Prepare MessageFormat argument
|
||||
Object[] args = new Object[] {
|
||||
8.5, // argument for DecimalFormat
|
||||
new Date(1705502102677L), // argument for SimpleDateFormat
|
||||
random.nextInt(6) // argument for ChoiceFormat
|
||||
};
|
||||
|
||||
String pattern1 = null;
|
||||
String result1 = null;
|
||||
String pattern2 = null;
|
||||
String result2 = null;
|
||||
try {
|
||||
|
||||
// Format using the given MessageFormat
|
||||
pattern1 = format1.toPattern();
|
||||
result1 = format1.format(args);
|
||||
|
||||
// Round-trip via toPattern() and repeat
|
||||
MessageFormat format2 = new MessageFormat(pattern1);
|
||||
pattern2 = format2.toPattern();
|
||||
result2 = format2.format(args);
|
||||
|
||||
// Check equivalence
|
||||
assertEquals(result1, result2);
|
||||
assertEquals(pattern1, pattern2);
|
||||
|
||||
// Debug
|
||||
//showRoundTrip(format1, pattern1, result1, pattern2, result2);
|
||||
} catch (RuntimeException | Error e) {
|
||||
System.out.println(String.format("%n********** FAILURE **********%n"));
|
||||
System.out.println(String.format("%s%n", e));
|
||||
if (!spitSeed) {
|
||||
System.out.println(String.format("*** Random seed was 0x%016xL%n", randomSeed));
|
||||
spitSeed = true;
|
||||
}
|
||||
showRoundTrip(format1, pattern1, result1, pattern2, result2);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<Arguments> generateRoundTripTestCases() {
|
||||
final ArrayList<Arguments> argList = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_RANDOM_TEST_CASES; i++)
|
||||
argList.add(Arguments.of(randomFormat()));
|
||||
return argList.stream();
|
||||
}
|
||||
|
||||
// Generate a "random" MessageFormat. We do this by creating a MessageFormat with "{0}" placeholders
|
||||
// and then substituting in random DecimalFormat, DateFormat, and ChoiceFormat subformats. The goal here
|
||||
// is to avoid using pattern strings to construct formats, because they're what we're trying to check.
|
||||
private static MessageFormat randomFormat() {
|
||||
|
||||
// Create a temporary MessageFormat containing "{0}" placeholders and random text
|
||||
StringBuilder tempPattern = new StringBuilder();
|
||||
int numParts = random.nextInt(3) + 1;
|
||||
for (int i = 0; i < numParts; i++) {
|
||||
if (random.nextBoolean())
|
||||
tempPattern.append("{0}"); // temporary placeholder for a subformat
|
||||
else
|
||||
tempPattern.append(quoteText(randomText()));
|
||||
}
|
||||
|
||||
// Replace all the "{0}" placeholders with random subformats
|
||||
MessageFormat format = new MessageFormat(tempPattern.toString());
|
||||
Format[] formats = format.getFormats();
|
||||
for (int i = 0; i < formats.length; i++)
|
||||
formats[i] = randomSubFormat(0);
|
||||
format.setFormats(formats);
|
||||
|
||||
// Done
|
||||
return format;
|
||||
}
|
||||
|
||||
// Generate some random text
|
||||
private static String randomText() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
int length = random.nextInt(6);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = (char)(0x20 + random.nextInt(0x5f));
|
||||
buf.append(ch);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Quote non-alphanumeric characters in the given plain text
|
||||
private static String quoteText(String string) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean quoted = false;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char ch = string.charAt(i);
|
||||
if (ch == '\'')
|
||||
buf.append("''");
|
||||
else if (!(ch == ' ' || Character.isLetter(ch) || Character.isDigit(ch))) {
|
||||
if (!quoted) {
|
||||
buf.append('\'');
|
||||
quoted = true;
|
||||
}
|
||||
buf.append(ch);
|
||||
} else {
|
||||
if (quoted) {
|
||||
buf.append('\'');
|
||||
quoted = false;
|
||||
}
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
if (quoted)
|
||||
buf.append('\'');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Create a random subformat for a MessageFormat
|
||||
private static Format randomSubFormat(int nesting) {
|
||||
int which;
|
||||
if (nesting >= MAX_FORMAT_NESTING)
|
||||
which = random.nextInt(2); // no more recursion
|
||||
else
|
||||
which = random.nextInt(3);
|
||||
switch (which) {
|
||||
case 0:
|
||||
return new DecimalFormat("#.##");
|
||||
case 1:
|
||||
return new SimpleDateFormat("YYYY-MM-DD");
|
||||
default:
|
||||
int numChoices = random.nextInt(3) + 1;
|
||||
assert numChoices > 0;
|
||||
final double[] limits = new double[numChoices];
|
||||
final String[] formats = new String[numChoices];
|
||||
for (int i = 0; i < limits.length; i++) {
|
||||
limits[i] = (double)i;
|
||||
formats[i] = randomMessageFormatContaining(randomSubFormat(nesting + 1));
|
||||
}
|
||||
return new ChoiceFormat(limits, formats);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a MessageFormat pattern string that includes the given Format as a subformat.
|
||||
// The result will be one option in a ChoiceFormat which is nested in an outer MessageFormat.
|
||||
// A ChoiceFormat option string is just a plain string; it's only when that plain string
|
||||
// bubbles up to a containing MessageFormat that it gets interpreted as a MessageFormat string,
|
||||
// and that only happens if the option string contains a '{' character. That will always
|
||||
// be the case for the strings returned by this method of course.
|
||||
private static String randomMessageFormatContaining(Format format) {
|
||||
String beforeText = quoteText(randomText().replaceAll("\\{", "")); // avoid invalid MessageFormat syntax
|
||||
String afterText = quoteText(randomText().replaceAll("\\{", "")); // avoid invalid MessageFormat syntax
|
||||
String middleText;
|
||||
if (format instanceof DecimalFormat dfmt)
|
||||
middleText = String.format("{0,number,%s}", dfmt.toPattern());
|
||||
else if (format instanceof SimpleDateFormat sdfmt)
|
||||
middleText = String.format("{1,date,%s}", sdfmt.toPattern());
|
||||
else if (format instanceof ChoiceFormat cfmt)
|
||||
middleText = String.format("{2,choice,%s}", cfmt.toPattern());
|
||||
else
|
||||
throw new RuntimeException("internal error");
|
||||
return String.format("text%d [%s] %s text%d [%s]", ++textCount, beforeText, middleText, ++textCount, afterText);
|
||||
}
|
||||
|
||||
// Debug printing
|
||||
|
||||
private void showRoundTrip(MessageFormat format1, String pattern1, String result1, String pattern2, String result2) {
|
||||
print(0, format1);
|
||||
System.out.println();
|
||||
if (pattern1 != null)
|
||||
System.out.println(String.format(" pattern1 = %s", javaLiteral(pattern1)));
|
||||
if (result1 != null)
|
||||
System.out.println(String.format(" result1 = %s", javaLiteral(result1)));
|
||||
if (pattern2 != null)
|
||||
System.out.println(String.format(" pattern2 = %s", javaLiteral(pattern2)));
|
||||
if (result2 != null)
|
||||
System.out.println(String.format(" result2 = %s", javaLiteral(result2)));
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static void print(int depth, Object format) {
|
||||
if (format == null)
|
||||
return;
|
||||
if (format instanceof String)
|
||||
System.out.println(String.format("%s- %s", indent(depth), javaLiteral((String)format)));
|
||||
else if (format instanceof MessageFormat)
|
||||
print(depth, (MessageFormat)format);
|
||||
else if (format instanceof DecimalFormat)
|
||||
print(depth, (DecimalFormat)format);
|
||||
else if (format instanceof SimpleDateFormat)
|
||||
print(depth, (SimpleDateFormat)format);
|
||||
else if (format instanceof ChoiceFormat)
|
||||
print(depth, (ChoiceFormat)format);
|
||||
else
|
||||
throw new RuntimeException("internal error: " + format.getClass());
|
||||
}
|
||||
|
||||
private static void print(int depth, MessageFormat format) {
|
||||
System.out.println(String.format("%s- %s: %s", indent(depth), "MessageFormat", javaLiteral(format.toPattern())));
|
||||
for (Format subformat : format.getFormats())
|
||||
print(depth + 1, subformat);
|
||||
}
|
||||
|
||||
private static void print(int depth, DecimalFormat format) {
|
||||
System.out.println(String.format("%s- %s: %s", indent(depth), "DecimalFormat", javaLiteral(format.toPattern())));
|
||||
}
|
||||
|
||||
private static void print(int depth, SimpleDateFormat format) {
|
||||
System.out.println(String.format("%s- %s: %s", indent(depth), "SimpleDateFormat", javaLiteral(format.toPattern())));
|
||||
}
|
||||
|
||||
private static void print(int depth, ChoiceFormat format) {
|
||||
System.out.println(String.format("%s- %s: %s", indent(depth), "ChoiceFormat", javaLiteral(format.toPattern())));
|
||||
for (Object subformat : format.getFormats())
|
||||
print(depth + 1, subformat);
|
||||
}
|
||||
|
||||
private static String indent(int depth) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < depth; i++)
|
||||
buf.append(" ");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Print a Java string in double quotes so it looks like a String literal (for easy pasting into jshell)
|
||||
private static String javaLiteral(String string) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append('"');
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
char ch = string.charAt(i);
|
||||
switch (ch) {
|
||||
case '"':
|
||||
case '\\':
|
||||
buf.append('\\');
|
||||
// FALLTHROUGH
|
||||
default:
|
||||
buf.append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf.append('"').toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 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 4105380
|
||||
* @summary basic tests for new methods getFormatsByArgumentIndex, setFormatByArgumentIndex, setFormatsByArgumentIndex
|
||||
*/
|
||||
|
||||
import java.text.ChoiceFormat;
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class MessageFormatsByArgumentIndex {
|
||||
|
||||
private static String choicePattern = "0.0#are no files|1.0#is one file|1.0<are {0,number,integer} files";
|
||||
private static String quotedChoicePattern = choicePattern.replaceAll("([{}])", "'$1'");
|
||||
|
||||
public static void main(String[] args) {
|
||||
Format[] subformats;
|
||||
|
||||
MessageFormat format = new MessageFormat("{3, choice," + choicePattern + "}, {2}, {0}");
|
||||
|
||||
subformats = format.getFormatsByArgumentIndex();
|
||||
checkSubformatLength(subformats, 4);
|
||||
checkSubformat(subformats, 0, null);
|
||||
checkSubformat(subformats, 1, null);
|
||||
checkSubformat(subformats, 2, null);
|
||||
checkSubformat(subformats, 3, new ChoiceFormat(choicePattern));
|
||||
|
||||
subformats = format.getFormats();
|
||||
checkSubformatLength(subformats, 3);
|
||||
checkSubformat(subformats, 0, new ChoiceFormat(choicePattern));
|
||||
checkSubformat(subformats, 1, null);
|
||||
checkSubformat(subformats, 2, null);
|
||||
|
||||
format.setFormatByArgumentIndex(0, NumberFormat.getInstance());
|
||||
|
||||
checkPattern(format.toPattern(), "{3,choice," + quotedChoicePattern + "}, {2}, {0,number}");
|
||||
|
||||
subformats = format.getFormatsByArgumentIndex();
|
||||
checkSubformatLength(subformats, 4);
|
||||
checkSubformat(subformats, 0, NumberFormat.getInstance());
|
||||
checkSubformat(subformats, 1, null);
|
||||
checkSubformat(subformats, 2, null);
|
||||
checkSubformat(subformats, 3, new ChoiceFormat(choicePattern));
|
||||
|
||||
subformats = format.getFormats();
|
||||
checkSubformatLength(subformats, 3);
|
||||
checkSubformat(subformats, 0, new ChoiceFormat(choicePattern));
|
||||
checkSubformat(subformats, 1, null);
|
||||
checkSubformat(subformats, 2, NumberFormat.getInstance());
|
||||
|
||||
format.setFormatsByArgumentIndex(subformats);
|
||||
|
||||
checkPattern(format.toPattern(),
|
||||
"{3,choice," + quotedChoicePattern + "}, {2,number}, {0,choice," + quotedChoicePattern + "}");
|
||||
|
||||
subformats = format.getFormatsByArgumentIndex();
|
||||
checkSubformatLength(subformats, 4);
|
||||
checkSubformat(subformats, 0, new ChoiceFormat(choicePattern));
|
||||
checkSubformat(subformats, 1, null);
|
||||
checkSubformat(subformats, 2, NumberFormat.getInstance());
|
||||
checkSubformat(subformats, 3, new ChoiceFormat(choicePattern));
|
||||
|
||||
subformats = format.getFormats();
|
||||
checkSubformatLength(subformats, 3);
|
||||
checkSubformat(subformats, 0, new ChoiceFormat(choicePattern));
|
||||
checkSubformat(subformats, 1, NumberFormat.getInstance());
|
||||
checkSubformat(subformats, 2, new ChoiceFormat(choicePattern));
|
||||
|
||||
}
|
||||
|
||||
private static void checkPattern(String actual, String expected) {
|
||||
if (!expected.equals(actual)) {
|
||||
throw new RuntimeException("unexpected pattern:\n expected: " + expected + "\n actual: " + actual);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSubformatLength(Format[] subformats, int expected) {
|
||||
if (subformats.length != expected) {
|
||||
throw new RuntimeException("unexpected subformat length:\n expected: " + expected + "\n actual: " + subformats.length);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSubformat(Format[] subformats, int index, Format expected) {
|
||||
Format subformat = subformats[index];
|
||||
if (subformat == expected) {
|
||||
return;
|
||||
}
|
||||
if ((subformat != null) && subformat.equals(expected)) {
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("found unexpected subformat for argument " + index + ":\n expected: " + expected + "\n actual: " + subformat);
|
||||
}
|
||||
}
|
||||
709
test/jdk/java/text/Format/MessageFormat/MessageRegression.java
Normal file
709
test/jdk/java/text/Format/MessageFormat/MessageRegression.java
Normal file
|
|
@ -0,0 +1,709 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 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 4031438 4058973 4074764 4094906 4104976 4105380 4106659 4106660 4106661
|
||||
* 4111739 4112104 4113018 4114739 4114743 4116444 4118592 4118594 4120552
|
||||
* 4142938 4169959 4232154 4293229 8187551
|
||||
* @summary Regression tests for MessageFormat and associated classes
|
||||
* @library /java/text/testlib
|
||||
* @run junit MessageRegression
|
||||
*/
|
||||
/*
|
||||
(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.*;
|
||||
import java.io.IOException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class MessageRegression {
|
||||
|
||||
/* @bug 4074764
|
||||
* Null exception when formatting pattern with MessageFormat
|
||||
* with no parameters.
|
||||
*/
|
||||
@Test
|
||||
public void Test4074764() {
|
||||
String[] pattern = {"Message without param",
|
||||
"Message with param:{0}",
|
||||
"Longer Message with param {0}"};
|
||||
//difference between the two param strings are that
|
||||
//in the first one, the param position is within the
|
||||
//length of the string without param while it is not so
|
||||
//in the other case.
|
||||
|
||||
MessageFormat messageFormatter = new MessageFormat("");
|
||||
|
||||
try {
|
||||
//Apply pattern with param and print the result
|
||||
messageFormatter.applyPattern(pattern[1]);
|
||||
Object[] params = {new String("BUG"), new Date()};
|
||||
String tempBuffer = messageFormatter.format(params);
|
||||
if (!tempBuffer.equals("Message with param:BUG"))
|
||||
fail("MessageFormat with one param test failed.");
|
||||
System.out.println("Formatted with one extra param : " + tempBuffer);
|
||||
|
||||
//Apply pattern without param and print the result
|
||||
messageFormatter.applyPattern(pattern[0]);
|
||||
tempBuffer = messageFormatter.format(null);
|
||||
if (!tempBuffer.equals("Message without param"))
|
||||
fail("MessageFormat with no param test failed.");
|
||||
System.out.println("Formatted with no params : " + tempBuffer);
|
||||
|
||||
tempBuffer = messageFormatter.format(params);
|
||||
if (!tempBuffer.equals("Message without param"))
|
||||
fail("Formatted with arguments > subsitution failed. result = " + tempBuffer.toString());
|
||||
System.out.println("Formatted with extra params : " + tempBuffer);
|
||||
//This statement gives an exception while formatting...
|
||||
//If we use pattern[1] for the message with param,
|
||||
//we get an NullPointerException in MessageFormat.java(617)
|
||||
//If we use pattern[2] for the message with param,
|
||||
//we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)
|
||||
//Both are due to maxOffset not being reset to -1
|
||||
//in applyPattern() when the pattern does not
|
||||
//contain any param.
|
||||
} catch (Exception foo) {
|
||||
fail("Exception when formatting with no params.");
|
||||
}
|
||||
}
|
||||
|
||||
/* @bug 4058973
|
||||
* MessageFormat.toPattern has weird rounding behavior.
|
||||
*/
|
||||
@Test
|
||||
public void Test4058973() {
|
||||
|
||||
MessageFormat fmt = new MessageFormat("{0,choice,0.0#no files|1.0#one file|1.0< '{'0,number,integer'}' files}");
|
||||
String pat = fmt.toPattern();
|
||||
if (!pat.equals("{0,choice,0.0#no files|1.0#one file|1.0< '{'0,number,integer'}' files}")) {
|
||||
fail("MessageFormat.toPattern failed");
|
||||
}
|
||||
}
|
||||
/* @bug 4031438
|
||||
* More robust message formats.
|
||||
*/
|
||||
@Test
|
||||
public void Test4031438() {
|
||||
Locale locale = Locale.getDefault();
|
||||
Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale),
|
||||
locale + " does not use ASCII digits");
|
||||
|
||||
String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}.";
|
||||
String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.";
|
||||
|
||||
MessageFormat messageFormatter = new MessageFormat("");
|
||||
|
||||
try {
|
||||
System.out.println("Apply with pattern : " + pattern1);
|
||||
messageFormatter.applyPattern(pattern1);
|
||||
Object[] params = {7};
|
||||
String tempBuffer = messageFormatter.format(params);
|
||||
if (!tempBuffer.equals("Impossible {1} has occurred -- status code is 7 and message is {2}."))
|
||||
fail("Tests arguments < substitution failed. Formatted text=" +
|
||||
"<" + tempBuffer + ">");
|
||||
System.out.println("Formatted with 7 : " + tempBuffer);
|
||||
ParsePosition status = new ParsePosition(0);
|
||||
Object[] objs = messageFormatter.parse(tempBuffer, status);
|
||||
if (objs[params.length] != null)
|
||||
fail("Parse failed with more than expected arguments");
|
||||
for (int i = 0; i < objs.length; i++) {
|
||||
if (objs[i] != null && !objs[i].toString().equals(params[i].toString())) {
|
||||
fail("Parse failed on object " + objs[i] + " at index : " + i);
|
||||
}
|
||||
}
|
||||
tempBuffer = messageFormatter.format(null);
|
||||
if (!tempBuffer.equals("Impossible {1} has occurred -- status code is {0} and message is {2}."))
|
||||
fail("Tests with no arguments failed");
|
||||
System.out.println("Formatted with null : " + tempBuffer);
|
||||
System.out.println("Apply with pattern : " + pattern2);
|
||||
messageFormatter.applyPattern(pattern2);
|
||||
tempBuffer = messageFormatter.format(params);
|
||||
if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {1} test plus other {2} stuff."))
|
||||
fail("quote format test (w/ params) failed.");
|
||||
System.out.println("Formatted with params : " + tempBuffer);
|
||||
tempBuffer = messageFormatter.format(null);
|
||||
if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))
|
||||
fail("quote format test (w/ null) failed.");
|
||||
System.out.println("Formatted with null : " + tempBuffer);
|
||||
System.out.println("toPattern : " + messageFormatter.toPattern());
|
||||
} catch (Exception foo) {
|
||||
fail("Exception when formatting in bug 4031438. "+foo.getMessage());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void Test4052223()
|
||||
{
|
||||
ParsePosition pos = new ParsePosition(0);
|
||||
if (pos.getErrorIndex() != -1) {
|
||||
fail("ParsePosition.getErrorIndex initialization failed.");
|
||||
}
|
||||
MessageFormat fmt = new MessageFormat("There are {0} apples growing on the {1} tree.");
|
||||
String str = new String("There is one apple growing on the peach tree.");
|
||||
Object[] objs = fmt.parse(str, pos);
|
||||
System.out.println("unparsable string , should fail at " + pos.getErrorIndex());
|
||||
if (pos.getErrorIndex() == -1)
|
||||
fail("Bug 4052223 failed : parsing string " + str);
|
||||
pos.setErrorIndex(4);
|
||||
if (pos.getErrorIndex() != 4)
|
||||
fail("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4");
|
||||
ChoiceFormat f = new ChoiceFormat(
|
||||
"-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.");
|
||||
pos.setIndex(0); pos.setErrorIndex(-1);
|
||||
Number obj = f.parse("are negative", pos);
|
||||
if (pos.getErrorIndex() != -1 && obj.doubleValue() == -1.0)
|
||||
fail("Parse with \"are negative\" failed, at " + pos.getErrorIndex());
|
||||
pos.setIndex(0); pos.setErrorIndex(-1);
|
||||
obj = f.parse("are no or fraction ", pos);
|
||||
if (pos.getErrorIndex() != -1 && obj.doubleValue() == 0.0)
|
||||
fail("Parse with \"are no or fraction\" failed, at " + pos.getErrorIndex());
|
||||
pos.setIndex(0); pos.setErrorIndex(-1);
|
||||
obj = f.parse("go postal", pos);
|
||||
if (pos.getErrorIndex() == -1 && !Double.isNaN(obj.doubleValue()))
|
||||
fail("Parse with \"go postal\" failed, at " + pos.getErrorIndex());
|
||||
}
|
||||
/* @bug 4104976
|
||||
* ChoiceFormat.equals(null) throws NullPointerException
|
||||
*/
|
||||
@Test
|
||||
public void Test4104976()
|
||||
{
|
||||
double[] limits = {1, 20};
|
||||
String[] formats = {"xyz", "abc"};
|
||||
ChoiceFormat cf = new ChoiceFormat(limits, formats);
|
||||
try {
|
||||
System.out.println("Compares to null is always false, returned : ");
|
||||
System.out.println(cf.equals(null) ? "TRUE" : "FALSE");
|
||||
} catch (Exception foo) {
|
||||
fail("ChoiceFormat.equals(null) throws exception.");
|
||||
}
|
||||
}
|
||||
/* @bug 4106659
|
||||
* ChoiceFormat.ctor(double[], String[]) doesn't check
|
||||
* whether lengths of input arrays are equal.
|
||||
*/
|
||||
@Test
|
||||
public void Test4106659()
|
||||
{
|
||||
double[] limits = {1, 2, 3};
|
||||
String[] formats = {"one", "two"};
|
||||
ChoiceFormat cf = null;
|
||||
try {
|
||||
cf = new ChoiceFormat(limits, formats);
|
||||
} catch (Exception foo) {
|
||||
System.out.println("ChoiceFormat constructor should check for the array lengths");
|
||||
cf = null;
|
||||
}
|
||||
if (cf != null) fail(cf.format(5));
|
||||
}
|
||||
|
||||
/* @bug 4106660
|
||||
* ChoiceFormat.ctor(double[], String[]) allows unordered double array.
|
||||
* This is not a bug, added javadoc to emphasize the use of limit
|
||||
* array must be in ascending order.
|
||||
*/
|
||||
@Test
|
||||
public void Test4106660()
|
||||
{
|
||||
double[] limits = {3, 1, 2};
|
||||
String[] formats = {"Three", "One", "Two"};
|
||||
ChoiceFormat cf = new ChoiceFormat(limits, formats);
|
||||
double d = 5.0;
|
||||
String str = cf.format(d);
|
||||
if (!str.equals("Two"))
|
||||
fail("format(" + d + ") = " + cf.format(d));
|
||||
}
|
||||
|
||||
/* @bug 4111739
|
||||
* MessageFormat is incorrectly serialized/deserialized.
|
||||
*/
|
||||
@Test
|
||||
public void Test4111739()
|
||||
{
|
||||
MessageFormat format1 = null;
|
||||
MessageFormat format2 = null;
|
||||
ObjectOutputStream ostream = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
ObjectInputStream istream = null;
|
||||
|
||||
try {
|
||||
baos = new ByteArrayOutputStream();
|
||||
ostream = new ObjectOutputStream(baos);
|
||||
} catch(IOException e) {
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
format1 = new MessageFormat("pattern{0}");
|
||||
ostream.writeObject(format1);
|
||||
ostream.flush();
|
||||
|
||||
byte bytes[] = baos.toByteArray();
|
||||
|
||||
istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
format2 = (MessageFormat)istream.readObject();
|
||||
} catch(Exception e) {
|
||||
fail("Unexpected exception : " + e.getMessage());
|
||||
}
|
||||
|
||||
if (!format1.equals(format2)) {
|
||||
fail("MessageFormats before and after serialization are not" +
|
||||
" equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +
|
||||
format2 + "(" + format2.toPattern() + ")");
|
||||
} else {
|
||||
System.out.println("Serialization for MessageFormat is OK.");
|
||||
}
|
||||
}
|
||||
/* @bug 4114743
|
||||
* MessageFormat.applyPattern allows illegal patterns.
|
||||
*/
|
||||
@Test
|
||||
public void Test4114743()
|
||||
{
|
||||
String originalPattern = "initial pattern";
|
||||
MessageFormat mf = new MessageFormat(originalPattern);
|
||||
try {
|
||||
String illegalPattern = "ab { '}' de";
|
||||
mf.applyPattern(illegalPattern);
|
||||
fail("illegal pattern: \"" + illegalPattern + "\"");
|
||||
} catch (IllegalArgumentException foo) {
|
||||
if (!originalPattern.equals(mf.toPattern()))
|
||||
fail("pattern after: \"" + mf.toPattern() + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
/* @bug 4116444
|
||||
* MessageFormat.parse has different behavior in case of null.
|
||||
*/
|
||||
@Test
|
||||
public void Test4116444()
|
||||
{
|
||||
String[] patterns = {"", "one", "{0,date,short}"};
|
||||
MessageFormat mf = new MessageFormat("");
|
||||
|
||||
for (int i = 0; i < patterns.length; i++) {
|
||||
String pattern = patterns[i];
|
||||
mf.applyPattern(pattern);
|
||||
try {
|
||||
Object[] array = mf.parse(null, new ParsePosition(0));
|
||||
System.out.println("pattern: \"" + pattern + "\"");
|
||||
System.out.println(" parsedObjects: ");
|
||||
if (array != null) {
|
||||
System.out.println("{");
|
||||
for (int j = 0; j < array.length; j++) {
|
||||
if (array[j] != null)
|
||||
fail("\"" + array[j].toString() + "\"");
|
||||
else
|
||||
System.out.println("null");
|
||||
if (j < array.length - 1) System.out.println(",");
|
||||
}
|
||||
System.out.println("}") ;
|
||||
} else {
|
||||
System.out.println("null");
|
||||
}
|
||||
System.out.println("");
|
||||
} catch (Exception e) {
|
||||
fail("pattern: \"" + pattern + "\"");
|
||||
fail(" Exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* @bug 4114739 (FIX and add javadoc)
|
||||
* MessageFormat.format has undocumented behavior about empty format objects.
|
||||
*/
|
||||
@Test
|
||||
public void Test4114739()
|
||||
{
|
||||
|
||||
MessageFormat mf = new MessageFormat("<{0}>");
|
||||
Object[] objs1 = null;
|
||||
Object[] objs2 = {};
|
||||
Object[] objs3 = {null};
|
||||
try {
|
||||
System.out.println("pattern: \"" + mf.toPattern() + "\"");
|
||||
System.out.println("format(null) : ");
|
||||
System.out.println("\"" + mf.format(objs1) + "\"");
|
||||
System.out.println("format({}) : ");
|
||||
System.out.println("\"" + mf.format(objs2) + "\"");
|
||||
System.out.println("format({null}) :");
|
||||
System.out.println("\"" + mf.format(objs3) + "\"");
|
||||
} catch (Exception e) {
|
||||
fail("Exception thrown for null argument tests.");
|
||||
}
|
||||
}
|
||||
|
||||
/* @bug 4113018
|
||||
* MessageFormat.applyPattern works wrong with illegal patterns.
|
||||
*/
|
||||
@Test
|
||||
public void Test4113018()
|
||||
{
|
||||
String originalPattern = "initial pattern";
|
||||
MessageFormat mf = new MessageFormat(originalPattern);
|
||||
String illegalPattern = "format: {0, xxxYYY}";
|
||||
System.out.println("pattern before: \"" + mf.toPattern() + "\"");
|
||||
System.out.println("illegal pattern: \"" + illegalPattern + "\"");
|
||||
try {
|
||||
mf.applyPattern(illegalPattern);
|
||||
fail("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (!originalPattern.equals(mf.toPattern()))
|
||||
fail("pattern after: \"" + mf.toPattern() + "\"");
|
||||
}
|
||||
}
|
||||
/* @bug 4106661
|
||||
* ChoiceFormat is silent about the pattern usage in javadoc.
|
||||
*/
|
||||
@Test
|
||||
public void Test4106661()
|
||||
{
|
||||
ChoiceFormat fmt = new ChoiceFormat(
|
||||
"-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.");
|
||||
System.out.println("Formatter Pattern : " + fmt.toPattern());
|
||||
|
||||
System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
|
||||
System.out.println("Format with -1.0 : " + fmt.format(-1.0));
|
||||
System.out.println("Format with 0 : " + fmt.format(0));
|
||||
System.out.println("Format with 0.9 : " + fmt.format(0.9));
|
||||
System.out.println("Format with 1.0 : " + fmt.format(1));
|
||||
System.out.println("Format with 1.5 : " + fmt.format(1.5));
|
||||
System.out.println("Format with 2 : " + fmt.format(2));
|
||||
System.out.println("Format with 2.1 : " + fmt.format(2.1));
|
||||
System.out.println("Format with NaN : " + fmt.format(Double.NaN));
|
||||
System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
|
||||
}
|
||||
/* @bug 4094906
|
||||
* ChoiceFormat should accept \u221E as eq. to INF.
|
||||
*/
|
||||
@Test
|
||||
public void Test4094906()
|
||||
{
|
||||
ChoiceFormat fmt = new ChoiceFormat(
|
||||
"-\u221E<are negative|0<are no or fraction|1#is one|1.0<is 1+|\u221E<are many.");
|
||||
if (!fmt.toPattern().startsWith("-\u221E<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|\u221E<are many."))
|
||||
fail("Formatter Pattern : " + fmt.toPattern());
|
||||
System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
|
||||
System.out.println("Format with -1.0 : " + fmt.format(-1.0));
|
||||
System.out.println("Format with 0 : " + fmt.format(0));
|
||||
System.out.println("Format with 0.9 : " + fmt.format(0.9));
|
||||
System.out.println("Format with 1.0 : " + fmt.format(1));
|
||||
System.out.println("Format with 1.5 : " + fmt.format(1.5));
|
||||
System.out.println("Format with 2 : " + fmt.format(2));
|
||||
System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
|
||||
}
|
||||
|
||||
/* @bug 4118592
|
||||
* MessageFormat.parse fails with ChoiceFormat.
|
||||
*/
|
||||
@Test
|
||||
public void Test4118592()
|
||||
{
|
||||
MessageFormat mf = new MessageFormat("");
|
||||
String pattern = "{0,choice,1#YES|2#NO}";
|
||||
String prefix = "";
|
||||
for (int i = 0; i < 5; i++) {
|
||||
String formatted = prefix + "YES";
|
||||
mf.applyPattern(prefix + pattern);
|
||||
prefix += "x";
|
||||
Object[] objs = mf.parse(formatted, new ParsePosition(0));
|
||||
System.out.println(i + ". pattern :\"" + mf.toPattern() + "\"");
|
||||
System.out.println(" \"" + formatted + "\" parsed as ");
|
||||
if (objs == null) System.out.println(" null");
|
||||
else System.out.println(" " + objs[0]);
|
||||
}
|
||||
}
|
||||
/* @bug 4118594
|
||||
* MessageFormat.parse fails for some patterns.
|
||||
*/
|
||||
@Test
|
||||
public void Test4118594()
|
||||
{
|
||||
MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
|
||||
String forParsing = "x, y, z";
|
||||
Object[] objs = mf.parse(forParsing, new ParsePosition(0));
|
||||
System.out.println("pattern: \"" + mf.toPattern() + "\"");
|
||||
System.out.println("text for parsing: \"" + forParsing + "\"");
|
||||
if (!objs[0].toString().equals("z"))
|
||||
fail("argument0: \"" + objs[0] + "\"");
|
||||
mf.setLocale(Locale.US);
|
||||
mf.applyPattern("{0,number,#.##}, {0,number,#.#}");
|
||||
Object[] oldobjs = {3.1415};
|
||||
String result = mf.format( oldobjs );
|
||||
System.out.println("pattern: \"" + mf.toPattern() + "\"");
|
||||
System.out.println("text for parsing: \"" + result + "\"");
|
||||
// result now equals "3.14, 3.1"
|
||||
if (!result.equals("3.14, 3.1"))
|
||||
fail("result = " + result);
|
||||
Object[] newobjs = mf.parse(result, new ParsePosition(0));
|
||||
// newobjs now equals {new Double(3.1)}
|
||||
if (((Double)newobjs[0]).doubleValue() != 3.1)
|
||||
fail( "newobjs[0] = " + newobjs[0]);
|
||||
}
|
||||
/* @bug 4105380
|
||||
* When using ChoiceFormat, MessageFormat is not good for I18n.
|
||||
*/
|
||||
@Test
|
||||
public void Test4105380()
|
||||
{
|
||||
String patternText1 = "The disk \"{1}\" contains {0}.";
|
||||
String patternText2 = "There are {0} on the disk \"{1}\"";
|
||||
MessageFormat form1 = new MessageFormat(patternText1);
|
||||
MessageFormat form2 = new MessageFormat(patternText2);
|
||||
double[] filelimits = {0,1,2};
|
||||
String[] filepart = {"no files","one file","{0,number} files"};
|
||||
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
|
||||
form1.setFormat(1, fileform);
|
||||
form2.setFormat(0, fileform);
|
||||
Object[] testArgs = {12373L, "MyDisk"};
|
||||
System.out.println(form1.format(testArgs));
|
||||
System.out.println(form2.format(testArgs));
|
||||
}
|
||||
/* @bug 4120552
|
||||
* MessageFormat.parse incorrectly sets errorIndex.
|
||||
*/
|
||||
@Test
|
||||
public void Test4120552()
|
||||
{
|
||||
MessageFormat mf = new MessageFormat("pattern");
|
||||
String texts[] = {"pattern", "pat", "1234"};
|
||||
System.out.println("pattern: \"" + mf.toPattern() + "\"");
|
||||
for (int i = 0; i < texts.length; i++) {
|
||||
ParsePosition pp = new ParsePosition(0);
|
||||
Object[] objs = mf.parse(texts[i], pp);
|
||||
System.out.println(" text for parsing: \"" + texts[i] + "\"");
|
||||
if (objs == null) {
|
||||
System.out.println(" (incorrectly formatted string)");
|
||||
if (pp.getErrorIndex() == -1)
|
||||
fail("Incorrect error index: " + pp.getErrorIndex());
|
||||
} else {
|
||||
System.out.println(" (correctly formatted string)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 4142938
|
||||
* MessageFormat handles single quotes in pattern wrong.
|
||||
* This is actually a problem in ChoiceFormat; it doesn't
|
||||
* understand single quotes.
|
||||
*/
|
||||
@Test
|
||||
public void Test4142938() {
|
||||
String pat = "''Vous'' {0,choice,0#n''|1#}avez s\u00E9lectionne\u00E9 " +
|
||||
"{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " +
|
||||
"personnel{0,choice,0#s|1#|2#s}.";
|
||||
MessageFormat mf = new MessageFormat(pat);
|
||||
|
||||
String[] PREFIX = {
|
||||
"'Vous' n'avez s\u00E9lectionne\u00E9 aucun clients personnels.",
|
||||
"'Vous' avez s\u00E9lectionne\u00E9 ",
|
||||
"'Vous' avez s\u00E9lectionne\u00E9 "
|
||||
};
|
||||
String[] SUFFIX = {
|
||||
null,
|
||||
" client personnel.",
|
||||
" clients personnels."
|
||||
};
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
String out = mf.format(new Object[]{i});
|
||||
if (SUFFIX[i] == null) {
|
||||
if (!out.equals(PREFIX[i]))
|
||||
fail("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");
|
||||
}
|
||||
else {
|
||||
if (!out.startsWith(PREFIX[i]) ||
|
||||
!out.endsWith(SUFFIX[i]))
|
||||
fail("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +
|
||||
SUFFIX[i] + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 4142938
|
||||
* Test the applyPattern and toPattern handling of single quotes
|
||||
* by ChoiceFormat. (This is in here because this was a bug reported
|
||||
* against MessageFormat.) The single quote is used to quote the
|
||||
* pattern characters '|', '#', '<', and '\u2264'. Two quotes in a row
|
||||
* is a quote literal.
|
||||
*/
|
||||
@Test
|
||||
public void TestChoicePatternQuote() {
|
||||
String[] DATA = {
|
||||
// Pattern 0 value 1 value
|
||||
"0#can''t|1#can", "can't", "can",
|
||||
"0#'pound(#)=''#'''|1#xyz", "pound(#)='#'", "xyz",
|
||||
"0#'1<2 | 1\u22641'|1#''", "1<2 | 1\u22641", "'",
|
||||
};
|
||||
for (int i=0; i<DATA.length; i+=3) {
|
||||
try {
|
||||
ChoiceFormat cf = new ChoiceFormat(DATA[i]);
|
||||
for (int j=0; j<=1; ++j) {
|
||||
String out = cf.format(j);
|
||||
if (!out.equals(DATA[i+1+j]))
|
||||
fail("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +
|
||||
out + "; want \"" + DATA[i+1+j] + '"');
|
||||
}
|
||||
String pat = cf.toPattern();
|
||||
String pat2 = new ChoiceFormat(pat).toPattern();
|
||||
if (!pat.equals(pat2))
|
||||
fail("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
|
||||
else
|
||||
System.out.println("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
fail("Fail: Pattern \"" + DATA[i] + "\" -> " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 4112104
|
||||
* MessageFormat.equals(null) throws a NullPointerException. The JLS states
|
||||
* that it should return false.
|
||||
*/
|
||||
@Test
|
||||
public void Test4112104() {
|
||||
MessageFormat format = new MessageFormat("");
|
||||
try {
|
||||
// This should NOT throw an exception
|
||||
if (format.equals(null)) {
|
||||
// It also should return false
|
||||
fail("MessageFormat.equals(null) returns false");
|
||||
}
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
fail("MessageFormat.equals(null) throws " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 4169959
|
||||
* MessageFormat does not format null objects. CANNOT REPRODUCE THIS BUG.
|
||||
*/
|
||||
@Test
|
||||
public void Test4169959() {
|
||||
// This works
|
||||
System.out.println(MessageFormat.format( "This will {0}", "work"));
|
||||
|
||||
// This fails
|
||||
System.out.println(MessageFormat.format( "This will {0}",
|
||||
new Object[]{ null } ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4232154() {
|
||||
boolean gotException = false;
|
||||
try {
|
||||
MessageFormat format = new MessageFormat("The date is {0:date}");
|
||||
} catch (Exception e) {
|
||||
gotException = true;
|
||||
if (!(e instanceof IllegalArgumentException)) {
|
||||
throw new RuntimeException("got wrong exception type");
|
||||
}
|
||||
if ("argument number too large at ".equals(e.getMessage())) {
|
||||
throw new RuntimeException("got wrong exception message");
|
||||
}
|
||||
}
|
||||
if (!gotException) {
|
||||
throw new RuntimeException("didn't get exception for invalid input");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test4293229() {
|
||||
MessageFormat format = new MessageFormat("'''{'0}'' '''{0}'''");
|
||||
Object[] args = { null };
|
||||
String expected = "'{0}' '{0}'";
|
||||
String result = format.format(args);
|
||||
if (!result.equals(expected)) {
|
||||
throw new RuntimeException("wrong format result - expected \"" +
|
||||
expected + "\", got \"" + result + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 8187551
|
||||
* test MessageFormat.setFormat() method to throw AIOOBE on invalid index.
|
||||
*/
|
||||
@Test
|
||||
public void test8187551() {
|
||||
//invalid cases ("pattern", "invalid format element index")
|
||||
String[][] invalidCases = {{"The disk \"{1}\" contains {0}.", "2"},
|
||||
{"The disk \"{1}\" contains {0}.", "9"},
|
||||
{"On {1}, there are {0} and {2} folders", "3"}};
|
||||
|
||||
//invalid cases (must throw exception)
|
||||
Arrays.stream(invalidCases).forEach(entry -> messageSetFormat(entry[0],
|
||||
Integer.valueOf(entry[1])));
|
||||
}
|
||||
|
||||
// test MessageFormat.setFormat() method for the given pattern and
|
||||
// format element index
|
||||
private void messageSetFormat(String pattern, int elemIndex) {
|
||||
MessageFormat form = new MessageFormat(pattern);
|
||||
|
||||
double[] fileLimits = {0, 1, 2};
|
||||
String[] filePart = {"no files", "one file", "{0,number} files"};
|
||||
ChoiceFormat fileForm = new ChoiceFormat(fileLimits, filePart);
|
||||
|
||||
boolean AIOOBEThrown = false;
|
||||
try {
|
||||
form.setFormat(elemIndex, fileForm);
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
AIOOBEThrown = true;
|
||||
}
|
||||
|
||||
if (!AIOOBEThrown) {
|
||||
throw new RuntimeException("[FAILED: Must throw" +
|
||||
" ArrayIndexOutOfBoundsException for" +
|
||||
" invalid index " + elemIndex + " used in" +
|
||||
" MessageFormat.setFormat(index, format)]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
103
test/jdk/java/text/Format/MessageFormat/MessageTest.java
Normal file
103
test/jdk/java/text/Format/MessageFormat/MessageTest.java
Normal 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
|
||||
* @summary test MessageFormat
|
||||
* @run junit MessageTest
|
||||
*/
|
||||
/*
|
||||
(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.*;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class MessageTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void TestMSGPatternTest() {
|
||||
Object[] testArgs = {
|
||||
1D, 3456D,
|
||||
"Disk", new Date(10000000000L)};
|
||||
|
||||
String[] testCases = {
|
||||
"Quotes '', '{', 'a' {0} '{0}'",
|
||||
"Quotes '', '{', 'a' {0,number} '{0}'",
|
||||
"'{'1,number,'#',##} {1,number,'#',##}",
|
||||
"There are {1} files on {2} at {3}",
|
||||
"On {2}, there are {1} files, with {0,number,currency}.",
|
||||
"'{1,number,percent}', {1,number,percent}, ",
|
||||
"'{1,date,full}', {1,date,full}, ",
|
||||
"'{3,date,full}', {3,date,full}, ",
|
||||
"'{1,number,#,##}' {1,number,#,##}",
|
||||
};
|
||||
|
||||
for (int i = 0; i < testCases.length; ++i) {
|
||||
Locale save = Locale.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.US);
|
||||
System.out.println("");
|
||||
System.out.println( i + " Pat in: " + testCases[i]);
|
||||
MessageFormat form = new MessageFormat(testCases[i]);
|
||||
System.out.println( i + " Pat out: " + form.toPattern());
|
||||
String result = form.format(testArgs);
|
||||
System.out.println( i + " Result: " + result);
|
||||
Object[] values = form.parse(result);
|
||||
for (int j = 0; j < testArgs.length; ++j) {
|
||||
Object testArg = testArgs[j];
|
||||
Object value = null;
|
||||
if (j < values.length) {
|
||||
value = values[j];
|
||||
}
|
||||
if ((testArg == null && value != null)
|
||||
|| (testArg != null && !testArg.equals(value))) {
|
||||
System.out.println( i + " " + j + " old: " + testArg);
|
||||
System.out.println( i + " " + j + " new: " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(java.text.ParseException pe ) {
|
||||
throw new RuntimeException("Error: MessageFormat.parse throws ParseException");
|
||||
}
|
||||
finally{
|
||||
Locale.setDefault(save);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
test/jdk/java/text/Format/MessageFormat/SerializationTest.java
Normal file
102
test/jdk/java/text/Format/MessageFormat/SerializationTest.java
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 8331446 8340554
|
||||
* @summary Check correctness of deserialization
|
||||
* @run junit SerializationTest
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class SerializationTest {
|
||||
|
||||
// Ensure basic correctness of serialization round trip
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void serializationRoundTrip(MessageFormat expectedMf)
|
||||
throws IOException, ClassNotFoundException {
|
||||
byte[] bytes = ser(expectedMf);
|
||||
MessageFormat actualMf = (MessageFormat) deSer(bytes);
|
||||
assertEquals(expectedMf, actualMf);
|
||||
}
|
||||
|
||||
// Various valid MessageFormats
|
||||
private static Stream<MessageFormat> serializationRoundTrip() {
|
||||
return Stream.of(
|
||||
// basic pattern
|
||||
new MessageFormat("{0} foo"),
|
||||
// Multiple arguments
|
||||
new MessageFormat("{0} {1} foo"),
|
||||
// duplicate arguments
|
||||
new MessageFormat("{0} {0} {1} foo"),
|
||||
// Non-ascending arguments
|
||||
new MessageFormat("{1} {0} foo"),
|
||||
// With locale
|
||||
new MessageFormat("{1} {0} foo", Locale.UK),
|
||||
// With null locale. (NPE not thrown, if no format defined)
|
||||
new MessageFormat("{1} {0} foo", null),
|
||||
// With formats
|
||||
new MessageFormat("{0,number,short} {0} {1,date,long} foo"),
|
||||
// Offset equal to pattern length (0)
|
||||
new MessageFormat("{0}"),
|
||||
// Offset equal to pattern length (1)
|
||||
new MessageFormat("X{0}"),
|
||||
// Offset 1 under pattern length
|
||||
new MessageFormat("X{0}X")
|
||||
);
|
||||
}
|
||||
|
||||
// Utility method to serialize
|
||||
private static byte[] ser(Object obj) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new
|
||||
ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new
|
||||
ObjectOutputStream(byteArrayOutputStream);
|
||||
oos.writeObject(obj);
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
// Utility method to deserialize
|
||||
private static Object deSer(byte[] bytes) throws
|
||||
IOException, ClassNotFoundException {
|
||||
ByteArrayInputStream byteArrayInputStream = new
|
||||
ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new
|
||||
ObjectInputStream(byteArrayInputStream);
|
||||
return ois.readObject();
|
||||
}
|
||||
}
|
||||
204
test/jdk/java/text/Format/MessageFormat/TemporalSubFormats.java
Normal file
204
test/jdk/java/text/Format/MessageFormat/TemporalSubFormats.java
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* 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 8318761
|
||||
* @summary Test MessageFormatPattern ability to recognize the appropriate
|
||||
* FormatType and FormatStyle for DateTimeFormatter(ClassicFormat).
|
||||
* This includes the types dtf_time, dtf_date, dtf_datetime,
|
||||
* and the DateTimeFormatter predefined formatters.
|
||||
* @run junit TemporalSubFormats
|
||||
*/
|
||||
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
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.assertThrows;
|
||||
|
||||
public class TemporalSubFormats {
|
||||
|
||||
// Check that applying the built-in DateTimeFormatter types returns the
|
||||
// correct Format and formats properly. Patterns are case-insensitive
|
||||
@ParameterizedTest
|
||||
@MethodSource("preDefinedTypes")
|
||||
public void preDefinedPatternsTest(String pattern, Format fmt) {
|
||||
var mFmt = new MessageFormat("quux{0,"+pattern+"}quux");
|
||||
Object[] temporals = new Object[]{LocalDate.now(), LocalTime.now(),
|
||||
ZonedDateTime.now(), LocalDateTime.now(), OffsetDateTime.now(), Instant.now()};
|
||||
for (Object val : temporals) {
|
||||
// Wrap in Object array for MessageFormat
|
||||
Object[] wrappedVal = new Object[]{val};
|
||||
|
||||
try {
|
||||
String mFmtted = mFmt.format(wrappedVal);
|
||||
// If current format can support the time object. Check equality of result
|
||||
assertEquals(mFmtted, "quux"+fmt.format(val)+"quux");
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// Otherwise, ensure both throw IAE on unsupported field
|
||||
assertThrows(IllegalArgumentException.class, () -> fmt.format(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provides String patterns and the associated (standalone) FormatType
|
||||
// Values should be case-insensitive
|
||||
private static Stream<Arguments> preDefinedTypes() {
|
||||
return Stream.of(
|
||||
Arguments.of("BASIC_ISO_DATE", DateTimeFormatter.BASIC_ISO_DATE.toFormat()),
|
||||
Arguments.of("ISO_LOCAL_DATE", DateTimeFormatter.ISO_LOCAL_DATE.toFormat()),
|
||||
Arguments.of("ISO_OFFSET_DATE", DateTimeFormatter.ISO_OFFSET_DATE.toFormat()),
|
||||
Arguments.of("ISO_DATE", DateTimeFormatter.ISO_DATE.toFormat()),
|
||||
Arguments.of("iso_local_time", DateTimeFormatter.ISO_LOCAL_TIME.toFormat()),
|
||||
Arguments.of("ISO_OFFSET_TIME", DateTimeFormatter.ISO_OFFSET_TIME.toFormat()),
|
||||
Arguments.of("iso_time", DateTimeFormatter.ISO_TIME.toFormat()),
|
||||
Arguments.of("ISO_LOCAL_DATE_TIME", DateTimeFormatter.ISO_LOCAL_DATE_TIME.toFormat()),
|
||||
Arguments.of("ISO_OFFSET_DATE_TIME", DateTimeFormatter.ISO_OFFSET_DATE_TIME.toFormat()),
|
||||
Arguments.of("ISO_ZONED_DATE_TIME", DateTimeFormatter.ISO_ZONED_DATE_TIME.toFormat()),
|
||||
Arguments.of("ISO_DATE_TIME", DateTimeFormatter.ISO_DATE_TIME.toFormat()),
|
||||
Arguments.of("ISO_ORDINAL_DATE", DateTimeFormatter.ISO_ORDINAL_DATE.toFormat()),
|
||||
Arguments.of("iso_week_date", DateTimeFormatter.ISO_WEEK_DATE.toFormat()),
|
||||
Arguments.of("ISO_INSTANT", DateTimeFormatter.ISO_INSTANT.toFormat()),
|
||||
Arguments.of("RFC_1123_DATE_TIME", DateTimeFormatter.RFC_1123_DATE_TIME.toFormat())
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the appropriate FormatType/Style combo returns correct Format
|
||||
// Unlike the other pattern tests, the formatted output is used to check
|
||||
// equality, as DateTimeFormatter does not implement equals()
|
||||
@ParameterizedTest
|
||||
@MethodSource("styles")
|
||||
public void applyPatternTest(String style, FormatStyle fStyle) {
|
||||
var time = ZonedDateTime.now();
|
||||
var date = LocalDate.now();
|
||||
|
||||
// Test dtf_date
|
||||
var dFmt = new MessageFormat("{0,dtf_date"+style+"}");
|
||||
assertEquals(DateTimeFormatter.ofLocalizedDate(fStyle).withLocale(
|
||||
dFmt.getLocale()).toFormat().format(date),
|
||||
dFmt.getFormatsByArgumentIndex()[0].format(date));
|
||||
|
||||
// Test dtf_time
|
||||
var tFmt = new MessageFormat("{0,dtf_time"+style+"}");
|
||||
assertEquals(DateTimeFormatter.ofLocalizedTime(fStyle).withLocale(
|
||||
tFmt.getLocale()).toFormat().format(time),
|
||||
tFmt.getFormatsByArgumentIndex()[0].format(time));
|
||||
|
||||
// Test dtf_datetime
|
||||
var dtFmt = new MessageFormat("{0,dtf_datetime"+style+"}");
|
||||
assertEquals(DateTimeFormatter.ofLocalizedDateTime(fStyle).withLocale(
|
||||
dtFmt.getLocale()).toFormat().format(time),
|
||||
dtFmt.getFormatsByArgumentIndex()[0].format(time));
|
||||
}
|
||||
|
||||
// Provides String patterns and the associated FormatStyle
|
||||
private static Stream<Arguments> styles() {
|
||||
return Stream.of(
|
||||
Arguments.of("", FormatStyle.MEDIUM),
|
||||
Arguments.of(",short", FormatStyle.SHORT),
|
||||
Arguments.of(",medium", FormatStyle.MEDIUM),
|
||||
Arguments.of(",long", FormatStyle.LONG),
|
||||
Arguments.of(",full", FormatStyle.FULL)
|
||||
);
|
||||
}
|
||||
|
||||
// Test that a proper Format from a SubformatPattern can be reproduced
|
||||
@Test
|
||||
public void subformatPatternTest() {
|
||||
// SubformatPattern invokes the same method for both dtf_date,
|
||||
// dtf_time, and dtf_datetime
|
||||
var pattern = "d MMM uuuu";
|
||||
var date = LocalDate.now();
|
||||
|
||||
// Test dtf_date
|
||||
var dFmt = new MessageFormat("{0,dtf_date,"+pattern+"}");
|
||||
assertEquals(DateTimeFormatter.ofPattern(pattern,dFmt.getLocale()).toFormat().format(date),
|
||||
dFmt.getFormatsByArgumentIndex()[0].format(date));
|
||||
|
||||
// Test dtf_time
|
||||
var tFmt = new MessageFormat("{0,dtf_time,"+pattern+"}");
|
||||
assertEquals(DateTimeFormatter.ofPattern(pattern,tFmt.getLocale()).toFormat().format(date),
|
||||
tFmt.getFormatsByArgumentIndex()[0].format(date));
|
||||
|
||||
// Test dtf_datetime
|
||||
var dtFmt = new MessageFormat("{0,dtf_datetime,"+pattern+"}");
|
||||
assertEquals(DateTimeFormatter.ofPattern(pattern,dtFmt.getLocale()).toFormat().format(date),
|
||||
dtFmt.getFormatsByArgumentIndex()[0].format(date));
|
||||
}
|
||||
|
||||
// Ensure that only the supported built-in FormatStyles or a
|
||||
// valid SubformatPattern are recognized
|
||||
@Test
|
||||
public void badApplyPatternTest() {
|
||||
// Not a supported FormatStyle: throws the underlying IAE from DTF
|
||||
// as it is interpreted as a subformatPattern
|
||||
IllegalArgumentException exc = assertThrows(IllegalArgumentException.class, () ->
|
||||
new MessageFormat("{0,dtf_date,longer}"));
|
||||
assertEquals("Unknown pattern letter: l", exc.getMessage());
|
||||
|
||||
// Not a legal SubformatPattern: throws the underlying IAE from DTF
|
||||
exc = assertThrows(IllegalArgumentException.class, () ->
|
||||
new MessageFormat("{0,dtf_date,VVV}"));
|
||||
assertEquals("Pattern letter count must be 2: V", exc.getMessage());
|
||||
|
||||
// Pre-defined ISO style does not exist and should be ignored
|
||||
assertDoesNotThrow(() -> new MessageFormat("{0,BASIC_ISO_DATE,foo}"),
|
||||
"Style on a pre-defined DTF should be ignored, instead of throwing an exception");
|
||||
}
|
||||
|
||||
// DateTimeFormatters cannot be recognized when toPattern() is invoked
|
||||
// Default behavior of unrecognizable Formats is a FormatElement
|
||||
// in the form of { ArgumentIndex }
|
||||
@Test
|
||||
public void nonRecognizableToPatternTest() {
|
||||
// Check SubformatPattern
|
||||
var validPattern = "yy";
|
||||
var mFmt = new MessageFormat("{0}");
|
||||
mFmt.setFormatByArgumentIndex(0, DateTimeFormatter.ofPattern(validPattern).toFormat());
|
||||
assertEquals("{0}", mFmt.toPattern());
|
||||
|
||||
// Check pre-defined styles
|
||||
var dFmt = new MessageFormat("{0,dtf_date,long}");
|
||||
assertEquals("{0}", dFmt.toPattern());
|
||||
var tFmt = new MessageFormat("{0,dtf_time,long}");
|
||||
assertEquals("{0}", tFmt.toPattern());
|
||||
var dtFmt = new MessageFormat("{0,dtf_datetime,long}");
|
||||
assertEquals("{0}", dtFmt.toPattern());
|
||||
}
|
||||
}
|
||||
57
test/jdk/java/text/Format/MessageFormat/ToStringTest.java
Normal file
57
test/jdk/java/text/Format/MessageFormat/ToStringTest.java
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.MessageFormat;
|
||||
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
|
||||
@Test
|
||||
public void expectedValueTest() {
|
||||
String expectedStr =
|
||||
"MessageFormat [locale: \"English (Canada)\", pattern: \"foo {0}\"]\n";
|
||||
var m = new MessageFormat("foo {0}", Locale.CANADA);
|
||||
assertEquals(expectedStr, m.toString());
|
||||
}
|
||||
|
||||
// Check the expected value when the locale is null
|
||||
@Test
|
||||
public void nullLocaleTest() {
|
||||
String expectedStr =
|
||||
"MessageFormat [locale: null, pattern: \"foo {0}\"]\n";
|
||||
var m = new MessageFormat("foo {0}", null);
|
||||
assertEquals(expectedStr, m.toString());
|
||||
}
|
||||
}
|
||||
87
test/jdk/java/text/Format/MessageFormat/bug4492719.java
Normal file
87
test/jdk/java/text/Format/MessageFormat/bug4492719.java
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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 4492719
|
||||
* @summary Confirm that Message.parse() interprets time zone which uses "GMT+/-" format correctly and doesn't throw ParseException.
|
||||
* @run junit/othervm bug4492719
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class bug4492719 {
|
||||
|
||||
// MessageFormat.parse() should be able to interpret a time zone
|
||||
// that uses "GMT+/-".
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
Locale savedLocale = Locale.getDefault();
|
||||
TimeZone savedTimeZone = TimeZone.getDefault();
|
||||
MessageFormat mf;
|
||||
boolean err =false;
|
||||
|
||||
String[] formats = {
|
||||
"short", "medium", "long", "full"
|
||||
};
|
||||
String[] timezones = {
|
||||
"America/Los_Angeles", "GMT", "GMT+09:00", "GMT-8:00",
|
||||
"GMT+123", "GMT-1234", "GMT+2", "GMT-13"
|
||||
};
|
||||
String text;
|
||||
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
try {
|
||||
for (int i = 0; i < timezones.length; i++) {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(timezones[i]));
|
||||
|
||||
for (int j = 0; j < formats.length; j++) {
|
||||
mf = new MessageFormat("{0,time," + formats[j] + "} - time");
|
||||
text = MessageFormat.format("{0,time," + formats[j] + "} - time",
|
||||
new Object [] { new Date(123456789012L)});
|
||||
Object[] objs = mf.parse(text);
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
err = true;
|
||||
System.err.println("Invalid ParseException occurred : " +
|
||||
e.getMessage());
|
||||
System.err.println(" TimeZone=" + TimeZone.getDefault());
|
||||
}
|
||||
finally {
|
||||
Locale.setDefault(savedLocale);
|
||||
TimeZone.setDefault(savedTimeZone);
|
||||
if (err) {
|
||||
throw new Exception("MessageFormat.parse(\"GMT format\") failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue