mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add implementation of java.text.MessageFormat
This commit is contained in:
parent
6145afcbf8
commit
90cc2c4677
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.teavm.classlib.java.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.teavm.classlib.java.util.TLocale;
|
||||
|
||||
public class TChoiceFormat extends TNumberFormat {
|
||||
private double[] choiceLimits;
|
||||
private String[] choiceFormats;
|
||||
|
||||
public TChoiceFormat(double[] limits, String[] formats) {
|
||||
setChoices(limits, formats);
|
||||
}
|
||||
|
||||
public TChoiceFormat(String template) {
|
||||
applyPattern(template);
|
||||
}
|
||||
|
||||
public void applyPattern(String template) {
|
||||
double[] limits = new double[5];
|
||||
List<String> formats = new ArrayList<>();
|
||||
int length = template.length();
|
||||
int limitCount = 0;
|
||||
int index = 0;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
TNumberFormat format = TNumberFormat.getInstance(TLocale.US);
|
||||
TParsePosition position = new TParsePosition(0);
|
||||
while (true) {
|
||||
index = skipWhitespace(template, index);
|
||||
if (index >= length) {
|
||||
if (limitCount == limits.length) {
|
||||
choiceLimits = limits;
|
||||
} else {
|
||||
choiceLimits = new double[limitCount];
|
||||
System.arraycopy(limits, 0, choiceLimits, 0, limitCount);
|
||||
}
|
||||
choiceFormats = new String[formats.size()];
|
||||
for (int i = 0; i < formats.size(); i++) {
|
||||
choiceFormats[i] = formats.get(i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
position.setIndex(index);
|
||||
Number value = format.parse(template, position);
|
||||
index = skipWhitespace(template, position.getIndex());
|
||||
if (position.getErrorIndex() != -1 || index >= length) {
|
||||
// Fix Harmony 540
|
||||
choiceLimits = new double[0];
|
||||
choiceFormats = new String[0];
|
||||
return;
|
||||
}
|
||||
char ch = template.charAt(index++);
|
||||
if (limitCount == limits.length) {
|
||||
double[] newLimits = new double[limitCount * 2];
|
||||
System.arraycopy(limits, 0, newLimits, 0, limitCount);
|
||||
limits = newLimits;
|
||||
}
|
||||
double next;
|
||||
switch (ch) {
|
||||
case '#':
|
||||
case '\u2264':
|
||||
next = value.doubleValue();
|
||||
break;
|
||||
case '<':
|
||||
next = nextDouble(value.doubleValue());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (limitCount > 0 && next <= limits[limitCount - 1]) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
buffer.setLength(0);
|
||||
position.setIndex(index);
|
||||
upTo(template, position, buffer, '|');
|
||||
index = position.getIndex();
|
||||
limits[limitCount++] = next;
|
||||
formats.add(buffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
TChoiceFormat clone = (TChoiceFormat) super.clone();
|
||||
clone.choiceLimits = choiceLimits.clone();
|
||||
clone.choiceFormats = choiceFormats.clone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof TChoiceFormat)) {
|
||||
return false;
|
||||
}
|
||||
TChoiceFormat choice = (TChoiceFormat) object;
|
||||
return Arrays.equals(choiceLimits, choice.choiceLimits)
|
||||
&& Arrays.equals(choiceFormats, choice.choiceFormats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer format(double value, StringBuffer buffer, TFieldPosition field) {
|
||||
for (int i = choiceLimits.length - 1; i >= 0; i--) {
|
||||
if (choiceLimits[i] <= value) {
|
||||
return buffer.append(choiceFormats[i]);
|
||||
}
|
||||
}
|
||||
return choiceFormats.length == 0 ? buffer : buffer.append(choiceFormats[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer format(long value, StringBuffer buffer, TFieldPosition field) {
|
||||
return format((double) value, buffer, field);
|
||||
}
|
||||
|
||||
public Object[] getFormats() {
|
||||
return choiceFormats;
|
||||
}
|
||||
|
||||
public double[] getLimits() {
|
||||
return choiceLimits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 0;
|
||||
for (int i = 0; i < choiceLimits.length; i++) {
|
||||
long v = Double.doubleToLongBits(choiceLimits[i]);
|
||||
hashCode += (int) (v ^ (v >>> 32)) + choiceFormats[i].hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public static double nextDouble(double value) {
|
||||
if (value == Double.POSITIVE_INFINITY) {
|
||||
return value;
|
||||
}
|
||||
long bits;
|
||||
// Handle -0.0
|
||||
if (value == 0) {
|
||||
bits = 0;
|
||||
} else {
|
||||
bits = Double.doubleToLongBits(value);
|
||||
}
|
||||
return Double.longBitsToDouble(value < 0 ? bits - 1 : bits + 1);
|
||||
}
|
||||
|
||||
public static double nextDouble(double value, boolean increment) {
|
||||
return increment ? nextDouble(value) : previousDouble(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number parse(String string, TParsePosition position) {
|
||||
int offset = position.getIndex();
|
||||
for (int i = 0; i < choiceFormats.length; i++) {
|
||||
if (string.startsWith(choiceFormats[i], offset)) {
|
||||
position.setIndex(offset + choiceFormats[i].length());
|
||||
return choiceLimits[i];
|
||||
}
|
||||
}
|
||||
position.setErrorIndex(offset);
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
public static double previousDouble(double value) {
|
||||
if (value == Double.NEGATIVE_INFINITY) {
|
||||
return value;
|
||||
}
|
||||
long bits;
|
||||
// Handle 0.0
|
||||
if (value == 0) {
|
||||
bits = 0x8000000000000000L;
|
||||
} else {
|
||||
bits = Double.doubleToLongBits(value);
|
||||
}
|
||||
return Double.longBitsToDouble(value <= 0 ? bits + 1 : bits - 1);
|
||||
}
|
||||
|
||||
public void setChoices(double[] limits, String[] formats) {
|
||||
if (limits.length != formats.length) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
choiceLimits = limits;
|
||||
choiceFormats = formats;
|
||||
}
|
||||
|
||||
private int skipWhitespace(String string, int index) {
|
||||
int length = string.length();
|
||||
while (index < length && Character.isWhitespace(string.charAt(index))) {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public String toPattern() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (int i = 0; i < choiceLimits.length; i++) {
|
||||
if (i != 0) {
|
||||
buffer.append('|');
|
||||
}
|
||||
String previous = String.valueOf(previousDouble(choiceLimits[i]));
|
||||
String limit = String.valueOf(choiceLimits[i]);
|
||||
if (previous.length() < limit.length()) {
|
||||
buffer.append(previous);
|
||||
buffer.append('<');
|
||||
} else {
|
||||
buffer.append(limit);
|
||||
buffer.append('#');
|
||||
}
|
||||
boolean quote = choiceFormats[i].indexOf('|') != -1;
|
||||
if (quote) {
|
||||
buffer.append('\'');
|
||||
}
|
||||
buffer.append(choiceFormats[i]);
|
||||
if (quote) {
|
||||
buffer.append('\'');
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
private boolean decimalSeparatorAlwaysShown;
|
||||
private boolean parseBigDecimal;
|
||||
int exponentDigits;
|
||||
String pattern;
|
||||
|
||||
public TDecimalFormat() {
|
||||
this(CLDRHelper.resolveNumberFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry()));
|
||||
|
@ -65,6 +66,11 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
TDecimalFormatParser parser = new TDecimalFormatParser();
|
||||
parser.parse(pattern);
|
||||
parser.apply(this);
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
String toPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols() {
|
||||
|
|
|
@ -0,0 +1,651 @@
|
|||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.classlib.java.text;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.teavm.classlib.java.util.TIterator;
|
||||
import org.teavm.classlib.java.util.TLocale;
|
||||
|
||||
public class TMessageFormat extends TFormat {
|
||||
private TLocale locale = TLocale.getDefault();
|
||||
transient private String[] strings;
|
||||
private int[] argumentNumbers;
|
||||
private TFormat[] formats;
|
||||
private int maxOffset;
|
||||
transient private int maxArgumentIndex;
|
||||
|
||||
public TMessageFormat(String template, TLocale locale) {
|
||||
this.locale = locale;
|
||||
applyPattern(template);
|
||||
}
|
||||
|
||||
public TMessageFormat(String template) {
|
||||
applyPattern(template);
|
||||
}
|
||||
|
||||
public void applyPattern(String template) {
|
||||
int length = template.length();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
TParsePosition position = new TParsePosition(0);
|
||||
List<String> localStrings = new ArrayList<>();
|
||||
int argCount = 0;
|
||||
int[] args = new int[10];
|
||||
int maxArg = -1;
|
||||
List<TFormat> localFormats = new ArrayList<>();
|
||||
while (position.getIndex() < length) {
|
||||
if (TFormat.upTo(template, position, buffer, '{')) {
|
||||
int arg = 0;
|
||||
int offset = position.getIndex();
|
||||
if (offset >= length) {
|
||||
throw new IllegalArgumentException("Invalid argument number");
|
||||
}
|
||||
// Get argument number
|
||||
while (true) {
|
||||
char ch = template.charAt(offset++);
|
||||
if (ch == '}' || ch == ',') {
|
||||
break;
|
||||
}
|
||||
if (ch < '0' && ch > '9') {
|
||||
throw new IllegalArgumentException("Invalid argument number");
|
||||
}
|
||||
arg = arg * 10 + (ch - '0');
|
||||
if (arg < 0 || offset >= length) {
|
||||
throw new IllegalArgumentException("Invalid argument number");
|
||||
}
|
||||
}
|
||||
offset--;
|
||||
position.setIndex(offset);
|
||||
localFormats.add(parseVariable(template, position));
|
||||
if (argCount >= args.length) {
|
||||
int[] newArgs = new int[args.length * 2];
|
||||
System.arraycopy(args, 0, newArgs, 0, args.length);
|
||||
args = newArgs;
|
||||
}
|
||||
args[argCount++] = arg;
|
||||
if (arg > maxArg) {
|
||||
maxArg = arg;
|
||||
}
|
||||
}
|
||||
localStrings.add(buffer.toString());
|
||||
buffer.setLength(0);
|
||||
}
|
||||
this.strings = new String[localStrings.size()];
|
||||
for (int i = 0; i < localStrings.size(); i++) {
|
||||
this.strings[i] = localStrings.get(i);
|
||||
}
|
||||
argumentNumbers = args;
|
||||
this.formats = new TFormat[argCount];
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
this.formats[i] = localFormats.get(i);
|
||||
}
|
||||
maxOffset = argCount - 1;
|
||||
maxArgumentIndex = maxArg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
TMessageFormat clone = (TMessageFormat) super.clone();
|
||||
TFormat[] array = new TFormat[formats.length];
|
||||
for (int i = formats.length; --i >= 0;) {
|
||||
if (formats[i] != null) {
|
||||
array[i] = (TFormat) formats[i].clone();
|
||||
}
|
||||
}
|
||||
clone.formats = array;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (!(object instanceof TMessageFormat)) {
|
||||
return false;
|
||||
}
|
||||
TMessageFormat format = (TMessageFormat) object;
|
||||
if (maxOffset != format.maxOffset) {
|
||||
return false;
|
||||
}
|
||||
// Must use a loop since the lengths may be different due
|
||||
// to serialization cross-loading
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
if (argumentNumbers[i] != format.argumentNumbers[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return locale.equals(format.locale)
|
||||
&& Arrays.equals(strings, format.strings)
|
||||
&& Arrays.equals(formats, format.formats);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TAttributedCharacterIterator formatToCharacterIterator(Object object) {
|
||||
if (object == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
List<FieldContainer> fields = new ArrayList<>();
|
||||
|
||||
// format the message, and find fields
|
||||
formatImpl((Object[]) object, buffer, new TFieldPosition(0), fields);
|
||||
|
||||
// create an AttributedString with the formatted buffer
|
||||
TAttributedString as = new TAttributedString(buffer.toString());
|
||||
|
||||
// add TMessageFormat field attributes and values to the AttributedString
|
||||
for (FieldContainer fc : fields) {
|
||||
as.addAttribute(fc.attribute, fc.value, fc.start, fc.end);
|
||||
}
|
||||
|
||||
// return the CharacterIterator from AttributedString
|
||||
return as.getIterator();
|
||||
}
|
||||
|
||||
public final StringBuffer format(Object[] objects, StringBuffer buffer, TFieldPosition field) {
|
||||
return formatImpl(objects, buffer, field, null);
|
||||
}
|
||||
|
||||
private StringBuffer formatImpl(Object[] objects, StringBuffer buffer, TFieldPosition position,
|
||||
List<FieldContainer> fields) {
|
||||
TFieldPosition passedField = new TFieldPosition(0);
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
buffer.append(strings[i]);
|
||||
int begin = buffer.length();
|
||||
Object arg;
|
||||
if (objects != null && argumentNumbers[i] < objects.length) {
|
||||
arg = objects[argumentNumbers[i]];
|
||||
} else {
|
||||
buffer.append('{');
|
||||
buffer.append(argumentNumbers[i]);
|
||||
buffer.append('}');
|
||||
handleArgumentField(begin, buffer.length(), argumentNumbers[i], position, fields);
|
||||
continue;
|
||||
}
|
||||
TFormat format = formats[i];
|
||||
if (format == null || arg == null) {
|
||||
if (arg instanceof Number) {
|
||||
format = TNumberFormat.getInstance();
|
||||
} else if (arg instanceof Date) {
|
||||
format = TDateFormat.getInstance();
|
||||
} else {
|
||||
buffer.append(arg);
|
||||
handleArgumentField(begin, buffer.length(), argumentNumbers[i], position, fields);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (format instanceof TChoiceFormat) {
|
||||
String result = format.format(arg);
|
||||
TMessageFormat mf = new TMessageFormat(result);
|
||||
mf.setLocale(locale);
|
||||
mf.format(objects, buffer, passedField);
|
||||
handleArgumentField(begin, buffer.length(), argumentNumbers[i], position, fields);
|
||||
handleformat(format, arg, begin, fields);
|
||||
} else {
|
||||
format.format(arg, buffer, passedField);
|
||||
handleArgumentField(begin, buffer.length(), argumentNumbers[i], position, fields);
|
||||
handleformat(format, arg, begin, fields);
|
||||
}
|
||||
}
|
||||
if (maxOffset + 1 < strings.length) {
|
||||
buffer.append(strings[maxOffset + 1]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private void handleArgumentField(int begin, int end, int argnumber, TFieldPosition position,
|
||||
List<FieldContainer> fields) {
|
||||
if (fields != null) {
|
||||
fields.add(new FieldContainer(begin, end, Field.ARGUMENT, argnumber));
|
||||
} else {
|
||||
if (position != null
|
||||
&& position.getFieldAttribute() == Field.ARGUMENT
|
||||
&& position.getEndIndex() == 0) {
|
||||
position.setBeginIndex(begin);
|
||||
position.setEndIndex(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An inner class to store attributes, values, start and end indices.
|
||||
* Instances of this inner class are used as elements for the fields vector
|
||||
*/
|
||||
static class FieldContainer {
|
||||
int start;
|
||||
int end;
|
||||
TAttributedCharacterIterator.Attribute attribute;
|
||||
Object value;
|
||||
|
||||
FieldContainer(int start, int end, TAttributedCharacterIterator.Attribute attribute, Object value) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.attribute = attribute;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleformat(TFormat format, Object arg, int begin, List<FieldContainer> fields) {
|
||||
if (fields != null) {
|
||||
TAttributedCharacterIterator iterator = format.formatToCharacterIterator(arg);
|
||||
while (iterator.getIndex() != iterator.getEndIndex()) {
|
||||
int start = iterator.getRunStart();
|
||||
int end = iterator.getRunLimit();
|
||||
|
||||
TIterator<TAttributedCharacterIterator.Attribute> iter = iterator.getAttributes().keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
TAttributedCharacterIterator.Attribute attribute = iter.next();
|
||||
Object value = iterator.getAttribute(attribute);
|
||||
fields.add(new FieldContainer(begin + start, begin + end, attribute, value));
|
||||
}
|
||||
iterator.setIndex(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final StringBuffer format(Object object, StringBuffer buffer, TFieldPosition field) {
|
||||
return format((Object[]) object, buffer, field);
|
||||
}
|
||||
|
||||
public static String format(String template, Object... objects) {
|
||||
if (objects != null) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] == null) {
|
||||
objects[i] = "null";
|
||||
}
|
||||
}
|
||||
}
|
||||
return new TMessageFormat(template).format(objects, new StringBuffer(), new TFieldPosition(0)).toString();
|
||||
}
|
||||
|
||||
public TFormat[] getFormats() {
|
||||
return formats.clone();
|
||||
}
|
||||
|
||||
public TFormat[] getFormatsByArgumentIndex() {
|
||||
TFormat[] answer = new TFormat[maxArgumentIndex + 1];
|
||||
for (int i = 0; i < maxOffset + 1; i++) {
|
||||
answer[argumentNumbers[i]] = formats[i];
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
public void setFormatByArgumentIndex(int argIndex, TFormat format) {
|
||||
for (int i = 0; i < maxOffset + 1; i++) {
|
||||
if (argumentNumbers[i] == argIndex) {
|
||||
formats[i] = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setFormatsByArgumentIndex(TFormat[] formats) {
|
||||
for (int j = 0; j < formats.length; j++) {
|
||||
for (int i = 0; i < maxOffset + 1; i++) {
|
||||
if (argumentNumbers[i] == j) {
|
||||
this.formats[i] = formats[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TLocale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 0;
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
hashCode += argumentNumbers[i] + strings[i].hashCode();
|
||||
if (formats[i] != null) {
|
||||
hashCode += formats[i].hashCode();
|
||||
}
|
||||
}
|
||||
if (maxOffset + 1 < strings.length) {
|
||||
hashCode += strings[maxOffset + 1].hashCode();
|
||||
}
|
||||
if (locale != null) {
|
||||
return hashCode + locale.hashCode();
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public Object[] parse(String string) throws ParseException {
|
||||
TParsePosition position = new TParsePosition(0);
|
||||
Object[] result = parse(string, position);
|
||||
if (position.getIndex() == 0) {
|
||||
throw new ParseException("MessageFormat.parseObject(String) parse failure", position.getErrorIndex());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object[] parse(String string, TParsePosition position) {
|
||||
if (string == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
TParsePosition internalPos = new TParsePosition(0);
|
||||
int offset = position.getIndex();
|
||||
Object[] result = new Object[maxArgumentIndex + 1];
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
String sub = strings[i];
|
||||
if (!string.startsWith(sub, offset)) {
|
||||
position.setErrorIndex(offset);
|
||||
return null;
|
||||
}
|
||||
offset += sub.length();
|
||||
Object parse;
|
||||
TFormat format = formats[i];
|
||||
if (format == null) {
|
||||
if (i + 1 < strings.length) {
|
||||
int next = string.indexOf(strings[i + 1], offset);
|
||||
if (next == -1) {
|
||||
position.setErrorIndex(offset);
|
||||
return null;
|
||||
}
|
||||
parse = string.substring(offset, next);
|
||||
offset = next;
|
||||
} else {
|
||||
parse = string.substring(offset);
|
||||
offset = string.length();
|
||||
}
|
||||
} else {
|
||||
internalPos.setIndex(offset);
|
||||
parse = format.parseObject(string, internalPos);
|
||||
if (internalPos.getErrorIndex() != -1) {
|
||||
position.setErrorIndex(offset);
|
||||
return null;
|
||||
}
|
||||
offset = internalPos.getIndex();
|
||||
}
|
||||
result[argumentNumbers[i]] = parse;
|
||||
}
|
||||
if (maxOffset + 1 < strings.length) {
|
||||
String sub = strings[maxOffset + 1];
|
||||
if (!string.startsWith(sub, offset)) {
|
||||
position.setErrorIndex(offset);
|
||||
return null;
|
||||
}
|
||||
offset += sub.length();
|
||||
}
|
||||
position.setIndex(offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseObject(String string, TParsePosition position) {
|
||||
return parse(string, position);
|
||||
}
|
||||
|
||||
private int match(String string, TParsePosition position, boolean last, String[] tokens) {
|
||||
int length = string.length();
|
||||
int offset = position.getIndex();
|
||||
int token = -1;
|
||||
while (offset < length && Character.isWhitespace(string.charAt(offset))) {
|
||||
offset++;
|
||||
}
|
||||
for (int i = tokens.length; --i >= 0;) {
|
||||
if (string.regionMatches(true, offset, tokens[i], 0, tokens[i].length())) {
|
||||
token = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token == -1) {
|
||||
return -1;
|
||||
}
|
||||
offset += tokens[token].length();
|
||||
while (offset < length && Character.isWhitespace(string.charAt(offset))) {
|
||||
offset++;
|
||||
}
|
||||
char ch;
|
||||
if (offset < length) {
|
||||
ch = string.charAt(offset);
|
||||
if (ch == '}' || (!last && ch == ',')) {
|
||||
position.setIndex(offset + 1);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private TFormat parseVariable(String string, TParsePosition position) {
|
||||
int length = string.length();
|
||||
int offset = position.getIndex();
|
||||
char ch;
|
||||
if (offset >= length) {
|
||||
throw new IllegalArgumentException("Missing element format");
|
||||
}
|
||||
|
||||
ch = string.charAt(offset++);
|
||||
if (ch != '}' && ch != ',') {
|
||||
throw new IllegalArgumentException("Missing element format");
|
||||
}
|
||||
|
||||
position.setIndex(offset);
|
||||
if (ch == '}') {
|
||||
return null;
|
||||
}
|
||||
int type = match(string, position, false, new String[] { "time", "date", "number", "choice" });
|
||||
if (type == -1) {
|
||||
throw new IllegalArgumentException("Unknown element format");
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
ch = string.charAt(position.getIndex() - 1);
|
||||
switch (type) {
|
||||
case 0: // time
|
||||
case 1: // date
|
||||
if (ch == '}') {
|
||||
return type == 1
|
||||
? TDateFormat.getDateInstance(DateFormat.DEFAULT, locale)
|
||||
: TDateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
|
||||
}
|
||||
int dateStyle = match(string, position, true, new String[] { "full", "long", "medium", "short" });
|
||||
if (dateStyle == -1) {
|
||||
TFormat.upToWithQuotes(string, position, buffer, '}', '{');
|
||||
return new TSimpleDateFormat(buffer.toString(), locale);
|
||||
}
|
||||
switch (dateStyle) {
|
||||
case 0:
|
||||
dateStyle = DateFormat.FULL;
|
||||
break;
|
||||
case 1:
|
||||
dateStyle = DateFormat.LONG;
|
||||
break;
|
||||
case 2:
|
||||
dateStyle = DateFormat.MEDIUM;
|
||||
break;
|
||||
case 3:
|
||||
dateStyle = DateFormat.SHORT;
|
||||
break;
|
||||
}
|
||||
return type == 1
|
||||
? TDateFormat.getDateInstance(dateStyle, locale)
|
||||
: TDateFormat.getTimeInstance(dateStyle, locale);
|
||||
case 2: // number
|
||||
if (ch == '}') {
|
||||
return TNumberFormat.getInstance();
|
||||
}
|
||||
int numberStyle = match(string, position, true, new String[] { "currency", "percent", "integer" });
|
||||
if (numberStyle == -1) {
|
||||
upToWithQuotes(string, position, buffer, '}', '{');
|
||||
return new TDecimalFormat(buffer.toString(), new TDecimalFormatSymbols(locale));
|
||||
}
|
||||
switch (numberStyle) {
|
||||
case 0: // currency
|
||||
return TNumberFormat.getCurrencyInstance(locale);
|
||||
case 1: // percent
|
||||
return TNumberFormat.getPercentInstance(locale);
|
||||
}
|
||||
return TNumberFormat.getIntegerInstance(locale);
|
||||
}
|
||||
// choice
|
||||
try {
|
||||
upToWithQuotes(string, position, buffer, '}', '{');
|
||||
} catch (IllegalArgumentException e) {
|
||||
// ignored
|
||||
}
|
||||
return new TChoiceFormat(buffer.toString());
|
||||
}
|
||||
|
||||
public void setFormat(int offset, TFormat format) {
|
||||
formats[offset] = format;
|
||||
}
|
||||
|
||||
public void setFormats(TFormat[] formats) {
|
||||
int min = this.formats.length;
|
||||
if (formats.length < min) {
|
||||
min = formats.length;
|
||||
}
|
||||
for (int i = 0; i < min; i++) {
|
||||
this.formats[i] = formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocale(TLocale locale) {
|
||||
this.locale = locale;
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
TFormat format = formats[i];
|
||||
if (format instanceof TDecimalFormat) {
|
||||
formats[i] = new TDecimalFormat(((TDecimalFormat) format).toPattern(),
|
||||
new TDecimalFormatSymbols(locale));
|
||||
} else if (format instanceof TSimpleDateFormat) {
|
||||
formats[i] = new TSimpleDateFormat(((TSimpleDateFormat) format).toPattern(), locale);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private String decodeDecimalFormat(StringBuffer buffer, TFormat format) {
|
||||
buffer.append(",number");
|
||||
if (format.equals(TNumberFormat.getNumberInstance(locale))) {
|
||||
// Empty block
|
||||
} else if (format.equals(TNumberFormat.getIntegerInstance(locale))) {
|
||||
buffer.append(",integer");
|
||||
} else if (format.equals(TNumberFormat.getCurrencyInstance(locale))) {
|
||||
buffer.append(",currency");
|
||||
} else if (format.equals(TNumberFormat.getPercentInstance(locale))) {
|
||||
buffer.append(",percent");
|
||||
} else {
|
||||
buffer.append(',');
|
||||
return ((TDecimalFormat) format).toPattern();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String decodeSimpleDateFormat(StringBuffer buffer, TFormat format) {
|
||||
if (format.equals(TDateFormat.getTimeInstance(DateFormat.DEFAULT, locale))) {
|
||||
buffer.append(",time");
|
||||
} else if (format.equals(TDateFormat.getDateInstance(DateFormat.DEFAULT, locale))) {
|
||||
buffer.append(",date");
|
||||
} else if (format.equals(TDateFormat.getTimeInstance(DateFormat.SHORT, locale))) {
|
||||
buffer.append(",time,short");
|
||||
} else if (format.equals(TDateFormat.getDateInstance(DateFormat.SHORT, locale))) {
|
||||
buffer.append(",date,short");
|
||||
} else if (format.equals(TDateFormat.getTimeInstance(DateFormat.LONG, locale))) {
|
||||
buffer.append(",time,long");
|
||||
} else if (format.equals(TDateFormat.getDateInstance(DateFormat.LONG, locale))) {
|
||||
buffer.append(",date,long");
|
||||
} else if (format.equals(TDateFormat.getTimeInstance(DateFormat.FULL, locale))) {
|
||||
buffer.append(",time,full");
|
||||
} else if (format.equals(TDateFormat.getDateInstance(DateFormat.FULL, locale))) {
|
||||
buffer.append(",date,full");
|
||||
} else {
|
||||
buffer.append(",date,");
|
||||
return ((TSimpleDateFormat) format).toPattern();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toPattern() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int i = 0; i <= maxOffset; i++) {
|
||||
appendQuoted(buffer, strings[i]);
|
||||
buffer.append('{');
|
||||
buffer.append(argumentNumbers[i]);
|
||||
TFormat format = formats[i];
|
||||
String pattern = null;
|
||||
if (format instanceof TChoiceFormat) {
|
||||
buffer.append(",choice,");
|
||||
pattern = ((TChoiceFormat) format).toPattern();
|
||||
} else if (format instanceof TDecimalFormat) {
|
||||
pattern = decodeDecimalFormat(buffer, format);
|
||||
} else if (format instanceof TSimpleDateFormat) {
|
||||
pattern = decodeSimpleDateFormat(buffer, format);
|
||||
} else if (format != null) {
|
||||
throw new IllegalArgumentException("Unknown format");
|
||||
}
|
||||
if (pattern != null) {
|
||||
boolean quote = false;
|
||||
int index = 0;
|
||||
int length = pattern.length();
|
||||
int count = 0;
|
||||
while (index < length) {
|
||||
char ch = pattern.charAt(index++);
|
||||
if (ch == '\'') {
|
||||
quote = !quote;
|
||||
}
|
||||
if (!quote) {
|
||||
if (ch == '{') {
|
||||
count++;
|
||||
}
|
||||
if (ch == '}') {
|
||||
if (count > 0) {
|
||||
count--;
|
||||
} else {
|
||||
buffer.append("'}");
|
||||
ch = '\'';
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.append(ch);
|
||||
}
|
||||
}
|
||||
buffer.append('}');
|
||||
}
|
||||
if (maxOffset + 1 < strings.length) {
|
||||
appendQuoted(buffer, strings[maxOffset + 1]);
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void appendQuoted(StringBuffer buffer, String string) {
|
||||
int length = string.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = string.charAt(i);
|
||||
if (ch == '{' || ch == '}') {
|
||||
buffer.append('\'');
|
||||
buffer.append(ch);
|
||||
buffer.append('\'');
|
||||
} else {
|
||||
buffer.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Field extends TFormat.Field {
|
||||
public static final Field ARGUMENT = new Field("message argument field");
|
||||
|
||||
protected Field(String fieldName) {
|
||||
super(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.teavm.classlib.java.text;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import java.text.ChoiceFormat;
|
||||
import java.text.DateFormat;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.teavm.junit.TeaVMProperties;
|
||||
import org.teavm.junit.TeaVMProperty;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
@TeaVMProperties(value = { @TeaVMProperty(key = "java.util.Locale.available", value = "en, en_US, fr") })
|
||||
public class MessageFormatTest {
|
||||
private MessageFormat format1;
|
||||
private MessageFormat format2;
|
||||
private MessageFormat format3;
|
||||
private Locale defaultLocale;
|
||||
|
||||
public MessageFormatTest() {
|
||||
defaultLocale = Locale.getDefault();
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
// test with repeating formats and max argument index < max offset
|
||||
String pattern = "A {3, number, currency} B {2, time} C {0, number, percent} D {4} "
|
||||
+ "E {1,choice,0#off|1#on} F {0, date}";
|
||||
format1 = new MessageFormat(pattern);
|
||||
|
||||
// test with max argument index > max offset
|
||||
pattern = "A {3, number, currency} B {8, time} C {0, number, percent} D {6} "
|
||||
+ "E {1,choice,0#off|1#on} F {0, date}";
|
||||
format2 = new MessageFormat(pattern);
|
||||
|
||||
// test with argument number being zero
|
||||
pattern = "A B C D E F";
|
||||
format3 = new MessageFormat(pattern);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorLjava_lang_StringLjava_util_Locale() {
|
||||
// Test for method java.text.MessageFormat(java.lang.String,
|
||||
// java.util.Locale)
|
||||
Locale mk = new Locale("mk", "MK");
|
||||
MessageFormat format = new MessageFormat(
|
||||
"Date: {0,date} Currency: {1, number, currency} Integer: {2, number, integer}",
|
||||
mk);
|
||||
|
||||
assertTrue("Wrong locale1", format.getLocale().equals(mk));
|
||||
assertTrue("Wrong locale2", format.getFormats()[0].equals(DateFormat.getDateInstance(DateFormat.DEFAULT, mk)));
|
||||
assertTrue("Wrong locale3", format.getFormats()[1].equals(NumberFormat.getCurrencyInstance(mk)));
|
||||
assertTrue("Wrong locale4", format.getFormats()[2].equals(NumberFormat.getIntegerInstance(mk)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorLjava_lang_String() {
|
||||
// Test for method java.text.MessageFormat(java.lang.String)
|
||||
MessageFormat format = new MessageFormat(
|
||||
"abc {4,time} def {3,date} ghi {2,number} jkl {1,choice,0#low|1#high} mnop {0}");
|
||||
assertTrue("Not a MessageFormat", format.getClass() == MessageFormat.class);
|
||||
Format[] formats = format.getFormats();
|
||||
assertNotNull("null formats", formats);
|
||||
assertTrue("Wrong format count: " + formats.length, formats.length >= 5);
|
||||
assertTrue("Wrong time format", formats[0].equals(DateFormat.getTimeInstance()));
|
||||
assertTrue("Wrong date format", formats[1].equals(DateFormat.getDateInstance()));
|
||||
assertTrue("Wrong number format", formats[2].equals(NumberFormat.getInstance()));
|
||||
assertTrue("Wrong choice format", formats[3].equals(new ChoiceFormat("0.0#low|1.0#high")));
|
||||
assertNull("Wrong string format", formats[4]);
|
||||
|
||||
Date date = new Date();
|
||||
FieldPosition pos = new FieldPosition(-1);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
format.format(new Object[] { "123", 1.6, 7.2, date, date }, buffer, pos);
|
||||
String result = buffer.toString();
|
||||
buffer.setLength(0);
|
||||
buffer.append("abc ");
|
||||
buffer.append(DateFormat.getTimeInstance().format(date));
|
||||
buffer.append(" def ");
|
||||
buffer.append(DateFormat.getDateInstance().format(date));
|
||||
buffer.append(" ghi ");
|
||||
buffer.append(NumberFormat.getInstance().format(new Double(7.2)));
|
||||
buffer.append(" jkl high mnop 123");
|
||||
assertTrue("Wrong answer:\n" + result + "\n" + buffer, result.equals(buffer.toString()));
|
||||
|
||||
assertEquals("Simple string", "Test message", new MessageFormat("Test message").format(new Object[0]));
|
||||
|
||||
result = new MessageFormat("Don't").format(new Object[0]);
|
||||
assertTrue("Should not throw IllegalArgumentException: " + result, "Dont".equals(result));
|
||||
|
||||
try {
|
||||
new MessageFormat("Invalid {1,foobar} format descriptor!");
|
||||
fail("Expected test_ConstructorLjava_lang_String to throw IAE.");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
try {
|
||||
new MessageFormat("Invalid {1,date,invalid-spec} format descriptor!");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// Regression for HARMONY-65
|
||||
try {
|
||||
new MessageFormat("{0,number,integer");
|
||||
fail("Assert 0: Failed to detect unmatched brackets.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applyPatternLjava_lang_String() {
|
||||
MessageFormat format = new MessageFormat("test");
|
||||
format.applyPattern("xx {0}");
|
||||
assertEquals("Invalid number", "xx 46", format.format(new Object[] { 46 }));
|
||||
Date date = new Date();
|
||||
String result = format.format(new Object[] { date });
|
||||
String expected = "xx " + DateFormat.getInstance().format(date);
|
||||
assertTrue("Invalid date:\n" + result + "\n" + expected, result.equals(expected));
|
||||
format = new MessageFormat("{0,date}{1,time}{2,number,integer}");
|
||||
format.applyPattern("nothing");
|
||||
assertEquals("Found formats", "nothing", format.toPattern());
|
||||
|
||||
format.applyPattern("{0}");
|
||||
assertNull("Wrong format", format.getFormats()[0]);
|
||||
assertEquals("Wrong pattern", "{0}", format.toPattern());
|
||||
|
||||
format.applyPattern("{0, \t\u001ftime }");
|
||||
assertTrue("Wrong time format", format.getFormats()[0].equals(DateFormat.getTimeInstance()));
|
||||
assertEquals("Wrong time pattern", "{0,time}", format.toPattern());
|
||||
format.applyPattern("{0,Time, Short\n}");
|
||||
assertTrue("Wrong short time format", format.getFormats()[0].equals(
|
||||
DateFormat.getTimeInstance(DateFormat.SHORT)));
|
||||
assertEquals("Wrong short time pattern", "{0,time,short}", format.toPattern());
|
||||
format.applyPattern("{0,TIME,\nmedium }");
|
||||
assertTrue("Wrong medium time format", format.getFormats()[0].equals(
|
||||
DateFormat.getTimeInstance(DateFormat.MEDIUM)));
|
||||
assertEquals("Wrong medium time pattern", "{0,time}", format.toPattern());
|
||||
format.applyPattern("{0,time,LONG}");
|
||||
assertTrue("Wrong long time format", format.getFormats()[0].equals(
|
||||
DateFormat.getTimeInstance(DateFormat.LONG)));
|
||||
assertEquals("Wrong long time pattern", "{0,time,long}", format.toPattern());
|
||||
format.setLocale(Locale.FRENCH); // use French since English has the
|
||||
// same LONG and FULL time patterns
|
||||
format.applyPattern("{0,time, Full}");
|
||||
assertTrue("Wrong full time format", format.getFormats()[0]
|
||||
.equals(DateFormat.getTimeInstance(DateFormat.FULL, Locale.FRENCH)));
|
||||
assertEquals("Wrong full time pattern", "{0,time,full}", format.toPattern());
|
||||
format.setLocale(Locale.getDefault());
|
||||
|
||||
format.applyPattern("{0, date}");
|
||||
assertTrue("Wrong date format", format.getFormats()[0].equals(DateFormat.getDateInstance()));
|
||||
assertEquals("Wrong date pattern", "{0,date}", format.toPattern());
|
||||
format.applyPattern("{0, date, short}");
|
||||
assertTrue("Wrong short date format", format.getFormats()[0]
|
||||
.equals(DateFormat.getDateInstance(DateFormat.SHORT)));
|
||||
assertEquals("Wrong short date pattern", "{0,date,short}", format.toPattern());
|
||||
format.applyPattern("{0, date, medium}");
|
||||
assertTrue("Wrong medium date format", format.getFormats()[0]
|
||||
.equals(DateFormat.getDateInstance(DateFormat.MEDIUM)));
|
||||
assertEquals("Wrong medium date pattern",
|
||||
"{0,date}", format.toPattern());
|
||||
format.applyPattern("{0, date, long}");
|
||||
assertTrue("Wrong long date format", format.getFormats()[0]
|
||||
.equals(DateFormat.getDateInstance(DateFormat.LONG)));
|
||||
assertEquals("Wrong long date pattern", "{0,date,long}", format.toPattern());
|
||||
format.applyPattern("{0, date, full}");
|
||||
assertTrue("Wrong full date format", format.getFormats()[0]
|
||||
.equals(DateFormat.getDateInstance(DateFormat.FULL)));
|
||||
assertEquals("Wrong full date pattern", "{0,date,full}", format.toPattern());
|
||||
|
||||
format.applyPattern("{0, date, MMM d {hh:mm:ss}}");
|
||||
assertEquals("Wrong time/date format", " MMM d {hh:mm:ss}", ((SimpleDateFormat) (format
|
||||
.getFormats()[0])).toPattern());
|
||||
assertEquals("Wrong time/date pattern",
|
||||
"{0,date, MMM d {hh:mm:ss}}", format.toPattern());
|
||||
|
||||
format.applyPattern("{0, number}");
|
||||
assertTrue("Wrong number format", format.getFormats()[0].equals(NumberFormat.getNumberInstance()));
|
||||
assertEquals("Wrong number pattern", "{0,number}", format.toPattern());
|
||||
format.applyPattern("{0, number, currency}");
|
||||
assertTrue("Wrong currency number format", format.getFormats()[0].equals(NumberFormat.getCurrencyInstance()));
|
||||
assertEquals("Wrong currency number pattern", "{0,number,currency}", format.toPattern());
|
||||
format.applyPattern("{0, number, percent}");
|
||||
assertTrue("Wrong percent number format", format.getFormats()[0].equals(NumberFormat.getPercentInstance()));
|
||||
assertEquals("Wrong percent number pattern", "{0,number,percent}", format.toPattern());
|
||||
format.applyPattern("{0, number, integer}");
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
nf.setMaximumFractionDigits(0);
|
||||
nf.setParseIntegerOnly(true);
|
||||
assertTrue("Wrong integer number format", format.getFormats()[0].equals(nf));
|
||||
assertEquals("Wrong integer number pattern", "{0,number,integer}", format.toPattern());
|
||||
|
||||
format.applyPattern("{0, number, {'#'}##0.0E0}");
|
||||
|
||||
/*
|
||||
* TODO validate these assertions
|
||||
* String actual = ((DecimalFormat)(format.getFormats()[0])).toPattern();
|
||||
* assertEquals("Wrong pattern number format", "' {#}'##0.0E0", actual);
|
||||
* assertEquals("Wrong pattern number pattern", "{0,number,' {#}'##0.0E0}", format.toPattern());
|
||||
*
|
||||
*/
|
||||
|
||||
format.applyPattern("{0, choice,0#no|1#one|2#{1,number}}");
|
||||
assertEquals("Wrong choice format", "0.0#no|1.0#one|2.0#{1,number}",
|
||||
((ChoiceFormat) format.getFormats()[0]).toPattern());
|
||||
assertEquals("Wrong choice pattern", "{0,choice,0.0#no|1.0#one|2.0#{1,number}}", format.toPattern());
|
||||
assertEquals("Wrong formatted choice", "3.6", format.format(new Object[] { 2, 3.6f }));
|
||||
|
||||
try {
|
||||
format.applyPattern("WRONG MESSAGE FORMAT {0,number,{}");
|
||||
fail("Expected IllegalArgumentException for invalid pattern");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// Regression for HARMONY-65
|
||||
MessageFormat mf = new MessageFormat("{0,number,integer}");
|
||||
String badpattern = "{0,number,#";
|
||||
try {
|
||||
mf.applyPattern(badpattern);
|
||||
fail("Assert 0: Failed to detect unmatched brackets.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_clone() {
|
||||
MessageFormat format = new MessageFormat("'{'choice'}'{0}");
|
||||
MessageFormat clone = (MessageFormat) format.clone();
|
||||
assertTrue("Clone not equal", format.equals(clone));
|
||||
assertEquals("Wrong answer", "{choice}{0}", format.format(new Object[] {}));
|
||||
clone.setFormat(0, DateFormat.getInstance());
|
||||
assertTrue("Clone shares format data", !format.equals(clone));
|
||||
format = (MessageFormat) clone.clone();
|
||||
Format[] formats = clone.getFormats();
|
||||
((SimpleDateFormat) formats[0]).applyPattern("adk123");
|
||||
assertTrue("Clone shares format data", !format.equals(clone));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_equalsLjava_lang_Object() {
|
||||
MessageFormat format1 = new MessageFormat("{0}");
|
||||
MessageFormat format2 = new MessageFormat("{1}");
|
||||
assertTrue("Should not be equal", !format1.equals(format2));
|
||||
format2.applyPattern("{0}");
|
||||
assertTrue("Should be equal", format1.equals(format2));
|
||||
SimpleDateFormat date = (SimpleDateFormat) DateFormat.getTimeInstance();
|
||||
format1.setFormat(0, DateFormat.getTimeInstance());
|
||||
format2.setFormat(0, new SimpleDateFormat(date.toPattern()));
|
||||
assertTrue("Should be equal2", format1.equals(format2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_hashCode() {
|
||||
assertEquals("Should be equal", 3648, new MessageFormat("rr", null).hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void format$Ljava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition() {
|
||||
MessageFormat format = new MessageFormat("{1,number,integer}");
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
format.format(new Object[] { "0", 53.863 }, buffer, new FieldPosition(0));
|
||||
assertEquals("Wrong result", "54", buffer.toString());
|
||||
format.applyPattern("{0,choice,0#zero|1#one '{1,choice,2#two {2,time}}'}");
|
||||
Date date = new Date();
|
||||
String expected = "one two " + DateFormat.getTimeInstance().format(date);
|
||||
String result = format.format(new Object[] { 1.6, 3, date });
|
||||
assertTrue("Choice not recursive:\n" + expected + "\n" + result, expected.equals(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFormats() {
|
||||
// test with repeating formats and max argument index < max offset
|
||||
Format[] formats = format1.getFormats();
|
||||
Format[] correctFormats = new Format[] {
|
||||
NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(),
|
||||
NumberFormat.getPercentInstance(), null,
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getDateInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test1:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test with max argument index > max offset
|
||||
formats = format2.getFormats();
|
||||
correctFormats = new Format[] { NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(),
|
||||
NumberFormat.getPercentInstance(), null,
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getDateInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test2:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test with argument number being zero
|
||||
formats = format3.getFormats();
|
||||
assertEquals("Test3: Returned wrong number of formats:", 0, formats.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFormatsByArgumentIndex() {
|
||||
// test with repeating formats and max argument index < max offset
|
||||
Format[] formats = format1.getFormatsByArgumentIndex();
|
||||
Format[] correctFormats = new Format[] { DateFormat.getDateInstance(),
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getTimeInstance(),
|
||||
NumberFormat.getCurrencyInstance(), null };
|
||||
|
||||
assertEquals("Test1:Returned wrong number of formats:",
|
||||
correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test with max argument index > max offset
|
||||
formats = format2.getFormatsByArgumentIndex();
|
||||
correctFormats = new Format[] { DateFormat.getDateInstance(),
|
||||
new ChoiceFormat("0#off|1#on"), null,
|
||||
NumberFormat.getCurrencyInstance(), null, null, null, null,
|
||||
DateFormat.getTimeInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test2:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test with argument number being zero
|
||||
formats = format3.getFormatsByArgumentIndex();
|
||||
assertEquals("Test3: Returned wrong number of formats:", 0, formats.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setFormatByArgumentIndexILjava_text_Format() {
|
||||
MessageFormat f1 = (MessageFormat) format1.clone();
|
||||
f1.setFormatByArgumentIndex(0, DateFormat.getTimeInstance());
|
||||
f1.setFormatByArgumentIndex(4, new ChoiceFormat("1#few|2#ok|3#a lot"));
|
||||
|
||||
// test with repeating formats and max argument index < max offset
|
||||
// compare getFormatsByArgumentIndex() results after calls to
|
||||
// setFormatByArgumentIndex()
|
||||
Format[] formats = f1.getFormatsByArgumentIndex();
|
||||
|
||||
Format[] correctFormats = new Format[] { DateFormat.getTimeInstance(),
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getTimeInstance(),
|
||||
NumberFormat.getCurrencyInstance(),
|
||||
new ChoiceFormat("1#few|2#ok|3#a lot")
|
||||
};
|
||||
|
||||
assertEquals("Test1A:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1B:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// compare getFormats() results after calls to
|
||||
// setFormatByArgumentIndex()
|
||||
formats = f1.getFormats();
|
||||
|
||||
correctFormats = new Format[] { NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(), DateFormat.getTimeInstance(),
|
||||
new ChoiceFormat("1#few|2#ok|3#a lot"),
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getTimeInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test1C:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1D:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test setting argumentIndexes that are not used
|
||||
MessageFormat f2 = (MessageFormat) format2.clone();
|
||||
f2.setFormatByArgumentIndex(2, NumberFormat.getPercentInstance());
|
||||
f2.setFormatByArgumentIndex(4, DateFormat.getTimeInstance());
|
||||
|
||||
formats = f2.getFormatsByArgumentIndex();
|
||||
correctFormats = format2.getFormatsByArgumentIndex();
|
||||
|
||||
assertEquals("Test2A:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2B:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
formats = f2.getFormats();
|
||||
correctFormats = format2.getFormats();
|
||||
|
||||
assertEquals("Test2C:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2D:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test exceeding the argumentIndex number
|
||||
MessageFormat f3 = (MessageFormat) format3.clone();
|
||||
f3.setFormatByArgumentIndex(1, NumberFormat.getCurrencyInstance());
|
||||
|
||||
formats = f3.getFormatsByArgumentIndex();
|
||||
assertEquals("Test3A:Returned wrong number of formats:", 0, formats.length);
|
||||
|
||||
formats = f3.getFormats();
|
||||
assertEquals("Test3B:Returned wrong number of formats:", 0, formats.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setFormatsByArgumentIndex$Ljava_text_Format() {
|
||||
MessageFormat f1 = (MessageFormat) format1.clone();
|
||||
|
||||
// test with repeating formats and max argument index < max offset
|
||||
// compare getFormatsByArgumentIndex() results after calls to
|
||||
// setFormatsByArgumentIndex(Format[])
|
||||
Format[] correctFormats = new Format[] { DateFormat.getTimeInstance(),
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getTimeInstance(),
|
||||
NumberFormat.getCurrencyInstance(),
|
||||
new ChoiceFormat("1#few|2#ok|3#a lot")
|
||||
};
|
||||
|
||||
f1.setFormatsByArgumentIndex(correctFormats);
|
||||
Format[] formats = f1.getFormatsByArgumentIndex();
|
||||
|
||||
assertEquals("Test1A:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1B:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// compare getFormats() results after calls to
|
||||
// setFormatByArgumentIndex()
|
||||
formats = f1.getFormats();
|
||||
correctFormats = new Format[] { NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(), DateFormat.getTimeInstance(),
|
||||
new ChoiceFormat("1#few|2#ok|3#a lot"),
|
||||
new ChoiceFormat("0#off|1#on"), DateFormat.getTimeInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test1C:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test1D:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test setting argumentIndexes that are not used
|
||||
MessageFormat f2 = (MessageFormat) format2.clone();
|
||||
Format[] inputFormats = new Format[] { DateFormat.getDateInstance(),
|
||||
new ChoiceFormat("0#off|1#on"),
|
||||
NumberFormat.getPercentInstance(),
|
||||
NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(), null, null, null,
|
||||
DateFormat.getTimeInstance()
|
||||
};
|
||||
f2.setFormatsByArgumentIndex(inputFormats);
|
||||
|
||||
formats = f2.getFormatsByArgumentIndex();
|
||||
correctFormats = format2.getFormatsByArgumentIndex();
|
||||
|
||||
assertEquals("Test2A:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2B:wrong format for argument index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
formats = f2.getFormats();
|
||||
correctFormats = new Format[] { NumberFormat.getCurrencyInstance(),
|
||||
DateFormat.getTimeInstance(), DateFormat.getDateInstance(),
|
||||
null, new ChoiceFormat("0#off|1#on"),
|
||||
DateFormat.getDateInstance()
|
||||
};
|
||||
|
||||
assertEquals("Test2C:Returned wrong number of formats:", correctFormats.length, formats.length);
|
||||
for (int i = 0; i < correctFormats.length; i++) {
|
||||
assertEquals("Test2D:wrong format for pattern index " + i + ":", correctFormats[i], formats[i]);
|
||||
}
|
||||
|
||||
// test exceeding the argumentIndex number
|
||||
MessageFormat f3 = (MessageFormat) format3.clone();
|
||||
f3.setFormatsByArgumentIndex(inputFormats);
|
||||
|
||||
formats = f3.getFormatsByArgumentIndex();
|
||||
assertEquals("Test3A:Returned wrong number of formats:", 0, formats.length);
|
||||
|
||||
formats = f3.getFormats();
|
||||
assertEquals("Test3B:Returned wrong number of formats:", 0, formats.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLjava_lang_StringLjava_text_ParsePosition() {
|
||||
MessageFormat format = new MessageFormat("date is {0,date,MMM d, yyyy}");
|
||||
ParsePosition pos = new ParsePosition(2);
|
||||
Object[] result = format.parse("xxdate is Feb 28, 1999", pos);
|
||||
assertTrue("No result: " + result.length, result.length >= 1);
|
||||
assertTrue("Wrong answer", result[0].equals(new GregorianCalendar(1999, Calendar.FEBRUARY, 28).getTime()));
|
||||
|
||||
MessageFormat mf = new MessageFormat("vm={0},{1},{2}");
|
||||
result = mf.parse("vm=win,foo,bar", new ParsePosition(0));
|
||||
assertTrue("Invalid parse", result[0].equals("win") && result[1].equals("foo") && result[2].equals("bar"));
|
||||
|
||||
mf = new MessageFormat("{0}; {0}; {0}");
|
||||
String parse = "a; b; c";
|
||||
result = mf.parse(parse, new ParsePosition(0));
|
||||
assertEquals("Wrong variable result", "c", result[0]);
|
||||
|
||||
mf = new MessageFormat("before {0}, after {1,number}");
|
||||
parse = "before you, after 42";
|
||||
pos.setIndex(0);
|
||||
pos.setErrorIndex(8);
|
||||
result = mf.parse(parse, pos);
|
||||
assertEquals(2, result.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setLocaleLjava_util_Locale() {
|
||||
MessageFormat format = new MessageFormat("date {0,date}");
|
||||
format.setLocale(Locale.CHINA);
|
||||
assertEquals("Wrong locale1", Locale.CHINA, format.getLocale());
|
||||
format.applyPattern("{1,date}");
|
||||
assertEquals("Wrong locale3", DateFormat.getDateInstance(DateFormat.DEFAULT,
|
||||
Locale.CHINA), format.getFormats()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toPattern() {
|
||||
String pattern = "[{0}]";
|
||||
MessageFormat mf = new MessageFormat(pattern);
|
||||
assertTrue("Wrong pattern", mf.toPattern().equals(pattern));
|
||||
|
||||
// Regression for HARMONY-59
|
||||
new MessageFormat("CHOICE {1,choice}").toPattern();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Locale.setDefault(defaultLocale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorLjava_util_Locale() {
|
||||
// Regression for HARMONY-65
|
||||
try {
|
||||
new MessageFormat("{0,number,integer", Locale.US);
|
||||
fail("Assert 0: Failed to detect unmatched brackets.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parse() throws ParseException {
|
||||
// Regression for HARMONY-63
|
||||
MessageFormat mf = new MessageFormat("{0,number,#,####}", Locale.US);
|
||||
Object[] res = mf.parse("1,00,00");
|
||||
assertEquals("Assert 0: incorrect size of parsed data ", 1, res.length);
|
||||
assertEquals("Assert 1: parsed value incorrectly", 10000L, res[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void format_Object() {
|
||||
// Regression for HARMONY-1875
|
||||
Locale.setDefault(Locale.CANADA);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
String pat = "text here {0, date, yyyyyyyyy } and here";
|
||||
String etalon = "text here 000002007 and here";
|
||||
MessageFormat obj = new MessageFormat(pat);
|
||||
assertEquals(etalon, obj.format(new Object[] { new Date(1198141737640L) }));
|
||||
|
||||
assertEquals("{0}", MessageFormat.format("{0}", (Object[]) null));
|
||||
assertEquals("nullABC", MessageFormat.format("{0}{1}", new String[]{null, "ABC"}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHARMONY5323() {
|
||||
Object[] messageArgs = new Object[11];
|
||||
for (int i = 0; i < messageArgs.length; i++) {
|
||||
messageArgs[i] = "dumb" + i;
|
||||
}
|
||||
|
||||
String res = MessageFormat.format("bgcolor=\"{10}\"", messageArgs);
|
||||
assertEquals(res, "bgcolor=\"dumb10\"");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user