Add implementation of java.text.MessageFormat

This commit is contained in:
Alexey Andreev 2017-11-03 00:32:16 +03:00
parent 6145afcbf8
commit 90cc2c4677
4 changed files with 1510 additions and 0 deletions

View File

@ -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();
}
}

View File

@ -47,6 +47,7 @@ public class TDecimalFormat extends TNumberFormat {
private boolean decimalSeparatorAlwaysShown; private boolean decimalSeparatorAlwaysShown;
private boolean parseBigDecimal; private boolean parseBigDecimal;
int exponentDigits; int exponentDigits;
String pattern;
public TDecimalFormat() { public TDecimalFormat() {
this(CLDRHelper.resolveNumberFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry())); this(CLDRHelper.resolveNumberFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry()));
@ -65,6 +66,11 @@ public class TDecimalFormat extends TNumberFormat {
TDecimalFormatParser parser = new TDecimalFormatParser(); TDecimalFormatParser parser = new TDecimalFormatParser();
parser.parse(pattern); parser.parse(pattern);
parser.apply(this); parser.apply(this);
this.pattern = pattern;
}
String toPattern() {
return pattern;
} }
public DecimalFormatSymbols getDecimalFormatSymbols() { public DecimalFormatSymbols getDecimalFormatSymbols() {

View File

@ -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);
}
}
}

View File

@ -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\"");
}
}