Merge commit '405aeb8a97eb0a5194c2803dde3968e10e1e509e' into HEAD
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
index 75a5218..e010116 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ref/ReferenceQueueTest.java
@@ -22,6 +22,7 @@
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
+import java.util.concurrent.CountDownLatch;
import libcore.java.lang.ref.FinalizationTester;
public class ReferenceQueueTest extends junit.framework.TestCase {
@@ -198,27 +199,29 @@
assertNull(rq.poll());
class RemoveThread extends Thread {
+ public final CountDownLatch inBlock = new CountDownLatch(1);
+ public final CountDownLatch outOfBlock = new CountDownLatch(1);
public void run() {
try {
+ inBlock.countDown();
rq.remove(1000L);
} catch(InterruptedException ie) {
isThrown = true;
}
+ outOfBlock.countDown();
}
}
RemoveThread rt = new RemoveThread();
rt.start();
try {
+ rt.inBlock.await();
+ // Try to be inside of rq.remove(1000L) if possible.
Thread.sleep(10);
- } catch(InterruptedException ie) {
-
- }
+ } catch(InterruptedException ie) {}
rt.interrupt();
try {
- Thread.sleep(10);
- } catch(InterruptedException ie) {
-
- }
+ rt.outOfBlock.await();
+ } catch(InterruptedException ie) {}
assertTrue(isThrown);
assertNull(rq.poll());
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index e4d6bd8..d52e586 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.ParsePosition;
+import java.util.Locale;
import junit.framework.TestCase;
@@ -466,4 +467,23 @@
assertEquals("GREATER_THAN_ONE", fmt.format(999999999D));
assertEquals("GREATER_THAN_ONE", fmt.format(Double.POSITIVE_INFINITY));
}
+
+ // http://b/19149384
+ public void testToPatternWithInfinities() {
+ final ChoiceFormat fmt = new ChoiceFormat(
+ "-\u221E<are negative|0<are fractions|1#is one|1.0<is 1+|\u221E<are many.");
+ assertEquals("-\u221E<are negative|0.0<are fractions|1.0#is one|1.0<is 1+|\u221E<are many.",
+ fmt.toPattern());
+ }
+
+ // http://b/19011159
+ public void testEscapedPatternWithConsecutiveQuotes() {
+ ChoiceFormat format = new ChoiceFormat("0#1'2''3'''4''''.");
+ String formatted = format.format(0);
+ assertEquals("12'3'4''.", formatted);
+
+ format = new ChoiceFormat("0#1'2''3'''''4''''.");
+ formatted = format.format(0);
+ assertEquals("12'3''4''.", formatted);
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
index 171f247..0920714 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/MessageFormatTest.java
@@ -950,4 +950,12 @@
String res = MessageFormat.format("bgcolor=\"{10}\"", messageArgs);
assertEquals(res, "bgcolor=\"example10\"");
}
+
+ // http://b/19011159
+ public void test19011159() {
+ final String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
+ final MessageFormat format = new MessageFormat(pattern, Locale.ENGLISH);
+ final Object[] zero0 = new Object[] { 0 };
+ assertEquals("ab12'3'4''.yz", format.format(zero0));
+ }
}
diff --git a/luni/src/main/java/java/text/ChoiceFormat.java b/luni/src/main/java/java/text/ChoiceFormat.java
index 014b8c7..3d3cb3a 100644
--- a/luni/src/main/java/java/text/ChoiceFormat.java
+++ b/luni/src/main/java/java/text/ChoiceFormat.java
@@ -303,37 +303,16 @@
}
/**
- * Returns the double value which is closest to the specified double but
- * larger.
- *
- * @param value
- * a double value.
- * @return the next larger double value.
+ * Equivalent to {@link Math#nextUp(double)}.
*/
public static final 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);
+ return Math.nextUp(value);
}
/**
- * Returns the double value which is closest to the specified double but
- * either larger or smaller as specified.
- *
- * @param value
- * a double value.
- * @param increment
- * {@code true} to get the next larger value, {@code false} to
- * get the previous smaller value.
- * @return the next larger or smaller double value.
+ * Equivalent to {@link Math#nextUp(double)} if {@code increment == true}, and
+ * {@link Math#nextAfter(double, double)} with {@code direction == Double.NEGATIVE_INFINITY}
+ * otherwise.
*/
public static double nextDouble(double value, boolean increment) {
return increment ? nextDouble(value) : previousDouble(value);
@@ -385,25 +364,11 @@
}
/**
- * Returns the double value which is closest to the specified double but
- * smaller.
- *
- * @param value
- * a double value.
- * @return the next smaller double value.
+ * Equivalent to {@link Math#nextAfter(double, double)} with
+ * {@code direction == Double.NEGATIVE_INFINITY}.
*/
public static final 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);
+ return Math.nextAfter(value, Double.NEGATIVE_INFINITY);
}
/**
@@ -453,9 +418,30 @@
if (i != 0) {
buffer.append('|');
}
- String previous = String.valueOf(previousDouble(choiceLimits[i]));
- String limit = String.valueOf(choiceLimits[i]);
- if (previous.length() < limit.length()) {
+
+ final String previous = String.valueOf(previousDouble(choiceLimits[i]));
+ final String limit = String.valueOf(choiceLimits[i]);
+
+ // Hack to make the output of toPattern parseable by another ChoiceFormat.
+ // String.valueOf() will emit "Infinity", which isn't parseable by our NumberFormat
+ // instances.
+ //
+ // Ideally, we'd just use NumberFormat.format() to emit output (to be symmetric with
+ // our usage of NumberFormat.parse()) but it's hard set the right number of significant
+ // digits in order to output a format string that's equivalent to the original input.
+ if (Double.isInfinite(choiceLimits[i]) ||
+ Double.isInfinite(previousDouble(choiceLimits[i]))) {
+ if (choiceLimits[i] < 0) {
+ buffer.append("-\u221E");
+ buffer.append('<');
+ } else {
+ buffer.append('\u221E');
+ buffer.append('<');
+ }
+ } else if (previous.length() < limit.length()) {
+ // What the... i don't even.... sigh. This is trying to figure out whether the
+ // element was a "<" or a "#". The idea being that users will specify "reasonable"
+ // quantities and calling nextDouble will result in a "longer" number in most cases.
buffer.append(previous);
buffer.append('<');
} else {
diff --git a/luni/src/main/java/java/text/Format.java b/luni/src/main/java/java/text/Format.java
index 58671fa..c4dc5f0 100644
--- a/luni/src/main/java/java/text/Format.java
+++ b/luni/src/main/java/java/text/Format.java
@@ -177,23 +177,26 @@
static boolean upTo(String string, ParsePosition position,
StringBuffer buffer, char stop) {
int index = position.getIndex(), length = string.length();
- boolean lastQuote = false, quote = false;
+
+ int numConsecutiveQuotes = 0;
+ boolean quote = false;
while (index < length) {
char ch = string.charAt(index++);
if (ch == '\'') {
- if (lastQuote) {
+ ++numConsecutiveQuotes;
+ if (numConsecutiveQuotes != 0 && numConsecutiveQuotes % 2 == 0) {
buffer.append('\'');
}
quote = !quote;
- lastQuote = true;
} else if (ch == stop && !quote) {
position.setIndex(index);
return true;
} else {
- lastQuote = false;
+ numConsecutiveQuotes = 0;
buffer.append(ch);
}
}
+
position.setIndex(index);
return false;
}
diff --git a/luni/src/main/java/java/text/MessageFormat.java b/luni/src/main/java/java/text/MessageFormat.java
index cf306a7..f48cebd 100644
--- a/luni/src/main/java/java/text/MessageFormat.java
+++ b/luni/src/main/java/java/text/MessageFormat.java
@@ -580,6 +580,12 @@
}
if (format instanceof ChoiceFormat) {
String result = format.format(arg);
+ // Escape quotes in the result because the ChoiceFormat would've already
+ // dealt with them for us. In other words, any quotes that are present in the
+ // result are due to escaped quotes in the original input. We should preserve
+ // them in the output instead of having them processed again with the message
+ // format we're creating below.
+ result = result.replace("'", "''");
MessageFormat mf = new MessageFormat(result);
mf.setLocale(locale);
mf.format(objects, buffer, passedField);