--- a/jdk/src/share/classes/java/text/DigitList.java Fri Jan 11 20:19:55 2013 +0000
+++ b/jdk/src/share/classes/java/text/DigitList.java Fri Jan 11 15:39:08 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
+import sun.misc.FloatingDecimal;
/**
* Digit List. Private to DecimalFormat.
@@ -62,7 +63,7 @@
* derived by placing all the digits of the list to the right of the
* decimal point, by 10^exponent.
*
- * @see java.util.Locale
+ * @see Locale
* @see Format
* @see NumberFormat
* @see DecimalFormat
@@ -286,14 +287,27 @@
* fractional digits to be converted. If false, total digits.
*/
final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
- set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
+
+ FloatingDecimal fd = new FloatingDecimal(source);
+ boolean hasBeenRoundedUp = fd.digitsRoundedUp();
+ boolean allDecimalDigits = fd.decimalDigitsExact();
+ String digitsString = fd.toJavaFormatString();
+
+ set(isNegative, digitsString,
+ hasBeenRoundedUp, allDecimalDigits,
+ maximumDigits, fixedPoint);
}
/**
* Generate a representation of the form DDDDD, DDDDD.DDDDD, or
* DDDDDE+/-DDDDD.
+ * @param roundedUp Boolean value indicating if the s digits were rounded-up.
+ * @param allDecimalDigits Boolean value indicating if the digits in s are
+ * an exact decimal representation of the double that was passed.
*/
- final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
+ final void set(boolean isNegative, String s,
+ boolean roundedUp, boolean allDecimalDigits,
+ int maximumDigits, boolean fixedPoint) {
this.isNegative = isNegative;
int len = s.length();
char[] source = getDataChars(len);
@@ -346,7 +360,7 @@
} else if (-decimalAt == maximumDigits) {
// If we round 0.0009 to 3 fractional digits, then we have to
// create a new one digit in the least significant location.
- if (shouldRoundUp(0)) {
+ if (shouldRoundUp(0, roundedUp, allDecimalDigits)) {
count = 1;
++decimalAt;
digits[0] = '1';
@@ -365,19 +379,26 @@
// Eliminate digits beyond maximum digits to be displayed.
// Round up if appropriate.
- round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
+ round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits,
+ roundedUp, allDecimalDigits);
}
/**
* Round the representation to the given number of digits.
* @param maximumDigits The maximum number of digits to be shown.
+ * @param alreadyRounded Boolean indicating if rounding up already happened.
+ * @param allDecimalDigits Boolean indicating if the digits provide an exact
+ * representation of the value.
+ *
* Upon return, count will be less than or equal to maximumDigits.
*/
- private final void round(int maximumDigits) {
+ private final void round(int maximumDigits,
+ boolean alreadyRounded,
+ boolean allDecimalDigits) {
// Eliminate digits beyond maximum digits to be displayed.
// Round up if appropriate.
if (maximumDigits >= 0 && maximumDigits < count) {
- if (shouldRoundUp(maximumDigits)) {
+ if (shouldRoundUp(maximumDigits, alreadyRounded, allDecimalDigits)) {
// Rounding up involved incrementing digits from LSD to MSD.
// In most cases this is simple, but in a worst case situation
// (9999..99) we have to adjust the decimalAt value.
@@ -423,8 +444,56 @@
* @return true if digit <code>maximumDigits-1</code> should be
* incremented
*/
- private boolean shouldRoundUp(int maximumDigits) {
+ private boolean shouldRoundUp(int maximumDigits,
+ boolean alreadyRounded,
+ boolean allDecimalDigits) {
if (maximumDigits < count) {
+ /*
+ * To avoid erroneous double-rounding or truncation when converting
+ * a binary double value to text, information about the exactness
+ * of the conversion result in FloatingDecimal, as well as any
+ * rounding done, is needed in this class.
+ *
+ * - For the HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below:
+ * In the case of formating float or double, We must take into
+ * account what FloatingDecimal has done in the binary to decimal
+ * conversion.
+ *
+ * Considering the tie cases, FloatingDecimal may round-up the
+ * value (returning decimal digits equal to tie when it is below),
+ * or "truncate" the value to the tie while value is above it,
+ * or provide the exact decimal digits when the binary value can be
+ * converted exactly to its decimal representation given formating
+ * rules of FloatingDecimal ( we have thus an exact decimal
+ * representation of the binary value).
+ *
+ * - If the double binary value was converted exactly as a decimal
+ * value, then DigitList code must apply the expected rounding
+ * rule.
+ *
+ * - If FloatingDecimal already rounded up the decimal value,
+ * DigitList should neither round up the value again in any of
+ * the three rounding modes above.
+ *
+ * - If FloatingDecimal has truncated the decimal value to
+ * an ending '5' digit, DigitList should round up the value in
+ * all of the three rounding modes above.
+ *
+ *
+ * This has to be considered only if digit at maximumDigits index
+ * is exactly the last one in the set of digits, otherwise there are
+ * remaining digits after that position and we dont have to consider
+ * what FloatingDecimal did.
+ *
+ * - Other rounding modes are not impacted by these tie cases.
+ *
+ * - For other numbers that are always converted to exact digits
+ * (like BigInteger, Long, ...), the passed alreadyRounded boolean
+ * have to be set to false, and allDecimalDigits has to be set to
+ * true in the upper DigitList call stack, providing the right state
+ * for those situations..
+ */
+
switch(roundingMode) {
case UP:
for (int i=maximumDigits; i<count; ++i) {
@@ -451,6 +520,13 @@
break;
case HALF_UP:
if (digits[maximumDigits] >= '5') {
+ // We should not round up if the rounding digits position is
+ // exactly the last index and if digits were already rounded.
+ if ((maximumDigits == (count - 1)) &&
+ (alreadyRounded))
+ return false;
+
+ // Value was exactly at or was above tie. We must round up.
return true;
}
break;
@@ -458,6 +534,21 @@
if (digits[maximumDigits] > '5') {
return true;
} else if (digits[maximumDigits] == '5' ) {
+ if (maximumDigits == (count - 1)) {
+ // The rounding position is exactly the last index.
+ if (allDecimalDigits || alreadyRounded)
+ /* FloatingDecimal rounded up (value was below tie),
+ * or provided the exact list of digits (value was
+ * an exact tie). We should not round up, following
+ * the HALF_DOWN rounding rule.
+ */
+ return false;
+ else
+ // Value was above the tie, we must round up.
+ return true;
+ }
+
+ // We must round up if it gives a non null digit after '5'.
for (int i=maximumDigits+1; i<count; ++i) {
if (digits[i] != '0') {
return true;
@@ -470,12 +561,32 @@
if (digits[maximumDigits] > '5') {
return true;
} else if (digits[maximumDigits] == '5' ) {
- for (int i=maximumDigits+1; i<count; ++i) {
- if (digits[i] != '0') {
+ if (maximumDigits == (count - 1)) {
+ // the rounding position is exactly the last index :
+ if (alreadyRounded)
+ // If FloatingDecimal rounded up (value was below tie),
+ // then we should not round up again.
+ return false;
+
+ if (!allDecimalDigits)
+ // Otherwise if the digits dont represent exact value,
+ // value was above tie and FloatingDecimal truncated
+ // digits to tie. We must round up.
return true;
+ else {
+ // This is an exact tie value, and FloatingDecimal
+ // provided all of the exact digits. We thus apply
+ // HALF_EVEN rounding rule.
+ return ((maximumDigits > 0) &&
+ (digits[maximumDigits-1] % 2 != 0));
+ }
+ } else {
+ // Rounds up if it gives a non null digit after '5'
+ for (int i=maximumDigits+1; i<count; ++i) {
+ if (digits[i] != '0')
+ return true;
}
}
- return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
}
break;
case UNNECESSARY:
@@ -542,7 +653,7 @@
count = right - left + 1;
System.arraycopy(digits, left, digits, 0, count);
}
- if (maximumDigits > 0) round(maximumDigits);
+ if (maximumDigits > 0) round(maximumDigits, false, true);
}
/**
@@ -559,7 +670,9 @@
String s = source.toString();
extendDigits(s.length());
- set(isNegative, s, maximumDigits, fixedPoint);
+ set(isNegative, s,
+ false, true,
+ maximumDigits, fixedPoint);
}
/**
@@ -584,7 +697,7 @@
count = right + 1;
if (maximumDigits > 0) {
- round(maximumDigits);
+ round(maximumDigits, false, true);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/text/Format/DecimalFormat/TieRoundingTest.java Fri Jan 11 15:39:08 2013 -0800
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ *
+ * @bug 7131459
+ * @summary test various situations of NumberFormat rounding when close to tie
+ * @author Olivier Lagneau
+ * @run main TieRoundingTest
+ *
+ */
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.math.RoundingMode;
+import java.util.Locale;
+
+public class TieRoundingTest {
+
+ static int testCounter = 0;
+ static int errorCounter = 0;
+ static boolean allPassed = true;
+
+ static void formatOutputTestDouble(NumberFormat nf,
+ double doubleToTest,
+ String tiePosition,
+ String inputDigits,
+ String expectedOutput) {
+
+ int mfd = nf.getMaximumFractionDigits();
+ RoundingMode rm = nf.getRoundingMode();
+ String result = nf.format(doubleToTest);
+
+ if (!result.equals(expectedOutput)) {
+ System.out.println();
+ System.out.println("========================================");
+ System.out.println("***Error formatting double value from string : " +
+ inputDigits);
+ System.out.println("NumberFormat pattern is : " +
+ ((DecimalFormat ) nf).toPattern());
+ System.out.println("Maximum number of fractional digits : " + mfd);
+ System.out.println("Fractional rounding digit : " + (mfd + 1));
+ System.out.println("Position of value relative to tie : " + tiePosition);
+ System.out.println("Rounding Mode : " + rm);
+ System.out.println("BigDecimal output : " +
+ new BigDecimal(doubleToTest).toString());
+ System.out.println("FloatingDecimal output : " + doubleToTest);
+ System.out.println(
+ "Error. Formatted result different from expected." +
+ "\nExpected output is : \"" + expectedOutput + "\"" +
+ "\nFormated output is : \"" + result + "\"");
+ System.out.println("========================================");
+ System.out.println();
+
+ errorCounter++;
+ allPassed = false;
+ } else {
+ testCounter++;
+ System.out.println("\nSuccess for double value : " + doubleToTest + " :");
+ System.out.println(" Input digits :" + inputDigits +
+ ", BigDecimal value : " +
+ new BigDecimal(doubleToTest).toString());
+ System.out.print(" Rounding mode: " + rm);
+ System.out.print(", fract digits : " + mfd);
+ System.out.print(", position : " + tiePosition + " tie");
+ System.out.print(", result : " + result);
+ System.out.println(", expected : " + expectedOutput);
+ }
+ }
+
+ static void formatOutputTestLong(NumberFormat nf,
+ long longToTest,
+ String tiePosition,
+ String inputDigits,
+ String expectedOutput) {
+
+ int mfd = nf.getMaximumFractionDigits();
+ RoundingMode rm = nf.getRoundingMode();
+ String result = nf.format(longToTest);
+
+ if (!result.equals(expectedOutput)) {
+ System.out.println();
+ System.out.println("========================================");
+ System.out.println("***Error formatting double value from string : " +
+ inputDigits);
+ System.out.println("NumberFormat pattern is : " +
+ ((DecimalFormat ) nf).toPattern());
+ System.out.println("Maximum number of fractional digits : " + mfd);
+ System.out.println("Fractional rounding digit : " + (mfd + 1));
+ System.out.println("Position of value relative to tie : " + tiePosition);
+ System.out.println("Rounding Mode : " + rm);
+ System.out.println(
+ "Error. Formatted result different from expected." +
+ "\nExpected output is : \"" + expectedOutput + "\"" +
+ "\nFormated output is : \"" + result + "\"");
+ System.out.println("========================================");
+ System.out.println();
+
+ errorCounter++;
+ allPassed = false;
+ } else {
+ testCounter++;
+ System.out.print("Success. Long input :" + inputDigits);
+ System.out.print(", rounding : " + rm);
+ System.out.print(", fract digits : " + mfd);
+ System.out.print(", tie position : " + tiePosition);
+ System.out.println(", expected : " + expectedOutput);
+
+ }
+ }
+
+ static void formatOutputTestObject(NumberFormat nf,
+ Object someNumber,
+ String tiePosition,
+ String inputDigits,
+ String expectedOutput) {
+
+ int mfd = nf.getMaximumFractionDigits();
+ RoundingMode rm = nf.getRoundingMode();
+ String result = nf.format(someNumber);
+
+ if (!result.equals(expectedOutput)) {
+ System.out.println();
+ System.out.println("========================================");
+ System.out.println("***Error formatting number value from string : " +
+ inputDigits);
+ System.out.println("NumberFormat pattern is : " +
+ ((DecimalFormat ) nf).toPattern());
+ System.out.println("Maximum number of fractional digits : " + mfd);
+ System.out.println("Fractional rounding digit : " + (mfd + 1));
+ System.out.println("Position of value relative to tie : " + tiePosition);
+ System.out.println("Rounding Mode : " + rm);
+ System.out.println("Number self output representation: " + someNumber);
+ System.out.println(
+ "Error. Formatted result different from expected." +
+ "\nExpected output is : \"" + expectedOutput + "\"" +
+ "\nFormated output is : \"" + result + "\"");
+ System.out.println("========================================");
+ System.out.println();
+
+ errorCounter++;
+ allPassed = false;
+ } else {
+ testCounter++;
+ System.out.print("Success. Number input :" + inputDigits);
+ System.out.print(", rounding : " + rm);
+ System.out.print(", fract digits : " + mfd);
+ System.out.print(", tie position : " + tiePosition);
+ System.out.println(", expected : " + expectedOutput);
+ }
+ }
+
+ public static void main(String[] args) {
+
+ // Only the 3 rounding modes below may be impacted by bug 7131459.
+ // So we do not test the other rounding modes.
+ RoundingMode[] roundingModes = {
+ RoundingMode.HALF_DOWN,
+ RoundingMode.HALF_EVEN,
+ RoundingMode.HALF_UP
+ };
+
+ // Precise the relative position of input value against its closest tie.
+ String[] tieRelativePositions = {
+ "below", "exact", "above",
+ "below", "exact", "above",
+ "below", "exact", "above",
+ "below", "exact", "above"
+ };
+
+ // =============== Testing double (and thus float) value cases =========
+
+ System.out.println("\n===== testing 3 digits rounding position =====");
+ double[] values3FractDigits = {
+ // unimpacting values close to tie, with less than 3 input fract digits
+ 1.115d, 1.125d, 1.135d,
+ // impacting close to tie values covering all 6 cases
+ 0.3115d, 0.3125d, 0.3135d,
+ 0.6865d, 0.6875d, 0.6885d,
+ // unimpacting values close to tie, with more than 3 input fract digits
+ 1.46885d, 2.46875d, 1.46865d
+ };
+
+ String[] inputs3FractDigits = {
+ "1.115d", "1.125d", "1.135d",
+ "0.3115d", "0.3125d", "0.3135d",
+ "0.6865d", "0.6875d", "0.6885d",
+ "1.46885d", "2.46875d", "1.46865d"
+ };
+
+ String[][] expected3FractDigits = {
+ {"1.115", "1.125", "1.135",
+ "0.311", "0.312", "0.314",
+ "0.686", "0.687", "0.689",
+ "1.469", "2.469", "1.469"
+ },
+ {"1.115", "1.125", "1.135",
+ "0.311", "0.312", "0.314",
+ "0.686", "0.688", "0.689",
+ "1.469", "2.469", "1.469"
+ },
+ {"1.115", "1.125", "1.135",
+ "0.311", "0.313", "0.314",
+ "0.686", "0.688", "0.689",
+ "1.469", "2.469", "1.469"
+ },
+ };
+
+
+ for (int r = 0; r < roundingModes.length; r++) {
+ NumberFormat dfDefault = NumberFormat.getInstance(Locale.US);
+ RoundingMode rmode = roundingModes[r];
+ dfDefault.setRoundingMode(rmode);
+ System.out.println("\n----- Now checking " + rmode +
+ " rounding mode -----");
+
+ for (int i = 0; i < values3FractDigits.length; i++) {
+ double d = values3FractDigits[i];
+ String tiePosition = tieRelativePositions[i];
+ String input = inputs3FractDigits[i];
+ String expected = expected3FractDigits[r][i];
+
+ formatOutputTestDouble(dfDefault, d, tiePosition, input, expected);
+ }
+ }
+
+ System.out.println("\n===== testing 5 digits rounding position =====");
+ double[] values5FractDigits = {
+ // unimpacting values close to tie, with less than 5 input fract digits
+ 1.3135d, 1.3125d, 1.3115d,
+ // impacting values close to tie, covering all 6 cases
+ 1.328115d, 1.328125d, 1.328135d,
+ 1.796865d, 1.796875d, 1.796885d,
+ // unimpacting values close to tie, with more than 5 input fract digits
+ 1.3281149999999d, 1.75390625d, 1.7968750000001d
+ };
+
+ String[] inputs5FractDigits = {
+ "1.3135d", "1.3125d", "1.3115d",
+ "1.328115d", "1.328125d", "1.328135d",
+ "1.796865d", "1.796875d", "1.796885d",
+ "1.3281149999999d", "1.75390625d", "1.7968750000001d"
+ };
+
+ String[][] expected5FractDigits = {
+ {"1.3135", "1.3125", "1.3115",
+ "1.32811", "1.32812", "1.32814",
+ "1.79686", "1.79687", "1.79689",
+ "1.32811", "1.75391", "1.79688"
+ },
+ {"1.3135", "1.3125", "1.3115",
+ "1.32811", "1.32812", "1.32814",
+ "1.79686", "1.79688", "1.79689",
+ "1.32811", "1.75391", "1.79688"
+ },
+ {"1.3135", "1.3125", "1.3115",
+ "1.32811", "1.32813", "1.32814",
+ "1.79686", "1.79688", "1.79689",
+ "1.32811", "1.75391", "1.79688"
+ }
+ };
+
+
+ for (int r = 0; r < roundingModes.length; r++) {
+ DecimalFormat df5 = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+ RoundingMode rmode = roundingModes[r];
+ df5.setRoundingMode(rmode);
+ System.out.println("\n----- Now checking " + rmode +
+ " rounding mode -----");
+ df5.applyPattern("#,###.#####");
+
+ for (int i = 0; i < values5FractDigits.length; i++) {
+ double d = values5FractDigits[i];
+ String tiePosition = tieRelativePositions[i];
+ String input = inputs5FractDigits[i];
+ String expected = expected5FractDigits[r][i];
+
+ formatOutputTestDouble(df5, d, tiePosition, input, expected);
+ }
+ }
+
+ // ==================== Testing long value cases ====================
+
+ System.out.println("\n===== testing long values =====");
+ long l = 123456789012345L;
+ DecimalFormat dfLong = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+ String tiePosition = "exact";
+ String input = "123456789012345L";
+ String expected = "123,456,789,012,345";
+ String result = dfLong.format(l);
+ formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+ dfLong.applyPattern("0.###E0");
+ expected = "1.235E14";
+ formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+ l = 123450000000000L;
+ input = "123450000000000L";
+ expected = "1.234E14";
+ formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+ l = 987750000000000L;
+ input = "987750000000000L";
+ expected = "9.878E14";
+ formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+ dfLong.applyPattern("#,###.0E0");
+ l = 987755000000000L;
+ input = "987755000000000L";
+ expected = "987.76E12";
+
+ formatOutputTestLong(dfLong, l, tiePosition, input, expected);
+
+
+ // ================= Testing BigInteger value cases =================
+
+ System.out.println("\n===== testing BigInteger values =====");
+ String stringValue = "12345678901234567890123456789012345";
+ BigInteger bi = new BigInteger(stringValue);
+ DecimalFormat dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+ tiePosition = "exact";
+ input = stringValue;
+ expected = "12,345,678,901,234,567,890,123,456,789,012,345";
+ formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+ dfBig.applyPattern("0.###E0");
+ expected = "1.235E34";
+ formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+ stringValue = "12345000000000000000000000000000000";
+ input = stringValue;
+ bi = new BigInteger(stringValue);
+ expected = "1.234E34";
+ formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+ stringValue = "12345000000000000000000000000000001";
+ input = stringValue;
+ bi = new BigInteger(stringValue);
+ expected = "1.235E34";
+ formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+ stringValue = "98755000000000000000000000000000000";
+ input = stringValue;
+ bi = new BigInteger(stringValue);
+ expected = "9.876E34";
+ formatOutputTestObject(dfBig, bi, tiePosition, input, expected);
+
+ dfLong.applyPattern("#,###.0E0");
+ stringValue = "98775500000000000000000000000000000";
+ input = stringValue;
+ expected = "987.76E34";
+
+ // =============== Testing BigDecimal value cases ================
+
+ System.out.println("\n===== testing BigDecimal values =====");
+ dfBig = (DecimalFormat) NumberFormat.getInstance(Locale.US);
+
+ stringValue = "0.68850000000000000088817841970012523233890533447265625";
+ BigDecimal bd = new BigDecimal(stringValue);
+ tiePosition = "exact";
+ input = stringValue;
+ expected = "0.689";
+ formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
+
+ stringValue = "0.31149999999999999911182158029987476766109466552734375";
+ bd = new BigDecimal(stringValue);
+ dfBig.applyPattern("#,##0.####");
+ tiePosition = "exact";
+ input = stringValue;
+ expected = "0.3115";
+ formatOutputTestObject(dfBig, bd, tiePosition, input, expected);
+
+ // ==================== Printing results and exiting ===================
+
+ System.out.println();
+ System.out.println("==> " + testCounter + " tests passed successfully");
+ System.out.println("==> " + errorCounter + " tests failed");
+
+ System.out.println();
+ if (allPassed) {
+ System.out.println(
+ "Success in formating all the values with the given parameters");
+ } else {
+ String s = "Test failed with " + errorCounter + " formating error(s).";
+ System.out.println(s);
+ throw new RuntimeException(s);
+ }
+ }
+}