mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Implement java.util.Formatter for subset of available specifiers
This commit is contained in:
parent
25011ee7a6
commit
5109691a8d
|
@ -97,7 +97,7 @@ public abstract class TNumberFormat extends TFormat {
|
||||||
return TLocale.getAvailableLocales();
|
return TLocale.getAvailableLocales();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getIntegerInstance() {
|
public static TNumberFormat getIntegerInstance() {
|
||||||
return getIntegerInstance(TLocale.getDefault());
|
return getIntegerInstance(TLocale.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public abstract class TNumberFormat extends TFormat {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getInstance() {
|
public static TNumberFormat getInstance() {
|
||||||
return getNumberInstance();
|
return getNumberInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ public abstract class TNumberFormat extends TFormat {
|
||||||
return minimumIntegerDigits;
|
return minimumIntegerDigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getNumberInstance() {
|
public static TNumberFormat getNumberInstance() {
|
||||||
return getNumberInstance(TLocale.getDefault());
|
return getNumberInstance(TLocale.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ public abstract class TNumberFormat extends TFormat {
|
||||||
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getPercentInstance() {
|
public static TNumberFormat getPercentInstance() {
|
||||||
return getPercentInstance(TLocale.getDefault());
|
return getPercentInstance(TLocale.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,11 +153,11 @@ public abstract class TNumberFormat extends TFormat {
|
||||||
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getCurrencyInstance() {
|
public static TNumberFormat getCurrencyInstance() {
|
||||||
return getCurrencyInstance(TLocale.getDefault());
|
return getCurrencyInstance(TLocale.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
public final static TNumberFormat getCurrencyInstance(TLocale locale) {
|
public static TNumberFormat getCurrencyInstance(TLocale locale) {
|
||||||
String pattern = CLDRHelper.resolveCurrencyFormat(locale.getLanguage(), locale.getCountry());
|
String pattern = CLDRHelper.resolveCurrencyFormat(locale.getLanguage(), locale.getCountry());
|
||||||
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
return new TDecimalFormat(pattern, new TDecimalFormatSymbols(locale));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TDuplicateFormatFlagsException extends TIllegalFormatException {
|
||||||
|
private String flags;
|
||||||
|
|
||||||
|
public TDuplicateFormatFlagsException(String flags) {
|
||||||
|
super("Duplicate format flags: " + flags);
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlags() {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TFormatFlagsConversionMismatchException extends TIllegalFormatException {
|
||||||
|
private String flags;
|
||||||
|
private char conversion;
|
||||||
|
|
||||||
|
public TFormatFlagsConversionMismatchException(String flags, char conversion) {
|
||||||
|
super("Illegal format flags " + flags + " for conversion " + conversion);
|
||||||
|
this.flags = flags;
|
||||||
|
this.conversion = conversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlags() {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getConversion() {
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public interface TFormattable {
|
||||||
|
void formatTo(TFormatter formatter, int flags, int width, int precision);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public final class TFormattableFlags {
|
||||||
|
private TFormattableFlags() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int LEFT_JUSTIFY = 1;
|
||||||
|
public static final int UPPERCASE = 2;
|
||||||
|
public static final int ALTERNATE = 4;
|
||||||
|
|
||||||
|
static final int SIGNED = 8;
|
||||||
|
static final int LEADING_SPACE = 16;
|
||||||
|
static final int ZERO_PADDED = 32;
|
||||||
|
static final int GROUPING_SEPARATOR = 64;
|
||||||
|
static final int PARENTHESIZED_NEGATIVE = 128;
|
||||||
|
static final int PREVIOUS_ARGUMENT = 256;
|
||||||
|
}
|
|
@ -0,0 +1,518 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.Flushable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.DuplicateFormatFlagsException;
|
||||||
|
import java.util.FormatFlagsConversionMismatchException;
|
||||||
|
import java.util.IllegalFormatConversionException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.UnknownFormatConversionException;
|
||||||
|
|
||||||
|
public final class TFormatter implements Closeable, Flushable {
|
||||||
|
private Locale locale;
|
||||||
|
private Appendable out;
|
||||||
|
private IOException ioException;
|
||||||
|
|
||||||
|
public TFormatter() {
|
||||||
|
this(Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(Appendable a) {
|
||||||
|
this(a, Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(Locale l) {
|
||||||
|
this(new StringBuilder(), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(Appendable a, Locale l) {
|
||||||
|
out = a;
|
||||||
|
locale = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(PrintStream ps) {
|
||||||
|
this(new OutputStreamWriter(ps));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(OutputStream os) {
|
||||||
|
this(new OutputStreamWriter(os));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(OutputStream os, String csn) throws UnsupportedEncodingException {
|
||||||
|
this(new OutputStreamWriter(os, csn));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter(OutputStream os, String csn, Locale l) throws UnsupportedEncodingException {
|
||||||
|
this(new OutputStreamWriter(os, csn), l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Locale locale() {
|
||||||
|
requireOpen();
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Appendable out() {
|
||||||
|
requireOpen();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requireOpen() {
|
||||||
|
if (out == null) {
|
||||||
|
throw new TFormatterClosedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
requireOpen();
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
requireOpen();
|
||||||
|
if (out instanceof Flushable) {
|
||||||
|
try {
|
||||||
|
((Flushable) out).flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
ioException = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
requireOpen();
|
||||||
|
try {
|
||||||
|
if (out instanceof Closeable) {
|
||||||
|
((Closeable) out).close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ioException = e;
|
||||||
|
} finally {
|
||||||
|
out = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOException ioException() {
|
||||||
|
return ioException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter format(String format, Object... args) {
|
||||||
|
return format(locale, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TFormatter format(Locale l, String format, Object... args) {
|
||||||
|
requireOpen();
|
||||||
|
try {
|
||||||
|
if (args == null) {
|
||||||
|
args = new Object[1];
|
||||||
|
}
|
||||||
|
new FormatWriter(this, out, l, format, args).write();
|
||||||
|
} catch (IOException e) {
|
||||||
|
ioException = e;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FormatWriter {
|
||||||
|
private static final String FORMAT_FLAGS = "--#+ 0,(<";
|
||||||
|
private static final int MASK_FOR_GENERAL_FORMAT =
|
||||||
|
TFormattableFlags.LEFT_JUSTIFY | TFormattableFlags.ALTERNATE
|
||||||
|
| TFormattableFlags.UPPERCASE | TFormattableFlags.PREVIOUS_ARGUMENT;
|
||||||
|
private static final int MASK_FOR_CHAR_FORMAT =
|
||||||
|
TFormattableFlags.LEFT_JUSTIFY | TFormattableFlags.UPPERCASE | TFormattableFlags.PREVIOUS_ARGUMENT;
|
||||||
|
private static final int MASK_FOR_INT_DECIMAL_FORMAT = MASK_FOR_GENERAL_FORMAT ^ TFormattableFlags.ALTERNATE
|
||||||
|
| TFormattableFlags.LEADING_SPACE | TFormattableFlags.ZERO_PADDED
|
||||||
|
| TFormattableFlags.PARENTHESIZED_NEGATIVE | TFormattableFlags.SIGNED
|
||||||
|
| TFormattableFlags.GROUPING_SEPARATOR;
|
||||||
|
private TFormatter formatter;
|
||||||
|
Appendable out;
|
||||||
|
Locale locale;
|
||||||
|
String format;
|
||||||
|
Object[] args;
|
||||||
|
int index;
|
||||||
|
int formatSpecifierStart;
|
||||||
|
int defaultArgumentIndex;
|
||||||
|
int argumentIndex;
|
||||||
|
int previousArgumentIndex;
|
||||||
|
int width;
|
||||||
|
int precision;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
FormatWriter(TFormatter formatter, Appendable out, Locale locale, String format, Object[] args) {
|
||||||
|
this.formatter = formatter;
|
||||||
|
this.out = out;
|
||||||
|
this.locale = locale;
|
||||||
|
this.format = format;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write() throws IOException {
|
||||||
|
while (true) {
|
||||||
|
int next = format.indexOf('%', index);
|
||||||
|
if (next < 0) {
|
||||||
|
out.append(format.substring(index));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out.append(format.substring(index, next));
|
||||||
|
index = next + 1;
|
||||||
|
|
||||||
|
formatSpecifierStart = index;
|
||||||
|
char specifier = parseFormatSpecifier();
|
||||||
|
configureFormat();
|
||||||
|
formatValue(specifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatValue(char specifier) throws IOException {
|
||||||
|
switch (specifier) {
|
||||||
|
case 'b':
|
||||||
|
formatBoolean(specifier, false);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
formatBoolean(specifier, true);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
formatHex(specifier, false);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
formatHex(specifier, true);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
formatString(specifier, false);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
formatString(specifier, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
formatChar(specifier, false);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
formatChar(specifier, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
formatDecimalInt(specifier, false);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
formatDecimalInt(specifier, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnknownFormatConversionException(String.valueOf(specifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatBoolean(char specifier, boolean upperCase) throws IOException {
|
||||||
|
verifyFlagsForGeneralFormat(specifier);
|
||||||
|
Object arg = args[argumentIndex];
|
||||||
|
String s = Boolean.toString(arg instanceof Boolean ? (Boolean) arg : arg != null);
|
||||||
|
formatGivenString(upperCase, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatHex(char specifier, boolean upperCase) throws IOException {
|
||||||
|
verifyFlagsForGeneralFormat(specifier);
|
||||||
|
Object arg = args[argumentIndex];
|
||||||
|
String s = arg != null ? Integer.toHexString(arg.hashCode()) : "null";
|
||||||
|
formatGivenString(upperCase, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatString(char specifier, boolean upperCase) throws IOException {
|
||||||
|
verifyFlagsForGeneralFormat(specifier);
|
||||||
|
Object arg = args[argumentIndex];
|
||||||
|
if (arg instanceof TFormattable) {
|
||||||
|
int flagsToPass = flags & 7;
|
||||||
|
if (upperCase) {
|
||||||
|
flagsToPass |= TFormattableFlags.UPPERCASE;
|
||||||
|
}
|
||||||
|
((TFormattable) arg).formatTo(formatter, flagsToPass, width, precision);
|
||||||
|
} else {
|
||||||
|
formatGivenString(upperCase, String.valueOf(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatChar(char specifier, boolean upperCase) throws IOException {
|
||||||
|
verifyFlags(specifier, MASK_FOR_CHAR_FORMAT);
|
||||||
|
Object arg = args[argumentIndex];
|
||||||
|
|
||||||
|
if (precision >= 0) {
|
||||||
|
throw new TIllegalFormatPrecisionException(precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
int c;
|
||||||
|
if (arg instanceof Character) {
|
||||||
|
c = (Character) arg;
|
||||||
|
} else if (arg instanceof Byte) {
|
||||||
|
c = (char) (byte) arg;
|
||||||
|
} else if (arg instanceof Short) {
|
||||||
|
c = (char) (short) arg;
|
||||||
|
} else if (arg instanceof Integer) {
|
||||||
|
c = (int) arg;
|
||||||
|
if (!Character.isValidCodePoint(c)) {
|
||||||
|
throw new TIllegalFormatCodePointException(c);
|
||||||
|
}
|
||||||
|
} else if (arg == null) {
|
||||||
|
formatGivenString(upperCase, "null");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new IllegalFormatConversionException(specifier, arg != null ? arg.getClass() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatGivenString(upperCase, new String(Character.toChars(c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatDecimalInt(char specifier, boolean upperCase) throws IOException {
|
||||||
|
verifyFlags(specifier, MASK_FOR_INT_DECIMAL_FORMAT);
|
||||||
|
if ((flags & TFormattableFlags.SIGNED) != 0 && (flags & TFormattableFlags.LEADING_SPACE) != 0) {
|
||||||
|
throw new TIllegalFormatFlagsException("+ ");
|
||||||
|
}
|
||||||
|
if ((flags & TFormattableFlags.ZERO_PADDED) != 0 && (flags & TFormattableFlags.LEFT_JUSTIFY) != 0) {
|
||||||
|
throw new TIllegalFormatFlagsException("0-");
|
||||||
|
}
|
||||||
|
if (precision >= 0) {
|
||||||
|
throw new TIllegalFormatPrecisionException(precision);
|
||||||
|
}
|
||||||
|
if ((flags & TFormattableFlags.LEFT_JUSTIFY) != 0 && width < 0) {
|
||||||
|
throw new TMissingFormatWidthException(format.substring(formatSpecifierStart, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
String str;
|
||||||
|
Object arg = args[argumentIndex];
|
||||||
|
boolean negative;
|
||||||
|
if (arg instanceof Long) {
|
||||||
|
long value = (Long) arg;
|
||||||
|
str = Long.toString(Math.abs(value));
|
||||||
|
negative = value < 0;
|
||||||
|
} else if (arg instanceof Integer || arg instanceof Byte || arg instanceof Short) {
|
||||||
|
int value = ((Number) arg).intValue();
|
||||||
|
str = Integer.toString(Math.abs(value));
|
||||||
|
negative = value < 0;
|
||||||
|
} else {
|
||||||
|
throw new IllegalFormatConversionException(specifier, arg != null ? arg.getClass() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
int additionalSymbols = 0;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (negative) {
|
||||||
|
if ((flags & TFormattableFlags.PARENTHESIZED_NEGATIVE) != 0) {
|
||||||
|
sb.append('(');
|
||||||
|
additionalSymbols += 2;
|
||||||
|
} else {
|
||||||
|
sb.append('-');
|
||||||
|
additionalSymbols++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((flags & TFormattableFlags.SIGNED) != 0) {
|
||||||
|
sb.append('+');
|
||||||
|
additionalSymbols++;
|
||||||
|
} else if ((flags & TFormattableFlags.LEADING_SPACE) != 0) {
|
||||||
|
sb.append(' ');
|
||||||
|
additionalSymbols++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder valueSb = new StringBuilder();
|
||||||
|
if ((flags & TFormattableFlags.GROUPING_SEPARATOR) != 0) {
|
||||||
|
char separator = new DecimalFormatSymbols(locale).getGroupingSeparator();
|
||||||
|
int size = ((DecimalFormat) NumberFormat.getNumberInstance(locale)).getGroupingSize();
|
||||||
|
int offset = str.length() % size;
|
||||||
|
if (offset == 0) {
|
||||||
|
offset = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int prev = 0;
|
||||||
|
for (int i = offset; i < str.length(); i += size) {
|
||||||
|
valueSb.append(str.substring(prev, i));
|
||||||
|
valueSb.append(separator);
|
||||||
|
prev = i;
|
||||||
|
}
|
||||||
|
valueSb.append(str.substring(prev));
|
||||||
|
} else {
|
||||||
|
valueSb.append(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & TFormattableFlags.ZERO_PADDED) != 0) {
|
||||||
|
int actual = valueSb.length() + additionalSymbols;
|
||||||
|
for (int i = actual; i < width; ++i) {
|
||||||
|
sb.append(Character.forDigit(0, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(valueSb);
|
||||||
|
|
||||||
|
if (negative && (flags & TFormattableFlags.PARENTHESIZED_NEGATIVE) != 0) {
|
||||||
|
sb.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
formatGivenString(upperCase, sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatGivenString(boolean upperCase, String str) throws IOException {
|
||||||
|
if (precision > 0) {
|
||||||
|
str = str.substring(0, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upperCase) {
|
||||||
|
str = str.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & TFormattableFlags.LEFT_JUSTIFY) != 0) {
|
||||||
|
out.append(str);
|
||||||
|
mayBeAppendSpaces(str);
|
||||||
|
} else {
|
||||||
|
mayBeAppendSpaces(str);
|
||||||
|
out.append(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyFlagsForGeneralFormat(char conversion) {
|
||||||
|
verifyFlags(conversion, MASK_FOR_GENERAL_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyFlags(char conversion, int mask) {
|
||||||
|
if ((flags | mask) != mask) {
|
||||||
|
throw new FormatFlagsConversionMismatchException(flagsToString(flags & ~mask), conversion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String flagsToString(int flags) {
|
||||||
|
int flagIndex = Integer.numberOfTrailingZeros(flags);
|
||||||
|
return String.valueOf(FORMAT_FLAGS.charAt(flagIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mayBeAppendSpaces(String str) throws IOException {
|
||||||
|
if (width > str.length()) {
|
||||||
|
int diff = width - str.length();
|
||||||
|
StringBuilder sb = new StringBuilder(diff);
|
||||||
|
for (int i = 0; i < diff; ++i) {
|
||||||
|
sb.append(' ');
|
||||||
|
}
|
||||||
|
out.append(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureFormat() {
|
||||||
|
if ((flags & TFormattableFlags.PREVIOUS_ARGUMENT) != 0) {
|
||||||
|
argumentIndex = Math.max(0, previousArgumentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argumentIndex == -1) {
|
||||||
|
argumentIndex = defaultArgumentIndex++;
|
||||||
|
}
|
||||||
|
previousArgumentIndex = argumentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char parseFormatSpecifier() {
|
||||||
|
flags = 0;
|
||||||
|
argumentIndex = -1;
|
||||||
|
width = -1;
|
||||||
|
precision = -1;
|
||||||
|
|
||||||
|
char c = format.charAt(index);
|
||||||
|
|
||||||
|
if (c != '0' && isDigit(c)) {
|
||||||
|
int n = readInt();
|
||||||
|
if (index < format.length() && format.charAt(index) == '$') {
|
||||||
|
index++;
|
||||||
|
argumentIndex = n - 1;
|
||||||
|
} else {
|
||||||
|
width = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseFlags();
|
||||||
|
|
||||||
|
if (width < 0 && index < format.length() && isDigit(format.charAt(index))) {
|
||||||
|
width = readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < format.length() && format.charAt(index) == '.') {
|
||||||
|
index++;
|
||||||
|
if (index >= format.length() || !isDigit(format.charAt(index))) {
|
||||||
|
throw new UnknownFormatConversionException(String.valueOf(format.charAt(index - 1)));
|
||||||
|
}
|
||||||
|
precision = readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= format.length()) {
|
||||||
|
throw new UnknownFormatConversionException(String.valueOf(format.charAt(format.length() - 1)));
|
||||||
|
}
|
||||||
|
return format.charAt(index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFlags() {
|
||||||
|
while (index < format.length()) {
|
||||||
|
char c = format.charAt(index);
|
||||||
|
int flag;
|
||||||
|
switch (c) {
|
||||||
|
case '-':
|
||||||
|
flag = TFormattableFlags.LEFT_JUSTIFY;
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
flag = TFormattableFlags.ALTERNATE;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
flag = TFormattableFlags.SIGNED;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
flag = TFormattableFlags.LEADING_SPACE;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
flag = TFormattableFlags.ZERO_PADDED;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
flag = TFormattableFlags.GROUPING_SEPARATOR;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
flag = TFormattableFlags.PARENTHESIZED_NEGATIVE;
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
flag = TFormattableFlags.PREVIOUS_ARGUMENT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((flags & flag) != 0) {
|
||||||
|
throw new DuplicateFormatFlagsException(String.valueOf(c));
|
||||||
|
}
|
||||||
|
flags |= flag;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readInt() {
|
||||||
|
int result = 0;
|
||||||
|
while (index < format.length() && isDigit(format.charAt(index))) {
|
||||||
|
result = result * 10 + (format.charAt(index++) - '0');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isDigit(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TFormatterClosedException extends IllegalStateException {
|
||||||
|
public TFormatterClosedException() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalFormatCodePointException extends TIllegalFormatException {
|
||||||
|
private int codePoint;
|
||||||
|
|
||||||
|
public TIllegalFormatCodePointException(int codePoint) {
|
||||||
|
super("Can't convert code point " + codePoint + " to char");
|
||||||
|
this.codePoint = codePoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCodePoint() {
|
||||||
|
return codePoint;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalFormatConversionException extends TIllegalFormatException {
|
||||||
|
private char conversion;
|
||||||
|
private Class<?> argumentClass;
|
||||||
|
|
||||||
|
public TIllegalFormatConversionException(char conversion, Class<?> argumentClass) {
|
||||||
|
super("Can't format argument of " + argumentClass + " using " + conversion + " conversion");
|
||||||
|
this.conversion = conversion;
|
||||||
|
this.argumentClass = argumentClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getConversion() {
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> getArgumentClass() {
|
||||||
|
return argumentClass;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalFormatException extends IllegalArgumentException {
|
||||||
|
TIllegalFormatException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TIllegalFormatException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalFormatFlagsException extends TIllegalFormatException {
|
||||||
|
private String flags;
|
||||||
|
|
||||||
|
public TIllegalFormatFlagsException(String flags) {
|
||||||
|
super("Illegal format flags: " + flags);
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlags() {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalFormatPrecisionException extends TIllegalFormatException {
|
||||||
|
private int precision;
|
||||||
|
|
||||||
|
public TIllegalFormatPrecisionException(int precision) {
|
||||||
|
super("Illegal precision: " + precision);
|
||||||
|
this.precision = precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPrecision() {
|
||||||
|
return precision;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TIllegalPrecisionException extends TIllegalFormatException {
|
||||||
|
private int precision;
|
||||||
|
|
||||||
|
public TIllegalPrecisionException(int precision) {
|
||||||
|
super("Illegal precision: " + precision);
|
||||||
|
this.precision = precision;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TMissingFormatWidthException extends TIllegalFormatException {
|
||||||
|
private String formatSpecifier;
|
||||||
|
|
||||||
|
public TMissingFormatWidthException(String formatSpecifier) {
|
||||||
|
super("Missing format with for specifier " + formatSpecifier);
|
||||||
|
this.formatSpecifier = formatSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormatSpecifier() {
|
||||||
|
return formatSpecifier;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
public class TUnknownFormatConversionException extends TIllegalFormatException {
|
||||||
|
private String conversion;
|
||||||
|
|
||||||
|
public TUnknownFormatConversionException(String conversion) {
|
||||||
|
super("Unknown format conversion: " + conversion);
|
||||||
|
this.conversion = conversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConversion() {
|
||||||
|
return conversion;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import java.util.DuplicateFormatFlagsException;
|
||||||
|
import java.util.FormatFlagsConversionMismatchException;
|
||||||
|
import java.util.Formattable;
|
||||||
|
import java.util.Formatter;
|
||||||
|
import java.util.IllegalFormatCodePointException;
|
||||||
|
import java.util.IllegalFormatConversionException;
|
||||||
|
import java.util.IllegalFormatFlagsException;
|
||||||
|
import java.util.IllegalFormatPrecisionException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.MissingFormatWidthException;
|
||||||
|
import java.util.UnknownFormatConversionException;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.teavm.junit.TeaVMTestRunner;
|
||||||
|
|
||||||
|
@RunWith(TeaVMTestRunner.class)
|
||||||
|
public class FormatterTest {
|
||||||
|
@Test(expected = UnknownFormatConversionException.class)
|
||||||
|
public void unexpectedEndOfFormatString() {
|
||||||
|
new Formatter().format("%1", "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = DuplicateFormatFlagsException.class)
|
||||||
|
public void duplicateFlag() {
|
||||||
|
new Formatter().format("%--s", "q");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnknownFormatConversionException.class)
|
||||||
|
public void noPrecisionAfterDot() {
|
||||||
|
new Formatter().format("%1.s", "q");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bothPreviousModifierAndArgumentIndexPresent() {
|
||||||
|
String result = new Formatter().format("%s %2$<s", "q", "w").toString();
|
||||||
|
assertEquals("q q", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatsBoolean() {
|
||||||
|
assertEquals("true", new Formatter().format("%b", true).toString());
|
||||||
|
assertEquals("false", new Formatter().format("%b", false).toString());
|
||||||
|
|
||||||
|
assertEquals("true", new Formatter().format("%b", new Object()).toString());
|
||||||
|
assertEquals("false", new Formatter().format("%b", null).toString());
|
||||||
|
|
||||||
|
assertEquals(" true", new Formatter().format("%6b", true).toString());
|
||||||
|
assertEquals("true ", new Formatter().format("%-6b", true).toString());
|
||||||
|
assertEquals("true", new Formatter().format("%2b", true).toString());
|
||||||
|
assertEquals("tr", new Formatter().format("%2.2b", true).toString());
|
||||||
|
assertEquals(" tr", new Formatter().format("%4.2b", true).toString());
|
||||||
|
assertEquals("TRUE", new Formatter().format("%B", true).toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%+b", true);
|
||||||
|
fail("Should have thrown exception");
|
||||||
|
} catch (FormatFlagsConversionMismatchException e) {
|
||||||
|
assertEquals("+", e.getFlags());
|
||||||
|
assertEquals('b', e.getConversion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatsString() {
|
||||||
|
assertEquals("23 foo", new Formatter().format("%s %s", 23, "foo").toString());
|
||||||
|
assertEquals("0:-1:-1", new Formatter().format("%s", new A()).toString());
|
||||||
|
assertEquals("0:2:-1", new Formatter().format("%2s", new A()).toString());
|
||||||
|
assertEquals("0:2:3", new Formatter().format("%2.3s", new A()).toString());
|
||||||
|
assertEquals("1:3:-1", new Formatter().format("%-3s", new A()).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class A implements Formattable {
|
||||||
|
@Override
|
||||||
|
public void formatTo(Formatter formatter, int flags, int width, int precision) {
|
||||||
|
formatter.format("%s", flags + ":" + width + ":" + precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatsHashCode() {
|
||||||
|
assertEquals("18cc6 17C13", new Formatter().format("%h %H", "foo", "bar").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void respectsFormatArgumentOrder() {
|
||||||
|
String result = new Formatter().format("%s %s %<s %1$s %<s %s %1$s %s %<s", "a", "b", "c", "d").toString();
|
||||||
|
assertEquals("a b b a a c a d d", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatsChar() {
|
||||||
|
assertEquals("x: Y:\uDBFF\uDFFF ", new Formatter().format("%c:%3C:%-3c", 'x', 'y', 0x10ffff).toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%c", Integer.MAX_VALUE);
|
||||||
|
fail("IllegalFormatCodePointException expected");
|
||||||
|
} catch (IllegalFormatCodePointException e) {
|
||||||
|
assertEquals(Integer.MAX_VALUE, e.getCodePoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("null", new Formatter().format("%c", new Object[] { null }).toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%C", new A());
|
||||||
|
fail("IllegalFormatConversionException expected");
|
||||||
|
} catch (IllegalFormatConversionException e) {
|
||||||
|
assertEquals(A.class, e.getArgumentClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%3.1c", 'X');
|
||||||
|
fail("IllegalFormatPrecisionException expected");
|
||||||
|
} catch (IllegalFormatPrecisionException e) {
|
||||||
|
assertEquals(1, e.getPrecision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatsDecimalInteger() {
|
||||||
|
assertEquals("1 2 3 4", new Formatter().format("%d %d %d %d", (byte) 1, (short) 2, 3, 4L).toString());
|
||||||
|
|
||||||
|
assertEquals("00023", new Formatter().format("%05d", 23).toString());
|
||||||
|
assertEquals("-0023", new Formatter().format("%05d", -23).toString());
|
||||||
|
assertEquals("00001,234", new Formatter(Locale.US).format("%0,9d", 1234).toString());
|
||||||
|
assertEquals("(001,234)", new Formatter(Locale.US).format("%0,(9d", -1234).toString());
|
||||||
|
|
||||||
|
assertEquals("1 12 123 1,234 12,345 123,456 1,234,567", new Formatter(Locale.US)
|
||||||
|
.format("%,d %,d %,d %,d %,d %,d %,d", 1, 12, 123, 1234, 12345, 123456, 1234567).toString());
|
||||||
|
|
||||||
|
assertEquals(" -123:-234 ", new Formatter().format("%6d:%-6d", -123, -234).toString());
|
||||||
|
|
||||||
|
assertEquals("+123 +0123 +0", new Formatter().format("%+d %+05d %+d", 123, 123, 0).toString());
|
||||||
|
|
||||||
|
assertEquals(": 123:-123:", new Formatter().format(":% d:% d:", 123, -123).toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%#d", 23);
|
||||||
|
fail("Should have thrown exception 1");
|
||||||
|
} catch (FormatFlagsConversionMismatchException e) {
|
||||||
|
assertEquals("#", e.getFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("% +d", 23);
|
||||||
|
fail("Should have thrown exception 2");
|
||||||
|
} catch (IllegalFormatFlagsException e) {
|
||||||
|
assertTrue(e.getFlags().contains("+"));
|
||||||
|
assertTrue(e.getFlags().contains(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%-01d", 23);
|
||||||
|
fail("Should have thrown exception 3");
|
||||||
|
} catch (IllegalFormatFlagsException e) {
|
||||||
|
assertTrue(e.getFlags().contains("-"));
|
||||||
|
assertTrue(e.getFlags().contains("0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%-d", 23);
|
||||||
|
fail("Should have thrown exception 4");
|
||||||
|
} catch (MissingFormatWidthException e) {
|
||||||
|
assertTrue(e.getFormatSpecifier().contains("d"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Formatter().format("%1.2d", 23);
|
||||||
|
fail("Should have thrown exception 5");
|
||||||
|
} catch (IllegalFormatPrecisionException e) {
|
||||||
|
assertEquals(2, e.getPrecision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user