summaryrefslogtreecommitdiffstats
path: root/text
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commitfdb2704414a9ed92394ada0d1395e4db86889465 (patch)
tree9b591a4a50054274a197f02b3ccb51313681879f /text
downloadlibcore-fdb2704414a9ed92394ada0d1395e4db86889465.zip
libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.gz
libcore-fdb2704414a9ed92394ada0d1395e4db86889465.tar.bz2
Initial Contribution
Diffstat (limited to 'text')
-rw-r--r--text/MODULE_LICENSE_APACHE20
-rw-r--r--text/src/main/java/java/text/Annotation.java39
-rw-r--r--text/src/main/java/java/text/AttributedCharacterIterator.java107
-rw-r--r--text/src/main/java/java/text/AttributedString.java670
-rw-r--r--text/src/main/java/java/text/Bidi.java554
-rw-r--r--text/src/main/java/java/text/BreakIterator.java458
-rw-r--r--text/src/main/java/java/text/CharacterIterator.java115
-rw-r--r--text/src/main/java/java/text/ChoiceFormat.java411
-rw-r--r--text/src/main/java/java/text/CollationElementIterator.java252
-rw-r--r--text/src/main/java/java/text/CollationKey.java103
-rw-r--r--text/src/main/java/java/text/Collator.java365
-rw-r--r--text/src/main/java/java/text/DateFormat.java803
-rw-r--r--text/src/main/java/java/text/DateFormatSymbols.java429
-rw-r--r--text/src/main/java/java/text/DecimalFormat.java952
-rw-r--r--text/src/main/java/java/text/DecimalFormatSymbols.java543
-rw-r--r--text/src/main/java/java/text/FieldPosition.java171
-rw-r--r--text/src/main/java/java/text/Format.java262
-rw-r--r--text/src/main/java/java/text/MessageFormat.java1037
-rw-r--r--text/src/main/java/java/text/NumberFormat.java774
-rw-r--r--text/src/main/java/java/text/ParseException.java52
-rw-r--r--text/src/main/java/java/text/ParsePosition.java120
-rw-r--r--text/src/main/java/java/text/RuleBasedBreakIterator.java205
-rw-r--r--text/src/main/java/java/text/RuleBasedCollator.java214
-rw-r--r--text/src/main/java/java/text/SimpleDateFormat.java1087
-rw-r--r--text/src/main/java/java/text/StringCharacterIterator.java279
-rw-r--r--text/src/main/java/java/text/package.html16
-rw-r--r--text/src/main/java/org/apache/harmony/text/BidiRun.java55
-rw-r--r--text/src/main/java/org/apache/harmony/text/BidiWrapper.java87
-rw-r--r--text/src/main/java/org/apache/harmony/text/internal/nls/Messages.java124
-rw-r--r--text/src/main/java/org/apache/harmony/text/internal/nls/messages.properties46
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/AllTests.java63
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/AnnotationTest.java54
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorAttributeTest.java170
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorTest.java178
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedStringTest.java462
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/BidiTest.java994
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/BreakIteratorTest.java597
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/ChoiceFormatTest.java477
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/CollationElementIteratorTest.java232
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/CollationKeyTest.java117
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/CollatorTest.java317
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DataFormatFieldTest.java223
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatSymbolsTest.java353
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatTest.java728
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java536
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java1869
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/FieldPositionTest.java239
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/FormatFieldTest.java46
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/FormatTest.java98
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatFieldTest.java110
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatTest.java1073
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatFieldTest.java109
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java1118
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/ParseExceptionTest.java66
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/ParsePositionTest.java124
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/RuleBasedCollatorTest.java350
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/SimpleDateFormatTest.java964
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/StringCharacterIteratorTest.java521
-rw-r--r--text/src/test/java/tests/text/AllTests.java40
-rw-r--r--text/src/test/resources/serialization/java/text/DecimalFormat.serbin0 -> 1384 bytes
-rw-r--r--text/src/test/resources/serialization/java/text/DecimalFormatSymbols.serbin0 -> 495 bytes
61 files changed, 22558 insertions, 0 deletions
diff --git a/text/MODULE_LICENSE_APACHE2 b/text/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text/MODULE_LICENSE_APACHE2
diff --git a/text/src/main/java/java/text/Annotation.java b/text/src/main/java/java/text/Annotation.java
new file mode 100644
index 0000000..922cbd0
--- /dev/null
+++ b/text/src/main/java/java/text/Annotation.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * Annotation
+ */
+public class Annotation {
+
+ private Object value;
+
+ public Annotation(Object attribute) {
+ value = attribute;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[value=" + value + ']'; //$NON-NLS-1$
+ }
+}
diff --git a/text/src/main/java/java/text/AttributedCharacterIterator.java b/text/src/main/java/java/text/AttributedCharacterIterator.java
new file mode 100644
index 0000000..c9504e8
--- /dev/null
+++ b/text/src/main/java/java/text/AttributedCharacterIterator.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * AttributedCharacterIterator
+ */
+public interface AttributedCharacterIterator extends CharacterIterator {
+
+ public static class Attribute implements Serializable {
+
+ private static final long serialVersionUID = -9142742483513960612L;
+
+ public static final Attribute INPUT_METHOD_SEGMENT = new Attribute(
+ "input_method_segment"); //$NON-NLS-1$
+
+ public static final Attribute LANGUAGE = new Attribute("language"); //$NON-NLS-1$
+
+ public static final Attribute READING = new Attribute("reading"); //$NON-NLS-1$
+
+ private String name;
+
+ protected Attribute(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public final boolean equals(Object object) {
+ if (object == null || !(object.getClass().equals(this.getClass()))) {
+ return false;
+ }
+ return name.equals(((Attribute) object).name);
+ }
+
+ protected String getName() {
+ return name;
+ }
+
+ @Override
+ public final int hashCode() {
+ return name.hashCode();
+ }
+
+ protected Object readResolve() throws InvalidObjectException {
+ if (this.getClass() != Attribute.class) {
+ // text.0C=cannot resolve subclasses
+ throw new InvalidObjectException(Messages.getString("text.0C")); //$NON-NLS-1$
+ }
+ if (this.equals(INPUT_METHOD_SEGMENT)) {
+ return INPUT_METHOD_SEGMENT;
+ }
+ if (this.equals(LANGUAGE)) {
+ return LANGUAGE;
+ }
+ if (this.equals(READING)) {
+ return READING;
+ }
+ // text.02=Unknown attribute
+ throw new InvalidObjectException(Messages.getString("text.02")); //$NON-NLS-1$
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + '(' + getName() + ')';
+ }
+ }
+
+ public Set<Attribute> getAllAttributeKeys();
+
+ public Object getAttribute(Attribute attribute);
+
+ public Map<Attribute, Object> getAttributes();
+
+ public int getRunLimit();
+
+ public int getRunLimit(Attribute attribute);
+
+ public int getRunLimit(Set<? extends Attribute> attributes);
+
+ public int getRunStart();
+
+ public int getRunStart(Attribute attribute);
+
+ public int getRunStart(Set<? extends Attribute> attributes);
+}
diff --git a/text/src/main/java/java/text/AttributedString.java b/text/src/main/java/java/text/AttributedString.java
new file mode 100644
index 0000000..6bcd8a3
--- /dev/null
+++ b/text/src/main/java/java/text/AttributedString.java
@@ -0,0 +1,670 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * AttributedString
+ */
+public class AttributedString {
+
+ String text;
+
+ Map<AttributedCharacterIterator.Attribute, List<Range>> attributeMap;
+
+ static class Range {
+ int start;
+
+ int end;
+
+ Object value;
+
+ Range(int s, int e, Object v) {
+ start = s;
+ end = e;
+ value = v;
+ }
+ }
+
+ static class AttributedIterator implements AttributedCharacterIterator {
+
+ private int begin, end, offset;
+
+ private AttributedString attrString;
+
+ private HashSet<Attribute> attributesAllowed;
+
+ AttributedIterator(AttributedString attrString) {
+ this.attrString = attrString;
+ begin = 0;
+ end = attrString.text.length();
+ offset = 0;
+ }
+
+ AttributedIterator(AttributedString attrString,
+ AttributedCharacterIterator.Attribute[] attributes, int begin,
+ int end) {
+ if (begin < 0 || end > attrString.text.length() || begin > end) {
+ throw new IllegalArgumentException();
+ }
+ this.begin = begin;
+ this.end = end;
+ offset = begin;
+ this.attrString = attrString;
+ if (attributes != null) {
+ HashSet<Attribute> set = new HashSet<Attribute>(
+ (attributes.length * 4 / 3) + 1);
+ for (int i = attributes.length; --i >= 0;) {
+ set.add(attributes[i]);
+ }
+ attributesAllowed = set;
+ }
+ }
+
+ /**
+ * Returns a new StringCharacterIterator with the same source String,
+ * begin, end, and current index as this StringCharacterIterator.
+ *
+ * @return a shallow copy of this StringCharacterIterator
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object clone() {
+ try {
+ AttributedIterator clone = (AttributedIterator) super.clone();
+ if (attributesAllowed != null) {
+ clone.attributesAllowed = (HashSet<Attribute>) attributesAllowed
+ .clone();
+ }
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the character at the current index in the source String.
+ *
+ * @return the current character, or DONE if the current index is past
+ * the end
+ */
+ public char current() {
+ if (offset == end) {
+ return DONE;
+ }
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Sets the current position to the begin index and returns the
+ * character at the begin index.
+ *
+ * @return the character at the begin index
+ */
+ public char first() {
+ if (begin == end) {
+ return DONE;
+ }
+ offset = begin;
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Returns the begin index in the source String.
+ *
+ * @return the index of the first character to iterate
+ */
+ public int getBeginIndex() {
+ return begin;
+ }
+
+ /**
+ * Returns the end index in the source String.
+ *
+ * @return the index one past the last character to iterate
+ */
+ public int getEndIndex() {
+ return end;
+ }
+
+ /**
+ * Returns the current index in the source String.
+ *
+ * @return the current index
+ */
+ public int getIndex() {
+ return offset;
+ }
+
+ private boolean inRange(Range range) {
+ if (!(range.value instanceof Annotation)) {
+ return true;
+ }
+ return range.start >= begin && range.start < end
+ && range.end > begin && range.end <= end;
+ }
+
+ private boolean inRange(List<Range> ranges) {
+ Iterator<Range> it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = it.next();
+ if (range.start >= begin && range.start < end) {
+ return !(range.value instanceof Annotation)
+ || (range.end > begin && range.end <= end);
+ } else if (range.end > begin && range.end <= end) {
+ return !(range.value instanceof Annotation)
+ || (range.start >= begin && range.start < end);
+ }
+ }
+ return false;
+ }
+
+ public Set<AttributedIterator.Attribute> getAllAttributeKeys() {
+ if (begin == 0 && end == attrString.text.length()
+ && attributesAllowed == null) {
+ return attrString.attributeMap.keySet();
+ }
+
+ Set<AttributedIterator.Attribute> result = new HashSet<Attribute>(
+ (attrString.attributeMap.size() * 4 / 3) + 1);
+ Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
+ .entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Attribute, List<Range>> entry = it.next();
+ if (attributesAllowed == null
+ || attributesAllowed.contains(entry.getKey())) {
+ List<Range> ranges = entry.getValue();
+ if (inRange(ranges)) {
+ result.add(entry.getKey());
+ }
+ }
+ }
+ return result;
+ }
+
+ private Object currentValue(List<Range> ranges) {
+ Iterator<Range> it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = it.next();
+ if (offset >= range.start && offset < range.end) {
+ return inRange(range) ? range.value : null;
+ }
+ }
+ return null;
+ }
+
+ public Object getAttribute(
+ AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute)) {
+ return null;
+ }
+ ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null) {
+ return null;
+ }
+ return currentValue(ranges);
+ }
+
+ public Map<Attribute, Object> getAttributes() {
+ Map<Attribute, Object> result = new HashMap<Attribute, Object>(
+ (attrString.attributeMap.size() * 4 / 3) + 1);
+ Iterator<Map.Entry<Attribute, List<Range>>> it = attrString.attributeMap
+ .entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Attribute, List<Range>> entry = it.next();
+ if (attributesAllowed == null
+ || attributesAllowed.contains(entry.getKey())) {
+ Object value = currentValue(entry.getValue());
+ if (value != null) {
+ result.put(entry.getKey(), value);
+ }
+ }
+ }
+ return result;
+ }
+
+ public int getRunLimit() {
+ return getRunLimit(getAllAttributeKeys());
+ }
+
+ private int runLimit(List<Range> ranges) {
+ int result = end;
+ ListIterator<Range> it = ranges.listIterator(ranges.size());
+ while (it.hasPrevious()) {
+ Range range = it.previous();
+ if (range.end <= begin) {
+ break;
+ }
+ if (offset >= range.start && offset < range.end) {
+ return inRange(range) ? range.end : result;
+ } else if (offset >= range.end) {
+ break;
+ }
+ result = range.start;
+ }
+ return result;
+ }
+
+ public int getRunLimit(AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute)) {
+ return end;
+ }
+ ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null) {
+ return end;
+ }
+ return runLimit(ranges);
+ }
+
+ public int getRunLimit(Set<? extends Attribute> attributes) {
+ int limit = end;
+ Iterator<? extends Attribute> it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = it.next();
+ int newLimit = getRunLimit(attribute);
+ if (newLimit < limit) {
+ limit = newLimit;
+ }
+ }
+ return limit;
+ }
+
+ public int getRunStart() {
+ return getRunStart(getAllAttributeKeys());
+ }
+
+ private int runStart(List<Range> ranges) {
+ int result = begin;
+ Iterator<Range> it = ranges.iterator();
+ while (it.hasNext()) {
+ Range range = it.next();
+ if (range.start >= end) {
+ break;
+ }
+ if (offset >= range.start && offset < range.end) {
+ return inRange(range) ? range.start : result;
+ } else if (offset < range.start) {
+ break;
+ }
+ result = range.end;
+ }
+ return result;
+ }
+
+ public int getRunStart(AttributedCharacterIterator.Attribute attribute) {
+ if (attributesAllowed != null
+ && !attributesAllowed.contains(attribute)) {
+ return begin;
+ }
+ ArrayList<Range> ranges = (ArrayList<Range>) attrString.attributeMap
+ .get(attribute);
+ if (ranges == null) {
+ return begin;
+ }
+ return runStart(ranges);
+ }
+
+ public int getRunStart(Set<? extends Attribute> attributes) {
+ int start = begin;
+ Iterator<? extends Attribute> it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = it.next();
+ int newStart = getRunStart(attribute);
+ if (newStart > start) {
+ start = newStart;
+ }
+ }
+ return start;
+ }
+
+ /**
+ * Sets the current position to the end index - 1 and returns the
+ * character at the current position.
+ *
+ * @return the character before the end index
+ */
+ public char last() {
+ if (begin == end) {
+ return DONE;
+ }
+ offset = end - 1;
+ return attrString.text.charAt(offset);
+ }
+
+ /**
+ * Increments the current index and returns the character at the new
+ * index.
+ *
+ * @return the character at the next index, or DONE if the next index is
+ * past the end
+ */
+ public char next() {
+ if (offset >= (end - 1)) {
+ offset = end;
+ return DONE;
+ }
+ return attrString.text.charAt(++offset);
+ }
+
+ /**
+ * Decrements the current index and returns the character at the new
+ * index.
+ *
+ * @return the character at the previous index, or DONE if the previous
+ * index is past the beginning
+ */
+ public char previous() {
+ if (offset == begin) {
+ return DONE;
+ }
+ return attrString.text.charAt(--offset);
+ }
+
+ /**
+ * Sets the current index in the source String.
+ *
+ * @return the character at the new index, or DONE if the index is past
+ * the end
+ *
+ * @exception IllegalArgumentException
+ * when the new index is less than the begin index or
+ * greater than the end index
+ */
+ public char setIndex(int location) {
+ if (location < begin || location > end) {
+ throw new IllegalArgumentException();
+ }
+ offset = location;
+ if (offset == end) {
+ return DONE;
+ }
+ return attrString.text.charAt(offset);
+ }
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator) {
+ if (iterator.getBeginIndex() > iterator.getEndIndex()) {
+ // text.0A=Invalid substring range
+ throw new IllegalArgumentException(Messages.getString("text.0A")); //$NON-NLS-1$
+ }
+ StringBuffer buffer = new StringBuffer();
+ for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex(); i++) {
+ buffer.append(iterator.current());
+ iterator.next();
+ }
+ text = buffer.toString();
+ Set<AttributedCharacterIterator.Attribute> attributes = iterator
+ .getAllAttributeKeys();
+ if (attributes == null) {
+ return;
+ }
+ attributeMap = new HashMap<Attribute, List<Range>>(
+ (attributes.size() * 4 / 3) + 1);
+
+ Iterator<Attribute> it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = it.next();
+ iterator.setIndex(0);
+ while (iterator.current() != CharacterIterator.DONE) {
+ int start = iterator.getRunStart(attribute);
+ int limit = iterator.getRunLimit(attribute);
+ Object value = iterator.getAttribute(attribute);
+ if (value != null) {
+ addAttribute(attribute, value, start, limit);
+ }
+ iterator.setIndex(limit);
+ }
+ }
+ }
+
+ private AttributedString(AttributedCharacterIterator iterator, int start,
+ int end, Set<Attribute> attributes) {
+ if (start < iterator.getBeginIndex() || end > iterator.getEndIndex()
+ || start > end) {
+ throw new IllegalArgumentException();
+ }
+
+ if (attributes == null) {
+ return;
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ iterator.setIndex(start);
+ while (iterator.getIndex() < end) {
+ buffer.append(iterator.current());
+ iterator.next();
+ }
+ text = buffer.toString();
+ attributeMap = new HashMap<Attribute, List<Range>>(
+ (attributes.size() * 4 / 3) + 1);
+
+ Iterator<Attribute> it = attributes.iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = it.next();
+ iterator.setIndex(start);
+ while (iterator.getIndex() < end) {
+ Object value = iterator.getAttribute(attribute);
+ int runStart = iterator.getRunStart(attribute);
+ int limit = iterator.getRunLimit(attribute);
+ if ((value instanceof Annotation && runStart >= start && limit <= end)
+ || (value != null && !(value instanceof Annotation))) {
+ addAttribute(attribute, value, (runStart < start ? start
+ : runStart)
+ - start, (limit > end ? end : limit) - start);
+ }
+ iterator.setIndex(limit);
+ }
+ }
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator, int start,
+ int end) {
+ this(iterator, start, end, iterator.getAllAttributeKeys());
+ }
+
+ public AttributedString(AttributedCharacterIterator iterator, int start,
+ int end, AttributedCharacterIterator.Attribute[] attributes) {
+ // BEGIN android-removed
+ // this(iterator, start, end, new HashSet<Attribute>(Arrays
+ // .asList(attributes)));
+ // END android-removed
+ // BEGIN android-added
+ this(iterator, start, end, (attributes == null? null :
+ new HashSet<Attribute>(Arrays.asList(attributes))));
+ // END android-added
+ }
+
+ public AttributedString(String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ text = value;
+ attributeMap = new HashMap<Attribute, List<Range>>(11);
+ }
+
+ public AttributedString(String value,
+ Map<? extends AttributedCharacterIterator.Attribute, ?> attributes) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ if (value.length() == 0 && !attributes.isEmpty()) {
+ // text.0B=Cannot add attributes to empty string
+ throw new IllegalArgumentException(Messages.getString("text.0B")); //$NON-NLS-1$
+ }
+ text = value;
+ attributeMap = new HashMap<Attribute, List<Range>>(
+ (attributes.size() * 4 / 3) + 1);
+ Iterator<?> it = attributes.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
+ ArrayList<Range> ranges = new ArrayList<Range>(1);
+ ranges.add(new Range(0, text.length(), entry.getValue()));
+ attributeMap.put((AttributedCharacterIterator.Attribute) entry
+ .getKey(), ranges);
+ }
+ }
+
+ public void addAttribute(AttributedCharacterIterator.Attribute attribute,
+ Object value) {
+ if (null == attribute) {
+ throw new NullPointerException();
+ }
+ if (text.length() == 0) {
+ throw new IllegalArgumentException();
+ }
+
+ List<Range> ranges = attributeMap.get(attribute);
+ if (ranges == null) {
+ ranges = new ArrayList<Range>(1);
+ attributeMap.put(attribute, ranges);
+ } else {
+ ranges.clear();
+ }
+ ranges.add(new Range(0, text.length(), value));
+ }
+
+ public void addAttribute(AttributedCharacterIterator.Attribute attribute,
+ Object value, int start, int end) {
+ if (null == attribute) {
+ throw new NullPointerException();
+ }
+ if (start < 0 || end > text.length() || start >= end) {
+ throw new IllegalArgumentException();
+ }
+
+ if (value == null) {
+ return;
+ }
+
+ List<Range> ranges = attributeMap.get(attribute);
+ if (ranges == null) {
+ ranges = new ArrayList<Range>(1);
+ ranges.add(new Range(start, end, value));
+ attributeMap.put(attribute, ranges);
+ return;
+ }
+ ListIterator<Range> it = ranges.listIterator();
+ while (it.hasNext()) {
+ Range range = it.next();
+ if (end <= range.start) {
+ it.previous();
+ break;
+ } else if (start < range.end
+ || (start == range.end && (value == null ? range.value == null
+ : value.equals(range.value)))) {
+ Range r1 = null, r3;
+ it.remove();
+ r1 = new Range(range.start, start, range.value);
+ r3 = new Range(end, range.end, range.value);
+
+ while (end > range.end && it.hasNext()) {
+ range = it.next();
+ if (end <= range.end) {
+ if (end > range.start
+ || (end == range.start && (value == null ? range.value == null
+ : value.equals(range.value)))) {
+ it.remove();
+ r3 = new Range(end, range.end, range.value);
+ break;
+ }
+ } else {
+ it.remove();
+ }
+ }
+
+ if (value == null ? r1.value == null : value.equals(r1.value)) {
+ if (value == null ? r3.value == null : value
+ .equals(r3.value)) {
+ it.add(new Range(r1.start < start ? r1.start : start,
+ r3.end > end ? r3.end : end, r1.value));
+ } else {
+ it.add(new Range(r1.start < start ? r1.start : start,
+ end, r1.value));
+ if (r3.start < r3.end) {
+ it.add(r3);
+ }
+ }
+ } else {
+ if (value == null ? r3.value == null : value
+ .equals(r3.value)) {
+ if (r1.start < r1.end) {
+ it.add(r1);
+ }
+ it.add(new Range(start, r3.end > end ? r3.end : end,
+ r3.value));
+ } else {
+ if (r1.start < r1.end) {
+ it.add(r1);
+ }
+ it.add(new Range(start, end, value));
+ if (r3.start < r3.end) {
+ it.add(r3);
+ }
+ }
+ }
+ return;
+ }
+ }
+ it.add(new Range(start, end, value));
+ }
+
+ public void addAttributes(
+ Map<? extends AttributedCharacterIterator.Attribute, ?> attributes,
+ int start, int end) {
+ Iterator<?> it = attributes.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) it.next();
+ addAttribute(
+ (AttributedCharacterIterator.Attribute) entry.getKey(),
+ entry.getValue(), start, end);
+ }
+ }
+
+ public AttributedCharacterIterator getIterator() {
+ return new AttributedIterator(this);
+ }
+
+ public AttributedCharacterIterator getIterator(
+ AttributedCharacterIterator.Attribute[] attributes) {
+ return new AttributedIterator(this, attributes, 0, text.length());
+ }
+
+ public AttributedCharacterIterator getIterator(
+ AttributedCharacterIterator.Attribute[] attributes, int start,
+ int end) {
+ return new AttributedIterator(this, attributes, start, end);
+ }
+}
diff --git a/text/src/main/java/java/text/Bidi.java b/text/src/main/java/java/text/Bidi.java
new file mode 100644
index 0000000..04e7df8
--- /dev/null
+++ b/text/src/main/java/java/text/Bidi.java
@@ -0,0 +1,554 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.awt.font.NumericShaper;
+import java.awt.font.TextAttribute;
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import org.apache.harmony.text.BidiRun;
+import org.apache.harmony.text.BidiWrapper;
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * Bidi is the class providing the bidirectional algorithm. The algorithm is
+ * defined in the Unicode Standard Annex #9, version 13, also described in The
+ * Unicode Standard, Version 4.0 .
+ *
+ * Use a Bidi object to get the information on the position reordering of a
+ * bidirectional text, such as Arabic or Hebrew. The natural display ordering of
+ * horizontal text in these languages is from right to left, while they order
+ * numbers from left to right.
+ *
+ * If the text contains multiple runs, the information of each run can be
+ * obtained from the run index. The level of any particular run indicates the
+ * direction of the text as well as the nesting level. Left-to-right runs have
+ * even levels while right-to-left runs have odd levels.
+ *
+ */
+public final class Bidi {
+ /**
+ * Constant that indicates the default base level. If there is no strong
+ * character, then set the paragraph level to 0 (left-to-right).
+ */
+ public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2;
+
+ /**
+ * Constant that indicates the default base level. If there is no strong
+ * character, then set the paragraph level to 1 (right-to-left).
+ */
+ public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1;
+
+ /**
+ * Constant that specifies the default base level as 0 (left-to-right).
+ */
+ public static final int DIRECTION_LEFT_TO_RIGHT = 0;
+
+ /**
+ * Constant that specifies the default base level as 1 (right-to-left).
+ */
+ public static final int DIRECTION_RIGHT_TO_LEFT = 1;
+
+ /**
+ * Create a Bidi object from the AttributedCharacterIterator of a paragraph
+ * text.
+ *
+ * The RUN_DIRECTION attribute determines the base direction of the
+ * bidirectional text. If it's not specified explicitly, the algorithm uses
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT by default.
+ *
+ * The BIDI_EMBEDDING attribute specifies the level of embedding for each
+ * character. Values between -1 and -62 denote overrides at the level's
+ * absolute value, values from 1 to 62 indicate embeddings, and the 0 value
+ * indicates the level is calculated by the algorithm automatically. For the
+ * character with no BIDI_EMBEDDING attribute or with a improper attribute
+ * value, such as a null value, the algorithm treats its embedding level as
+ * 0.
+ *
+ * The NUMERIC_SHAPING attribute specifies the instance of NumericShaper
+ * used to convert European digits to other decimal digits before performing
+ * the bidi algorithm.
+ *
+ * @param paragraph
+ *
+ * TODO Make these proper links again (problem with core vs. framework).
+ * see TextAttribute.BIDI_EMBEDDING
+ * see TextAttribute.NUMERIC_SHAPING
+ * see TextAttribute.RUN_DIRECTION
+ */
+ public Bidi(AttributedCharacterIterator paragraph) {
+ if (paragraph == null) {
+ // text.14=paragraph is null
+ throw new IllegalArgumentException(Messages.getString("text.14")); //$NON-NLS-1$
+ }
+
+ int begin = paragraph.getBeginIndex();
+ int end = paragraph.getEndIndex();
+ int length = end - begin;
+ char text[] = new char[length + 1]; // One more char for
+ // AttributedCharacterIterator.DONE
+
+ if (length != 0) {
+ text[0] = paragraph.first();
+ } else {
+ paragraph.first();
+ }
+
+ // First check the RUN_DIRECTION attribute.
+ int flags = DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+
+ Object direction = paragraph.getAttribute(TextAttribute.RUN_DIRECTION);
+ if (direction != null && direction instanceof Boolean) {
+ if (direction.equals(TextAttribute.RUN_DIRECTION_LTR)) {
+ flags = DIRECTION_LEFT_TO_RIGHT;
+ } else {
+ flags = DIRECTION_RIGHT_TO_LEFT;
+ }
+ }
+
+ // Retrieve the text and gather BIDI_EMBEDDINGS
+ byte embeddings[] = null;
+ for (int textLimit = 1, i = 1; i < length; textLimit = paragraph
+ .getRunLimit(TextAttribute.BIDI_EMBEDDING)
+ - begin + 1) {
+ Object embedding = paragraph
+ .getAttribute(TextAttribute.BIDI_EMBEDDING);
+ if (embedding != null && embedding instanceof Integer) {
+ int embLevel = ((Integer) embedding).intValue();
+
+ if (embeddings == null) {
+ embeddings = new byte[length];
+ }
+
+ for (; i < textLimit; i++) {
+ text[i] = paragraph.next();
+ embeddings[i - 1] = (byte) embLevel;
+ }
+ } else {
+ for (; i < textLimit; i++) {
+ text[i] = paragraph.next();
+ }
+ }
+ }
+
+ // Apply NumericShaper to the text
+ Object numericShaper = paragraph
+ .getAttribute(TextAttribute.NUMERIC_SHAPING);
+ if (numericShaper != null && numericShaper instanceof NumericShaper) {
+ ((NumericShaper) numericShaper).shape(text, 0, length);
+ }
+
+ long pBidi = createUBiDi(text, 0, embeddings, 0, length, flags);
+ readBidiInfo(pBidi);
+ BidiWrapper.ubidi_close(pBidi);
+ }
+
+ /**
+ * Create a Bidi object.
+ *
+ * @param text
+ * the char array of the paragraph text.
+ * @param textStart
+ * the start offset of the text array to perform the algorithm.
+ * @param embeddings
+ * the embedding level array of the paragraph text, specifying
+ * the embedding level information for each character. Values
+ * between -1 and -62 denote overrides at the level's absolute
+ * value, values from 1 to 62 indicate embeddings, and the 0
+ * value indicates the level is calculated by the algorithm
+ * automatically.
+ * @param embStart
+ * the start offset of the embeddings array to perform the
+ * algorithm.
+ * @param paragraphLength
+ * the length of the text to perform the algorithm. It must be
+ * text.length >= textStart + paragraphLength, and
+ * embeddings.length >= embStart + paragraphLength.
+ * @param flags
+ * indicates the base direction of the bidirectional text. It is
+ * expected that this will be one of the direction constant
+ * values defined in this class. An unknown value is treated as
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT.
+ *
+ * @see #DIRECTION_LEFT_TO_RIGHT
+ * @see #DIRECTION_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ */
+ public Bidi(char[] text, int textStart, byte[] embeddings, int embStart,
+ int paragraphLength, int flags) {
+ if (textStart < 0) {
+ // text.0D=Negative textStart value {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.0D", textStart)); //$NON-NLS-1$
+ }
+ if (embStart < 0) {
+ // text.10=Negative embStart value {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.10", embStart)); //$NON-NLS-1$
+ }
+ if (paragraphLength < 0) {
+ // text.11=Negative paragraph length {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.11", paragraphLength)); //$NON-NLS-1$
+ }
+ long pBidi = createUBiDi(text, textStart, embeddings, embStart,
+ paragraphLength, flags);
+ readBidiInfo(pBidi);
+ BidiWrapper.ubidi_close(pBidi);
+ }
+
+ /**
+ * Create a Bidi object.
+ *
+ * @param paragraph
+ * the String containing the paragraph text to perform the
+ * algorithm.
+ * @param flags
+ * indicates the base direction of the bidirectional text. It is
+ * expected that this will be one of the direction constant
+ * values defined in this class. An unknown value is treated as
+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT.
+ *
+ * @see #DIRECTION_LEFT_TO_RIGHT
+ * @see #DIRECTION_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ */
+ public Bidi(String paragraph, int flags) {
+ this((paragraph == null ? null : paragraph.toCharArray()), 0, null, 0,
+ (paragraph == null ? 0 : paragraph.length()), flags);
+ }
+
+ // create the native UBiDi struct, need to be closed with ubidi_close().
+ private static long createUBiDi(char[] text, int textStart,
+ byte[] embeddings, int embStart, int paragraphLength, int flags) {
+ char[] realText = null;
+
+ byte[] realEmbeddings = null;
+
+ if (text == null || text.length - textStart < paragraphLength) {
+ throw new IllegalArgumentException();
+ }
+ realText = new char[paragraphLength];
+ System.arraycopy(text, textStart, realText, 0, paragraphLength);
+
+ if (embeddings != null) {
+ if (embeddings.length - embStart < paragraphLength) {
+ throw new IllegalArgumentException();
+ }
+ if (paragraphLength > 0) {
+ Bidi temp = new Bidi(text, textStart, null, 0, paragraphLength,
+ flags);
+ realEmbeddings = new byte[paragraphLength];
+ System.arraycopy(temp.offsetLevel, 0, realEmbeddings, 0,
+ paragraphLength);
+ for (int i = 0; i < paragraphLength; i++) {
+ byte e = embeddings[i];
+ if (e < 0) {
+ realEmbeddings[i] = (byte) (BidiWrapper.UBIDI_LEVEL_OVERRIDE - e);
+ } else if (e > 0) {
+ realEmbeddings[i] = e;
+ } else {
+ realEmbeddings[i] |= (byte) BidiWrapper.UBIDI_LEVEL_OVERRIDE;
+ }
+ }
+ }
+ }
+
+ if (flags > 1 || flags < -2) {
+ flags = 0;
+ }
+
+ long bidi = BidiWrapper.ubidi_open();
+ BidiWrapper.ubidi_setPara(bidi, realText, paragraphLength,
+ (byte) flags, realEmbeddings);
+ return bidi;
+ }
+
+ // private constructor, used by createLineBidi()
+ private Bidi(long pBidi) {
+ readBidiInfo(pBidi);
+ }
+
+ // read info from the native UBiDi struct
+ private void readBidiInfo(long pBidi) {
+
+ length = BidiWrapper.ubidi_getLength(pBidi);
+
+ offsetLevel = (length == 0) ? null : BidiWrapper.ubidi_getLevels(pBidi);
+
+ baseLevel = BidiWrapper.ubidi_getParaLevel(pBidi);
+
+ int runCount = BidiWrapper.ubidi_countRuns(pBidi);
+ if (runCount == 0) {
+ unidirectional = true;
+ runs = null;
+ } else if (runCount < 0) {
+ runs = null;
+ } else {
+ runs = BidiWrapper.ubidi_getRuns(pBidi);
+
+ // Simplified case for one run which has the base level
+ if (runCount == 1 && runs[0].getLevel() == baseLevel) {
+ unidirectional = true;
+ runs = null;
+ }
+ }
+
+ direction = BidiWrapper.ubidi_getDirection(pBidi);
+ }
+
+ private int baseLevel;
+
+ private int length;
+
+ private byte[] offsetLevel;
+
+ private BidiRun[] runs;
+
+ private int direction;
+
+ private boolean unidirectional;
+
+ /**
+ * Return whether the base level is from left to right.
+ *
+ * @return true if the base level is from left to right.
+ */
+ public boolean baseIsLeftToRight() {
+ return baseLevel % 2 == 0 ? true : false;
+ }
+
+ /**
+ * Create a new Bidi object containing the information of one line from this
+ * object.
+ *
+ * @param lineStart
+ * the start offset of the line.
+ * @param lineLimit
+ * the limit of the line.
+ * @return the new line Bidi object. In this new object, the indices will
+ * range from 0 to (limit - start - 1).
+ */
+ public Bidi createLineBidi(int lineStart, int lineLimit) {
+ if (lineStart < 0 || lineLimit < 0 || lineLimit > length
+ || lineStart > lineLimit) {
+ // text.12=Invalid ranges (start={0}, limit={1}, length={2})
+ throw new IllegalArgumentException(Messages.getString(
+ "text.12", new Object[] { lineStart, lineLimit, length })); //$NON-NLS-1$
+ }
+ char[] text = new char[this.length];
+ Arrays.fill(text, 'a');
+ byte[] embeddings = new byte[this.length];
+ for (int i = 0; i < embeddings.length; i++) {
+ embeddings[i] = (byte) -this.offsetLevel[i];
+ }
+
+ int dir = this.baseIsLeftToRight() ? Bidi.DIRECTION_LEFT_TO_RIGHT
+ : Bidi.DIRECTION_RIGHT_TO_LEFT;
+
+ long parent = createUBiDi(text, 0, embeddings, 0, this.length, dir);
+
+ long line = BidiWrapper.ubidi_setLine(parent, lineStart, lineLimit);
+ Bidi result = new Bidi(line);
+ BidiWrapper.ubidi_close(line);
+ BidiWrapper.ubidi_close(parent);
+ return result;
+ }
+
+ /**
+ * Return the base level.
+ *
+ * @return the int value of the base level.
+ */
+ public int getBaseLevel() {
+ return baseLevel;
+ }
+
+ /**
+ * Return the length of the text in the Bidi object.
+ *
+ * @return the int value of the length.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Return the level of a specified character.
+ *
+ * @param offset
+ * the offset of the character.
+ * @return the int value of the level.
+ */
+ public int getLevelAt(int offset) {
+ try {
+ return offsetLevel[offset] & ~BidiWrapper.UBIDI_LEVEL_OVERRIDE;
+ } catch (RuntimeException e) {
+ return baseLevel;
+ }
+ }
+
+ /**
+ * Return the number of runs in the bidirectional text.
+ *
+ * @return the int value of runs, at least 1.
+ */
+ public int getRunCount() {
+ return unidirectional ? 1 : runs.length;
+ }
+
+ /**
+ * Return the level of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the level of the run.
+ */
+ public int getRunLevel(int run) {
+ return unidirectional ? baseLevel : runs[run].getLevel();
+ }
+
+ /**
+ * Return the limit offset of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the limit offset of the run.
+ */
+ public int getRunLimit(int run) {
+ return unidirectional ? length : runs[run].getLimit();
+ }
+
+ /**
+ * Return the start offset of a specified run.
+ *
+ * @param run
+ * the index of the run.
+ * @return the start offset of the run.
+ */
+ public int getRunStart(int run) {
+ return unidirectional ? 0 : runs[run].getStart();
+ }
+
+ /**
+ * Return whether the text is from left to right, that is, both the base
+ * direction and the text direction is from left to right.
+ *
+ * @return true if the text is from left to right.
+ */
+ public boolean isLeftToRight() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_LTR;
+ }
+
+ /**
+ * Return whether the text direction is mixed.
+ *
+ * @return true if the text direction is mixed.
+ */
+ public boolean isMixed() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_MIXED;
+ }
+
+ /**
+ * Return whether the text is from right to left, that is, both the base
+ * direction and the text direction is from right to left.
+ *
+ * @return true if the text is from right to left.
+ */
+ public boolean isRightToLeft() {
+ return direction == BidiWrapper.UBiDiDirection_UBIDI_RTL;
+ }
+
+ /**
+ * Reorder a range of objects according to their specified levels. This is a
+ * convenience function that does not use a Bidi object. The range of
+ * objects at index from objectStart to objectStart + count will be
+ * reordered according to the range of levels at index from levelStart to
+ * levelStart + count.
+ *
+ * @param levels
+ * the level array, which is already determined.
+ * @param levelStart
+ * the start offset of the range of the levels.
+ * @param objects
+ * the object array to reorder.
+ * @param objectStart
+ * the start offset of the range of objects.
+ * @param count
+ * the count of the range of objects to reorder.
+ */
+ public static void reorderVisually(byte[] levels, int levelStart,
+ Object[] objects, int objectStart, int count) {
+ if (count < 0 || levelStart < 0 || objectStart < 0
+ || count > levels.length - levelStart
+ || count > objects.length - objectStart) {
+ // text.13=Invalid ranges (levels={0}, levelStart={1}, objects={2},
+ // objectStart={3}, count={4})
+ throw new IllegalArgumentException(Messages.getString("text.13", //$NON-NLS-1$
+ new Object[] { levels.length, levelStart, objects.length,
+ objectStart, count }));
+ }
+ byte[] realLevels = new byte[count];
+ System.arraycopy(levels, levelStart, realLevels, 0, count);
+
+ int[] indices = BidiWrapper.ubidi_reorderVisual(realLevels, count);
+
+ LinkedList<Object> result = new LinkedList<Object>();
+ for (int i = 0; i < count; i++) {
+ result.addLast(objects[objectStart + indices[i]]);
+ }
+
+ System.arraycopy(result.toArray(), 0, objects, objectStart, count);
+ }
+
+ /**
+ * Return whether a range of characters of a text requires a Bidi object to
+ * display properly.
+ *
+ * @param text
+ * the char array of the text.
+ * @param start
+ * the start offset of the range of characters.
+ * @param limit
+ * the limit offset of the range of characters.
+ * @return true if the range of characters requires a Bidi object.
+ */
+ public static boolean requiresBidi(char[] text, int start, int limit) {
+ int length = text.length;
+ if (limit < 0 || start < 0 || start > limit || limit > length) {
+ throw new IllegalArgumentException();
+ }
+ Bidi bidi = new Bidi(text, start, null, 0, limit - start, 0);
+ return !bidi.isLeftToRight();
+ }
+
+ /**
+ * Return the internal message of the Bidi object, used in debugging.
+ *
+ * @return a string containing the internal message.
+ */
+ @Override
+ public String toString() {
+ return super.toString()
+ + "[direction: " + direction + " baselevel: " + baseLevel //$NON-NLS-1$ //$NON-NLS-2$
+ + " length: " + length + " runs: " + (unidirectional ? "null" : runs.toString()) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+}
diff --git a/text/src/main/java/java/text/BreakIterator.java b/text/src/main/java/java/text/BreakIterator.java
new file mode 100644
index 0000000..f1eb303
--- /dev/null
+++ b/text/src/main/java/java/text/BreakIterator.java
@@ -0,0 +1,458 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.util.Locale;
+
+/**
+ * This class is used to locate the boundaries of text. Instance of this class
+ * can be got by some factory methods:
+ * <ul>
+ * <li>
+ * <code>getCharacterInstance()<code> returns a BreakIterator that iterate the
+ * logical characters without worrying about how the character is stored. For
+ * example, some character may be stored in more than one Unicode code point
+ * according to Unicode specification, this character can handle the logical
+ * characters with multi code points.</li>
+ * <li>
+ * <code>getWordInstance()<code> returns a <code>BreakIterator</code> that
+ * iterate the word-breaks. The beginning and end of each word(including numbers)
+ * is treated as boundary position. Whitespace and punctuation are kept separate
+ * from real words.</li>
+ * <li>
+ * <code>getSentenceInstance()</code> returns a BreakIterator that iterate the
+ * sentence-breaks.</li>
+ * <li><code>getLineInstance()</code> returns a BreakIterator that iterate the
+ * line-breaks which can be used to wrap lines. This iterator can handle whitespaces,
+ * hyphens and punctuations.
+ * </ul>
+ *
+ * <code>BreakIterator</code> uses <code>CharacterIterator</code> to perform the
+ * analysis, so that any storage which provides <code>CharacterIterator</code>
+ * interface.
+ *
+ * @see CharacterIterator
+ */
+public abstract class BreakIterator implements Cloneable {
+
+ /*
+ * -----------------------------------------------------------------------
+ * constants
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * This constant is returned by iterate methods like previous() or next() if
+ * they have returned all valid boundaries.
+ */
+ public static final int DONE = -1;
+
+ private static final int LONG_LENGTH = 8;
+
+ private static final int INT_LENGTH = 4;
+
+ private static final int SHORT_LENGTH = 2;
+
+ /*
+ * -----------------------------------------------------------------------
+ * variables
+ * -----------------------------------------------------------------------
+ */
+ // the wrapped ICU implementation
+ com.ibm.icu4jni.text.BreakIterator wrapped;
+
+ /*
+ * -----------------------------------------------------------------------
+ * constructors
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Default constructor, just for invocation by subclass.
+ */
+ protected BreakIterator() {
+ super();
+ }
+
+ /*
+ * wrapping constructor
+ */
+ BreakIterator(com.ibm.icu4jni.text.BreakIterator iterator) {
+ wrapped = iterator;
+ }
+
+ /*
+ * -----------------------------------------------------------------------
+ * methods
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Return all supported locales.
+ *
+ * @return all supported locales
+ */
+ public static Locale[] getAvailableLocales() {
+ return com.ibm.icu4jni.text.BreakIterator.getAvailableLocales();
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate characters using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate characters using
+ * default locale.
+ */
+ public static BreakIterator getCharacterInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getCharacterInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate characters using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate characters using
+ * given locale.
+ */
+ public static BreakIterator getCharacterInstance(Locale where) {
+ if (where == null) {
+ throw new NullPointerException();
+ }
+
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getCharacterInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate line-breaks using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate line-breaks using
+ * default locale.
+ */
+ public static BreakIterator getLineInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getLineInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate line-breaks using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate line-breaks using
+ * given locale.
+ */
+ public static BreakIterator getLineInstance(Locale where) {
+ if (where == null) {
+ throw new NullPointerException();
+ }
+
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getLineInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate sentence-breaks
+ * using default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate sentence-breaks
+ * using default locale.
+ */
+ public static BreakIterator getSentenceInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getSentenceInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate sentence-breaks
+ * using given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate sentence-breaks
+ * using given locale.
+ */
+ public static BreakIterator getSentenceInstance(Locale where) {
+ if (where == null) {
+ throw new NullPointerException();
+ }
+
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getSentenceInstance(where));
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate word-breaks using
+ * default locale.
+ *
+ * @return a new instance of BreakIterator used to iterate word-breaks using
+ * default locale.
+ */
+ public static BreakIterator getWordInstance() {
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getWordInstance());
+ }
+
+ /**
+ * Return a new instance of BreakIterator used to iterate word-breaks using
+ * given locale.
+ *
+ * @param where
+ * the given locale
+ * @return a new instance of BreakIterator used to iterate word-breaks using
+ * given locale.
+ */
+ public static BreakIterator getWordInstance(Locale where) {
+ if (where == null) {
+ throw new NullPointerException();
+ }
+
+ return new RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator
+ .getWordInstance(where));
+ }
+
+ /**
+ * Return true if the given offset is a boundary position. If this method
+ * returns true, the current iteration position is set to the given
+ * position; if the function returns false, the current iteration position
+ * is set as though following() had been called.
+ *
+ * @param offset
+ * the given offset to check
+ * @return true if the given offset is a boundary position
+ */
+ public boolean isBoundary(int offset) {
+ return wrapped.isBoundary(offset);
+ }
+
+ /**
+ * Return the position of last boundary precede the given offset, and set
+ * current position to returned value, or <code>DONE</code> if the given
+ * offset specifies the starting position.
+ * <p>
+ * <code>IllegalArgumentException</code> will be thrown if given offset is
+ * invalid.
+ * </p>
+ *
+ * @param offset
+ * the given start position to be searched for
+ * @return the position of last boundary precede the given offset
+ */
+ public int preceding(int offset) {
+ return wrapped.preceding(offset);
+ }
+
+ /**
+ * Set the new text string to be analyzed, the current position will be
+ * reset to beginning of this new string, and the old string will lost.
+ *
+ * @param newText
+ * the new text string to be analyzed
+ */
+ public void setText(String newText) {
+ wrapped.setText(newText);
+ }
+
+ /*
+ * -----------------------------------------------------------------------
+ * abstract methods
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Return this iterator's current position.
+ *
+ * @return this iterator's current position
+ */
+ public abstract int current();
+
+ /**
+ * Set this iterator's current position to the first boundary, and return
+ * this position.
+ *
+ * @return the position of first boundary
+ */
+ public abstract int first();
+
+ /**
+ * Set the position of the first boundary following the given offset, and
+ * return this position. If there is no boundary after the given offset,
+ * return DONE.
+ * <p>
+ * <code>IllegalArgumentException</code> will be thrown if given offset is
+ * invalid.
+ * </p>
+ *
+ * @param offset
+ * the given position to be searched for
+ * @return the position of the first boundary following the given offset
+ */
+ public abstract int following(int offset);
+
+ /**
+ * Return a <code>CharacterIterator</code> which represents the text being
+ * analyzed. Please note that the returned value is probably the internal
+ * iterator used by this object, so that if the invoker want to modify the
+ * status of the returned iterator, a clone operation at first is
+ * recommended.
+ *
+ * @return a <code>CharacterIterator</code> which represents the text
+ * being analyzed.
+ */
+ public abstract CharacterIterator getText();
+
+ /**
+ * Set this iterator's current position to the last boundary, and return
+ * this position.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int last();
+
+ /**
+ * Set this iterator's current position to the next boundary after current
+ * position, and return this position. Return <code>DONE</code> if no
+ * boundary found after current position.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int next();
+
+ /**
+ * Set this iterator's current position to the next boundary after the given
+ * position, and return this position. Return <code>DONE</code> if no
+ * boundary found after the given position.
+ *
+ * @param n
+ * the given position.
+ * @return the position of last boundary
+ */
+ public abstract int next(int n);
+
+ /**
+ * Set this iterator's current position to the previous boundary before
+ * current position, and return this position. Return <code>DONE</code> if
+ * no boundary found before current position.
+ *
+ * @return the position of last boundary
+ */
+ public abstract int previous();
+
+ /**
+ * Set new text to be analyzed by given <code>CharacterIterator</code>.
+ * The position will be reset to the beginning of the new text, and other
+ * status of this iterator will be kept.
+ *
+ * @param newText
+ * the given <code>CharacterIterator</code> refer to the text
+ * to be analyzed
+ */
+ public abstract void setText(CharacterIterator newText);
+
+ /*
+ * -----------------------------------------------------------------------
+ * methods override Object
+ * -----------------------------------------------------------------------
+ */
+ /**
+ * Create copy of this iterator, all status including current position is
+ * kept.
+ *
+ * @return copy of this iterator
+ */
+ @Override
+ public Object clone() {
+ try {
+ BreakIterator cloned = (BreakIterator) super.clone();
+ cloned.wrapped = (com.ibm.icu4jni.text.BreakIterator) wrapped.clone();
+ return cloned;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError(e.getMessage());
+ }
+ }
+
+ /**
+ * Get a long value from the given byte array, start from given offset.
+ *
+ * @param buf
+ * the bytes to be converted
+ * @param offset
+ * the start position of conversion
+ * @return the converted long value
+ */
+ protected static long getLong(byte[] buf, int offset) {
+ if (null == buf) {
+ throw new NullPointerException();
+ }
+ if (offset < 0 || buf.length - offset < LONG_LENGTH) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ long result = 0;
+ for (int i = offset; i < offset + LONG_LENGTH; i++) {
+ result = (result << 8) | (buf[i] & 0xff);
+ }
+ return result;
+ }
+
+ /**
+ * Get an int value from the given byte array, start from given offset.
+ *
+ * @param buf
+ * the bytes to be converted
+ * @param offset
+ * the start position of conversion
+ * @return the converted int value
+ */
+ protected static int getInt(byte[] buf, int offset) {
+ if (null == buf) {
+ throw new NullPointerException();
+ }
+ if (offset < 0 || buf.length - INT_LENGTH < offset) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ int result = 0;
+ for (int i = offset; i < offset + INT_LENGTH; i++) {
+ result = (result << 8) | (buf[i] & 0xff);
+ }
+ return result;
+ }
+
+ /**
+ * Get a short value from the given byte array, start from given offset.
+ *
+ * @param buf
+ * the bytes to be converted
+ * @param offset
+ * the start position of conversion
+ * @return the converted short value
+ */
+ protected static short getShort(byte[] buf, int offset) {
+ if (null == buf) {
+ throw new NullPointerException();
+ }
+ if (offset < 0 || buf.length - SHORT_LENGTH < offset) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ short result = 0;
+ for (int i = offset; i < offset + SHORT_LENGTH; i++) {
+ result = (short) ((result << 8) | (buf[i] & 0xff));
+ }
+ return result;
+ }
+}
diff --git a/text/src/main/java/java/text/CharacterIterator.java b/text/src/main/java/java/text/CharacterIterator.java
new file mode 100644
index 0000000..195beeb
--- /dev/null
+++ b/text/src/main/java/java/text/CharacterIterator.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * CharacterIterator is used to sequence over a group of characters. The
+ * iteration starts at the begin index in the group of character and continues
+ * to one index before the end index.
+ */
+public interface CharacterIterator extends Cloneable {
+
+ /**
+ * A constant which indicates there is no character.
+ */
+ public static final char DONE = '\uffff';
+
+ /**
+ * Returns a new CharacterIterator with the same properties.
+ *
+ * @return a shallow copy of this CharacterIterator
+ *
+ * @see java.lang.Cloneable
+ */
+ public Object clone();
+
+ /**
+ * Returns the character at the current index.
+ *
+ * @return the current character, or DONE if the current index is past the
+ * end
+ */
+ public char current();
+
+ /**
+ * Sets the current position to the begin index and returns the character at
+ * the begin index.
+ *
+ * @return the character at the begin index
+ */
+ public char first();
+
+ /**
+ * Returns the begin index.
+ *
+ * @return the index of the first character to iterate
+ */
+ public int getBeginIndex();
+
+ /**
+ * Returns the end index.
+ *
+ * @return the index one past the last character to iterate
+ */
+ public int getEndIndex();
+
+ /**
+ * Returns the current index.
+ *
+ * @return the current index
+ */
+ public int getIndex();
+
+ /**
+ * Sets the current position to the end index - 1 and returns the character
+ * at the current position.
+ *
+ * @return the character before the end index
+ */
+ public char last();
+
+ /**
+ * Increments the current index and returns the character at the new index.
+ *
+ * @return the character at the next index, or DONE if the next index is
+ * past the end
+ */
+ public char next();
+
+ /**
+ * Decrements the current index and returns the character at the new index.
+ *
+ * @return the character at the previous index, or DONE if the previous
+ * index is past the beginning
+ */
+ public char previous();
+
+ /**
+ * Sets the current index.
+ *
+ * @param location The index the <code>CharacterIterator</code> is set to.
+ *
+ * @return the character at the new index, or DONE if the index is past the
+ * end
+ *
+ * @exception IllegalArgumentException
+ * when the new index is less than the begin index or greater
+ * than the end index
+ */
+ public char setIndex(int location);
+}
diff --git a/text/src/main/java/java/text/ChoiceFormat.java b/text/src/main/java/java/text/ChoiceFormat.java
new file mode 100644
index 0000000..5a6bb69
--- /dev/null
+++ b/text/src/main/java/java/text/ChoiceFormat.java
@@ -0,0 +1,411 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * ChoiceFormat is used to associate strings with ranges of double values. The
+ * strings and ranges are either specified using arrays or with a pattern which
+ * is parsed to determine the Strings and ranges.
+ */
+
+public class ChoiceFormat extends NumberFormat {
+
+ private static final long serialVersionUID = 1795184449645032964L;
+
+ private double[] choiceLimits;
+
+ private String[] choiceFormats;
+
+ /**
+ * Constructs a new ChoiceFormat with the specified ranges and associated
+ * strings.
+ *
+ * @param limits
+ * an array of double, the ranges are greater or equal to the
+ * value in lower index up to less than the value in the next
+ * higher index. The bounds of the lowest and highest indexes are
+ * negative and positive infinity.
+ * @param formats
+ * the strings associated with the ranges. The lower bound of the
+ * associated range is at the same index as the string.
+ */
+ public ChoiceFormat(double[] limits, String[] formats) {
+ setChoices(limits, formats);
+ }
+
+ /**
+ * Constructs a new ChoiceFormat with the strings and ranges parsed from the
+ * specified pattern.
+ *
+ * @param template
+ * the pattern of strings and ranges
+ *
+ * @exception IllegalArgumentException
+ * then an error occurs parsing the pattern
+ */
+ public ChoiceFormat(String template) {
+ applyPattern(template);
+ }
+
+ /**
+ * Parses the pattern to determine new strings and ranges for this
+ * ChoiceFormat.
+ *
+ * @param template
+ * the pattern of strings and ranges
+ *
+ * @exception IllegalArgumentException
+ * then an error occurs parsing the pattern
+ */
+ public void applyPattern(String template) {
+ double[] limits = new double[5];
+ List<String> formats = new ArrayList<String>();
+ int length = template.length(), limitCount = 0, index = 0;
+ StringBuffer buffer = new StringBuffer();
+ NumberFormat format = NumberFormat.getInstance(Locale.US);
+ ParsePosition position = new ParsePosition(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());
+ }
+ }
+
+ /**
+ * Returns a new instance of ChoiceFormat with the same ranges and strings
+ * as this ChoiceFormat.
+ *
+ * @return a shallow copy of this ChoiceFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ ChoiceFormat clone = (ChoiceFormat) super.clone();
+ clone.choiceLimits = choiceLimits.clone();
+ clone.choiceFormats = choiceFormats.clone();
+ return clone;
+ }
+
+ /**
+ * Compares the specified object to this ChoiceFormat and answer if they are
+ * equal. The object must be an instance of ChoiceFormat and have the same
+ * limits and formats.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this ChoiceFormat, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof ChoiceFormat)) {
+ return false;
+ }
+ ChoiceFormat choice = (ChoiceFormat) object;
+ return Arrays.equals(choiceLimits, choice.choiceLimits)
+ && Arrays.equals(choiceFormats, choice.choiceFormats);
+ }
+
+ /**
+ * Appends to the specified StringBuffer the string associated with the
+ * range in which the specified double value fits.
+ *
+ * @param value
+ * the double to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition which is ignored
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ @Override
+ public StringBuffer format(double value, StringBuffer buffer,
+ FieldPosition 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]);
+ }
+
+ /**
+ * Appends to the specified StringBuffer the string associated with the
+ * range in which the specified long value fits.
+ *
+ * @param value
+ * the long to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition which is ignored
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ @Override
+ public StringBuffer format(long value, StringBuffer buffer,
+ FieldPosition field) {
+ return format((double) value, buffer, field);
+ }
+
+ /**
+ * Returns the Strings associated with the ranges of this ChoiceFormat.
+ *
+ * @return an array of String
+ */
+ public Object[] getFormats() {
+ return choiceFormats;
+ }
+
+ /**
+ * Returns the ranges of this ChoiceFormat.
+ *
+ * @return an array of double, the ranges are greater or equal to the value
+ * in lower index up to less than the value in the next higher
+ * index. The bounds of the lowest and highest indexes are negative
+ * and positive infinity.
+ */
+ public double[] getLimits() {
+ return choiceLimits;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @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;
+ }
+
+ /**
+ * Returns the double value which is closest to the specified double but
+ * larger.
+ *
+ * @param value
+ * a double value
+ * @return the next larger double value
+ */
+ 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);
+ }
+
+ /**
+ * 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
+ * true to get a larger value, false to get a smaller value
+ * @return the next larger or smaller double value
+ */
+ public static double nextDouble(double value, boolean increment) {
+ return increment ? nextDouble(value) : previousDouble(value);
+ }
+
+ /**
+ * Parse a Double from the specified String starting at the index specified
+ * by the ParsePosition. The String is compared to the strings of this
+ * ChoiceFormat and if a match occurs, the answer is the lower bound of the
+ * corresponding range. If the string is successfully parsed, the index of
+ * the ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return a Double resulting from the parse, or Double.NaN if there is an
+ * error
+ */
+ @Override
+ public Number parse(String string, ParsePosition 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 new Double(choiceLimits[i]);
+ }
+ }
+ position.setErrorIndex(offset);
+ return new Double(Double.NaN);
+ }
+
+ /**
+ * Returns the double value which is closest to the specified double but
+ * smaller.
+ *
+ * @param value
+ * a double value
+ * @return the next smaller double value
+ */
+ 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);
+ }
+
+ /**
+ * Sets the ranges and associated strings of this ChoiceFormat.
+ *
+ * @param limits
+ * an array of double, the ranges are greater or equal to the
+ * value in lower index up to less than the value in the next
+ * higher index. The bounds of the lowest and highest indexes are
+ * negative and positive infinity.
+ * @param formats
+ * the strings associated with the ranges. The lower bound of the
+ * range is at the same index as the string.
+ */
+ 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;
+ }
+
+ /**
+ * Returns the pattern of this ChoiceFormat which specified the ranges and
+ * their associated strings.
+ *
+ * @return the pattern
+ */
+ public String toPattern() {
+ StringBuffer buffer = new StringBuffer();
+ 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();
+ }
+}
diff --git a/text/src/main/java/java/text/CollationElementIterator.java b/text/src/main/java/java/text/CollationElementIterator.java
new file mode 100644
index 0000000..a25f554
--- /dev/null
+++ b/text/src/main/java/java/text/CollationElementIterator.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+// BEGIN android-note
+// Fixed Unicode escape sequences to make the file 7-bit clean.
+// END android-note
+
+/**
+ * <p>
+ * <code>CollationElementIterator</code> is created by a
+ * <code>RuleBasedCollator</code> to iterate through a string. The return
+ * result of each iteration is a 32-bit collation element that defines the
+ * ordering priority of the next character or sequence of characters in the
+ * source string.
+ * </p>
+ * <p>
+ * For illustration, consider the following in Spanish:
+ * </p>
+ *
+ * <p>
+ * <code>
+ * "ca" -> the first collation element is collation_element('c') and second
+ * collation element is collation_element('a').
+ * </code>
+ * </p>
+ *
+ * <p>
+ * <code>
+ * Since "ch" in Spanish sorts as one entity, the below example returns one
+ * collation element for the two characters 'c' and 'h'
+ * </code>
+ * </p>
+ *
+ * <p>
+ * <code>
+ * "cha" -> the first collation element is collation_element('ch') and second
+ * collation element is collation_element('a').
+ * </code>
+ * </p>
+ * <p>
+ * And in German,
+ * </p>
+ *
+ * <p>
+ * <code>
+ * Since the character '&#92;u0086' is a composed character of 'a' and 'e', the iterator
+ * returns two collation elements for the single character '&#92;u0086'
+ * </code>
+ * </p>
+ * <p>
+ * <code>
+ * "&#92;u0086b" -> the first
+ * collation element is collation_element('a'), the second collation element is
+ * collation_element('e'), and the third collation element is
+ * collation_element('b').
+ * </code>
+ * </p>
+ *
+ */
+public final class CollationElementIterator {
+
+ /**
+ * This constant is returned by the iterator in the methods
+ * <code>next()</code> and <code>previous()</code> when the end or the
+ * beginning of the source string has been reached, and there are no more
+ * valid collation elements to return.
+ */
+ public static final int NULLORDER = -1;
+
+ private com.ibm.icu4jni.text.CollationElementIterator icuIterator;
+
+ CollationElementIterator(com.ibm.icu4jni.text.CollationElementIterator iterator) {
+ this.icuIterator = iterator;
+ }
+
+ /**
+ * Obtains the maximum length of any expansion sequence that ends with the
+ * specified collation element. If there is no expansion with this collation
+ * element as the last element, returns <code>1</code>.
+ *
+ * @param order
+ * a collation element that has been previously obtained from a
+ * call to either the {@link #next()} or {@link #previous()}
+ * method.
+ * @return the maximum length of any expansion sequence ending with the
+ * specified collation element.
+ */
+ public int getMaxExpansion(int order) {
+ return this.icuIterator.getMaxExpansion(order);
+ }
+
+ /**
+ * Obtains the character offset in the source string corresponding to the
+ * next collation element. This value could be any of: <ui>
+ * <li>The index of the first character in the source string that matches
+ * the value of the next collation element. (This means that if
+ * setOffset(offset) sets the index in the middle of a contraction,
+ * getOffset() returns the index of the first character in the contraction,
+ * which may not be equal to the original offset that was set. Hence calling
+ * getOffset() immediately after setOffset(offset) does not guarantee that
+ * the original offset set will be returned.)</li>
+ * <li>If normalization is on, the index of the immediate subsequent
+ * character, or composite character with the first character, having a
+ * combining class of 0.</li>
+ * <li>The length of the source string, if iteration has reached the end.
+ * </li>
+ * <ui>
+ *
+ * @return The position of the collation element in the source string that
+ * will be returned in the next invocation of the {@link #next()}
+ * method.
+ */
+ public int getOffset() {
+ return this.icuIterator.getOffset();
+ }
+
+ /**
+ * Obtains the next collation element in the source string.
+ *
+ * @return the next collation element or <code>NULLORDER</code> if the end
+ * of the iteration has been reached.
+ */
+ public int next() {
+ return this.icuIterator.next();
+ }
+
+ /**
+ * Obtains the previous collation element in the source string.
+ *
+ * @return the previous collation element, or <code>NULLORDER</code> when
+ * the start of the iteration has been reached.
+ */
+ public int previous() {
+ return this.icuIterator.previous();
+ }
+
+ /**
+ * Obtains the primary order of the specified collation element, i.e. the
+ * first 16 bits. This value is unsigned.
+ *
+ * @param order
+ * @return the element's 16 bits primary order.
+ */
+ public static final int primaryOrder(int order) {
+ return com.ibm.icu4jni.text.CollationElementIterator.primaryOrder(order);
+ }
+
+ /**
+ * Repositions the cursor to point at the first element of the current
+ * string. The next call to <code>next()</code> or <code>previous()</code>
+ * will return the first and last collation element in the string,
+ * respectively.
+ * <p>
+ * If the <code>RuleBasedCollator</code> used by this iterator has had its
+ * attributes changed, calling <code>reset()</code> will reinitialize the
+ * iterator to use the new attributes.
+ * </p>
+ */
+ public void reset() {
+ this.icuIterator.reset();
+ }
+
+ /**
+ * Obtains the secondary order of the specified collation element, i.e. the
+ * 16th to 23th bits, inclusive. This value is unsigned.
+ *
+ * @param order
+ * @return the 8 bit secondary order of the element
+ */
+ public static final short secondaryOrder(int order) {
+ return (short) com.ibm.icu4jni.text.CollationElementIterator
+ .secondaryOrder(order);
+ }
+
+ /**
+ * Points the iterator at the collation element associated with the
+ * character in the source string which is found at the supplied offset.
+ * After this call completes, an invocation of the {@link #next()} method
+ * will return this collation element.
+ * <p>
+ * If <code>newOffset</code> corresponds to a character which is part of a
+ * sequence that maps to a single collation element the iterator is adjusted
+ * to the start of that sequence. As a result of this, any subsequent call
+ * made to <code>getOffset()</code> may not return the same value set by
+ * this method.
+ * </p>
+ * <p>
+ * If the decomposition mode is on, and offset is in the middle of a
+ * decomposable range of source text, the iterator may not return a correct
+ * result for the next forwards or backwards iteration. The user must ensure
+ * that the offset is not in the middle of a decomposable range.
+ * </p>
+ *
+ * @param newOffset
+ * the character offset into the original source string to set.
+ * Note that this is not an offset into the corresponding
+ * sequence of collation elements.
+ */
+ public void setOffset(int newOffset) {
+ this.icuIterator.setOffset(newOffset);
+ }
+
+ /**
+ * Sets a new source string iterator for iteration, and reset the offset to
+ * the beginning of the text.
+ *
+ * @param source
+ * the new source string iterator for iteration.
+ */
+ public void setText(CharacterIterator source) {
+ this.icuIterator.setText(source);
+ }
+
+ /**
+ * Sets a new source string for iteration, and reset the offset to the
+ * beginning of the text.
+ *
+ * @param source
+ * the new source string for iteration
+ */
+ public void setText(String source) {
+ this.icuIterator.setText(source);
+ }
+
+ /**
+ * Obtains the tertiary order of the specified collation element, i.e. the
+ * last 8 bits. This value is unsigned.
+ *
+ * @param order
+ * @return the 8 bits tertiary order of the element
+ */
+ public static final short tertiaryOrder(int order) {
+ return (short) com.ibm.icu4jni.text.CollationElementIterator
+ .tertiaryOrder(order);
+ }
+}
diff --git a/text/src/main/java/java/text/CollationKey.java b/text/src/main/java/java/text/CollationKey.java
new file mode 100644
index 0000000..45b6afa
--- /dev/null
+++ b/text/src/main/java/java/text/CollationKey.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * CollationKey represents the collation order of a particular String for a
+ * specific Collator. CollationKeys can be compared to determine the relative
+ * ordering of their source Strings. This is useful when the Strings must be
+ * compared multiple times, as in sorting.
+ */
+public final class CollationKey implements Comparable<CollationKey> {
+
+ private String source;
+
+ private com.ibm.icu4jni.text.CollationKey icuKey;
+
+ CollationKey(String source, com.ibm.icu4jni.text.CollationKey key) {
+ this.source = source;
+ this.icuKey = key;
+ }
+
+ /**
+ * Compare the receiver to the specified CollationKey to determine the
+ * relative ordering.
+ *
+ * @param value
+ * a CollationKey
+ * @return an int < 0 if this CollationKey is less than the specified
+ * CollationKey, 0 if they are equal, and > 0 if this CollationKey
+ * is greater
+ */
+ public int compareTo(CollationKey value) {
+ return icuKey.compareTo(value.icuKey);
+ }
+
+ /**
+ * Compares the specified object to this CollationKey and answer if they are
+ * equal. The object must be an instance of CollationKey and have the same
+ * source string and collation key. The instances of CollationKey must have
+ * been created by the same Collator.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this CollationKey, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof CollationKey)) {
+ return false;
+ }
+ CollationKey collationKey = (CollationKey) object;
+ return icuKey.equals(collationKey.icuKey);
+ }
+
+ /**
+ * Answer the String from which this CollationKey was created.
+ *
+ * @return a String
+ */
+ public String getSourceString() {
+ return this.source;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return icuKey.hashCode();
+ }
+
+ /**
+ * Answer the collation key as a byte array.
+ *
+ * @return an array of bytes
+ */
+ public byte[] toByteArray() {
+ return icuKey.toByteArray();
+ }
+}
diff --git a/text/src/main/java/java/text/Collator.java b/text/src/main/java/java/text/Collator.java
new file mode 100644
index 0000000..45c1eb1
--- /dev/null
+++ b/text/src/main/java/java/text/Collator.java
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.security.AccessController;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.apache.harmony.luni.util.PriviAction;
+
+/**
+ * Collator is an abstract class which is the root of classes which provide
+ * Locale specific String comparison to determine their ordering with respect to
+ * each other.
+ */
+public abstract class Collator implements Comparator<Object>, Cloneable {
+
+ static final int EQUAL = 0;
+
+ static final int GREATER = 1;
+
+ static final int LESS = -1;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int NO_DECOMPOSITION = 0;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int CANONICAL_DECOMPOSITION = 1;
+
+ /**
+ * Constant used to specify the decomposition rule.
+ */
+ public static final int FULL_DECOMPOSITION = 2;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int PRIMARY = 0;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int SECONDARY = 1;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int TERTIARY = 2;
+
+ /**
+ * Constant used to specify the collation strength.
+ */
+ public static final int IDENTICAL = 3;
+
+ private static int CACHE_SIZE;
+
+ static {
+ // CACHE_SIZE includes key and value, so needs to be double
+ String cacheSize = AccessController
+ .doPrivileged(new PriviAction<String>("collator.cache")); //$NON-NLS-1$
+ if (cacheSize != null) {
+ try {
+ CACHE_SIZE = Integer.parseInt(cacheSize);
+ } catch (NumberFormatException e) {
+ CACHE_SIZE = 6;
+ }
+ } else {
+ CACHE_SIZE = 6;
+ }
+ }
+
+ private static Vector<Collator> cache = new Vector<Collator>(CACHE_SIZE);
+
+ // Wrapper class of ICU4J Collator
+ com.ibm.icu4jni.text.Collator icuColl;
+
+ Collator(com.ibm.icu4jni.text.Collator wrapper) {
+ this.icuColl = wrapper;
+ }
+
+ /**
+ * Constructs a new instance of this Collator.
+ */
+ protected Collator() {
+ super();
+ }
+
+ /**
+ * Returns a new Collator with the same decomposition rule and strength
+ * value as this Collator.
+ *
+ * @return a shallow copy of this Collator
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ try {
+ Collator clone = (Collator) super.clone();
+ clone.icuColl = (com.ibm.icu4jni.text.Collator) this.icuColl.clone();
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Compares the two objects to determine their relative ordering. The
+ * objects must be Strings.
+ *
+ * @param object1
+ * the first String to compare
+ * @param object2
+ * the second String to compare
+ * @return an int < 0 if object1 is less than object2, 0 if they are equal,
+ * and > 0 if object1 is greater than object2
+ *
+ * @exception ClassCastException
+ * when the objects are not Strings
+ */
+ public int compare(Object object1, Object object2) {
+ return compare((String) object1, (String) object2);
+ }
+
+ /**
+ * Compares the two Strings to determine their relative ordering.
+ *
+ * @param string1
+ * the first String to compare
+ * @param string2
+ * the second String to compare
+ * @return an int < 0 if string1 is less than string2, 0 if they are equal,
+ * and > 0 if string1 is greater than string2
+ */
+ public abstract int compare(String string1, String string2);
+
+ /**
+ * Compares the specified object to this Collator and answer if they are
+ * equal. The object must be an instance of Collator and have the same
+ * strength and decomposition values.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this Collator, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Collator)) {
+ return false;
+ }
+ Collator collator = (Collator) object;
+ return this.icuColl == null ? collator.icuColl == null : this.icuColl
+ .equals(collator.icuColl);
+ }
+
+ /**
+ * Compares the two Strings using the collation rules to determine if they
+ * are equal.
+ *
+ * @param string1
+ * the first String to compare
+ * @param string2
+ * the second String to compare
+ * @return true if the strings are equal using the collation rules, false
+ * otherwise
+ */
+ public boolean equals(String string1, String string2) {
+ return compare(string1, string2) == 0;
+ }
+
+ /**
+ * Gets the list of installed Locales which support Collator.
+ *
+ * @return an array of Locale
+ */
+ public static Locale[] getAvailableLocales() {
+ return com.ibm.icu4jni.text.Collator.getAvailableLocales();
+ }
+
+ /**
+ * Returns a CollationKey for the specified String for this Collator with
+ * the current decomposition rule and strength value.
+ *
+ * @param string
+ * the collation key.
+ * @return a CollationKey
+ */
+ public abstract CollationKey getCollationKey(String string);
+
+ /**
+ * Returns the decomposition rule for this Collator.
+ *
+ * @return the decomposition rule, either NO_DECOMPOSITION,
+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION
+ */
+ public int getDecomposition() {
+ return decompositionMode_ICU_Java(this.icuColl.getDecomposition());
+ }
+
+ /**
+ * Returns a Collator instance which is appropriate for the default Locale.
+ *
+ * @return a Collator
+ */
+ public static Collator getInstance() {
+ return getInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a Collator instance which is appropriate for the specified
+ * Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a Collator
+ */
+ public static Collator getInstance(Locale locale) {
+ String key = locale.toString();
+ for (int i = cache.size() - 1; i >= 0; i -= 2) {
+ if (cache.elementAt(i).equals(key)) {
+ return (Collator) (cache.elementAt(i - 1)).clone();
+ }
+ }
+
+ return new RuleBasedCollator(com.ibm.icu4jni.text.Collator
+ .getInstance(locale));
+ }
+
+ /**
+ * Returns the strength value for this Collator.
+ *
+ * @return the strength value, either PRIMARY, SECONDARY, TERTIARY, or
+ * IDENTICAL
+ */
+ public int getStrength() {
+ return strength_ICU_Java(this.icuColl.getStrength());
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals(Object)
+ * @see #equals(String, String)
+ */
+ @Override
+ public abstract int hashCode();
+
+ /**
+ * Sets the decomposition rule for this Collator.
+ *
+ * @param value
+ * the decomposition rule, either NO_DECOMPOSITION,
+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION
+ *
+ * @exception IllegalArgumentException
+ * when the decomposition rule is not valid
+ */
+ public void setDecomposition(int value) {
+ this.icuColl.setDecomposition(decompositionMode_Java_ICU(value));
+ }
+
+ /**
+ * Sets the strength value for this Collator.
+ *
+ * @param value
+ * the strength value, either PRIMARY, SECONDARY, TERTIARY, or
+ * IDENTICAL
+ *
+ * @exception IllegalArgumentException
+ * when the strength value is not valid
+ */
+ public void setStrength(int value) {
+ this.icuColl.setStrength(strength_Java_ICU(value));
+ }
+
+ private int decompositionMode_Java_ICU(int mode) {
+ int icuDecomp = mode;
+ switch (mode) {
+ case Collator.CANONICAL_DECOMPOSITION:
+ icuDecomp = com.ibm.icu4jni.text.Collator.CANONICAL_DECOMPOSITION;
+ break;
+ case Collator.NO_DECOMPOSITION:
+ icuDecomp = com.ibm.icu4jni.text.Collator.NO_DECOMPOSITION;
+ break;
+ }
+ return icuDecomp;
+ }
+
+ private int decompositionMode_ICU_Java(int mode) {
+ int javaMode = mode;
+ switch (mode) {
+ case com.ibm.icu4jni.text.Collator.NO_DECOMPOSITION:
+ javaMode = Collator.NO_DECOMPOSITION;
+ break;
+ case com.ibm.icu4jni.text.Collator.CANONICAL_DECOMPOSITION:
+ javaMode = Collator.CANONICAL_DECOMPOSITION;
+ break;
+ }
+ return javaMode;
+ }
+
+ private int strength_Java_ICU(int value) {
+ int icuValue = value;
+ switch (value) {
+ case Collator.PRIMARY:
+ icuValue = com.ibm.icu4jni.text.Collator.PRIMARY;
+ break;
+ case Collator.SECONDARY:
+ icuValue = com.ibm.icu4jni.text.Collator.SECONDARY;
+ break;
+ case Collator.TERTIARY:
+ icuValue = com.ibm.icu4jni.text.Collator.TERTIARY;
+ break;
+ case Collator.IDENTICAL:
+ icuValue = com.ibm.icu4jni.text.Collator.IDENTICAL;
+ break;
+ }
+ return icuValue;
+
+ }
+
+ private int strength_ICU_Java(int value) {
+ int javaValue = value;
+ switch (value) {
+ case com.ibm.icu4jni.text.Collator.PRIMARY:
+ javaValue = Collator.PRIMARY;
+ break;
+ case com.ibm.icu4jni.text.Collator.SECONDARY:
+ javaValue = Collator.SECONDARY;
+ break;
+ case com.ibm.icu4jni.text.Collator.TERTIARY:
+ javaValue = Collator.TERTIARY;
+ break;
+ case com.ibm.icu4jni.text.Collator.IDENTICAL:
+ javaValue = Collator.IDENTICAL;
+ break;
+ }
+ return javaValue;
+ }
+}
diff --git a/text/src/main/java/java/text/DateFormat.java b/text/src/main/java/java/text/DateFormat.java
new file mode 100644
index 0000000..6fca4f6
--- /dev/null
+++ b/text/src/main/java/java/text/DateFormat.java
@@ -0,0 +1,803 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.InvalidObjectException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * DateFormat is the abstract superclass of formats which format and parse
+ * Dates.
+ */
+public abstract class DateFormat extends Format {
+
+ private static final long serialVersionUID = 7218322306649953788L;
+
+ /**
+ * The calendar that this <code>DateFormat</code> uses to format a number
+ * representing a date.
+ */
+ protected Calendar calendar;
+
+ /**
+ * The number format used to format a number.
+ */
+ protected NumberFormat numberFormat;
+
+ /**
+ * Format style constant.
+ */
+ public final static int DEFAULT = 2;
+
+ /**
+ * Format style constant.
+ */
+ public final static int FULL = 0;
+
+ /**
+ * Format style constant.
+ */
+ public final static int LONG = 1;
+
+ /**
+ * Format style constant.
+ */
+ public final static int MEDIUM = 2;
+
+ /**
+ * Format style constant.
+ */
+ public final static int SHORT = 3;
+
+ /**
+ * Field constant.
+ */
+ public final static int ERA_FIELD = 0;
+
+ /**
+ * Field constant.
+ */
+ public final static int YEAR_FIELD = 1;
+
+ /**
+ * Field constant.
+ */
+ public final static int MONTH_FIELD = 2;
+
+ /**
+ * Field constant.
+ */
+ public final static int DATE_FIELD = 3;
+
+ /**
+ * Field constant.
+ */
+ public final static int HOUR_OF_DAY1_FIELD = 4;
+
+ /**
+ * Field constant.
+ */
+ public final static int HOUR_OF_DAY0_FIELD = 5;
+
+ /**
+ * Field constant.
+ */
+ public final static int MINUTE_FIELD = 6;
+
+ /**
+ * Field constant.
+ */
+ public final static int SECOND_FIELD = 7;
+
+ /**
+ * Field constant.
+ */
+ public final static int MILLISECOND_FIELD = 8;
+
+ /**
+ * Field constant.
+ */
+ public final static int DAY_OF_WEEK_FIELD = 9;
+
+ /**
+ * Field constant.
+ */
+ public final static int DAY_OF_YEAR_FIELD = 10;
+
+ /**
+ * Field constant.
+ */
+ public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
+
+ /**
+ * Field constant.
+ */
+ public final static int WEEK_OF_YEAR_FIELD = 12;
+
+ /**
+ * Field constant.
+ */
+ public final static int WEEK_OF_MONTH_FIELD = 13;
+
+ /**
+ * Field constant.
+ */
+ public final static int AM_PM_FIELD = 14;
+
+ /**
+ * Field constant.
+ */
+ public final static int HOUR1_FIELD = 15;
+
+ /**
+ * Field constant.
+ */
+ public final static int HOUR0_FIELD = 16;
+
+ /**
+ * Field constant.
+ */
+ public final static int TIMEZONE_FIELD = 17;
+
+ /**
+ * Constructs a new instance of DateFormat.
+ *
+ */
+ protected DateFormat() {
+ }
+
+ /**
+ * Returns a new instance of DateFormat with the same properties.
+ *
+ * @return a shallow copy of this DateFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ DateFormat clone = (DateFormat) super.clone();
+ clone.calendar = (Calendar) calendar.clone();
+ clone.numberFormat = (NumberFormat) numberFormat.clone();
+ return clone;
+ }
+
+ /**
+ * Compares the specified object to this DateFormat and answer if they are
+ * equal. The object must be an instance of DateFormat with the same
+ * properties.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this DateFormat, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof DateFormat)) {
+ return false;
+ }
+ DateFormat dateFormat = (DateFormat) object;
+ return numberFormat.equals(dateFormat.numberFormat)
+ && calendar.getTimeZone().equals(
+ dateFormat.calendar.getTimeZone())
+ && calendar.getFirstDayOfWeek() == dateFormat.calendar
+ .getFirstDayOfWeek()
+ && calendar.getMinimalDaysInFirstWeek() == dateFormat.calendar
+ .getMinimalDaysInFirstWeek()
+ && calendar.isLenient() == dateFormat.calendar.isLenient();
+ }
+
+ /**
+ * Formats the specified object into the specified StringBuffer using the
+ * rules of this DateFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param object
+ * the object to format, must be a Date or a Number. If the
+ * object is a Number, a Date is constructed using the
+ * <code>longValue()</code> of the Number.
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ *
+ * @exception IllegalArgumentException
+ * when the object is not a Date or a Number
+ */
+ @Override
+ public final StringBuffer format(Object object, StringBuffer buffer,
+ FieldPosition field) {
+ if (object instanceof Date) {
+ return format((Date) object, buffer, field);
+ }
+ if (object instanceof Number) {
+ return format(new Date(((Number) object).longValue()), buffer,
+ field);
+ }
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Formats the specified Date using the rules of this DateFormat.
+ *
+ * @param date
+ * the Date to format
+ * @return the formatted String
+ */
+ public final String format(Date date) {
+ return format(date, new StringBuffer(), new FieldPosition(0))
+ .toString();
+ }
+
+ /**
+ * Formats the specified Date into the specified StringBuffer using the
+ * rules of this DateFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param date
+ * the Date to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public abstract StringBuffer format(Date date, StringBuffer buffer,
+ FieldPosition field);
+
+ /**
+ * Gets the list of installed Locales which support DateFormat.
+ *
+ * @return an array of Locale
+ */
+ public static Locale[] getAvailableLocales() {
+ return Locale.getAvailableLocales();
+ }
+
+ /**
+ * Returns the Calendar used by this DateFormat.
+ *
+ * @return a Calendar
+ */
+ public Calendar getCalendar() {
+ return calendar;
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates in the
+ * DEFAULT style for the default Locale.
+ *
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateInstance() {
+ return getDateInstance(DEFAULT);
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates in the
+ * specified style for the default Locale.
+ *
+ * @param style
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateInstance(int style) {
+ checkDateStyle(style);
+ return getDateInstance(style, Locale.getDefault());
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates in the
+ * specified style for the specified Locale.
+ *
+ * @param style
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @param locale
+ * the Locale
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateInstance(int style, Locale locale) {
+ checkDateStyle(style);
+ ResourceBundle bundle = getBundle(locale);
+ String pattern = bundle.getString("Date_" + getStyleName(style)); //$NON-NLS-1$
+ return new SimpleDateFormat(pattern, locale);
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates and times
+ * in the DEFAULT style for the default Locale.
+ *
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateTimeInstance() {
+ return getDateTimeInstance(DEFAULT, DEFAULT);
+ }
+
+ /**
+ * Returns a <code>DateFormat</code> instance for the formatting and
+ * parsing of both dates and times in the manner appropriate to the default
+ * Locale.
+ *
+ * @param dateStyle
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @param timeStyle
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateTimeInstance(int dateStyle,
+ int timeStyle) {
+ checkTimeStyle(timeStyle);
+ checkDateStyle(dateStyle);
+ return getDateTimeInstance(dateStyle, timeStyle, Locale.getDefault());
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates and times
+ * in the specified styles for the specified Locale.
+ *
+ * @param dateStyle
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @param timeStyle
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @param locale
+ * the Locale
+ * @return a DateFormat
+ */
+ public final static DateFormat getDateTimeInstance(int dateStyle,
+ int timeStyle, Locale locale) {
+ checkTimeStyle(timeStyle);
+ checkDateStyle(dateStyle);
+ ResourceBundle bundle = getBundle(locale);
+ String pattern = bundle.getString("Date_" + getStyleName(dateStyle)) //$NON-NLS-1$
+ + " " + bundle.getString("Time_" + getStyleName(timeStyle)); //$NON-NLS-1$ //$NON-NLS-2$
+ return new SimpleDateFormat(pattern, locale);
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing dates and times
+ * in the SHORT style for the default Locale.
+ *
+ * @return a DateFormat
+ */
+ public final static DateFormat getInstance() {
+ return getDateTimeInstance(SHORT, SHORT);
+ }
+
+ /**
+ * Returns the NumberFormat used by this DateFormat.
+ *
+ * @return a NumberFormat
+ */
+ public NumberFormat getNumberFormat() {
+ return numberFormat;
+ }
+
+ static String getStyleName(int style) {
+ String styleName;
+ switch (style) {
+ case SHORT:
+ styleName = "SHORT"; //$NON-NLS-1$
+ break;
+ case MEDIUM:
+ styleName = "MEDIUM"; //$NON-NLS-1$
+ break;
+ case LONG:
+ styleName = "LONG"; //$NON-NLS-1$
+ break;
+ case FULL:
+ styleName = "FULL"; //$NON-NLS-1$
+ break;
+ default:
+ styleName = ""; //$NON-NLS-1$
+ }
+ return styleName;
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing times in the
+ * DEFAULT style for the default Locale.
+ *
+ * @return a DateFormat
+ */
+ public final static DateFormat getTimeInstance() {
+ return getTimeInstance(DEFAULT);
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing times in the
+ * specified style for the default Locale.
+ *
+ * @param style
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @return a DateFormat
+ */
+ public final static DateFormat getTimeInstance(int style) {
+ checkTimeStyle(style);
+ return getTimeInstance(style, Locale.getDefault());
+ }
+
+ /**
+ * Returns a DateFormat instance for formatting and parsing times in the
+ * specified style for the specified Locale.
+ *
+ * @param style
+ * one of SHORT, MEDIUM, LONG, FULL, or DEFAULT
+ * @param locale
+ * the Locale
+ * @return a DateFormat
+ */
+ public final static DateFormat getTimeInstance(int style, Locale locale) {
+ checkTimeStyle(style);
+ ResourceBundle bundle = getBundle(locale);
+ String pattern = bundle.getString("Time_" + getStyleName(style)); //$NON-NLS-1$
+ return new SimpleDateFormat(pattern, locale);
+ }
+
+ /**
+ * Returns the TimeZone of the Calendar used by this DateFormat.
+ *
+ * @return a TimeZone
+ */
+ public TimeZone getTimeZone() {
+ return calendar.getTimeZone();
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return calendar.getFirstDayOfWeek()
+ + calendar.getMinimalDaysInFirstWeek()
+ + calendar.getTimeZone().hashCode()
+ + (calendar.isLenient() ? 1231 : 1237)
+ + numberFormat.hashCode();
+ }
+
+ /**
+ * Returns if the Calendar used by this DateFormat is lenient.
+ *
+ * @return true when the Calendar is lenient, false otherwise
+ */
+ public boolean isLenient() {
+ return calendar.isLenient();
+ }
+
+ /**
+ * Parse a Date from the specified String using the rules of this
+ * DateFormat.
+ *
+ * @param string
+ * the String to parse
+ * @return the Date resulting from the parse
+ *
+ * @exception ParseException
+ * when an error occurs during parsing
+ */
+ public Date parse(String string) throws ParseException {
+ ParsePosition position = new ParsePosition(0);
+ Date date = parse(string, position);
+ if (position.getErrorIndex() != -1 || position.getIndex() == 0) {
+ // text.19=Unparseable date: {0}
+ throw new ParseException(
+ Messages.getString("text.19", string), position.getErrorIndex()); //$NON-NLS-1$
+ }
+ return date;
+ }
+
+ /**
+ * Parse a Date from the specified String starting at the index specified by
+ * the ParsePosition. If the string is successfully parsed, the index of the
+ * ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the Date resulting from the parse, or null if there is an error
+ */
+ public abstract Date parse(String string, ParsePosition position);
+
+ /**
+ * Parse a Date from the specified String starting at the index specified by
+ * the ParsePosition. If the string is successfully parsed, the index of the
+ * ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the Date resulting from the parse, or null if there is an error
+ */
+ @Override
+ public Object parseObject(String string, ParsePosition position) {
+ return parse(string, position);
+ }
+
+ /**
+ * Sets the Calendar used by this DateFormat.
+ *
+ * @param cal
+ * the Calendar
+ */
+ public void setCalendar(Calendar cal) {
+ calendar = cal;
+ }
+
+ /**
+ * Sets if the Calendar used by this DateFormat is lenient.
+ *
+ * @param value
+ * true to set the Calendar to be lenient, false otherwise
+ */
+ public void setLenient(boolean value) {
+ calendar.setLenient(value);
+ }
+
+ /**
+ * Sets the NumberFormat used by this DateFormat.
+ *
+ * @param format
+ * the NumberFormat
+ */
+ public void setNumberFormat(NumberFormat format) {
+ numberFormat = format;
+ }
+
+ /**
+ * Sets the TimeZone of the Calendar used by this DateFormat.
+ *
+ * @param timezone
+ * the TimeZone
+ */
+ public void setTimeZone(TimeZone timezone) {
+ calendar.setTimeZone(timezone);
+ }
+
+ /**
+ * The instances of this inner class are used as attribute keys and values
+ * in AttributedCharacterIterator that
+ * SimpleDateFormat.formatToCharacterIterator() method returns.
+ * <p>
+ * There is no public constructor to this class, the only instances are the
+ * constants defined here.
+ * <p>
+ */
+ public static class Field extends Format.Field {
+
+ private static final long serialVersionUID = 7441350119349544720L;
+
+ private static Hashtable<Integer, Field> table = new Hashtable<Integer, Field>();
+
+ /**
+ * Marks the era part of a date.
+ */
+ public final static Field ERA = new Field("era", Calendar.ERA); //$NON-NLS-1$
+
+ /**
+ * Marks the year part of a date.
+ */
+ public final static Field YEAR = new Field("year", Calendar.YEAR); //$NON-NLS-1$
+
+ /**
+ * Marks the month part of a date.
+ */
+ public final static Field MONTH = new Field("month", Calendar.MONTH); //$NON-NLS-1$
+
+ /**
+ * Marks the hour of the day part of a date (0-11).
+ */
+ public final static Field HOUR_OF_DAY0 = new Field("hour of day", //$NON-NLS-1$
+ Calendar.HOUR_OF_DAY);
+
+ /**
+ * Marks the hour of the day part of a date (1-12).
+ */
+ public final static Field HOUR_OF_DAY1 = new Field("hour of day 1", -1); //$NON-NLS-1$
+
+ /**
+ * Marks the minute part of a time.
+ */
+ public final static Field MINUTE = new Field("minute", Calendar.MINUTE); //$NON-NLS-1$
+
+ /**
+ * Marks the second part of a time.
+ */
+ public final static Field SECOND = new Field("second", Calendar.SECOND); //$NON-NLS-1$
+
+ /**
+ * Marks the millisecond part of a time.
+ */
+ public final static Field MILLISECOND = new Field("millisecond", //$NON-NLS-1$
+ Calendar.MILLISECOND);
+
+ /**
+ * Marks the day of the week part of a date.
+ */
+ public final static Field DAY_OF_WEEK = new Field("day of week", //$NON-NLS-1$
+ Calendar.DAY_OF_WEEK);
+
+ /**
+ * Marks the day of the month part of a date.
+ */
+ public final static Field DAY_OF_MONTH = new Field("day of month", //$NON-NLS-1$
+ Calendar.DAY_OF_MONTH);
+
+ /**
+ * Marks the day of the year part of a date.
+ */
+ public final static Field DAY_OF_YEAR = new Field("day of year", //$NON-NLS-1$
+ Calendar.DAY_OF_YEAR);
+
+ /**
+ * Marks the day of the week in the month part of a date.
+ */
+ public final static Field DAY_OF_WEEK_IN_MONTH = new Field(
+ "day of week in month", Calendar.DAY_OF_WEEK_IN_MONTH); //$NON-NLS-1$
+
+ /**
+ * Marks the week of the year part of a date.
+ */
+ public final static Field WEEK_OF_YEAR = new Field("week of year", //$NON-NLS-1$
+ Calendar.WEEK_OF_YEAR);
+
+ /**
+ * Marks the week of the month part of a date.
+ */
+ public final static Field WEEK_OF_MONTH = new Field("week of month", //$NON-NLS-1$
+ Calendar.WEEK_OF_MONTH);
+
+ /**
+ * Marks the time indicator part of a date.
+ */
+ public final static Field AM_PM = new Field("am pm", Calendar.AM_PM); //$NON-NLS-1$
+
+ /**
+ * Marks the hour part of a date (0-11).
+ */
+ public final static Field HOUR0 = new Field("hour", Calendar.HOUR); //$NON-NLS-1$
+
+ /**
+ * Marks the hour part of a date (1-12).
+ */
+ public final static Field HOUR1 = new Field("hour 1", -1); //$NON-NLS-1$
+
+ /**
+ * Marks the time zone part of a date.
+ */
+ public final static Field TIME_ZONE = new Field("time zone", -1); //$NON-NLS-1$
+
+ /**
+ * The Calendar field that this Field represents.
+ */
+ private int calendarField = -1;
+
+ /**
+ * Constructs a new instance of DateFormat.Field with the given
+ * fieldName and calendar field.
+ * @param fieldName The field name.
+ * @param calendarField the calender field type of the field.
+ */
+ protected Field(String fieldName, int calendarField) {
+ super(fieldName);
+ this.calendarField = calendarField;
+ if (calendarField != -1
+ && table.get(new Integer(calendarField)) == null) {
+ table.put(new Integer(calendarField), this);
+ }
+ }
+
+ /**
+ * Returns the Calendar field this Field represents
+ *
+ * @return int calendar field
+ */
+ public int getCalendarField() {
+ return calendarField;
+ }
+
+ /**
+ * Returns the DateFormat.Field instance for the given calendar field
+ *
+ * @param calendarField
+ * a calendar field constant
+ * @return null if there is no Field for this calendar field
+ */
+ public static Field ofCalendarField(int calendarField) {
+ if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT) {
+ throw new IllegalArgumentException();
+ }
+
+ return table.get(new Integer(calendarField));
+ }
+
+ /**
+ * Serialization method resolve instances to the constant
+ * DateFormat.Field values
+ */
+ @Override
+ protected Object readResolve() throws InvalidObjectException {
+ if (calendarField != -1) {
+ try {
+ Field result = ofCalendarField(calendarField);
+ if (result != null && this.equals(result)) {
+ return result;
+ }
+ } catch (IllegalArgumentException e) {
+ // text.02=Unknown attribute
+ throw new InvalidObjectException(Messages
+ .getString("text.02")); //$NON-NLS-1$
+ }
+ } else {
+ if (this.equals(TIME_ZONE)) {
+ return TIME_ZONE;
+ }
+ if (this.equals(HOUR1)) {
+ return HOUR1;
+ }
+ if (this.equals(HOUR_OF_DAY1)) {
+ return HOUR_OF_DAY1;
+ }
+ }
+ // text.02=Unknown attribute
+ throw new InvalidObjectException(Messages.getString("text.02")); //$NON-NLS-1$
+ }
+ }
+
+ private static void checkDateStyle(int style) {
+ if (!(style == SHORT || style == MEDIUM || style == LONG
+ || style == FULL || style == DEFAULT)) {
+ // text.0E=Illegal date style: {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.0E", style)); //$NON-NLS-1$
+ }
+ }
+
+ private static void checkTimeStyle(int style) {
+ if (!(style == SHORT || style == MEDIUM || style == LONG
+ || style == FULL || style == DEFAULT)) {
+ // text.0F=Illegal time style: {0}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.0F", style)); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/text/src/main/java/java/text/DateFormatSymbols.java b/text/src/main/java/java/text/DateFormatSymbols.java
new file mode 100644
index 0000000..e843334
--- /dev/null
+++ b/text/src/main/java/java/text/DateFormatSymbols.java
@@ -0,0 +1,429 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.Serializable;
+// BEGIN android-added
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+// END android-added
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+// BEGIN android-added
+import com.ibm.icu4jni.util.Resources;
+// END android-added
+
+/**
+ * DateFormatSymbols holds the Strings used in the formating and parsing of
+ * dates and times.
+ */
+public class DateFormatSymbols implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = -5987973545549424702L;
+
+ private String localPatternChars;
+
+ String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays;
+
+ String[][] zoneStrings;
+
+// BEGIN android-added
+ /**
+ * Locale, necessary to lazily load time zone strings. We force the time
+ * zone names to load upon serialization, so this will never be needed
+ * post deserialization.
+ */
+ transient final Locale locale;
+
+ /**
+ * Gets zone strings, initializing them if necessary. Does not create
+ * a defensive copy, so make sure you do so before exposing the returned
+ * arrays to clients.
+ */
+ synchronized String[][] internalZoneStrings() {
+ if (zoneStrings == null) {
+ zoneStrings = Resources.getDisplayTimeZones(locale.toString());
+ }
+ return zoneStrings;
+ }
+// END android-added
+
+ /**
+ * Constructs a new DateFormatSymbols containing the symbols for the default
+ * Locale.
+ */
+ public DateFormatSymbols() {
+ this(Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new DateFormatSymbols containing the symbols for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ */
+ public DateFormatSymbols(Locale locale) {
+ ResourceBundle bundle = Format.getBundle(locale);
+ localPatternChars = bundle.getString("LocalPatternChars"); //$NON-NLS-1$
+ ampms = bundle.getStringArray("ampm"); //$NON-NLS-1$
+ eras = bundle.getStringArray("eras"); //$NON-NLS-1$
+ months = bundle.getStringArray("months"); //$NON-NLS-1$
+ shortMonths = bundle.getStringArray("shortMonths"); //$NON-NLS-1$
+ shortWeekdays = bundle.getStringArray("shortWeekdays"); //$NON-NLS-1$
+ weekdays = bundle.getStringArray("weekdays"); //$NON-NLS-1$
+
+// BEGIN android-changed
+ // zoneStrings = (String[][]) bundle.getObject("timezones"); //$NON-NLS-1$
+ this.locale = locale;
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
+ }
+ }
+// END android-changed
+
+ /**
+ * Compares the specified object to this DateFormatSymbols and answer if
+ * they are equal. The object must be an instance of DateFormatSymbols with
+ * the same symbols.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this DateFormatSymbols,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof DateFormatSymbols)) {
+ return false;
+ }
+ DateFormatSymbols obj = (DateFormatSymbols) object;
+ if (!localPatternChars.equals(obj.localPatternChars)) {
+ return false;
+ }
+ if (!Arrays.equals(ampms, obj.ampms)) {
+ return false;
+ }
+ if (!Arrays.equals(eras, obj.eras)) {
+ return false;
+ }
+ if (!Arrays.equals(months, obj.months)) {
+ return false;
+ }
+ if (!Arrays.equals(shortMonths, obj.shortMonths)) {
+ return false;
+ }
+ if (!Arrays.equals(shortWeekdays, obj.shortWeekdays)) {
+ return false;
+ }
+ if (!Arrays.equals(weekdays, obj.weekdays)) {
+ return false;
+ }
+
+// BEGIN android-changed
+ // Quick check that may keep us from having to load the zone strings.
+ if (zoneStrings == null && obj.zoneStrings == null
+ && !locale.equals(obj.locale)) {
+ return false;
+ }
+
+ // Make sure zone strings are loaded.
+ internalZoneStrings();
+ obj.internalZoneStrings();
+// END android-changed
+
+ if (zoneStrings.length != obj.zoneStrings.length) {
+ return false;
+ }
+ for (String[] element : zoneStrings) {
+ if (element.length != element.length) {
+ return false;
+ }
+ for (int j = 0; j < element.length; j++) {
+ if (element[j] != element[j]
+ && !(element[j].equals(element[j]))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the array of Strings which represent AM and PM. Use the Calendar
+ * constants Calendar.AM and Calendar.PM to index into the array.
+ *
+ * @return an array of String
+ */
+ public String[] getAmPmStrings() {
+ return ampms.clone();
+ }
+
+ /**
+ * Returns the array of Strings which represent BC and AD. Use the Calendar
+ * constants GregorianCalendar.BC and GregorianCalendar.AD to index into the
+ * array.
+ *
+ * @return an array of String
+ */
+ public String[] getEras() {
+ return eras.clone();
+ }
+
+ /**
+ * Returns the pattern characters used by SimpleDateFormat to specify date
+ * and time fields.
+ *
+ * @return a String containing the pattern characters
+ */
+ public String getLocalPatternChars() {
+ return localPatternChars;
+ }
+
+ /**
+ * Returns the array of Strings containing the full names of the months. Use
+ * the Calendar constants Calendar.JANUARY, etc. to index into the array.
+ *
+ * @return an array of String
+ */
+ public String[] getMonths() {
+ return months.clone();
+ }
+
+ /**
+ * Returns the array of Strings containing the abbreviated names of the
+ * months. Use the Calendar constants Calendar.JANUARY, etc. to index into
+ * the array.
+ *
+ * @return an array of String
+ */
+ public String[] getShortMonths() {
+ return shortMonths.clone();
+ }
+
+ /**
+ * Returns the array of Strings containing the abbreviated names of the days
+ * of the week. Use the Calendar constants Calendar.SUNDAY, etc. to index
+ * into the array.
+ *
+ * @return an array of String
+ */
+ public String[] getShortWeekdays() {
+ return shortWeekdays.clone();
+ }
+
+ /**
+ * Returns the array of Strings containing the full names of the days of the
+ * week. Use the Calendar constants Calendar.SUNDAY, etc. to index into the
+ * array.
+ *
+ * @return an array of String
+ */
+ public String[] getWeekdays() {
+ return weekdays.clone();
+ }
+
+ /**
+ * Returns the two-dimensional array of Strings containing the names of the
+ * timezones. Each element in the array is an array of five Strings, the
+ * first is a TimeZone ID, and second and third are the full and abbreviated
+ * timezone names for standard time, and the fourth and fifth are the full
+ * and abbreviated names for daylight time.
+ *
+ * @return a two-dimensional array of String
+ */
+ public String[][] getZoneStrings() {
+// BEGIN android-added
+ String[][] zoneStrings = internalZoneStrings();
+// END android-added
+
+ String[][] clone = new String[zoneStrings.length][];
+ for (int i = zoneStrings.length; --i >= 0;) {
+ clone[i] = zoneStrings[i].clone();
+ }
+ return clone;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ int hashCode;
+ hashCode = localPatternChars.hashCode();
+ for (String element : ampms) {
+ hashCode += element.hashCode();
+ }
+ for (String element : eras) {
+ hashCode += element.hashCode();
+ }
+ for (String element : months) {
+ hashCode += element.hashCode();
+ }
+ for (String element : shortMonths) {
+ hashCode += element.hashCode();
+ }
+ for (String element : shortWeekdays) {
+ hashCode += element.hashCode();
+ }
+ for (String element : weekdays) {
+ hashCode += element.hashCode();
+ }
+
+// BEGIN android-added
+ String[][] zoneStrings = internalZoneStrings();
+// END android-added
+
+ for (String[] element : zoneStrings) {
+ for (int j = 0; j < element.length; j++) {
+ hashCode += element[j].hashCode();
+ }
+ }
+ return hashCode;
+ }
+
+ /**
+ * Sets the array of Strings which represent AM and PM. Use the Calendar
+ * constants Calendar.AM and Calendar.PM to index into the array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setAmPmStrings(String[] data) {
+ ampms = data.clone();
+ }
+
+ /**
+ * Sets the array of Strings which represent BC and AD. Use the Calendar
+ * constants GregorianCalendar.BC and GregorianCalendar.AD to index into the
+ * array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setEras(String[] data) {
+ eras = data.clone();
+ }
+
+ /**
+ * Sets the pattern characters used by SimpleDateFormat to specify date and
+ * time fields.
+ *
+ * @param data
+ * the String containing the pattern characters
+ *
+ * @exception NullPointerException
+ * when the data is null
+ */
+ public void setLocalPatternChars(String data) {
+ if (data == null) {
+ throw new NullPointerException();
+ }
+ localPatternChars = data;
+ }
+
+ /**
+ * Sets the array of Strings containing the full names of the months. Use
+ * the Calendar constants Calendar.JANUARY, etc. to index into the array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setMonths(String[] data) {
+ months = data.clone();
+ }
+
+ /**
+ * Sets the array of Strings containing the abbreviated names of the months.
+ * Use the Calendar constants Calendar.JANUARY, etc. to index into the
+ * array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setShortMonths(String[] data) {
+ shortMonths = data.clone();
+ }
+
+ /**
+ * Sets the array of Strings containing the abbreviated names of the days of
+ * the week. Use the Calendar constants Calendar.SUNDAY, etc. to index into
+ * the array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setShortWeekdays(String[] data) {
+ shortWeekdays = data.clone();
+ }
+
+ /**
+ * Sets the array of Strings containing the full names of the days of the
+ * week. Use the Calendar constants Calendar.SUNDAY, etc. to index into the
+ * array.
+ *
+ * @param data
+ * the array of Strings
+ */
+ public void setWeekdays(String[] data) {
+ weekdays = data.clone();
+ }
+
+ /**
+ * Sets the two-dimensional array of Strings containing the names of the
+ * timezones. Each element in the array is an array of five Strings, the
+ * first is a TimeZone ID, and second and third are the full and abbreviated
+ * timezone names for standard time, and the fourth and fifth are the full
+ * and abbreviated names for daylight time.
+ *
+ * @param data
+ * the two-dimensional array of Strings
+ */
+ public void setZoneStrings(String[][] data) {
+ zoneStrings = data.clone();
+ }
+
+// BEGIN android-added
+ private void writeObject(ObjectOutputStream out)
+ throws IOException {
+ // Ensure internal zone strings are initialized to ensure backward
+ // compatibility.
+ internalZoneStrings();
+
+ out.defaultWriteObject();
+ }
+// END android-added
+}
diff --git a/text/src/main/java/java/text/DecimalFormat.java b/text/src/main/java/java/text/DecimalFormat.java
new file mode 100644
index 0000000..b22f6a9
--- /dev/null
+++ b/text/src/main/java/java/text/DecimalFormat.java
@@ -0,0 +1,952 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Currency;
+import java.util.Locale;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * DecimalFormat is used to format and parse numbers, both integers and
+ * fractions, based on a pattern. The pattern characters used can be either
+ * localized or non-localized.
+ */
+public class DecimalFormat extends NumberFormat {
+
+ private static final long serialVersionUID = 864413376551465018L;
+
+ private transient boolean parseBigDecimal = false;
+
+ private transient DecimalFormatSymbols symbols;
+
+ private transient com.ibm.icu4jni.text.DecimalFormat dform;
+
+ private transient com.ibm.icu4jni.text.DecimalFormatSymbols icuSymbols;
+
+ private static final int CURRENT_SERIAL_VERTION = 3;
+
+ private transient int serialVersionOnStream = 3;
+
+ /**
+ * Constructs a new DecimalFormat for formatting and parsing numbers for the
+ * default Locale.
+ */
+ public DecimalFormat() {
+ this(getPattern(Locale.getDefault(), "Number")); //$NON-NLS-1$
+ }
+
+ /**
+ * Constructs a new DecimalFormat using the specified non-localized pattern
+ * and the DecimalFormatSymbols for the default Locale.
+ *
+ * @param pattern
+ * the non-localized pattern
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public DecimalFormat(String pattern) {
+ this(pattern, new DecimalFormatSymbols());
+ }
+
+ /**
+ * Constructs a new DecimalFormat using the specified non-localized pattern
+ * and DecimalFormatSymbols.
+ *
+ * @param pattern
+ * the non-localized pattern
+ * @param value
+ * the DecimalFormatSymbols
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public DecimalFormat(String pattern, DecimalFormatSymbols value) {
+ symbols = (DecimalFormatSymbols) value.clone();
+ Locale locale = (Locale) this.getInternalField("locale", symbols); //$NON-NLS-1$
+ icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale);
+ copySymbols(icuSymbols, symbols);
+
+ dform = new com.ibm.icu4jni.text.DecimalFormat(pattern, icuSymbols);
+
+ super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
+ super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
+ super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
+ super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
+ }
+
+ /**
+ * Changes the pattern of this DecimalFormat to the specified pattern which
+ * uses localized pattern characters.
+ *
+ * @param pattern
+ * the localized pattern
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public void applyLocalizedPattern(String pattern) {
+ dform.applyLocalizedPattern(pattern);
+ }
+
+ /**
+ * Changes the pattern of this SimpleDateFormat to the specified pattern
+ * which uses non-localized pattern characters.
+ *
+ * @param pattern
+ * the non-localized pattern
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public void applyPattern(String pattern) {
+
+ dform.applyPattern(pattern);
+ }
+
+ /**
+ * Returns a new instance of DecimalFormat with the same pattern and
+ * properties as this DecimalFormat.
+ *
+ * @return a shallow copy of this DecimalFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ DecimalFormat clone = (DecimalFormat) super.clone();
+ clone.dform = (com.ibm.icu4jni.text.DecimalFormat) dform.clone();
+ clone.symbols = (DecimalFormatSymbols) symbols.clone();
+ return clone;
+ }
+
+ /**
+ * Compares the specified object to this DecimalFormat and answer if they
+ * are equal. The object must be an instance of DecimalFormat with the same
+ * pattern and properties.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this DecimalFormat,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof DecimalFormat)) {
+ return false;
+ }
+ DecimalFormat format = (DecimalFormat) object;
+ return (this.dform == null ? format.dform == null : this.dform
+ .equals(format.dform));
+ }
+
+ /**
+ * Formats the specified object using the rules of this DecimalNumberFormat
+ * and returns an AttributedCharacterIterator with the formatted number and
+ * attributes.
+ *
+ * @param object
+ * the object to format
+ * @return an AttributedCharacterIterator with the formatted number and
+ * attributes
+ *
+ * @exception NullPointerException
+ * when the object is null
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ @Override
+ public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+ if (object == null) {
+ throw new NullPointerException();
+ }
+ return dform.formatToCharacterIterator(object);
+ }
+
+ /**
+ * Formats the double value into the specified StringBuffer using the
+ * pattern of this DecimalFormat. If the field specified by the
+ * FieldPosition is formatted, set the begin and end index of the formatted
+ * field in the FieldPosition.
+ *
+ * @param value
+ * the double to format
+ * @param buffer
+ * the StringBuffer
+ * @param position
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ @Override
+ public StringBuffer format(double value, StringBuffer buffer,
+ FieldPosition position) {
+ return dform.format(value, buffer, position);
+ }
+
+ /**
+ * Formats the long value into the specified StringBuffer using the pattern
+ * of this DecimalFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param value
+ * the long to format
+ * @param buffer
+ * the StringBuffer
+ * @param position
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ @Override
+ public StringBuffer format(long value, StringBuffer buffer,
+ FieldPosition position) {
+ return dform.format(value, buffer, position);
+ }
+
+ /**
+ * Formats the number into the specified StringBuffer using the pattern of
+ * this DecimalFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param number
+ * the object to format
+ * @param toAppendTo
+ * the StringBuffer
+ * @param pos
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ * @throws IllegalArgumentException
+ * if the given number is not instance of <code>Number</code>
+ */
+ @Override
+ public final StringBuffer format(Object number, StringBuffer toAppendTo,
+ FieldPosition pos) {
+ if (!(number instanceof Number)) {
+ throw new IllegalArgumentException();
+ }
+ if (toAppendTo == null || pos == null) {
+ throw new NullPointerException();
+ }
+ if (number instanceof BigInteger || number instanceof BigDecimal) {
+ return dform.format(number, toAppendTo, pos);
+ }
+ return super.format(number, toAppendTo, pos);
+ }
+
+ /**
+ * Returns the DecimalFormatSymbols used by this DecimalFormat.
+ *
+ * @return a DecimalFormatSymbols
+ */
+ public DecimalFormatSymbols getDecimalFormatSymbols() {
+ return (DecimalFormatSymbols) symbols.clone();
+ }
+
+ /**
+ * Returns the currency used by this decimal format.
+ *
+ * @return currency of DecimalFormatSymbols used by this decimal format
+ * @see DecimalFormatSymbols#getCurrency()
+ */
+ @Override
+ public Currency getCurrency() {
+ final Currency cur = dform.getCurrency();
+ final String code = (cur == null) ? "XXX" : cur.getCurrencyCode(); //$NON-NLS-1$
+
+ return Currency.getInstance(code);
+ }
+
+ /**
+ * Returns the number of digits grouped together by the grouping separator.
+ *
+ * @return the number of digits grouped together
+ */
+ public int getGroupingSize() {
+ return dform.getGroupingSize();
+ }
+
+ /**
+ * Returns the multiplier which is applied to the number before formatting
+ * or after parsing.
+ *
+ * @return the multiplier
+ */
+ public int getMultiplier() {
+ return dform.getMultiplier();
+ }
+
+ /**
+ * Returns the prefix which is formatted or parsed before a negative number.
+ *
+ * @return the negative prefix
+ */
+ public String getNegativePrefix() {
+ return dform.getNegativePrefix();
+ }
+
+ /**
+ * Returns the suffix which is formatted or parsed after a negative number.
+ *
+ * @return the negative suffix
+ */
+ public String getNegativeSuffix() {
+ return dform.getNegativeSuffix();
+ }
+
+ /**
+ * Returns the prefix which is formatted or parsed before a positive number.
+ *
+ * @return the positive prefix
+ */
+ public String getPositivePrefix() {
+ return dform.getPositivePrefix();
+ }
+
+ /**
+ * Returns the suffix which is formatted or parsed after a positive number.
+ *
+ * @return the positive suffix
+ */
+ public String getPositiveSuffix() {
+ return dform.getPositiveSuffix();
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return dform.hashCode();
+ }
+
+ /**
+ * Returns whether the decimal separator is shown when there are no
+ * fractional digits.
+ *
+ * @return true if the decimal separator should always be formatted, false
+ * otherwise
+ */
+ public boolean isDecimalSeparatorAlwaysShown() {
+ return dform.isDecimalSeparatorAlwaysShown();
+ }
+
+ /**
+ * This value indicates whether the return object of the parse operation
+ * will be of type BigDecimal. This value will default to false.
+ *
+ * @return true and parse will always return BigDecimals, false and the type
+ * of the result will be Long or Double.
+ */
+ public boolean isParseBigDecimal() {
+ return this.parseBigDecimal;
+ }
+
+ /**
+ * When DecimalFormat is used to parsing, and this value is set to true,
+ * then all the resulting number will be of type
+ * <code>java.lang.Integer</code>. Except that, NaN, positive and
+ * negative infinity are still returned as <code>java.lang.Double</code>
+ *
+ * In this implementation, com.ibm.icu4jni.text.DecimalFormat is wrapped to
+ * fulfill most of the format and parse feature. And this method is
+ * delegated to the wrapped instance of com.ibm.icu4jni.text.DecimalFormat.
+ *
+ * @param value
+ * If set to true, all the resulting number will be of type
+ * java.lang.Integer except some special cases.
+ */
+ @Override
+ public void setParseIntegerOnly(boolean value) {
+ dform.setParseIntegerOnly(value);
+ }
+
+ /**
+ * Returns true if this <code>DecimalFormat</code>'s all resulting number
+ * will be of type <code>java.lang.Integer</code>
+ *
+ * @return true if this <code>DecimalFormat</code>'s all resulting number
+ * will be of type <code>java.lang.Integer</code>
+ */
+ @Override
+ public boolean isParseIntegerOnly() {
+ return dform.isParseIntegerOnly();
+ }
+
+ private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0);
+
+ /**
+ * Parse a Long or Double from the specified String starting at the index
+ * specified by the ParsePosition. If the string is successfully parsed, the
+ * index of the ParsePosition is updated to the index following the parsed
+ * text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return a Long or Double resulting from the parse, or null if there is an
+ * error. The result will be a Long if the parsed number is an
+ * integer in the range of a long, otherwise the result is a Double.
+ */
+ @Override
+ public Number parse(String string, ParsePosition position) {
+ Number number = dform.parse(string, position);
+ if (null == number) {
+ return null;
+ }
+ // BEGIN android-removed
+ // if (this.isParseBigDecimal()) {
+ // if (number instanceof Long) {
+ // return new BigDecimal(number.longValue());
+ // }
+ // if ((number instanceof Double) && !((Double) number).isInfinite()
+ // && !((Double) number).isNaN()) {
+ //
+ // return new BigDecimal(number.doubleValue());
+ // }
+ // if (number instanceof BigInteger) {
+ // return new BigDecimal(number.doubleValue());
+ // }
+ // if (number instanceof com.ibm.icu.math.BigDecimal) {
+ // return new BigDecimal(number.toString());
+ // }
+ // return number;
+ // }
+ // if ((number instanceof com.ibm.icu.math.BigDecimal)
+ // || (number instanceof BigInteger)) {
+ // return new Double(number.doubleValue());
+ // }
+ // END android-removed
+ // BEGIN android-added
+ if (this.isParseBigDecimal()) {
+ if (number instanceof Long) {
+ return new BigDecimal(number.longValue());
+ }
+ if ((number instanceof Double) && !((Double) number).isInfinite()
+ && !((Double) number).isNaN()) {
+
+ return new BigDecimal(number.toString());
+ }
+ if (number instanceof BigInteger) {
+ return new BigDecimal(number.toString());
+ }
+ return number;
+ }
+ if ((number instanceof BigDecimal) || (number instanceof BigInteger)) {
+ return new Double(number.doubleValue());
+ }
+ // END android-added
+
+ if (this.isParseIntegerOnly() && number.equals(NEGATIVE_ZERO_DOUBLE)) {
+ return new Long(0);
+ }
+ return number;
+
+ }
+
+ /**
+ * Sets the DecimalFormatSymbols used by this DecimalFormat.
+ *
+ * @param value
+ * the DecimalFormatSymbols
+ */
+ public void setDecimalFormatSymbols(DecimalFormatSymbols value) {
+ if (value != null) {
+ symbols = (DecimalFormatSymbols) value.clone();
+ icuSymbols = dform.getDecimalFormatSymbols();
+ copySymbols(icuSymbols, symbols);
+ dform.setDecimalFormatSymbols(icuSymbols);
+ }
+ }
+
+ /**
+ * Sets the currency used by this decimal format. The min and max fraction
+ * digits remain the same.
+ *
+ * @param currency
+ * @see DecimalFormatSymbols#setCurrency(Currency)
+ */
+ @Override
+ public void setCurrency(Currency currency) {
+ dform.setCurrency(Currency.getInstance(currency
+ .getCurrencyCode()));
+ symbols.setCurrency(currency);
+ }
+
+ /**
+ * Sets whether the decimal separator is shown when there are no fractional
+ * digits.
+ *
+ * @param value
+ * true if the decimal separator should always be formatted,
+ * false otherwise
+ */
+ public void setDecimalSeparatorAlwaysShown(boolean value) {
+ dform.setDecimalSeparatorAlwaysShown(value);
+ }
+
+ /**
+ * Sets the number of digits grouped together by the grouping separator.
+ *
+ * @param value
+ * the number of digits grouped together
+ */
+ public void setGroupingSize(int value) {
+ dform.setGroupingSize(value);
+ }
+
+ /**
+ * Sets whether or not grouping will be used in this format. Grouping
+ * affects both parsing and formatting.
+ *
+ * @param value
+ * true if uses grouping,false otherwise.
+ *
+ */
+ @Override
+ public void setGroupingUsed(boolean value) {
+ dform.setGroupingUsed(value);
+ }
+
+ /**
+ * This value indicates whether grouping will be used in this format.
+ *
+ * @return true if grouping is used,false otherwise.
+ */
+ @Override
+ public boolean isGroupingUsed() {
+ return dform.isGroupingUsed();
+ }
+
+ /**
+ * Sets the maximum number of fraction digits that are printed when
+ * formatting. If the maximum is less than the number of fraction digits,
+ * the least significant digits are truncated. Limit the maximum to
+ * DOUBLE_FRACTION_DIGITS.
+ *
+ * @param value
+ * the maximum number of fraction digits
+ */
+ @Override
+ public void setMaximumFractionDigits(int value) {
+ super.setMaximumFractionDigits(value);
+ dform.setMaximumFractionDigits(value);
+ }
+
+ /**
+ * Sets the maximum number of integer digits that are printed when
+ * formatting. If the maximum is less than the number of integer digits, the
+ * most significant digits are truncated. Limit the maximum to
+ * DOUBLE_INTEGER_DIGITS.
+ *
+ * @param value
+ * the maximum number of integer digits
+ */
+ @Override
+ public void setMaximumIntegerDigits(int value) {
+ super.setMaximumIntegerDigits(value);
+ dform.setMaximumIntegerDigits(value);
+ }
+
+ /**
+ * Sets the minimum number of fraction digits that are printed when
+ * formatting. Limit the minimum to DOUBLE_FRACTION_DIGITS.
+ *
+ * @param value
+ * the minimum number of fraction digits
+ */
+ @Override
+ public void setMinimumFractionDigits(int value) {
+ super.setMinimumFractionDigits(value);
+ dform.setMinimumFractionDigits(value);
+ }
+
+ /**
+ * Sets the minimum number of integer digits that are printed when
+ * formatting. Limit the minimum to DOUBLE_INTEGER_DIGITS.
+ *
+ * @param value
+ * the minimum number of integer digits
+ */
+ @Override
+ public void setMinimumIntegerDigits(int value) {
+ super.setMinimumIntegerDigits(value);
+ dform.setMinimumIntegerDigits(value);
+ }
+
+ /**
+ * Sets the multiplier which is applied to the number before formatting or
+ * after parsing.
+ *
+ * @param value
+ * the multiplier
+ */
+ public void setMultiplier(int value) {
+ dform.setMultiplier(value);
+ }
+
+ /**
+ * Sets the prefix which is formatted or parsed before a negative number.
+ *
+ * @param value
+ * the negative prefix
+ */
+ public void setNegativePrefix(String value) {
+ dform.setNegativePrefix(value);
+ }
+
+ /**
+ * Sets the suffix which is formatted or parsed after a negative number.
+ *
+ * @param value
+ * the negative suffix
+ */
+ public void setNegativeSuffix(String value) {
+ dform.setNegativeSuffix(value);
+ }
+
+ /**
+ * Sets the prefix which is formatted or parsed before a positive number.
+ *
+ * @param value
+ * the positive prefix
+ */
+ public void setPositivePrefix(String value) {
+ dform.setPositivePrefix(value);
+ }
+
+ /**
+ * Sets the suffix which is formatted or parsed after a positive number.
+ *
+ * @param value
+ * the positive suffix
+ */
+ public void setPositiveSuffix(String value) {
+ dform.setPositiveSuffix(value);
+ }
+
+ /**
+ * Let users change the behavior of a DecimalFormat, If set to true all the
+ * returned objects will be of type BigDecimal
+ *
+ * @param newValue
+ * true if all the returned objects should be type of BigDecimal
+ */
+ public void setParseBigDecimal(boolean newValue) {
+ this.parseBigDecimal = newValue;
+ }
+
+ /**
+ * Returns the pattern of this DecimalFormat using localized pattern
+ * characters.
+ *
+ * @return the localized pattern
+ */
+ public String toLocalizedPattern() {
+ return dform.toLocalizedPattern();
+ }
+
+ /**
+ * Returns the pattern of this DecimalFormat using non-localized pattern
+ * characters.
+ *
+ * @return the non-localized pattern
+ */
+ public String toPattern() {
+ return dform.toPattern();
+ }
+
+ // the fields list to be serialized
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("positivePrefix", String.class), //$NON-NLS-1$
+ new ObjectStreamField("positiveSuffix", String.class), //$NON-NLS-1$
+ new ObjectStreamField("negativePrefix", String.class), //$NON-NLS-1$
+ new ObjectStreamField("negativeSuffix", String.class), //$NON-NLS-1$
+ new ObjectStreamField("posPrefixPattern", String.class), //$NON-NLS-1$
+ new ObjectStreamField("posSuffixPattern", String.class), //$NON-NLS-1$
+ new ObjectStreamField("negPrefixPattern", String.class), //$NON-NLS-1$
+ new ObjectStreamField("negSuffixPattern", String.class), //$NON-NLS-1$
+ new ObjectStreamField("multiplier", int.class), //$NON-NLS-1$
+ new ObjectStreamField("groupingSize", byte.class), //$NON-NLS-1$
+ // BEGIN android-added
+ new ObjectStreamField("groupingUsed", boolean.class), //$NON-NLS-1$
+ // END android-added
+ new ObjectStreamField("decimalSeparatorAlwaysShown", boolean.class), //$NON-NLS-1$
+ new ObjectStreamField("parseBigDecimal", boolean.class), //$NON-NLS-1$
+ new ObjectStreamField("symbols", DecimalFormatSymbols.class), //$NON-NLS-1$
+ new ObjectStreamField("useExponentialNotation", boolean.class), //$NON-NLS-1$
+ new ObjectStreamField("minExponentDigits", byte.class), //$NON-NLS-1$
+ new ObjectStreamField("maximumIntegerDigits", int.class), //$NON-NLS-1$
+ new ObjectStreamField("minimumIntegerDigits", int.class), //$NON-NLS-1$
+ new ObjectStreamField("maximumFractionDigits", int.class), //$NON-NLS-1$
+ new ObjectStreamField("minimumFractionDigits", int.class), //$NON-NLS-1$
+ new ObjectStreamField("serialVersionOnStream", int.class), }; //$NON-NLS-1$
+
+ /**
+ * Writes serialized fields following serialized forms specified by Java
+ * specification.
+ *
+ * @param stream
+ * the output stream to write serialized bytes
+ * @throws IOException
+ * if some I/O error occurs
+ * @throws ClassNotFoundException
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("positivePrefix", dform.getPositivePrefix()); //$NON-NLS-1$
+ fields.put("positiveSuffix", dform.getPositiveSuffix()); //$NON-NLS-1$
+ fields.put("negativePrefix", dform.getNegativePrefix()); //$NON-NLS-1$
+ fields.put("negativeSuffix", dform.getNegativeSuffix()); //$NON-NLS-1$
+ String posPrefixPattern = (String) this.getInternalField(
+ "posPrefixPattern", dform); //$NON-NLS-1$
+ fields.put("posPrefixPattern", posPrefixPattern); //$NON-NLS-1$
+ String posSuffixPattern = (String) this.getInternalField(
+ "posSuffixPattern", dform); //$NON-NLS-1$
+ fields.put("posSuffixPattern", posSuffixPattern); //$NON-NLS-1$
+ String negPrefixPattern = (String) this.getInternalField(
+ "negPrefixPattern", dform); //$NON-NLS-1$
+ fields.put("negPrefixPattern", negPrefixPattern); //$NON-NLS-1$
+ String negSuffixPattern = (String) this.getInternalField(
+ "negSuffixPattern", dform); //$NON-NLS-1$
+ fields.put("negSuffixPattern", negSuffixPattern); //$NON-NLS-1$
+ fields.put("multiplier", dform.getMultiplier()); //$NON-NLS-1$
+ fields.put("groupingSize", (byte) dform.getGroupingSize()); //$NON-NLS-1$
+ // BEGIN android-added
+ fields.put("groupingUsed", dform.isGroupingUsed()); //$NON-NLS-1$
+ // END android-added
+ fields.put("decimalSeparatorAlwaysShown", dform //$NON-NLS-1$
+ .isDecimalSeparatorAlwaysShown());
+ fields.put("parseBigDecimal", parseBigDecimal); //$NON-NLS-1$
+ fields.put("symbols", symbols); //$NON-NLS-1$
+ boolean useExponentialNotation = ((Boolean) this.getInternalField(
+ "useExponentialNotation", dform)).booleanValue(); //$NON-NLS-1$
+ fields.put("useExponentialNotation", useExponentialNotation); //$NON-NLS-1$
+ byte minExponentDigits = ((Byte) this.getInternalField(
+ "minExponentDigits", dform)).byteValue(); //$NON-NLS-1$
+ fields.put("minExponentDigits", minExponentDigits); //$NON-NLS-1$
+ fields.put("maximumIntegerDigits", dform.getMaximumIntegerDigits()); //$NON-NLS-1$
+ fields.put("minimumIntegerDigits", dform.getMinimumIntegerDigits()); //$NON-NLS-1$
+ fields.put("maximumFractionDigits", dform.getMaximumFractionDigits()); //$NON-NLS-1$
+ fields.put("minimumFractionDigits", dform.getMinimumFractionDigits()); //$NON-NLS-1$
+ fields.put("serialVersionOnStream", CURRENT_SERIAL_VERTION); //$NON-NLS-1$
+ stream.writeFields();
+
+ }
+
+ /**
+ * Reads serialized fields following serialized forms specified by Java
+ * specification.
+ *
+ * @param stream
+ * the input stream to read serialized bytes
+ * @throws IOException
+ * if some I/O error occurs
+ * @throws ClassNotFoundException
+ * if some class of serialized objects or fields cannot be found
+ */
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+
+ ObjectInputStream.GetField fields = stream.readFields();
+ String positivePrefix = (String) fields.get("positivePrefix", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ String positiveSuffix = (String) fields.get("positiveSuffix", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ String negativePrefix = (String) fields.get("negativePrefix", "-"); //$NON-NLS-1$ //$NON-NLS-2$
+ String negativeSuffix = (String) fields.get("negativeSuffix", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+ String posPrefixPattern = (String) fields.get("posPrefixPattern", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ String posSuffixPattern = (String) fields.get("posSuffixPattern", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ String negPrefixPattern = (String) fields.get("negPrefixPattern", "-"); //$NON-NLS-1$ //$NON-NLS-2$
+ String negSuffixPattern = (String) fields.get("negSuffixPattern", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+ int multiplier = fields.get("multiplier", 1); //$NON-NLS-1$
+ byte groupingSize = fields.get("groupingSize", (byte) 3); //$NON-NLS-1$
+ // BEGIN android-added
+ boolean groupingUsed = fields.get("groupingUsed", true); //$NON-NLS-1$
+ // END android-added
+ boolean decimalSeparatorAlwaysShown = fields.get(
+ "decimalSeparatorAlwaysShown", false); //$NON-NLS-1$
+ boolean parseBigDecimal = fields.get("parseBigDecimal", false); //$NON-NLS-1$
+ symbols = (DecimalFormatSymbols) fields.get("symbols", null); //$NON-NLS-1$
+
+ boolean useExponentialNotation = fields.get("useExponentialNotation", //$NON-NLS-1$
+ false);
+ byte minExponentDigits = fields.get("minExponentDigits", (byte) 0); //$NON-NLS-1$
+
+ int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309); //$NON-NLS-1$
+ int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309); //$NON-NLS-1$
+ int maximumFractionDigits = fields.get("maximumFractionDigits", 340); //$NON-NLS-1$
+ int minimumFractionDigits = fields.get("minimumFractionDigits", 340); //$NON-NLS-1$
+ this.serialVersionOnStream = fields.get("serialVersionOnStream", 0); //$NON-NLS-1$
+
+ Locale locale = (Locale) getInternalField("locale", symbols); //$NON-NLS-1$
+ // BEGIN android-removed
+ // dform = new com.ibm.icu4jni.text.DecimalFormat("", //$NON-NLS-1$
+ // new com.ibm.icu4jni.text.DecimalFormatSymbols(locale));
+ // END android-removed
+ // BEGIN android-added
+ icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale);
+ copySymbols(icuSymbols, symbols);
+ dform = new com.ibm.icu4jni.text.DecimalFormat("", //$NON-NLS-1$
+ icuSymbols);
+ // END android-added
+ setInternalField("useExponentialNotation", dform, new Boolean( //$NON-NLS-1$
+ useExponentialNotation));
+ setInternalField("minExponentDigits", dform, //$NON-NLS-1$
+ new Byte(minExponentDigits));
+ dform.setPositivePrefix(positivePrefix);
+ dform.setPositiveSuffix(positiveSuffix);
+ dform.setNegativePrefix(negativePrefix);
+ dform.setNegativeSuffix(negativeSuffix);
+ setInternalField("posPrefixPattern", dform, posPrefixPattern); //$NON-NLS-1$
+ setInternalField("posSuffixPattern", dform, posSuffixPattern); //$NON-NLS-1$
+ setInternalField("negPrefixPattern", dform, negPrefixPattern); //$NON-NLS-1$
+ setInternalField("negSuffixPattern", dform, negSuffixPattern); //$NON-NLS-1$
+ dform.setMultiplier(multiplier);
+ dform.setGroupingSize(groupingSize);
+ dform.setGroupingUsed(groupingUsed);
+ dform.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
+ dform.setMinimumIntegerDigits(minimumIntegerDigits);
+ dform.setMaximumIntegerDigits(maximumIntegerDigits);
+ dform.setMinimumFractionDigits(minimumFractionDigits);
+ dform.setMaximumFractionDigits(maximumFractionDigits);
+ this.setParseBigDecimal(parseBigDecimal);
+
+ if (super.getMaximumIntegerDigits() > Integer.MAX_VALUE
+ || super.getMinimumIntegerDigits() > Integer.MAX_VALUE
+ || super.getMaximumFractionDigits() > Integer.MAX_VALUE
+ || super.getMinimumIntegerDigits() > Integer.MAX_VALUE) {
+ // text.09=The deserialized date is invalid
+ throw new InvalidObjectException(Messages.getString("text.09")); //$NON-NLS-1$
+ }
+ if (serialVersionOnStream < 3) {
+ setMaximumIntegerDigits(super.getMinimumIntegerDigits());
+ setMinimumIntegerDigits(super.getMinimumIntegerDigits());
+ setMaximumFractionDigits(super.getMaximumFractionDigits());
+ setMinimumFractionDigits(super.getMinimumFractionDigits());
+ }
+ if (serialVersionOnStream < 1) {
+ this.setInternalField("useExponentialNotation", dform, //$NON-NLS-1$
+ Boolean.FALSE);
+ }
+ serialVersionOnStream = 3;
+ }
+
+ /*
+ * Copies decimal format symbols from text object to ICU one.
+ *
+ * @param icu the object which receives the new values. @param dfs the
+ * object which contains the new values.
+ */
+ private void copySymbols(final com.ibm.icu4jni.text.DecimalFormatSymbols icu,
+ final DecimalFormatSymbols dfs) {
+ icu.setCurrency(Currency.getInstance(dfs.getCurrency()
+ .getCurrencyCode()));
+ icu.setCurrencySymbol(dfs.getCurrencySymbol());
+ icu.setDecimalSeparator(dfs.getDecimalSeparator());
+ icu.setDigit(dfs.getDigit());
+ icu.setGroupingSeparator(dfs.getGroupingSeparator());
+ icu.setInfinity(dfs.getInfinity());
+ icu
+ .setInternationalCurrencySymbol(dfs
+ .getInternationalCurrencySymbol());
+ icu.setMinusSign(dfs.getMinusSign());
+ icu.setMonetaryDecimalSeparator(dfs.getMonetaryDecimalSeparator());
+ icu.setNaN(dfs.getNaN());
+ icu.setPatternSeparator(dfs.getPatternSeparator());
+ icu.setPercent(dfs.getPercent());
+ icu.setPerMill(dfs.getPerMill());
+ icu.setZeroDigit(dfs.getZeroDigit());
+ }
+
+ /*
+ * Sets private field value by reflection.
+ *
+ * @param fieldName the field name to be set @param target the object which
+ * field to be set @param value the value to be set
+ */
+ private void setInternalField(final String fieldName, final Object target,
+ final Object value) {
+ AccessController
+ .doPrivileged(new PrivilegedAction<java.lang.reflect.Field>() {
+ public java.lang.reflect.Field run() {
+ java.lang.reflect.Field field = null;
+ try {
+ field = target.getClass().getDeclaredField(
+ fieldName);
+ field.setAccessible(true);
+ field.set(target, value);
+ } catch (Exception e) {
+ return null;
+ }
+ return field;
+ }
+ });
+ }
+
+ /*
+ * Gets private field value by reflection.
+ *
+ * @param fieldName the field name to be set @param target the object which
+ * field to be gotten
+ */
+ private Object getInternalField(final String fieldName, final Object target) {
+ Object value = AccessController
+ .doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ Object result = null;
+ java.lang.reflect.Field field = null;
+ try {
+ field = target.getClass().getDeclaredField(
+ fieldName);
+ field.setAccessible(true);
+ result = field.get(target);
+ } catch (Exception e1) {
+ return null;
+ }
+ return result;
+ }
+ });
+ return value;
+ }
+
+}
diff --git a/text/src/main/java/java/text/DecimalFormatSymbols.java b/text/src/main/java/java/text/DecimalFormatSymbols.java
new file mode 100644
index 0000000..4918a1f
--- /dev/null
+++ b/text/src/main/java/java/text/DecimalFormatSymbols.java
@@ -0,0 +1,543 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * DecimalFormatSymbols holds the symbols used in the formating and parsing of
+ * numbers.
+ */
+public final class DecimalFormatSymbols implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 5772796243397350300L;
+
+ private final int ZeroDigit = 0, Digit = 1, DecimalSeparator = 2,
+ GroupingSeparator = 3, PatternSeparator = 4, Percent = 5,
+ PerMill = 6, Exponent = 7, MonetaryDecimalSeparator = 8,
+ MinusSign = 9;
+
+ transient char[] patternChars;
+
+ private transient Currency currency;
+
+ private transient Locale locale;
+
+ private String infinity, NaN, currencySymbol, intlCurrencySymbol;
+
+ /**
+ * Constructs a new DecimalFormatSymbols containing the symbols for the
+ * default Locale.
+ */
+ public DecimalFormatSymbols() {
+ this(Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new DecimalFormatSymbols containing the symbols for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ */
+ public DecimalFormatSymbols(Locale locale) {
+ ResourceBundle bundle = Format.getBundle(locale);
+ patternChars = bundle.getString("DecimalPatternChars").toCharArray(); //$NON-NLS-1$
+ infinity = bundle.getString("Infinity"); //$NON-NLS-1$
+ NaN = bundle.getString("NaN"); //$NON-NLS-1$
+ this.locale = locale;
+ try {
+ currency = Currency.getInstance(locale);
+ currencySymbol = currency.getSymbol(locale);
+ intlCurrencySymbol = currency.getCurrencyCode();
+ } catch (IllegalArgumentException e) {
+ currency = Currency.getInstance("XXX"); //$NON-NLS-1$
+ currencySymbol = bundle.getString("CurrencySymbol"); //$NON-NLS-1$
+ intlCurrencySymbol = bundle.getString("IntCurrencySymbol"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns a new DecimalFormatSymbols with the same symbols as this
+ * DecimalFormatSymbols.
+ *
+ * @return a shallow copy of this DecimalFormatSymbols
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ try {
+ DecimalFormatSymbols symbols = (DecimalFormatSymbols) super.clone();
+ symbols.patternChars = patternChars.clone();
+ return symbols;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Compares the specified object to this DecimalFormatSymbols and answer if
+ * they are equal. The object must be an instance of DecimalFormatSymbols
+ * with the same symbols.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this
+ * DecimalFormatSymbols, false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof DecimalFormatSymbols)) {
+ return false;
+ }
+ DecimalFormatSymbols obj = (DecimalFormatSymbols) object;
+ return Arrays.equals(patternChars, obj.patternChars)
+ && infinity.equals(obj.infinity) && NaN.equals(obj.NaN)
+ && currencySymbol.equals(obj.currencySymbol)
+ && intlCurrencySymbol.equals(obj.intlCurrencySymbol);
+ }
+
+ /**
+ * Returns the currency.
+ * <p>
+ * <code>null<code> is returned
+ * if <code>setInternationalCurrencySymbol()</code> has been previously called
+ * with a value that is not a valid ISO 4217 currency code.
+ * <p>
+ *
+ * @return the currency that was set in the constructor, <code>setCurrency()</code>,
+ * or <code>setInternationalCurrencySymbol()</code>, or </code>null</code>
+ *
+ * @see #setCurrency(Currency)
+ * @see #setInternationalCurrencySymbol(String)
+ */
+ public Currency getCurrency() {
+ return currency;
+ }
+
+ /**
+ * Returns the international currency symbol.
+ *
+ * @return a String
+ */
+ public String getInternationalCurrencySymbol() {
+ return intlCurrencySymbol;
+ }
+
+ /**
+ * Returns the currency symbol.
+ *
+ * @return a String
+ */
+ public String getCurrencySymbol() {
+ return currencySymbol;
+ }
+
+ /**
+ * Returns the character which represents the decimal point in a number.
+ *
+ * @return a char
+ */
+ public char getDecimalSeparator() {
+ return patternChars[DecimalSeparator];
+ }
+
+ /**
+ * Returns the character which represents a single digit in a format
+ * pattern.
+ *
+ * @return a char
+ */
+ public char getDigit() {
+ return patternChars[Digit];
+ }
+
+ /**
+ * Returns the character used as the thousands separator in a number.
+ *
+ * @return a char
+ */
+ public char getGroupingSeparator() {
+ return patternChars[GroupingSeparator];
+ }
+
+ /**
+ * Returns the String which represents infinity.
+ *
+ * @return a String
+ */
+ public String getInfinity() {
+ return infinity;
+ }
+
+ String getLocalPatternChars() {
+ // Don't include the MonetaryDecimalSeparator or the MinusSign
+ return new String(patternChars, 0, patternChars.length - 2);
+ }
+
+ /**
+ * Returns the minus sign character.
+ *
+ * @return a char
+ */
+ public char getMinusSign() {
+ return patternChars[MinusSign];
+ }
+
+ /**
+ * Returns the character which represents the decimal point in a monetary
+ * value.
+ *
+ * @return a char
+ */
+ public char getMonetaryDecimalSeparator() {
+ return patternChars[MonetaryDecimalSeparator];
+ }
+
+ /**
+ * Returns the String which represents NaN.
+ *
+ * @return a String
+ */
+ public String getNaN() {
+ return NaN;
+ }
+
+ /**
+ * Returns the character which separates the positive and negative patterns
+ * in a format pattern.
+ *
+ * @return a char
+ */
+ public char getPatternSeparator() {
+ return patternChars[PatternSeparator];
+ }
+
+ /**
+ * Returns the percent character.
+ *
+ * @return a char
+ */
+ public char getPercent() {
+ return patternChars[Percent];
+ }
+
+ /**
+ * Returns the mille percent sign character.
+ *
+ * @return a char
+ */
+ public char getPerMill() {
+ return patternChars[PerMill];
+ }
+
+ /**
+ * Returns the character which represents zero.
+ *
+ * @return a char
+ */
+ public char getZeroDigit() {
+ return patternChars[ZeroDigit];
+ }
+
+ char getExponential() {
+ return patternChars[Exponent];
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return new String(patternChars).hashCode() + infinity.hashCode()
+ + NaN.hashCode() + currencySymbol.hashCode()
+ + intlCurrencySymbol.hashCode();
+ }
+
+ /**
+ * Sets the currency.
+ * <p>
+ * The international currency symbol and currency symbol are updated, but
+ * the min and max number of fraction digits stay the same.
+ * <p>
+ *
+ * @param currency
+ * the new currency
+ *
+ * @throws java.lang.NullPointerException
+ * if currency is null
+ */
+ public void setCurrency(Currency currency) {
+ if (currency == null) {
+ throw new NullPointerException();
+ }
+ if (currency == this.currency) {
+ return;
+ }
+ this.currency = currency;
+ intlCurrencySymbol = currency.getCurrencyCode();
+ currencySymbol = currency.getSymbol(locale);
+ }
+
+ /**
+ * Sets the international currency symbol.
+ * <p>
+ * currency and currency symbol also are updated, if <code>value</code> is
+ * a valid ISO4217 currency code.
+ * <p>
+ * The min and max number of fraction digits stay the same.
+ *
+ * @param value
+ * currency code
+ */
+ public void setInternationalCurrencySymbol(String value) {
+ if (value == null) {
+ currency = null;
+ intlCurrencySymbol = null;
+ return;
+ }
+
+ if (value.equals(intlCurrencySymbol)) {
+ return;
+ }
+
+ try {
+ currency = Currency.getInstance(value);
+ currencySymbol = currency.getSymbol(locale);
+ } catch (IllegalArgumentException e) {
+ currency = null;
+ }
+ intlCurrencySymbol = value;
+ }
+
+ /**
+ * Sets the currency symbol.
+ *
+ * @param value
+ * a String
+ */
+ public void setCurrencySymbol(String value) {
+ currencySymbol = value;
+ }
+
+ /**
+ * Sets the character which represents the decimal point in a number.
+ *
+ * @param value
+ * the decimal separator character
+ */
+ public void setDecimalSeparator(char value) {
+ patternChars[DecimalSeparator] = value;
+ }
+
+ /**
+ * Sets the character which represents a single digit in a format pattern.
+ *
+ * @param value
+ * the digit character
+ */
+ public void setDigit(char value) {
+ patternChars[Digit] = value;
+ }
+
+ /**
+ * Sets the character used as the thousands separator in a number.
+ *
+ * @param value
+ * the grouping separator character
+ */
+ public void setGroupingSeparator(char value) {
+ patternChars[GroupingSeparator] = value;
+ }
+
+ /**
+ * Sets the String which represents infinity.
+ *
+ * @param value
+ * the String
+ */
+ public void setInfinity(String value) {
+ infinity = value;
+ }
+
+ /**
+ * Sets the minus sign character.
+ *
+ * @param value
+ * the minus sign character
+ */
+ public void setMinusSign(char value) {
+ patternChars[MinusSign] = value;
+ }
+
+ /**
+ * Sets the character which represents the decimal point in a monetary
+ * value.
+ *
+ * @param value
+ * the monetary decimal separator character
+ */
+ public void setMonetaryDecimalSeparator(char value) {
+ patternChars[MonetaryDecimalSeparator] = value;
+ }
+
+ /**
+ * Sets the String which represents NaN.
+ *
+ * @param value
+ * the String
+ */
+ public void setNaN(String value) {
+ NaN = value;
+ }
+
+ /**
+ * Sets the character which separates the positive and negative patterns in
+ * a format pattern.
+ *
+ * @param value
+ * the pattern separator character
+ */
+ public void setPatternSeparator(char value) {
+ patternChars[PatternSeparator] = value;
+ }
+
+ /**
+ * Sets the percent character.
+ *
+ * @param value
+ * the percent character
+ */
+ public void setPercent(char value) {
+ patternChars[Percent] = value;
+ }
+
+ /**
+ * Sets the mille percent sign character.
+ *
+ * @param value
+ * the mille percent character
+ */
+ public void setPerMill(char value) {
+ patternChars[PerMill] = value;
+ }
+
+ /**
+ * Sets the character which represents zero.
+ *
+ * @param value
+ * the zero digit character
+ */
+ public void setZeroDigit(char value) {
+ patternChars[ZeroDigit] = value;
+ }
+
+ void setExponential(char value) {
+ patternChars[Exponent] = value;
+ }
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("currencySymbol", String.class), //$NON-NLS-1$
+ new ObjectStreamField("decimalSeparator", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("digit", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("exponential", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("groupingSeparator", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("infinity", String.class), //$NON-NLS-1$
+ new ObjectStreamField("intlCurrencySymbol", String.class), //$NON-NLS-1$
+ new ObjectStreamField("minusSign", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("monetarySeparator", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("NaN", String.class), //$NON-NLS-1$
+ new ObjectStreamField("patternSeparator", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("percent", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("perMill", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("serialVersionOnStream", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("zeroDigit", Character.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("locale", Locale.class), }; //$NON-NLS-1$
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("currencySymbol", currencySymbol); //$NON-NLS-1$
+ fields.put("decimalSeparator", getDecimalSeparator()); //$NON-NLS-1$
+ fields.put("digit", getDigit()); //$NON-NLS-1$
+ fields.put("exponential", getExponential()); //$NON-NLS-1$
+ fields.put("groupingSeparator", getGroupingSeparator()); //$NON-NLS-1$
+ fields.put("infinity", infinity); //$NON-NLS-1$
+ fields.put("intlCurrencySymbol", intlCurrencySymbol); //$NON-NLS-1$
+ fields.put("minusSign", getMinusSign()); //$NON-NLS-1$
+ fields.put("monetarySeparator", getMonetaryDecimalSeparator()); //$NON-NLS-1$
+ fields.put("NaN", NaN); //$NON-NLS-1$
+ fields.put("patternSeparator", getPatternSeparator()); //$NON-NLS-1$
+ fields.put("percent", getPercent()); //$NON-NLS-1$
+ fields.put("perMill", getPerMill()); //$NON-NLS-1$
+ fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
+ fields.put("zeroDigit", getZeroDigit()); //$NON-NLS-1$
+ fields.put("locale", locale); //$NON-NLS-1$
+ stream.writeFields();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = stream.readFields();
+ patternChars = new char[10];
+ currencySymbol = (String) fields.get("currencySymbol", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ setDecimalSeparator(fields.get("decimalSeparator", '.')); //$NON-NLS-1$
+ setDigit(fields.get("digit", '#')); //$NON-NLS-1$
+ setGroupingSeparator(fields.get("groupingSeparator", ',')); //$NON-NLS-1$
+ infinity = (String) fields.get("infinity", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ intlCurrencySymbol = (String) fields.get("intlCurrencySymbol", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ setMinusSign(fields.get("minusSign", '-')); //$NON-NLS-1$
+ NaN = (String) fields.get("NaN", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ setPatternSeparator(fields.get("patternSeparator", ';')); //$NON-NLS-1$
+ setPercent(fields.get("percent", '%')); //$NON-NLS-1$
+ setPerMill(fields.get("perMill", '\u2030')); //$NON-NLS-1$
+ setZeroDigit(fields.get("zeroDigit", '0')); //$NON-NLS-1$
+ locale = (Locale) fields.get("locale", null); //$NON-NLS-1$
+ if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$
+ setMonetaryDecimalSeparator(getDecimalSeparator());
+ setExponential('E');
+ } else {
+ setMonetaryDecimalSeparator(fields.get("monetarySeparator", '.')); //$NON-NLS-1$
+ setExponential(fields.get("exponential", 'E')); //$NON-NLS-1$
+
+ }
+ try {
+ currency = Currency.getInstance(intlCurrencySymbol);
+ } catch (IllegalArgumentException e) {
+ currency = null;
+ }
+ }
+}
diff --git a/text/src/main/java/java/text/FieldPosition.java b/text/src/main/java/java/text/FieldPosition.java
new file mode 100644
index 0000000..2319b8e
--- /dev/null
+++ b/text/src/main/java/java/text/FieldPosition.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * FieldPosition is used to identify fields in formatted Strings.
+ */
+public class FieldPosition {
+
+ private int myField, beginIndex, endIndex;
+
+ private Format.Field myAttribute;
+
+ /**
+ * Constructs a new FieldPosition on the specified field.
+ *
+ * @param field
+ * the field to identify
+ */
+ public FieldPosition(int field) {
+ myField = field;
+ }
+
+ /**
+ * Constructs a new FieldPosition on the specified Field attribute.
+ *
+ * @param attribute
+ * the field attribute to identify
+ */
+ public FieldPosition(Format.Field attribute) {
+ myAttribute = attribute;
+ myField = -1;
+ }
+
+ /**
+ * Constructs a new FieldPosition on the specified Field attribute and field
+ * id.
+ *
+ * @param attribute
+ * the field attribute to identify
+ * @param field
+ * the field to identify
+ */
+ public FieldPosition(Format.Field attribute, int field) {
+ myAttribute = attribute;
+ myField = field;
+ }
+
+ void clear() {
+ beginIndex = endIndex = 0;
+ }
+
+ /**
+ * Compares the specified object to this FieldPosition and answer if they
+ * are equal. The object must be an instance of FieldPosition with the same
+ * field, begin index and end index.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this fieldPosition,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof FieldPosition)) {
+ return false;
+ }
+ FieldPosition pos = (FieldPosition) object;
+ return myField == pos.myField && myAttribute == pos.myAttribute
+ && beginIndex == pos.beginIndex && endIndex == pos.endIndex;
+ }
+
+ /**
+ * Returns the index of the beginning of the field.
+ *
+ * @return the first index of the field
+ */
+ public int getBeginIndex() {
+ return beginIndex;
+ }
+
+ /**
+ * Returns the index one past the end of the field.
+ *
+ * @return one past the index of the last character in the field
+ */
+ public int getEndIndex() {
+ return endIndex;
+ }
+
+ /**
+ * Returns the field which is being identified.
+ *
+ * @return the field
+ */
+ public int getField() {
+ return myField;
+ }
+
+ /**
+ * Returns the attribute which is being identified.
+ *
+ * @return the field
+ */
+ public Format.Field getFieldAttribute() {
+ return myAttribute;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ int attributeHash = (myAttribute == null) ? 0 : myAttribute.hashCode();
+ return attributeHash + myField * 10 + beginIndex * 100 + endIndex;
+ }
+
+ /**
+ * Sets the index of the beginning of the field.
+ *
+ * @param index
+ * the index of the first character in the field
+ */
+ public void setBeginIndex(int index) {
+ beginIndex = index;
+ }
+
+ /**
+ * Sets the index of the end of the field.
+ *
+ * @param index
+ * one past the index of the last character in the field
+ */
+ public void setEndIndex(int index) {
+ endIndex = index;
+ }
+
+ /**
+ * Returns the string representation of this FieldPosition.
+ *
+ * @return the string representation of this FieldPosition
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[attribute=" + myAttribute + ", field=" //$NON-NLS-1$ //$NON-NLS-2$
+ + myField + ", beginIndex=" + beginIndex + ", endIndex=" //$NON-NLS-1$ //$NON-NLS-2$
+ + endIndex + "]"; //$NON-NLS-1$
+ }
+}
diff --git a/text/src/main/java/java/text/Format.java b/text/src/main/java/java/text/Format.java
new file mode 100644
index 0000000..1b93898
--- /dev/null
+++ b/text/src/main/java/java/text/Format.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * Format is the abstract superclass of classes which format and parse objects
+ * according to Locale specific rules.
+ */
+public abstract class Format implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = -299282585814624189L;
+
+ /**
+ * Constructs a new instance of Format.
+ *
+ */
+ public Format() {
+ }
+
+ /**
+ * Returns a copy of this Format.
+ *
+ * @return a shallow copy of this Format
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ static ResourceBundle getBundle(final Locale locale) {
+ return AccessController
+ .doPrivileged(new PrivilegedAction<ResourceBundle>() {
+ public ResourceBundle run() {
+ return ResourceBundle
+ .getBundle(
+ "org.apache.harmony.luni.internal.locale.Locale", locale); //$NON-NLS-1$
+ }
+ });
+ }
+
+ String convertPattern(String template, String fromChars, String toChars,
+ boolean check) {
+ if (!check && fromChars.equals(toChars)) {
+ return template;
+ }
+ boolean quote = false;
+ StringBuilder output = new StringBuilder();
+ int length = template.length();
+ for (int i = 0; i < length; i++) {
+ int index;
+ char next = template.charAt(i);
+ if (next == '\'') {
+ quote = !quote;
+ }
+ if (!quote && (index = fromChars.indexOf(next)) != -1) {
+ output.append(toChars.charAt(index));
+ } else if (check
+ && !quote
+ && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ // text.05=Invalid pattern char {0} in {1}
+ throw new IllegalArgumentException(Messages.getString(
+ "text.05", String.valueOf(next), template)); //$NON-NLS-1$
+ } else {
+ output.append(next);
+ }
+ }
+ if (quote) {
+ // text.04=Unterminated quote
+ throw new IllegalArgumentException(Messages.getString("text.04")); //$NON-NLS-1$
+ }
+ return output.toString();
+ }
+
+ /**
+ * Formats the specified object using the rules of this Format.
+ *
+ *
+ * @param object
+ * the object to format
+ * @return the formatted String
+ *
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ public final String format(Object object) {
+ return format(object, new StringBuffer(), new FieldPosition(0))
+ .toString();
+ }
+
+ /**
+ * Formats the specified object into the specified StringBuffer using the
+ * rules of this Format. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param object
+ * the object to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ *
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ public abstract StringBuffer format(Object object, StringBuffer buffer,
+ FieldPosition field);
+
+ /**
+ * Formats the specified object using the rules of this format and returns
+ * an AttributedCharacterIterator with the formatted String and no
+ * attributes.
+ * <p>
+ * Subclasses should return an AttributedCharacterIterator with the
+ * appropriate attributes.
+ *
+ * @param object
+ * the object to format
+ * @return an AttributedCharacterIterator with the formatted object and
+ * attributes
+ *
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+ return new AttributedString(format(object)).getIterator();
+ }
+
+ /**
+ * Parse the specified String using the rules of this Format.
+ *
+ * @param string
+ * the String to parse
+ * @return the object resulting from the parse
+ *
+ * @exception ParseException
+ * when an error occurs during parsing
+ */
+ public Object parseObject(String string) throws ParseException {
+ ParsePosition position = new ParsePosition(0);
+ Object result = parseObject(string, position);
+ if (position.getErrorIndex() != -1 || position.getIndex() == 0) {
+ throw new ParseException(null, position.getErrorIndex());
+ }
+ return result;
+ }
+
+ /**
+ * Parse the specified String starting at the index specified by the
+ * ParsePosition. If the string is successfully parsed, the index of the
+ * ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the object resulting from the parse, or null if there is an error
+ */
+ public abstract Object parseObject(String string, ParsePosition position);
+
+ static boolean upTo(String string, ParsePosition position,
+ StringBuffer buffer, char stop) {
+ int index = position.getIndex(), length = string.length();
+ boolean lastQuote = false, quote = false;
+ while (index < length) {
+ char ch = string.charAt(index++);
+ if (ch == '\'') {
+ if (lastQuote) {
+ buffer.append('\'');
+ }
+ quote = !quote;
+ lastQuote = true;
+ } else if (ch == stop && !quote) {
+ position.setIndex(index);
+ return true;
+ } else {
+ lastQuote = false;
+ buffer.append(ch);
+ }
+ }
+ position.setIndex(index);
+ return false;
+ }
+
+ static boolean upToWithQuotes(String string, ParsePosition position,
+ StringBuffer buffer, char stop, char start) {
+ int index = position.getIndex(), length = string.length(), count = 1;
+ boolean quote = false;
+ while (index < length) {
+ char ch = string.charAt(index++);
+ if (ch == '\'') {
+ quote = !quote;
+ }
+ if (!quote) {
+ if (ch == stop) {
+ count--;
+ }
+ if (count == 0) {
+ position.setIndex(index);
+ return true;
+ }
+ if (ch == start) {
+ count++;
+ }
+ }
+ buffer.append(ch);
+ }
+ // text.07=Unmatched braces in the pattern
+ throw new IllegalArgumentException(Messages.getString("text.07")); //$NON-NLS-1$
+ }
+
+ /**
+ * This inner class is used to represent Format attributes in the
+ * AttributedCharacterIterator that formatToCharacterIterator() method
+ * returns in the Format subclasses.
+ */
+ public static class Field extends AttributedCharacterIterator.Attribute {
+
+ private static final long serialVersionUID = 276966692217360283L;
+
+ /**
+ * Constructs a new instance of Field with the given fieldName.
+ *
+ * @param fieldName The field name.
+ */
+ protected Field(String fieldName) {
+ super(fieldName);
+ }
+ }
+}
diff --git a/text/src/main/java/java/text/MessageFormat.java b/text/src/main/java/java/text/MessageFormat.java
new file mode 100644
index 0000000..40fd90c
--- /dev/null
+++ b/text/src/main/java/java/text/MessageFormat.java
@@ -0,0 +1,1037 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * MessageFormat is used to format and parse arguments based on a pattern. The
+ * pattern specifies how each argument will be formatted and concatenated with
+ * other text to produce the formatted output.
+ */
+public class MessageFormat extends Format {
+
+ private static final long serialVersionUID = 6479157306784022952L;
+
+ private Locale locale = Locale.getDefault();
+
+ transient private String[] strings;
+
+ private int[] argumentNumbers;
+
+ private Format[] formats;
+
+ private int maxOffset;
+
+ transient private int maxArgumentIndex;
+
+ /**
+ * Constructs a new MessageFormat using the specified pattern and the
+ * specified Locale for Formats.
+ *
+ * @param template
+ * the pattern
+ * @param locale
+ * the locale
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public MessageFormat(String template, Locale locale) {
+ this.locale = locale;
+ applyPattern(template);
+ }
+
+ /**
+ * Constructs a new MessageFormat using the specified pattern and the
+ * default Locale for Formats.
+ *
+ * @param template
+ * the pattern
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public MessageFormat(String template) {
+ applyPattern(template);
+ }
+
+ /**
+ * Changes this MessageFormat to use the specified pattern.
+ *
+ * @param template
+ * the pattern
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public void applyPattern(String template) {
+ int length = template.length();
+ StringBuffer buffer = new StringBuffer();
+ ParsePosition position = new ParsePosition(0);
+ Vector<String> localStrings = new Vector<String>();
+ int argCount = 0;
+ int[] args = new int[10];
+ int maxArg = -1;
+ Vector<Format> localFormats = new Vector<Format>();
+ while (position.getIndex() < length) {
+ if (Format.upTo(template, position, buffer, '{')) {
+ byte arg;
+ int offset = position.getIndex();
+ if (offset >= length
+ || (arg = (byte) Character.digit(template
+ .charAt(offset++), 10)) == -1) {
+ // text.19=Invalid argument number
+ throw new IllegalArgumentException(Messages
+ .getString("text.19")); //$NON-NLS-1$
+ }
+ position.setIndex(offset);
+ localFormats.addElement(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.addElement(buffer.toString());
+ buffer.setLength(0);
+ }
+ this.strings = new String[localStrings.size()];
+ for (int i = 0; i < localStrings.size(); i++) {
+ this.strings[i] = localStrings.elementAt(i);
+ }
+ argumentNumbers = args;
+ this.formats = new Format[argCount];
+ for (int i = 0; i < argCount; i++) {
+ this.formats[i] = localFormats.elementAt(i);
+ }
+ maxOffset = argCount - 1;
+ maxArgumentIndex = maxArg;
+ }
+
+ /**
+ * Returns a new instance of MessageFormat with the same pattern and Formats
+ * as this MessageFormat.
+ *
+ * @return a shallow copy of this MessageFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ MessageFormat clone = (MessageFormat) super.clone();
+ Format[] array = new Format[formats.length];
+ for (int i = formats.length; --i >= 0;) {
+ if (formats[i] != null) {
+ array[i] = (Format) formats[i].clone();
+ }
+ }
+ clone.formats = array;
+ return clone;
+ }
+
+ /**
+ * Compares the specified object to this MessageFormat and answer if they
+ * are equal. The object must be an instance of MessageFormat and have the
+ * same pattern.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this MessageFormat,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof MessageFormat)) {
+ return false;
+ }
+ MessageFormat format = (MessageFormat) 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);
+ }
+
+ /**
+ * Formats the specified object using the rules of this MessageFormat and
+ * returns an AttributedCharacterIterator with the formatted message and
+ * attributes. The AttributedCharacterIterator returned also includes the
+ * attributes from the formats of this MessageFormat.
+ *
+ * @param object
+ * the object to format
+ * @return an AttributedCharacterIterator with the formatted message and
+ * attributes
+ *
+ * @exception IllegalArgumentException
+ * when the arguments in the object array cannot be formatted
+ * by this Format
+ */
+ @Override
+ public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+ if (object == null) {
+ throw new NullPointerException();
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ Vector<FieldContainer> fields = new Vector<FieldContainer>();
+
+ // format the message, and find fields
+ formatImpl((Object[]) object, buffer, new FieldPosition(0), fields);
+
+ // create an AttributedString with the formatted buffer
+ AttributedString as = new AttributedString(buffer.toString());
+
+ // add MessageFormat field attributes and values to the AttributedString
+ for (int i = 0; i < fields.size(); i++) {
+ FieldContainer fc = fields.elementAt(i);
+ as.addAttribute(fc.attribute, fc.value, fc.start, fc.end);
+ }
+
+ // return the CharacterIterator from AttributedString
+ return as.getIterator();
+ }
+
+ /**
+ * Formats the Object arguments into the specified StringBuffer using the
+ * pattern of this MessageFormat.
+ * <p>
+ * If Field Attribute of the FieldPosition supplied is
+ * MessageFormat.Field.ARGUMENT, then begin and end index of this field
+ * position is set to the location of the first occurrence of a message
+ * format argument. Otherwise the FieldPosition is ignored
+ * <p>
+ *
+ * @param objects
+ * the array of Objects to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition.
+ *
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public final StringBuffer format(Object[] objects, StringBuffer buffer,
+ FieldPosition field) {
+ return formatImpl(objects, buffer, field, null);
+ }
+
+ private StringBuffer formatImpl(Object[] objects, StringBuffer buffer,
+ FieldPosition position, Vector<FieldContainer> fields) {
+ FieldPosition passedField = new FieldPosition(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;
+ }
+ Format format = formats[i];
+ if (format == null || arg == null) {
+ if (arg instanceof Number) {
+ format = NumberFormat.getInstance();
+ } else if (arg instanceof Date) {
+ format = DateFormat.getInstance();
+ } else {
+ buffer.append(arg);
+ handleArgumentField(begin, buffer.length(),
+ argumentNumbers[i], position, fields);
+ continue;
+ }
+ }
+ if (format instanceof ChoiceFormat) {
+ String result = format.format(arg);
+ MessageFormat mf = new MessageFormat(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;
+ }
+
+ /**
+ * Adds a new FieldContainer with MessageFormat.Field.ARGUMENT field,
+ * argnumber, begin and end index to the fields vector, or sets the
+ * position's begin and end index if it has MessageFormat.Field.ARGUMENT as
+ * its field attribute.
+ *
+ * @param begin
+ * @param end
+ * @param argnumber
+ * @param position
+ * @param fields
+ */
+ private void handleArgumentField(int begin, int end, int argnumber,
+ FieldPosition position, Vector<FieldContainer> fields) {
+ if (fields != null) {
+ fields.add(new FieldContainer(begin, end, Field.ARGUMENT,
+ new Integer(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
+ */
+ private static class FieldContainer {
+ int start, end;
+
+ AttributedCharacterIterator.Attribute attribute;
+
+ Object value;
+
+ public FieldContainer(int start, int end,
+ AttributedCharacterIterator.Attribute attribute, Object value) {
+ this.start = start;
+ this.end = end;
+ this.attribute = attribute;
+ this.value = value;
+ }
+ }
+
+ /**
+ * If fields vector is not null, find and add the fields of this format to
+ * the fields vector by iterating through its AttributedCharacterIterator
+ *
+ * @param format
+ * the format to find fields for
+ * @param arg
+ * object to format
+ * @param begin
+ * the index where the string this format has formatted begins
+ * @param fields
+ * fields vector, each entry in this vector are of type
+ * FieldContainer.
+ */
+ private void handleformat(Format format, Object arg, int begin,
+ Vector<FieldContainer> fields) {
+ if (fields != null) {
+ AttributedCharacterIterator iterator = format
+ .formatToCharacterIterator(arg);
+ while (iterator.getIndex() != iterator.getEndIndex()) {
+ int start = iterator.getRunStart();
+ int end = iterator.getRunLimit();
+
+ Iterator<?> it = iterator.getAttributes().keySet().iterator();
+ while (it.hasNext()) {
+ AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
+ .next();
+ Object value = iterator.getAttribute(attribute);
+ fields.add(new FieldContainer(begin + start, begin + end,
+ attribute, value));
+ }
+ iterator.setIndex(end);
+ }
+ }
+ }
+
+ /**
+ * Formats the specified object into the specified StringBuffer using the
+ * pattern of this MessageFormat.
+ *
+ * @param object
+ * the object to format, must be an array of Object
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * a FieldPosition which is ignored
+ * @return the StringBuffer parameter <code>buffer</code>
+ *
+ * @exception ClassCastException
+ * when <code>object</code> is not an array of Object
+ */
+ @Override
+ public final StringBuffer format(Object object, StringBuffer buffer,
+ FieldPosition field) {
+ return format((Object[]) object, buffer, field);
+ }
+
+ /**
+ * Formats the Object arguments using the specified MessageFormat pattern.
+ *
+ * @param template
+ * the pattern
+ * @param objects
+ * the array of Objects to format
+ * @return the formatted result
+ *
+ * @exception IllegalArgumentException
+ * when the pattern cannot be parsed
+ */
+ public static String format(String template, Object... objects) {
+ return new MessageFormat(template).format(objects);
+ }
+
+ /**
+ * Returns the Formats of this MessageFormat.
+ *
+ * @return an array of Format
+ */
+ public Format[] getFormats() {
+ return formats.clone();
+ }
+
+ /**
+ * Returns the formats used for each argument index. If an argument is
+ * placed more than once in the pattern string, than returns the format of
+ * the last one.
+ *
+ * @return an array of formats, ordered by argument index
+ */
+ public Format[] getFormatsByArgumentIndex() {
+ Format[] answer = new Format[maxArgumentIndex + 1];
+ for (int i = 0; i < maxOffset + 1; i++) {
+ answer[argumentNumbers[i]] = formats[i];
+ }
+ return answer;
+ }
+
+ /**
+ * Sets the format used for argument at index <code>argIndex</code>to
+ * <code>format</code>
+ *
+ * @param argIndex
+ * @param format
+ */
+ public void setFormatByArgumentIndex(int argIndex, Format format) {
+ for (int i = 0; i < maxOffset + 1; i++) {
+ if (argumentNumbers[i] == argIndex) {
+ formats[i] = format;
+ }
+ }
+ }
+
+ /**
+ * Sets the formats used for each argument <code>The formats</code> array
+ * elements should be in the order of the argument indices.
+ *
+ * @param formats
+ */
+ public void setFormatsByArgumentIndex(Format[] 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];
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the Locale used when creating Formats.
+ *
+ * @return the Locale used to create Formats
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @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;
+ }
+
+ /**
+ * Parse the message arguments from the specified String using the rules of
+ * this MessageFormat.
+ *
+ * @param string
+ * the String to parse
+ * @return the array of Object arguments resulting from the parse
+ *
+ * @exception ParseException
+ * when an error occurs during parsing
+ */
+ public Object[] parse(String string) throws ParseException {
+ ParsePosition position = new ParsePosition(0);
+ Object[] result = parse(string, position);
+ if (position.getErrorIndex() != -1 || position.getIndex() == 0) {
+ throw new ParseException(null, position.getErrorIndex());
+ }
+ return result;
+ }
+
+ /**
+ * Parse the message argument from the specified String starting at the
+ * index specified by the ParsePosition. If the string is successfully
+ * parsed, the index of the ParsePosition is updated to the index following
+ * the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the array of Object arguments resulting from the parse, or null
+ * if there is an error
+ */
+ public Object[] parse(String string, ParsePosition position) {
+ if (string == null) {
+ return new Object[0];
+ }
+ ParsePosition internalPos = new ParsePosition(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;
+ Format 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;
+ }
+
+ /**
+ * Parse the message argument from the specified String starting at the
+ * index specified by the ParsePosition. If the string is successfully
+ * parsed, the index of the ParsePosition is updated to the index following
+ * the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the array of Object arguments resulting from the parse, or null
+ * if there is an error
+ */
+ @Override
+ public Object parseObject(String string, ParsePosition position) {
+ return parse(string, position);
+ }
+
+ private int match(String string, ParsePosition position, boolean last,
+ String[] tokens) {
+ int length = string.length(), offset = position.getIndex(), 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)) == '}' || (!last && ch == ','))) {
+ position.setIndex(offset + 1);
+ return token;
+ }
+ return -1;
+ }
+
+ private Format parseVariable(String string, ParsePosition position) {
+ int length = string.length(), offset = position.getIndex();
+ char ch;
+ if (offset >= length
+ || ((ch = string.charAt(offset++)) != '}' && ch != ',')) {
+ // text.15=Missing element format
+ throw new IllegalArgumentException(Messages.getString("text.15")); //$NON-NLS-1$
+ }
+ position.setIndex(offset);
+ if (ch == '}') {
+ return null;
+ }
+ int type = match(string, position, false, new String[] { "time", //$NON-NLS-1$
+ "date", "number", "choice" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ if (type == -1) {
+ // text.16=Unknown element format
+ throw new IllegalArgumentException(Messages.getString("text.16")); //$NON-NLS-1$
+ }
+ StringBuffer buffer = new StringBuffer();
+ ch = string.charAt(position.getIndex() - 1);
+ switch (type) {
+ case 0: // time
+ case 1: // date
+ if (ch == '}') {
+ return type == 1 ? DateFormat.getDateInstance(
+ DateFormat.DEFAULT, locale) : DateFormat
+ .getTimeInstance(DateFormat.DEFAULT, locale);
+ }
+ int dateStyle = match(string, position, true, new String[] {
+ "full", "long", "medium", "short" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ if (dateStyle == -1) {
+ Format.upToWithQuotes(string, position, buffer, '}', '{');
+ return new SimpleDateFormat(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 ? DateFormat
+ .getDateInstance(dateStyle, locale) : DateFormat
+ .getTimeInstance(dateStyle, locale);
+ case 2: // number
+ if (ch == '}') {
+ return NumberFormat.getInstance();
+ }
+ int numberStyle = match(string, position, true, new String[] {
+ "currency", "percent", "integer" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ if (numberStyle == -1) {
+ Format.upToWithQuotes(string, position, buffer, '}', '{');
+ return new DecimalFormat(buffer.toString(),
+ new DecimalFormatSymbols(locale));
+ }
+ switch (numberStyle) {
+ case 0: // currency
+ return NumberFormat.getCurrencyInstance(locale);
+ case 1: // percent
+ return NumberFormat.getPercentInstance(locale);
+ }
+ return NumberFormat.getIntegerInstance(locale);
+ }
+ // choice
+ try {
+ Format.upToWithQuotes(string, position, buffer, '}', '{');
+ } catch (IllegalArgumentException e) {
+ // ignored
+ }
+ return new ChoiceFormat(buffer.toString());
+ }
+
+ /**
+ * Sets the specified Format used by this MessageFormat.
+ *
+ * @param offset
+ * the format to change
+ * @param format
+ * the Format
+ */
+ public void setFormat(int offset, Format format) {
+ formats[offset] = format;
+ }
+
+ /**
+ * Sets the Formats used by this MessageFormat.
+ *
+ * @param formats
+ * an array of Format
+ */
+ public void setFormats(Format[] 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];
+ }
+ }
+
+ /**
+ * Sets the Locale to use when creating Formats.
+ *
+ * @param locale
+ * the Locale
+ */
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ for (int i = 0; i <= maxOffset; i++) {
+ Format format = formats[i];
+ // BEGIN android-removed
+ //if (format instanceof DecimalFormat) {
+ // formats[i] = new DecimalFormat(((DecimalFormat) format)
+ // .toPattern(), new DecimalFormatSymbols(locale));
+ //} else if (format instanceof SimpleDateFormat) {
+ // formats[i] = new SimpleDateFormat(((SimpleDateFormat) format)
+ // .toPattern(), locale);
+ //}
+ // END android-removed
+ // BEGIN android-added
+ // java specification undefined for null argument, change into
+ // a more tolerant implementation
+ if (format instanceof DecimalFormat) {
+ try {
+ formats[i] = new DecimalFormat(((DecimalFormat) format)
+ .toPattern(), new DecimalFormatSymbols(locale));
+ } catch (NullPointerException npe){
+ formats[i] = null;
+ }
+ } else if (format instanceof SimpleDateFormat) {
+ try {
+ formats[i] = new SimpleDateFormat(((SimpleDateFormat) format)
+ .toPattern(), locale);
+ } catch (NullPointerException npe) {
+ formats[i] = null;
+ }
+ }
+ // END android-added
+ }
+ }
+
+ private String decodeDecimalFormat(StringBuffer buffer, Format format) {
+ buffer.append(",number"); //$NON-NLS-1$
+ if (format.equals(NumberFormat.getNumberInstance(locale))) {
+ // Empty block
+ } else if (format.equals(NumberFormat.getIntegerInstance(locale))) {
+ buffer.append(",integer"); //$NON-NLS-1$
+ } else if (format.equals(NumberFormat.getCurrencyInstance(locale))) {
+ buffer.append(",currency"); //$NON-NLS-1$
+ } else if (format.equals(NumberFormat.getPercentInstance(locale))) {
+ buffer.append(",percent"); //$NON-NLS-1$
+ } else {
+ buffer.append(',');
+ return ((DecimalFormat) format).toPattern();
+ }
+ return null;
+ }
+
+ private String decodeSimpleDateFormat(StringBuffer buffer, Format format) {
+ if (format.equals(DateFormat
+ .getTimeInstance(DateFormat.DEFAULT, locale))) {
+ buffer.append(",time"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getDateInstance(DateFormat.DEFAULT,
+ locale))) {
+ buffer.append(",date"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getTimeInstance(DateFormat.SHORT,
+ locale))) {
+ buffer.append(",time,short"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getDateInstance(DateFormat.SHORT,
+ locale))) {
+ buffer.append(",date,short"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getTimeInstance(DateFormat.LONG,
+ locale))) {
+ buffer.append(",time,long"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getDateInstance(DateFormat.LONG,
+ locale))) {
+ buffer.append(",date,long"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getTimeInstance(DateFormat.FULL,
+ locale))) {
+ buffer.append(",time,full"); //$NON-NLS-1$
+ } else if (format.equals(DateFormat.getDateInstance(DateFormat.FULL,
+ locale))) {
+ buffer.append(",date,full"); //$NON-NLS-1$
+ } else {
+ buffer.append(",date,"); //$NON-NLS-1$
+ return ((SimpleDateFormat) format).toPattern();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the pattern of this MessageFormat.
+ *
+ * @return the pattern
+ */
+ public String toPattern() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i <= maxOffset; i++) {
+ appendQuoted(buffer, strings[i]);
+ buffer.append('{');
+ buffer.append(argumentNumbers[i]);
+ Format format = formats[i];
+ String pattern = null;
+ if (format instanceof ChoiceFormat) {
+ buffer.append(",choice,"); //$NON-NLS-1$
+ pattern = ((ChoiceFormat) format).toPattern();
+ } else if (format instanceof DecimalFormat) {
+ pattern = decodeDecimalFormat(buffer, format);
+ } else if (format instanceof SimpleDateFormat) {
+ pattern = decodeSimpleDateFormat(buffer, format);
+ } else if (format != null) {
+ // text.17=Unknown format
+ throw new IllegalArgumentException(Messages
+ .getString("text.17")); //$NON-NLS-1$
+ }
+ if (pattern != null) {
+ boolean quote = false;
+ int index = 0, length = pattern.length(), 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("'}"); //$NON-NLS-1$
+ 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);
+ }
+ }
+ }
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("argumentNumbers", int[].class), //$NON-NLS-1$
+ new ObjectStreamField("formats", Format[].class), //$NON-NLS-1$
+ new ObjectStreamField("locale", Locale.class), //$NON-NLS-1$
+ new ObjectStreamField("maxOffset", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("offsets", int[].class), //$NON-NLS-1$
+ new ObjectStreamField("pattern", String.class), }; //$NON-NLS-1$
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("argumentNumbers", argumentNumbers); //$NON-NLS-1$
+ Format[] compatibleFormats = formats;
+ fields.put("formats", compatibleFormats); //$NON-NLS-1$
+ fields.put("locale", locale); //$NON-NLS-1$
+ fields.put("maxOffset", maxOffset); //$NON-NLS-1$
+ int offset = 0;
+ int offsetsLength = maxOffset + 1;
+ int[] offsets = new int[offsetsLength];
+ StringBuffer pattern = new StringBuffer();
+ for (int i = 0; i <= maxOffset; i++) {
+ offset += strings[i].length();
+ offsets[i] = offset;
+ pattern.append(strings[i]);
+ }
+ if (maxOffset + 1 < strings.length) {
+ pattern.append(strings[maxOffset + 1]);
+ }
+ fields.put("offsets", offsets); //$NON-NLS-1$
+ fields.put("pattern", pattern.toString()); //$NON-NLS-1$
+ stream.writeFields();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = stream.readFields();
+ argumentNumbers = (int[]) fields.get("argumentNumbers", null); //$NON-NLS-1$
+ formats = (Format[]) fields.get("formats", null); //$NON-NLS-1$
+ locale = (Locale) fields.get("locale", null); //$NON-NLS-1$
+ maxOffset = fields.get("maxOffset", 0); //$NON-NLS-1$
+ int[] offsets = (int[]) fields.get("offsets", null); //$NON-NLS-1$
+ String pattern = (String) fields.get("pattern", null); //$NON-NLS-1$
+ int length;
+ if (maxOffset < 0) {
+ length = pattern.length() > 0 ? 1 : 0;
+ } else {
+ length = maxOffset
+ + (offsets[maxOffset] == pattern.length() ? 1 : 2);
+ }
+ strings = new String[length];
+ int last = 0;
+ for (int i = 0; i <= maxOffset; i++) {
+ strings[i] = pattern.substring(last, offsets[i]);
+ last = offsets[i];
+ }
+ if (maxOffset + 1 < strings.length) {
+ strings[strings.length - 1] = pattern.substring(last, pattern
+ .length());
+ }
+ }
+
+ /**
+ * The instances of this inner class are used as attribute keys in
+ * AttributedCharacterIterator that
+ * MessageFormat.formatToCharacterIterator() method returns.
+ * <p>
+ * There is no public constructor to this class, the only instances are the
+ * constants defined here.
+ */
+ public static class Field extends Format.Field {
+
+ private static final long serialVersionUID = 7899943957617360810L;
+
+ /**
+ * This constant stands for the message argument.
+ */
+ public static final Field ARGUMENT = new Field("message argument field"); //$NON-NLS-1$
+
+ /**
+ * Constructs a new instance of MessageFormat.Field with the given field
+ * name.
+ * @param fieldName The field name.
+ */
+ protected Field(String fieldName) {
+ super(fieldName);
+ }
+
+ /**
+ * serialization method resolve instances to the constant
+ * MessageFormat.Field values
+ */
+ @Override
+ protected Object readResolve() throws InvalidObjectException {
+ String name = this.getName();
+ if (name == null) {
+ // text.18=Not a valid {0}, subclass should override
+ // readResolve()
+ throw new InvalidObjectException(Messages.getString(
+ "text.18", "MessageFormat.Field")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (name.equals(ARGUMENT.getName())) {
+ return ARGUMENT;
+ }
+ // text.18=Not a valid {0}, subclass should override readResolve()
+ throw new InvalidObjectException(Messages.getString(
+ "text.18", "MessageFormat.Field")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+}
diff --git a/text/src/main/java/java/text/NumberFormat.java b/text/src/main/java/java/text/NumberFormat.java
new file mode 100644
index 0000000..5289b69
--- /dev/null
+++ b/text/src/main/java/java/text/NumberFormat.java
@@ -0,0 +1,774 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * NumberFormat is the abstract superclass of Formats which format and parse
+ * Numbers.
+ */
+public abstract class NumberFormat extends Format {
+
+ private static final long serialVersionUID = -2308460125733713944L;
+
+ /**
+ * Field constant.
+ */
+ public static final int INTEGER_FIELD = 0;
+
+ /**
+ * Field constant.
+ */
+ public static final int FRACTION_FIELD = 1;
+
+ private boolean groupingUsed = true, parseIntegerOnly = false;
+
+ private int maximumIntegerDigits = 40, minimumIntegerDigits = 1,
+ maximumFractionDigits = 3, minimumFractionDigits = 0;
+
+ /**
+ * Constructs a new instance of DateFormat.
+ */
+ public NumberFormat() {
+ }
+
+ /**
+ * Returns a new NumberFormat with the same properties as this NumberFormat.
+ *
+ * @return a shallow copy of this NumberFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ return super.clone();
+ }
+
+ /**
+ * Compares the specified object to this NumberFormat and answer if they are
+ * equal. The object must be an instance of NumberFormat and have the same
+ * properties.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this NumberFormat, false
+ * otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof NumberFormat)) {
+ return false;
+ }
+ NumberFormat obj = (NumberFormat) object;
+ return groupingUsed == obj.groupingUsed
+ && parseIntegerOnly == obj.parseIntegerOnly
+ && maximumFractionDigits == obj.maximumFractionDigits
+ && maximumIntegerDigits == obj.maximumIntegerDigits
+ && minimumFractionDigits == obj.minimumFractionDigits
+ && minimumIntegerDigits == obj.minimumIntegerDigits;
+ }
+
+ /**
+ * Formats the specified double using the rules of this NumberFormat.
+ *
+ * @param value
+ * the double to format
+ * @return the formatted String
+ */
+ public final String format(double value) {
+ return format(value, new StringBuffer(), new FieldPosition(0))
+ .toString();
+ }
+
+ /**
+ * Formats the double value into the specified StringBuffer using the rules
+ * of this NumberFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param value
+ * the double to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public abstract StringBuffer format(double value, StringBuffer buffer,
+ FieldPosition field);
+
+ /**
+ * Formats the specified long using the rules of this NumberFormat.
+ *
+ * @param value
+ * the long to format
+ * @return the formatted String
+ */
+ public final String format(long value) {
+ return format(value, new StringBuffer(), new FieldPosition(0))
+ .toString();
+ }
+
+ /**
+ * Formats the long value into the specified StringBuffer using the rules of
+ * this NumberFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param value
+ * the long to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ */
+ public abstract StringBuffer format(long value, StringBuffer buffer,
+ FieldPosition field);
+
+ /**
+ * Formats the specified object into the specified StringBuffer using the
+ * rules of this DateFormat. If the field specified by the FieldPosition is
+ * formatted, set the begin and end index of the formatted field in the
+ * FieldPosition.
+ *
+ * @param object
+ * the object to format, must be a Number
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ *
+ * @exception IllegalArgumentException
+ * when the object is not a Number
+ */
+ @Override
+ public StringBuffer format(Object object, StringBuffer buffer,
+ FieldPosition field) {
+ if (object instanceof Number) {
+ double dv = ((Number) object).doubleValue();
+ long lv = ((Number) object).longValue();
+ if (dv == lv) {
+ return format(lv, buffer, field);
+ }
+ return format(dv, buffer, field);
+ }
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Gets the list of installed Locales which support NumberFormat.
+ *
+ * @return an array of Locale
+ */
+ public static Locale[] getAvailableLocales() {
+ return Locale.getAvailableLocales();
+ }
+
+ /**
+ * Returns the currency used by this number format
+ * <p>
+ * This implementation throws UnsupportedOperationException, concrete sub
+ * classes should override if they support currency formatting.
+ * <p>
+ *
+ * @return currency currency that was set in getInstance() or in
+ * setCurrency(), or null
+ * @throws java.lang.UnsupportedOperationException
+ */
+ public Currency getCurrency() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing currency for the
+ * default Locale.
+ *
+ * @return a NumberFormat
+ */
+ public final static NumberFormat getCurrencyInstance() {
+ return getCurrencyInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing currency for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a NumberFormat
+ */
+ public static NumberFormat getCurrencyInstance(Locale locale) {
+ return getInstance(locale, "Currency"); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing integers for the
+ * default Locale.
+ *
+ * @return a NumberFormat
+ */
+ public final static NumberFormat getIntegerInstance() {
+ return getIntegerInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing integers for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a NumberFormat
+ */
+ public static NumberFormat getIntegerInstance(Locale locale) {
+ NumberFormat format = getInstance(locale, "Integer"); //$NON-NLS-1$
+ format.setParseIntegerOnly(true);
+ return format;
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing numbers for the default
+ * Locale.
+ *
+ * @return a NumberFormat
+ */
+ public final static NumberFormat getInstance() {
+ return getNumberInstance();
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing numbers for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a NumberFormat
+ */
+ public static NumberFormat getInstance(Locale locale) {
+ return getNumberInstance(locale);
+ }
+
+ static NumberFormat getInstance(Locale locale, String type) {
+ return new DecimalFormat(getPattern(locale, type),
+ new DecimalFormatSymbols(locale));
+ }
+
+ /**
+ * Returns the maximum number of fraction digits that are printed when
+ * formatting. If the maximum is less than the number of fraction digits,
+ * the least significant digits are truncated.
+ *
+ * @return the maximum number of fraction digits
+ */
+ public int getMaximumFractionDigits() {
+ return maximumFractionDigits;
+ }
+
+ /**
+ * Returns the maximum number of integer digits that are printed when
+ * formatting. If the maximum is less than the number of integer digits, the
+ * most significant digits are truncated.
+ *
+ * @return the maximum number of integer digits
+ */
+ public int getMaximumIntegerDigits() {
+ return maximumIntegerDigits;
+ }
+
+ /**
+ * Returns the minimum number of fraction digits that are printed when
+ * formatting.
+ *
+ * @return the minimum number of fraction digits
+ */
+ public int getMinimumFractionDigits() {
+ return minimumFractionDigits;
+ }
+
+ /**
+ * Returns the minimum number of integer digits that are printed when
+ * formatting.
+ *
+ * @return the minimum number of integer digits
+ */
+ public int getMinimumIntegerDigits() {
+ return minimumIntegerDigits;
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing numbers for the default
+ * Locale.
+ *
+ * @return a NumberFormat
+ */
+ public final static NumberFormat getNumberInstance() {
+ return getNumberInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing numbers for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a NumberFormat
+ */
+ public static NumberFormat getNumberInstance(Locale locale) {
+ return getInstance(locale, "Number"); //$NON-NLS-1$
+ }
+
+ static String getPattern(Locale locale, String type) {
+ ResourceBundle bundle = getBundle(locale);
+ return bundle.getString(type);
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing percentages for the
+ * default Locale.
+ *
+ * @return a NumberFormat
+ */
+ public final static NumberFormat getPercentInstance() {
+ return getPercentInstance(Locale.getDefault());
+ }
+
+ /**
+ * Returns a NumberFormat for formatting and parsing percentages for the
+ * specified Locale.
+ *
+ * @param locale
+ * the Locale
+ * @return a NumberFormat
+ */
+ public static NumberFormat getPercentInstance(Locale locale) {
+ return getInstance(locale, "Percent"); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return (groupingUsed ? 1231 : 1237) + (parseIntegerOnly ? 1231 : 1237)
+ + maximumFractionDigits + maximumIntegerDigits
+ + minimumFractionDigits + minimumIntegerDigits;
+ }
+
+ /**
+ * Returns whether this NumberFormat formats and parses numbers using a
+ * grouping separator.
+ *
+ * @return true when a grouping separator is used, false otherwise
+ */
+ public boolean isGroupingUsed() {
+ return groupingUsed;
+ }
+
+ /**
+ * Returns whether this NumberFormat only parses integer numbers. Parsing
+ * stops if a decimal separator is encountered.
+ *
+ * @return true if this NumberFormat only parses integers, false for parsing
+ * integers or fractions
+ */
+ public boolean isParseIntegerOnly() {
+ return parseIntegerOnly;
+ }
+
+ /**
+ * Parse a Number from the specified String using the rules of this
+ * NumberFormat.
+ *
+ * @param string
+ * the String to parse
+ * @return the Number resulting from the parse
+ *
+ * @exception ParseException
+ * when an error occurs during parsing
+ */
+ public Number parse(String string) throws ParseException {
+ ParsePosition pos = new ParsePosition(0);
+ Number number = parse(string, pos);
+ if (pos.getErrorIndex() != -1 || pos.getIndex() == 0) {
+ throw new ParseException(null, pos.getErrorIndex());
+ }
+ return number;
+ }
+
+ /**
+ * Parse a Number from the specified String starting at the index specified
+ * by the ParsePosition. If the string is successfully parsed, the index of
+ * the ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the Number resulting from the parse, or null if there is an error
+ */
+ public abstract Number parse(String string, ParsePosition position);
+
+ /**
+ * Parse a Number from the specified String starting at the index specified
+ * by the ParsePosition. If the string is successfully parsed, the index of
+ * the ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the Number resulting from the parse, or null if there is an error
+ */
+ @Override
+ public final Object parseObject(String string, ParsePosition position) {
+ if (position == null) {
+ // text.1A=position is null
+ throw new NullPointerException(Messages.getString("text.1A")); //$NON-NLS-1$
+ }
+
+ try {
+ return parse(string, position);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the currency used by this number format when formatting currency
+ * values.
+ * <p>
+ * The min and max fraction digits remain the same.
+ * <p>
+ * This implementation throws UnsupportedOperationException, concrete sub
+ * classes should override if they support currency formatting.
+ * <p>
+ *
+ * @param currency
+ * the new Currency
+ * @throws java.lang.UnsupportedOperationException
+ */
+ public void setCurrency(Currency currency) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets whether this NumberFormat formats and parses numbers using a
+ * grouping separator.
+ *
+ * @param value
+ * true when a grouping separator is used, false otherwise
+ */
+ public void setGroupingUsed(boolean value) {
+ groupingUsed = value;
+ }
+
+ /**
+ * Sets the maximum number of fraction digits that are printed when
+ * formatting. If the maximum is less than the number of fraction digits,
+ * the least significant digits are truncated.
+ *
+ * @param value
+ * the maximum number of fraction digits
+ */
+ public void setMaximumFractionDigits(int value) {
+ maximumFractionDigits = value < 0 ? 0 : value;
+ if (maximumFractionDigits < minimumFractionDigits) {
+ minimumFractionDigits = maximumFractionDigits;
+ }
+ }
+
+ /**
+ * Used to specify the new maximum count of integer digits that are printed
+ * when formatting. If the maximum is less than the number of integer
+ * digits, the most significant digits are truncated.
+ *
+ * @param value
+ * the new maximum number of integer numerals for display
+ */
+ public void setMaximumIntegerDigits(int value) {
+ maximumIntegerDigits = value < 0 ? 0 : value;
+ if (maximumIntegerDigits < minimumIntegerDigits) {
+ minimumIntegerDigits = maximumIntegerDigits;
+ }
+ }
+
+ /**
+ * Sets the minimum number of fraction digits that are printed when
+ * formatting.
+ *
+ * @param value
+ * the minimum number of fraction digits
+ */
+ public void setMinimumFractionDigits(int value) {
+ minimumFractionDigits = value < 0 ? 0 : value;
+ if (maximumFractionDigits < minimumFractionDigits) {
+ maximumFractionDigits = minimumFractionDigits;
+ }
+ }
+
+ /**
+ * Sets the minimum number of integer digits that are printed when
+ * formatting.
+ *
+ * @param value
+ * the minimum number of integer digits
+ */
+ public void setMinimumIntegerDigits(int value) {
+ minimumIntegerDigits = value < 0 ? 0 : value;
+ if (maximumIntegerDigits < minimumIntegerDigits) {
+ maximumIntegerDigits = minimumIntegerDigits;
+ }
+ }
+
+ /**
+ * Specifies if this NumberFormat should only parse numbers as integers or
+ * else as any kind of number. If this is called with a <code>true</code>
+ * value then subsequent parsing attempts will stop if a decimal separator
+ * is encountered.
+ *
+ * @param value
+ * <code>true</code> to only parse integers, <code>false</code>
+ * to parse integers and fractions
+ */
+ public void setParseIntegerOnly(boolean value) {
+ parseIntegerOnly = value;
+ }
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("groupingUsed", Boolean.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("maxFractionDigits", Byte.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("maximumFractionDigits", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("maximumIntegerDigits", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("maxIntegerDigits", Byte.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("minFractionDigits", Byte.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("minimumFractionDigits", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("minimumIntegerDigits", Integer.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("minIntegerDigits", Byte.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("parseIntegerOnly", Boolean.TYPE), //$NON-NLS-1$
+ new ObjectStreamField("serialVersionOnStream", Integer.TYPE), }; //$NON-NLS-1$
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("groupingUsed", groupingUsed); //$NON-NLS-1$
+ fields
+ .put(
+ "maxFractionDigits", //$NON-NLS-1$
+ maximumFractionDigits < Byte.MAX_VALUE ? (byte) maximumFractionDigits
+ : Byte.MAX_VALUE);
+ fields.put("maximumFractionDigits", maximumFractionDigits); //$NON-NLS-1$
+ fields.put("maximumIntegerDigits", maximumIntegerDigits); //$NON-NLS-1$
+ fields
+ .put(
+ "maxIntegerDigits", //$NON-NLS-1$
+ maximumIntegerDigits < Byte.MAX_VALUE ? (byte) maximumIntegerDigits
+ : Byte.MAX_VALUE);
+ fields
+ .put(
+ "minFractionDigits", //$NON-NLS-1$
+ minimumFractionDigits < Byte.MAX_VALUE ? (byte) minimumFractionDigits
+ : Byte.MAX_VALUE);
+ fields.put("minimumFractionDigits", minimumFractionDigits); //$NON-NLS-1$
+ fields.put("minimumIntegerDigits", minimumIntegerDigits); //$NON-NLS-1$
+ fields
+ .put(
+ "minIntegerDigits", //$NON-NLS-1$
+ minimumIntegerDigits < Byte.MAX_VALUE ? (byte) minimumIntegerDigits
+ : Byte.MAX_VALUE);
+ fields.put("parseIntegerOnly", parseIntegerOnly); //$NON-NLS-1$
+ fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
+ stream.writeFields();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = stream.readFields();
+ groupingUsed = fields.get("groupingUsed", true); //$NON-NLS-1$
+ parseIntegerOnly = fields.get("parseIntegerOnly", false); //$NON-NLS-1$
+ if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$
+ maximumFractionDigits = fields.get("maxFractionDigits", (byte) 3); //$NON-NLS-1$
+ maximumIntegerDigits = fields.get("maxIntegerDigits", (byte) 40); //$NON-NLS-1$
+ minimumFractionDigits = fields.get("minFractionDigits", (byte) 0); //$NON-NLS-1$
+ minimumIntegerDigits = fields.get("minIntegerDigits", (byte) 1); //$NON-NLS-1$
+ } else {
+ maximumFractionDigits = fields.get("maximumFractionDigits", 3); //$NON-NLS-1$
+ maximumIntegerDigits = fields.get("maximumIntegerDigits", 40); //$NON-NLS-1$
+ minimumFractionDigits = fields.get("minimumFractionDigits", 0); //$NON-NLS-1$
+ minimumIntegerDigits = fields.get("minimumIntegerDigits", 1); //$NON-NLS-1$
+ }
+ if (minimumIntegerDigits > maximumIntegerDigits
+ || minimumFractionDigits > maximumFractionDigits) {
+ // text.00=min digits greater than max digits
+ throw new InvalidObjectException(Messages.getString("text.00")); //$NON-NLS-1$
+ }
+ if (minimumIntegerDigits < 0 || maximumIntegerDigits < 0
+ || minimumFractionDigits < 0 || maximumFractionDigits < 0) {
+ // text.01=min or max digits negative
+ throw new InvalidObjectException(Messages.getString("text.01")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * The instances of this inner class are used as attribute keys and values
+ * in AttributedCharacterIterator that
+ * NumberFormat.formatToCharacterIterator() method returns.
+ * <p>
+ * There is no public constructor to this class, the only instances are the
+ * constants defined here.
+ * <p>
+ */
+ public static class Field extends Format.Field {
+
+ private static final long serialVersionUID = 7494728892700160890L;
+
+ /**
+ * This constant stands for the number sign.
+ */
+ public static final Field SIGN = new Field("sign"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the integer part of the number.
+ */
+ public static final Field INTEGER = new Field("integer"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the fraction part of the number.
+ */
+ public static final Field FRACTION = new Field("fraction"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the exponent part of the number.
+ */
+ public static final Field EXPONENT = new Field("exponent"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the exponent sign symbol.
+ */
+ public static final Field EXPONENT_SIGN = new Field("exponent sign"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the exponent symbol.
+ */
+ public static final Field EXPONENT_SYMBOL = new Field("exponent symbol"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the decimal separator.
+ */
+ public static final Field DECIMAL_SEPARATOR = new Field(
+ "decimal separator"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the grouping separator.
+ */
+ public static final Field GROUPING_SEPARATOR = new Field(
+ "grouping separator"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the percent symbol.
+ */
+ public static final Field PERCENT = new Field("percent"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the permille symbol.
+ */
+ public static final Field PERMILLE = new Field("per mille"); //$NON-NLS-1$
+
+ /**
+ * This constant stands for the currency symbol.
+ */
+ public static final Field CURRENCY = new Field("currency"); //$NON-NLS-1$
+
+ /**
+ * Constructs a new instance of NumberFormat.Field with the given field
+ * name.
+ *
+ * @param fieldName The field name.
+ */
+ protected Field(String fieldName) {
+ super(fieldName);
+ }
+
+ /**
+ * serialization method resolve instances to the constant
+ * NumberFormat.Field values
+ */
+ @Override
+ protected Object readResolve() throws InvalidObjectException {
+ if (this.equals(INTEGER)) {
+ return INTEGER;
+ }
+ if (this.equals(FRACTION)) {
+ return FRACTION;
+ }
+ if (this.equals(EXPONENT)) {
+ return EXPONENT;
+ }
+ if (this.equals(EXPONENT_SIGN)) {
+ return EXPONENT_SIGN;
+ }
+ if (this.equals(EXPONENT_SYMBOL)) {
+ return EXPONENT_SYMBOL;
+ }
+ if (this.equals(CURRENCY)) {
+ return CURRENCY;
+ }
+ if (this.equals(DECIMAL_SEPARATOR)) {
+ return DECIMAL_SEPARATOR;
+ }
+ if (this.equals(GROUPING_SEPARATOR)) {
+ return GROUPING_SEPARATOR;
+ }
+ if (this.equals(PERCENT)) {
+ return PERCENT;
+ }
+ if (this.equals(PERMILLE)) {
+ return PERMILLE;
+ }
+ if (this.equals(SIGN)) {
+ return SIGN;
+ }
+ // text.02=Unknown attribute
+ throw new InvalidObjectException(Messages.getString("text.02")); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/text/src/main/java/java/text/ParseException.java b/text/src/main/java/java/text/ParseException.java
new file mode 100644
index 0000000..b8b4226
--- /dev/null
+++ b/text/src/main/java/java/text/ParseException.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * A ParseException is thrown when the String being parsed is not in the correct
+ * form.
+ */
+public class ParseException extends Exception {
+
+ private static final long serialVersionUID = 2703218443322787634L;
+
+ private int errorOffset;
+
+ /**
+ * Constructs a new instance of this class with its walkback, message and
+ * the location of the error filled in.
+ *
+ * @param detailMessage
+ * String The detail message for the exception.
+ * @param location
+ * int The index at which the parse exception occurred.
+ */
+ public ParseException(String detailMessage, int location) {
+ super(detailMessage);
+ errorOffset = location;
+ }
+
+ /**
+ * Returns the index at which the parse exception occurred.
+ *
+ * @return int The index of the parse exception.
+ */
+ public int getErrorOffset() {
+ return errorOffset;
+ }
+}
diff --git a/text/src/main/java/java/text/ParsePosition.java b/text/src/main/java/java/text/ParsePosition.java
new file mode 100644
index 0000000..e59b841
--- /dev/null
+++ b/text/src/main/java/java/text/ParsePosition.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * ParsePosition is used to track the current position in a String being parsed.
+ */
+public class ParsePosition {
+
+ private int currentPosition, errorIndex = -1;
+
+ /**
+ * Constructs a new ParsePosition at the specified index.
+ *
+ * @param index
+ * the index to begin parsing
+ */
+ public ParsePosition(int index) {
+ currentPosition = index;
+ }
+
+ /**
+ * Compares the specified object to this ParsePosition and answer if they
+ * are equal. The object must be an instance of ParsePosition and have the
+ * same index and error index.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this ParsePosition,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof ParsePosition)) {
+ return false;
+ }
+ ParsePosition pos = (ParsePosition) object;
+ return currentPosition == pos.currentPosition
+ && errorIndex == pos.errorIndex;
+ }
+
+ /**
+ * Returns the index at which the parse could not continue.
+ *
+ * @return the index of the parse error, or -1 if there is no error
+ */
+ public int getErrorIndex() {
+ return errorIndex;
+ }
+
+ /**
+ * Returns the current parse position.
+ *
+ * @return the current position
+ */
+ public int getIndex() {
+ return currentPosition;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return currentPosition + errorIndex;
+ }
+
+ /**
+ * Sets the index at which the parse could not continue.
+ *
+ * @param index
+ * the index of the parse error
+ */
+ public void setErrorIndex(int index) {
+ errorIndex = index;
+ }
+
+ /**
+ * Sets the current parse position.
+ *
+ * @param index
+ * the current parse position
+ */
+ public void setIndex(int index) {
+ currentPosition = index;
+ }
+
+ /**
+ * Returns the string representation of this FieldPosition.
+ *
+ * @return the string representation of this FieldPosition
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[index=" + currentPosition //$NON-NLS-1$
+ + ", errorIndex=" + errorIndex + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/text/src/main/java/java/text/RuleBasedBreakIterator.java b/text/src/main/java/java/text/RuleBasedBreakIterator.java
new file mode 100644
index 0000000..a08fd9f
--- /dev/null
+++ b/text/src/main/java/java/text/RuleBasedBreakIterator.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/*
+ * Default implementation of BreakIterator, wrap
+ * com.ibm.icu.text.RuleBasedBreakIterator
+ *
+ */
+class RuleBasedBreakIterator extends BreakIterator {
+
+ /*
+ * Wrapping construction
+ */
+ RuleBasedBreakIterator(com.ibm.icu4jni.text.BreakIterator iterator) {
+ super(iterator);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#current()
+ */
+ @Override
+ public int current() {
+ return wrapped.current();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#first()
+ */
+ @Override
+ public int first() {
+ return wrapped.first();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#following(int)
+ */
+ @Override
+ public int following(int offset) {
+ validateOffset(offset);
+ return wrapped.following(offset);
+ }
+
+ /*
+ * check the offset, throw exception if it is invalid
+ */
+ private void validateOffset(int offset) {
+ CharacterIterator it = wrapped.getText();
+ if (offset < it.getBeginIndex() || offset >= it.getEndIndex()) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#getText()
+ */
+ @Override
+ public CharacterIterator getText() {
+ return wrapped.getText();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#last()
+ */
+ @Override
+ public int last() {
+ return wrapped.last();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#next()
+ */
+ @Override
+ public int next() {
+ return wrapped.next();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#next(int)
+ */
+ @Override
+ public int next(int n) {
+ return wrapped.next(n);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#previous()
+ */
+ @Override
+ public int previous() {
+ return wrapped.previous();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
+ */
+ @Override
+ public void setText(CharacterIterator newText) {
+ // call a method to check if null pointer
+ newText.current();
+ wrapped.setText(newText);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#isBoundary(int)
+ */
+ @Override
+ public boolean isBoundary(int offset) {
+ validateOffset(offset);
+ return wrapped.isBoundary(offset);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.text.BreakIterator#preceding(int)
+ */
+ @Override
+ public int preceding(int offset) {
+ validateOffset(offset);
+ return wrapped.preceding(offset);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RuleBasedBreakIterator)) {
+ return false;
+ }
+ return wrapped.equals(((RuleBasedBreakIterator) o).wrapped);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return wrapped.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return wrapped.hashCode();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public Object clone() {
+ RuleBasedBreakIterator cloned = (RuleBasedBreakIterator) super.clone();
+ cloned.wrapped = (com.ibm.icu4jni.text.RuleBasedBreakIterator) wrapped
+ .clone();
+ return cloned;
+ }
+
+}
diff --git a/text/src/main/java/java/text/RuleBasedCollator.java b/text/src/main/java/java/text/RuleBasedCollator.java
new file mode 100644
index 0000000..c3cd531
--- /dev/null
+++ b/text/src/main/java/java/text/RuleBasedCollator.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * <code>RuleBasedCollator</code> is a concrete subclass of
+ * <code>Collator</code>. It allows customization of the
+ * <code>Collator</code> via user-specified rule sets.
+ * <code>RuleBasedCollator</code> is designed to be fully compliant to the <a
+ * href="http://www.unicode.org/unicode/reports/tr10/"> Unicode Collation
+ * Algorithm (UCA) </a> and conforms to ISO 14651.
+ * </p>
+ * <p>
+ * Create a <code>RuleBasedCollator</code> from a locale by calling the
+ * <code>getInstance(Locale)</code> factory method in the base class
+ * <code>Collator</code>.<code>Collator.getInstance(Locale)</code> creates
+ * a <code>RuleBasedCollator</code> object based on the collation rules
+ * defined by the argument locale. If a customized collation is required, use
+ * the <code>RuleBasedCollator(String)</code> constructor with the appropriate
+ * rules. The customized <code>RuleBasedCollator</code> will base its ordering
+ * on UCA, while re-adjusting the attributes and orders of the characters in the
+ * specified rule accordingly.
+ * </p>
+ *
+ */
+public class RuleBasedCollator extends Collator {
+
+ RuleBasedCollator(com.ibm.icu4jni.text.Collator wrapper) {
+ super(wrapper);
+ }
+
+ /**
+ * Constructs a new instance of <code>RuleBasedCollator</code> using the
+ * specified <code>rules</code>.
+ *
+ * @param rules
+ * the collation rules.
+ * @throws ParseException
+ * when the rules contains an invalid collation rule syntax.
+ */
+ public RuleBasedCollator(String rules) throws ParseException {
+ if (rules == null) {
+ throw new NullPointerException();
+ }
+ if (rules.length() == 0) {
+ // text.06=Build rules empty
+ throw new ParseException(Messages.getString("text.06"), 0); //$NON-NLS-1$
+ }
+
+ try {
+ this.icuColl = new com.ibm.icu4jni.text.RuleBasedCollator(rules);
+ } catch (Exception e) {
+ if (e instanceof ParseException) {
+ throw (ParseException) e;
+ }
+ /*
+ * -1 means it's not a ParseException. Maybe IOException thrown when
+ * an error occured while reading internal data.
+ */
+ throw new ParseException(e.getMessage(), -1);
+ }
+ }
+
+ /**
+ * Obtains a <code>CollationElementIterator</code> for the given
+ * <code>CharacterIterator</code>. The source iterator's integrity will
+ * be preserved since a new copy will be created for use.
+ *
+ * @param source
+ * the specified source
+ * @return a <code>CollationElementIterator</code> for the source.
+ */
+ public CollationElementIterator getCollationElementIterator(
+ CharacterIterator source) {
+ if (source == null) {
+ throw new NullPointerException();
+ }
+ return new CollationElementIterator(
+ ((com.ibm.icu4jni.text.RuleBasedCollator) this.icuColl)
+ .getCollationElementIterator(source));
+ }
+
+ /**
+ * Obtains a <code>CollationElementIterator</code> for the given String.
+ *
+ * @param source
+ * the specified source
+ * @return a <code>CollationElementIterator</code> for the given String
+ */
+ public CollationElementIterator getCollationElementIterator(String source) {
+ if (source == null) {
+ throw new NullPointerException();
+ }
+ return new CollationElementIterator(
+ ((com.ibm.icu4jni.text.RuleBasedCollator) this.icuColl)
+ .getCollationElementIterator(source));
+ }
+
+ /**
+ * Obtains the collation rules of the <code>RuleBasedCollator</code>.
+ *
+ * @return the collation rules.
+ */
+ public String getRules() {
+ return ((com.ibm.icu4jni.text.RuleBasedCollator) this.icuColl).getRules();
+ }
+
+ /**
+ * Obtains the cloned object of the <code>RuleBasedCollator</code>
+ *
+ * @return the cloned object of the <code>RuleBasedCollator</code>
+ */
+ @Override
+ public Object clone() {
+ RuleBasedCollator clone = (RuleBasedCollator) super.clone();
+ return clone;
+ }
+
+ /**
+ * Compares the <code>source</code> text <code>String</code> to the
+ * <code>target</code> text <code>String</code> according to the
+ * collation rules, strength and decomposition mode for this
+ * <code>RuleBasedCollator</code>. See the <code>Collator</code> class
+ * description for an example of use.
+ * <p>
+ * General recommendation: If comparisons are to be done to the same String
+ * multiple times, it would be more efficient to generate
+ * <code>CollationKeys</code> for the <code>String</code> s and use
+ * <code>CollationKey.compareTo(CollationKey)</code> for the comparisons.
+ * If the each Strings are compared to only once, using the method
+ * RuleBasedCollator.compare(String, String) will have a better performance.
+ * </p>
+ *
+ * @param source
+ * the source text
+ * @param target
+ * the target text
+ * @return an integer which may be a negative value, zero, or else a
+ * positive value depending on whether <code>source</code> is less
+ * than, equivalent to, or greater than <code>target</code>.
+ */
+ @Override
+ public int compare(String source, String target) {
+ if (source == null || target == null) {
+ // text.08=one of arguments is null
+ throw new NullPointerException(Messages.getString("text.08")); //$NON-NLS-1$
+ }
+ return this.icuColl.compare(source, target);
+ }
+
+ /**
+ * Obtains the <code>CollationKey</code> for the given source text.
+ *
+ * @param source
+ * the specified source text
+ * @return the <code>CollationKey</code> for the given source text.
+ */
+ @Override
+ public CollationKey getCollationKey(String source) {
+ com.ibm.icu4jni.text.CollationKey icuKey = this.icuColl
+ .getCollationKey(source);
+ if (icuKey == null) {
+ return null;
+ }
+ return new CollationKey(source, icuKey);
+ }
+
+ /**
+ * Obtains a unique hash code for the <code>RuleBasedCollator</code>
+ *
+ * @return the hash code for the <code>RuleBasedCollator</code>
+ */
+ @Override
+ public int hashCode() {
+ return ((com.ibm.icu4jni.text.RuleBasedCollator) this.icuColl).getRules()
+ .hashCode();
+ }
+
+ /**
+ * Compares the equality of two <code>RuleBasedCollator</code> objects.
+ * <code>RuleBasedCollator</code> objects are equal if they have the same
+ * collation rules and the same attributes.
+ *
+ * @param obj
+ * the other object.
+ * @return <code>true</code> if this <code>RuleBasedCollator</code> has
+ * exactly the same collation behaviour as obj, <code>false</code>
+ * otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Collator)) {
+ return false;
+ }
+ return super.equals(obj);
+ }
+}
diff --git a/text/src/main/java/java/text/SimpleDateFormat.java b/text/src/main/java/java/text/SimpleDateFormat.java
new file mode 100644
index 0000000..70bdf9b
--- /dev/null
+++ b/text/src/main/java/java/text/SimpleDateFormat.java
@@ -0,0 +1,1087 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import org.apache.harmony.text.internal.nls.Messages;
+
+/**
+ * SimpleDateFormat is used to format and parse Gregorian calendar dates and
+ * times based on a pattern of date and time fields. Each date and time field is
+ * specified in the pattern by a specific character. The characters used can be
+ * either localized or non-localized. For some fields, which have both numeric
+ * and text representations or abbreviated as well as full names, the number of
+ * grouped characters specifies how the field is formatted or parsed.
+ */
+public class SimpleDateFormat extends DateFormat {
+
+ private static final long serialVersionUID = 4774881970558875024L;
+
+ private static final String patternChars = "GyMdkHmsSEDFwWahKzZ"; //$NON-NLS-1$
+
+ private String pattern;
+
+ private DateFormatSymbols formatData;
+
+ transient private int creationYear;
+
+ private Date defaultCenturyStart;
+
+ /**
+ * Constructs a new SimpleDateFormat for formatting and parsing dates and
+ * times in the SHORT style for the default Locale.
+ */
+ public SimpleDateFormat() {
+ this(Locale.getDefault());
+ pattern = defaultPattern();
+ formatData = new DateFormatSymbols(Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new SimpleDateFormat using the specified non-localized
+ * pattern and the DateFormatSymbols and Calendar for the default Locale.
+ *
+ * @param pattern
+ * the pattern
+ *
+ * @exception NullPointerException
+ * if a <code>null</code> value of <code>pattern</code>
+ * is supplied.
+ * @exception IllegalArgumentException
+ * if <code>pattern</code> is not considered to be useable
+ * by this formatter.
+ */
+ public SimpleDateFormat(String pattern) {
+ this(pattern, Locale.getDefault());
+ }
+
+ /**
+ * Constructs a new SimpleDateFormat using the specified non-localized
+ * pattern and DateFormatSymbols and the Calendar for the default Locale.
+ *
+ * @param template
+ * the pattern
+ * @param value
+ * the DateFormatSymbols
+ *
+ * @exception NullPointerException
+ * if the pattern is null
+ * @exception IllegalArgumentException
+ * if the pattern is invalid
+ */
+ public SimpleDateFormat(String template, DateFormatSymbols value) {
+ this(Locale.getDefault());
+ validatePattern(template);
+ pattern = template;
+ formatData = (DateFormatSymbols) value.clone();
+ }
+
+ /**
+ * Constructs a new SimpleDateFormat using the specified non-localized
+ * pattern and the DateFormatSymbols and Calendar for the specified Locale.
+ *
+ * @param template
+ * the pattern
+ * @param locale
+ * the Locale
+ *
+ * @exception NullPointerException
+ * if the pattern is null
+ * @exception IllegalArgumentException
+ * if the pattern is invalid
+ */
+ public SimpleDateFormat(String template, Locale locale) {
+ this(locale);
+ validatePattern(template);
+ pattern = template;
+ formatData = new DateFormatSymbols(locale);
+ }
+
+ private SimpleDateFormat(Locale locale) {
+ numberFormat = NumberFormat.getInstance(locale);
+ numberFormat.setParseIntegerOnly(true);
+ numberFormat.setGroupingUsed(false);
+ calendar = new GregorianCalendar(locale);
+ calendar.add(Calendar.YEAR, -80);
+ creationYear = calendar.get(Calendar.YEAR);
+ defaultCenturyStart = calendar.getTime();
+ }
+
+ private void append(StringBuffer buffer, FieldPosition position,
+ Vector<FieldPosition> fields, char format, int count) {
+ int field = -1;
+ int index = patternChars.indexOf(format);
+ if (index == -1) {
+ // text.03=Unknown pattern character - '{0}'
+ throw new IllegalArgumentException(Messages.getString(
+ "text.03", format)); //$NON-NLS-1$
+ }
+
+ int beginPosition = buffer.length();
+ Field dateFormatField = null;
+
+ switch (index) {
+ case ERA_FIELD:
+ dateFormatField = Field.ERA;
+ buffer.append(formatData.eras[calendar.get(Calendar.ERA)]);
+ break;
+ case YEAR_FIELD:
+ dateFormatField = Field.YEAR;
+ int year = calendar.get(Calendar.YEAR);
+ if (count < 4) {
+ appendNumber(buffer, 2, year %= 100);
+ } else {
+ appendNumber(buffer, count, year);
+ }
+ break;
+ case MONTH_FIELD:
+ dateFormatField = Field.MONTH;
+ int month = calendar.get(Calendar.MONTH);
+ if (count <= 2) {
+ appendNumber(buffer, count, month + 1);
+ } else if (count == 3) {
+ buffer.append(formatData.shortMonths[month]);
+ } else {
+ buffer.append(formatData.months[month]);
+ }
+ break;
+ case DATE_FIELD:
+ dateFormatField = Field.DAY_OF_MONTH;
+ field = Calendar.DATE;
+ break;
+ case HOUR_OF_DAY1_FIELD: // k
+ dateFormatField = Field.HOUR_OF_DAY1;
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ appendNumber(buffer, count, hour == 0 ? 24 : hour);
+ break;
+ case HOUR_OF_DAY0_FIELD: // H
+ dateFormatField = Field.HOUR_OF_DAY0;
+ field = Calendar.HOUR_OF_DAY;
+ break;
+ case MINUTE_FIELD:
+ dateFormatField = Field.MINUTE;
+ field = Calendar.MINUTE;
+ break;
+ case SECOND_FIELD:
+ dateFormatField = Field.SECOND;
+ field = Calendar.SECOND;
+ break;
+ case MILLISECOND_FIELD:
+ dateFormatField = Field.MILLISECOND;
+ int value = calendar.get(Calendar.MILLISECOND);
+ appendNumber(buffer, count, value);
+ break;
+ case DAY_OF_WEEK_FIELD:
+ dateFormatField = Field.DAY_OF_WEEK;
+ int day = calendar.get(Calendar.DAY_OF_WEEK);
+ if (count < 4) {
+ buffer.append(formatData.shortWeekdays[day]);
+ } else {
+ buffer.append(formatData.weekdays[day]);
+ }
+ break;
+ case DAY_OF_YEAR_FIELD:
+ dateFormatField = Field.DAY_OF_YEAR;
+ field = Calendar.DAY_OF_YEAR;
+ break;
+ case DAY_OF_WEEK_IN_MONTH_FIELD:
+ dateFormatField = Field.DAY_OF_WEEK_IN_MONTH;
+ field = Calendar.DAY_OF_WEEK_IN_MONTH;
+ break;
+ case WEEK_OF_YEAR_FIELD:
+ dateFormatField = Field.WEEK_OF_YEAR;
+ field = Calendar.WEEK_OF_YEAR;
+ break;
+ case WEEK_OF_MONTH_FIELD:
+ dateFormatField = Field.WEEK_OF_MONTH;
+ field = Calendar.WEEK_OF_MONTH;
+ break;
+ case AM_PM_FIELD:
+ dateFormatField = Field.AM_PM;
+ buffer.append(formatData.ampms[calendar.get(Calendar.AM_PM)]);
+ break;
+ case HOUR1_FIELD: // h
+ dateFormatField = Field.HOUR1;
+ hour = calendar.get(Calendar.HOUR);
+ appendNumber(buffer, count, hour == 0 ? 12 : hour);
+ break;
+ case HOUR0_FIELD: // K
+ dateFormatField = Field.HOUR0;
+ field = Calendar.HOUR;
+ break;
+ case TIMEZONE_FIELD: // z
+ dateFormatField = Field.TIME_ZONE;
+ appendTimeZone(buffer, count, true);
+ break;
+ case (TIMEZONE_FIELD + 1): // Z
+ dateFormatField = Field.TIME_ZONE;
+ appendTimeZone(buffer, count, false);
+ break;
+ }
+ if (field != -1) {
+ appendNumber(buffer, count, calendar.get(field));
+ }
+
+ if (fields != null) {
+ position = new FieldPosition(dateFormatField);
+ position.setBeginIndex(beginPosition);
+ position.setEndIndex(buffer.length());
+ fields.add(position);
+ } else {
+ // Set to the first occurrence
+ if ((position.getFieldAttribute() == dateFormatField || (position
+ .getFieldAttribute() == null && position.getField() == index))
+ && position.getEndIndex() == 0) {
+ position.setBeginIndex(beginPosition);
+ position.setEndIndex(buffer.length());
+ }
+ }
+ }
+
+ private void appendTimeZone(StringBuffer buffer, int count,
+ boolean generalTimezone) {
+ // cannot call TimeZone.getDisplayName() because it would not use
+ // the DateFormatSymbols of this SimpleDateFormat
+
+ if (generalTimezone) {
+ String id = calendar.getTimeZone().getID();
+// BEGIN android-changed
+ String[][] zones = formatData.internalZoneStrings();
+// END android-changed
+ String[] zone = null;
+ for (String[] element : zones) {
+ if (id.equals(element[0])) {
+ zone = element;
+ break;
+ }
+ }
+ if (zone == null) {
+ int offset = calendar.get(Calendar.ZONE_OFFSET)
+ + calendar.get(Calendar.DST_OFFSET);
+ char sign = '+';
+ if (offset < 0) {
+ sign = '-';
+ offset = -offset;
+ }
+ buffer.append("GMT"); //$NON-NLS-1$
+ buffer.append(sign);
+ appendNumber(buffer, 2, offset / 3600000);
+ buffer.append(':');
+ appendNumber(buffer, 2, (offset % 3600000) / 60000);
+ } else {
+ int daylight = calendar.get(Calendar.DST_OFFSET) == 0 ? 0 : 2;
+ if (count < 4) {
+ buffer.append(zone[2 + daylight]);
+ } else {
+ buffer.append(zone[1 + daylight]);
+ }
+ }
+ } else {
+ int offset = calendar.get(Calendar.ZONE_OFFSET)
+ + calendar.get(Calendar.DST_OFFSET);
+ char sign = '+';
+ if (offset < 0) {
+ sign = '-';
+ offset = -offset;
+ }
+ buffer.append(sign);
+ appendNumber(buffer, 2, offset / 3600000);
+ appendNumber(buffer, 2, (offset % 3600000) / 60000);
+ }
+ }
+
+ private void appendNumber(StringBuffer buffer, int count, int value) {
+ int minimumIntegerDigits = numberFormat.getMinimumIntegerDigits();
+ numberFormat.setMinimumIntegerDigits(count);
+ numberFormat.format(new Integer(value), buffer, new FieldPosition(0));
+ numberFormat.setMinimumIntegerDigits(minimumIntegerDigits);
+ }
+
+ /**
+ * Changes the pattern of this SimpleDateFormat to the specified pattern
+ * which uses localized pattern characters.
+ *
+ * @param template
+ * the localized pattern
+ */
+ public void applyLocalizedPattern(String template) {
+ pattern = convertPattern(template, formatData.getLocalPatternChars(),
+ patternChars, true);
+ }
+
+ /**
+ * Changes the pattern of this SimpleDateFormat to the specified pattern
+ * which uses non-localized pattern characters.
+ *
+ * @param template
+ * the non-localized pattern
+ *
+ * @exception NullPointerException
+ * if the pattern is null
+ * @exception IllegalArgumentException
+ * if the pattern is invalid
+ */
+ public void applyPattern(String template) {
+ validatePattern(template);
+ pattern = template;
+ }
+
+ /**
+ * Returns a new SimpleDateFormat with the same pattern and properties as
+ * this SimpleDateFormat.
+ *
+ * @return a shallow copy of this SimpleDateFormat
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ SimpleDateFormat clone = (SimpleDateFormat) super.clone();
+ clone.formatData = (DateFormatSymbols) formatData.clone();
+ clone.defaultCenturyStart = new Date(defaultCenturyStart.getTime());
+ return clone;
+ }
+
+ private static String defaultPattern() {
+ ResourceBundle bundle = getBundle(Locale.getDefault());
+ String styleName = getStyleName(SHORT);
+ return bundle.getString("Date_" + styleName) + " " //$NON-NLS-1$ //$NON-NLS-2$
+ + bundle.getString("Time_" + styleName); //$NON-NLS-1$
+ }
+
+ /**
+ * Compares the specified object to this SimpleDateFormat and answer if they
+ * are equal. The object must be an instance of SimpleDateFormat and have
+ * the same DateFormat properties, pattern, DateFormatSymbols, and creation
+ * year.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this SimpleDateFormat,
+ * false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof SimpleDateFormat)) {
+ return false;
+ }
+ SimpleDateFormat simple = (SimpleDateFormat) object;
+ return super.equals(object) && pattern.equals(simple.pattern)
+ && formatData.equals(simple.formatData);
+ }
+
+ private Date error(ParsePosition position, int offset, TimeZone zone) {
+ position.setErrorIndex(offset);
+ calendar.setTimeZone(zone);
+ return null;
+ }
+
+ /**
+ * Formats the specified object using the rules of this SimpleDateFormat and
+ * returns an AttributedCharacterIterator with the formatted Date and
+ * attributes.
+ *
+ * @param object
+ * the object to format
+ * @return an AttributedCharacterIterator with the formatted date and
+ * attributes
+ *
+ * @exception NullPointerException
+ * when the object is null
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ @Override
+ public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+ if (object == null) {
+ throw new NullPointerException();
+ }
+ if (object instanceof Date) {
+ return formatToCharacterIteratorImpl((Date) object);
+ }
+ if (object instanceof Number) {
+ return formatToCharacterIteratorImpl(new Date(((Number) object)
+ .longValue()));
+ }
+ throw new IllegalArgumentException();
+ }
+
+ private AttributedCharacterIterator formatToCharacterIteratorImpl(Date date) {
+ StringBuffer buffer = new StringBuffer();
+ Vector<FieldPosition> fields = new Vector<FieldPosition>();
+
+ // format the date, and find fields
+ formatImpl(date, buffer, null, fields);
+
+ // create and AttributedString with the formatted buffer
+ AttributedString as = new AttributedString(buffer.toString());
+
+ // add DateFormat field attributes to the AttributedString
+ for (int i = 0; i < fields.size(); i++) {
+ FieldPosition pos = fields.elementAt(i);
+ Format.Field attribute = pos.getFieldAttribute();
+ as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos
+ .getEndIndex());
+ }
+
+ // return the CharacterIterator from AttributedString
+ return as.getIterator();
+ }
+
+ /**
+ * Formats the specified Date into the specified StringBuffer using the
+ * pattern of this SimpleDateFormat. If the field specified by the
+ * FieldPosition is formatted, set the begin and end index of the formatted
+ * field in the FieldPosition.
+ *
+ * @param date
+ * the Date to format
+ * @param buffer
+ * the StringBuffer
+ * @param field
+ * the FieldPosition
+ * @return the StringBuffer parameter <code>buffer</code>
+ *
+ * @exception IllegalArgumentException
+ * when there are invalid characters in the pattern
+ */
+ @Override
+ public StringBuffer format(Date date, StringBuffer buffer,
+ FieldPosition field) {
+ return formatImpl(date, buffer, field, null);
+ }
+
+ /**
+ * Validate the format character.
+ *
+ * @param format
+ * the format character
+ *
+ * @throws IllegalArgumentException
+ * when the format character is invalid
+ */
+ private void validateFormat(char format) {
+ int index = patternChars.indexOf(format);
+ if (index == -1) {
+ // text.03=Unknown pattern character - '{0}'
+ throw new IllegalArgumentException(Messages.getString(
+ "text.03", format)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Validate the pattern.
+ *
+ * @param template
+ * the pattern to validate.
+ *
+ * @throws NullPointerException
+ * if the pattern is null
+ * @throws IllegalArgumentException
+ * if the pattern is invalid
+ */
+ private void validatePattern(String template) {
+ boolean quote = false;
+ int next, last = -1, count = 0;
+
+ final int patternLength = template.length();
+ for (int i = 0; i < patternLength; i++) {
+ next = (template.charAt(i));
+ if (next == '\'') {
+ if (count > 0) {
+ validateFormat((char) last);
+ count = 0;
+ }
+ if (last == next) {
+ last = -1;
+ } else {
+ last = next;
+ }
+ quote = !quote;
+ continue;
+ }
+ if (!quote
+ && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ if (last == next) {
+ count++;
+ } else {
+ if (count > 0) {
+ validateFormat((char) last);
+ }
+ last = next;
+ count = 1;
+ }
+ } else {
+ if (count > 0) {
+ validateFormat((char) last);
+ count = 0;
+ }
+ last = -1;
+ }
+ }
+ if (count > 0) {
+ validateFormat((char) last);
+ }
+
+ if (quote) {
+ // text.04=Unterminated quote {0}
+ throw new IllegalArgumentException(Messages.getString("text.04")); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Formats the date.
+ * <p>
+ * If the FieldPosition <code>field</code> is not null, and the field
+ * specified by this FieldPosition is formatted, set the begin and end index
+ * of the formatted field in the FieldPosition.
+ * <p>
+ * If the Vector <code>fields</code> is not null, find fields of this
+ * date, set FieldPositions with these fields, and add them to the fields
+ * vector.
+ *
+ * @param date
+ * Date to Format
+ * @param buffer
+ * StringBuffer to store the resulting formatted String
+ * @param field
+ * FieldPosition to set begin and end index of the field
+ * specified, if it is part of the format for this date
+ * @param fields
+ * Vector used to store the FieldPositions for each field in this
+ * date
+ *
+ * @return the formatted Date
+ *
+ * @exception IllegalArgumentException
+ * when the object cannot be formatted by this Format
+ */
+ private StringBuffer formatImpl(Date date, StringBuffer buffer,
+ FieldPosition field, Vector<FieldPosition> fields) {
+
+ boolean quote = false;
+ int next, last = -1, count = 0;
+ calendar.setTime(date);
+ if (field != null) {
+ field.clear();
+ }
+
+ final int patternLength = pattern.length();
+ for (int i = 0; i < patternLength; i++) {
+ next = (pattern.charAt(i));
+ if (next == '\'') {
+ if (count > 0) {
+ append(buffer, field, fields, (char) last, count);
+ count = 0;
+ }
+ if (last == next) {
+ buffer.append('\'');
+ last = -1;
+ } else {
+ last = next;
+ }
+ quote = !quote;
+ continue;
+ }
+ if (!quote
+ && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ if (last == next) {
+ count++;
+ } else {
+ if (count > 0) {
+ append(buffer, field, fields, (char) last, count);
+ }
+ last = next;
+ count = 1;
+ }
+ } else {
+ if (count > 0) {
+ append(buffer, field, fields, (char) last, count);
+ count = 0;
+ }
+ last = -1;
+ buffer.append((char) next);
+ }
+ }
+ if (count > 0) {
+ append(buffer, field, fields, (char) last, count);
+ }
+ return buffer;
+ }
+
+ /**
+ * Returns the Date which is the start of the one hundred year period for
+ * two digits year values.
+ *
+ * @return a Date
+ */
+ public Date get2DigitYearStart() {
+ return defaultCenturyStart;
+ }
+
+ /**
+ * Returns the DateFormatSymbols used by this SimpleDateFormat.
+ *
+ * @return a DateFormatSymbols
+ */
+ public DateFormatSymbols getDateFormatSymbols() {
+ // Return a clone so the arrays in the ResourceBundle are not modified
+ return (DateFormatSymbols) formatData.clone();
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode() + pattern.hashCode() + formatData.hashCode()
+ + creationYear;
+ }
+
+ private int parse(String string, int offset, char format, int count) {
+ int index = patternChars.indexOf(format);
+ if (index == -1) {
+ // text.03=Unknown pattern character - '{0}'
+ throw new IllegalArgumentException(Messages.getString(
+ "text.03", format)); //$NON-NLS-1$
+ }
+ int field = -1;
+ int absolute = 0;
+ if (count < 0) {
+ count = -count;
+ absolute = count;
+ }
+ switch (index) {
+ case ERA_FIELD:
+ return parseText(string, offset, formatData.eras, Calendar.ERA);
+ case YEAR_FIELD:
+ if (count >= 3) {
+ field = Calendar.YEAR;
+ } else {
+ ParsePosition position = new ParsePosition(offset);
+ Number result = parseNumber(absolute, string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ int year = result.intValue();
+ // A two digit year must be exactly two digits, i.e. 01
+ if ((position.getIndex() - offset) == 2 && year >= 0) {
+ year += creationYear / 100 * 100;
+ if (year < creationYear) {
+ year += 100;
+ }
+ }
+ calendar.set(Calendar.YEAR, year);
+ return position.getIndex();
+ }
+ break;
+ case MONTH_FIELD:
+ if (count <= 2) {
+ return parseNumber(absolute, string, offset,
+ Calendar.MONTH, -1);
+ }
+ index = parseText(string, offset, formatData.months,
+ Calendar.MONTH);
+ if (index < 0) {
+ return parseText(string, offset, formatData.shortMonths,
+ Calendar.MONTH);
+ }
+ return index;
+ case DATE_FIELD:
+ field = Calendar.DATE;
+ break;
+ case HOUR_OF_DAY1_FIELD:
+ ParsePosition position = new ParsePosition(offset);
+ Number result = parseNumber(absolute, string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ int hour = result.intValue();
+ if (hour == 24) {
+ hour = 0;
+ }
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ return position.getIndex();
+ case HOUR_OF_DAY0_FIELD:
+ field = Calendar.HOUR_OF_DAY;
+ break;
+ case MINUTE_FIELD:
+ field = Calendar.MINUTE;
+ break;
+ case SECOND_FIELD:
+ field = Calendar.SECOND;
+ break;
+ case MILLISECOND_FIELD:
+ field = Calendar.MILLISECOND;
+ break;
+ case DAY_OF_WEEK_FIELD:
+ index = parseText(string, offset, formatData.weekdays,
+ Calendar.DAY_OF_WEEK);
+ if (index < 0) {
+ return parseText(string, offset, formatData.shortWeekdays,
+ Calendar.DAY_OF_WEEK);
+ }
+ return index;
+ case DAY_OF_YEAR_FIELD:
+ field = Calendar.DAY_OF_YEAR;
+ break;
+ case DAY_OF_WEEK_IN_MONTH_FIELD:
+ field = Calendar.DAY_OF_WEEK_IN_MONTH;
+ break;
+ case WEEK_OF_YEAR_FIELD:
+ field = Calendar.WEEK_OF_YEAR;
+ break;
+ case WEEK_OF_MONTH_FIELD:
+ field = Calendar.WEEK_OF_MONTH;
+ break;
+ case AM_PM_FIELD:
+ return parseText(string, offset, formatData.ampms,
+ Calendar.AM_PM);
+ case HOUR1_FIELD:
+ position = new ParsePosition(offset);
+ result = parseNumber(absolute, string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ hour = result.intValue();
+ if (hour == 12) {
+ hour = 0;
+ }
+ calendar.set(Calendar.HOUR, hour);
+ return position.getIndex();
+ case HOUR0_FIELD:
+ field = Calendar.HOUR;
+ break;
+ case TIMEZONE_FIELD:
+ return parseTimeZone(string, offset);
+ case (TIMEZONE_FIELD + 1):
+ return parseTimeZone(string, offset);
+ }
+ if (field != -1) {
+ return parseNumber(absolute, string, offset, field, 0);
+ }
+ return offset;
+ }
+
+ /**
+ * Parse a Date from the specified String starting at the index specified by
+ * the ParsePosition. If the string is successfully parsed, the index of the
+ * ParsePosition is updated to the index following the parsed text.
+ *
+ * @param string
+ * the String to parse according to the pattern of this
+ * SimpleDateFormat
+ * @param position
+ * the ParsePosition, updated on return with the index following
+ * the parsed text, or on error the index is unchanged and the
+ * error index is set to the index where the error occurred
+ * @return the Date resulting from the parse, or null if there is an error
+ *
+ * @exception IllegalArgumentException
+ * when there are invalid characters in the pattern
+ */
+ @Override
+ public Date parse(String string, ParsePosition position) {
+ boolean quote = false;
+ int next, last = -1, count = 0, offset = position.getIndex();
+ int length = string.length();
+ calendar.clear();
+ TimeZone zone = calendar.getTimeZone();
+ final int patternLength = pattern.length();
+ for (int i = 0; i < patternLength; i++) {
+ next = pattern.charAt(i);
+ if (next == '\'') {
+ if (count > 0) {
+ if ((offset = parse(string, offset, (char) last, count)) < 0) {
+ return error(position, -offset - 1, zone);
+ }
+ count = 0;
+ }
+ if (last == next) {
+ if (offset >= length || string.charAt(offset) != '\'') {
+ return error(position, offset, zone);
+ }
+ offset++;
+ last = -1;
+ } else {
+ last = next;
+ }
+ quote = !quote;
+ continue;
+ }
+ if (!quote
+ && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ if (last == next) {
+ count++;
+ } else {
+ if (count > 0) {
+ if ((offset = parse(string, offset, (char) last, -count)) < 0) {
+ return error(position, -offset - 1, zone);
+ }
+ }
+ last = next;
+ count = 1;
+ }
+ } else {
+ if (count > 0) {
+ if ((offset = parse(string, offset, (char) last, count)) < 0) {
+ return error(position, -offset - 1, zone);
+ }
+ count = 0;
+ }
+ last = -1;
+ if (offset >= length || string.charAt(offset) != next) {
+ return error(position, offset, zone);
+ }
+ offset++;
+ }
+ }
+ if (count > 0) {
+ if ((offset = parse(string, offset, (char) last, count)) < 0) {
+ return error(position, -offset - 1, zone);
+ }
+ }
+ Date date;
+ try {
+ date = calendar.getTime();
+ } catch (IllegalArgumentException e) {
+ return error(position, offset, zone);
+ }
+ position.setIndex(offset);
+ calendar.setTimeZone(zone);
+ return date;
+ }
+
+ private Number parseNumber(int max, String string, ParsePosition position) {
+ int digit, length = string.length(), result = 0;
+ int index = position.getIndex();
+ if (max > 0 && max < length - index) {
+ length = index + max;
+ }
+ while (index < length
+ && (string.charAt(index) == ' ' || string.charAt(index) == '\t')) {
+ index++;
+ }
+ if (max == 0) {
+ position.setIndex(index);
+ return numberFormat.parse(string, position);
+ }
+
+ while (index < length
+ && (digit = Character.digit(string.charAt(index), 10)) != -1) {
+ index++;
+ result = result * 10 + digit;
+ }
+ if (index == position.getIndex()) {
+ position.setErrorIndex(index);
+ return null;
+ }
+ position.setIndex(index);
+ return new Integer(result);
+ }
+
+ private int parseNumber(int max, String string, int offset, int field,
+ int skew) {
+ ParsePosition position = new ParsePosition(offset);
+ Number result = parseNumber(max, string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ calendar.set(field, result.intValue() + skew);
+ return position.getIndex();
+ }
+
+ private int parseText(String string, int offset, String[] text, int field) {
+ int found = -1;
+ for (int i = 0; i < text.length; i++) {
+ if (text[i].length() == 0) {
+ continue;
+ }
+ if (string
+ .regionMatches(true, offset, text[i], 0, text[i].length())) {
+ // Search for the longest match, in case some fields are subsets
+ if (found == -1 || text[i].length() > text[found].length()) {
+ found = i;
+ }
+ }
+ }
+ if (found != -1) {
+ calendar.set(field, found);
+ return offset + text[found].length();
+ }
+ return -offset - 1;
+ }
+
+ private int parseTimeZone(String string, int offset) {
+// BEGIN android-changed
+ String[][] zones = formatData.internalZoneStrings();
+// END android-changed
+ boolean foundGMT = string.regionMatches(offset, "GMT", 0, 3); //$NON-NLS-1$
+ if (foundGMT) {
+ offset += 3;
+ }
+ char sign;
+ if (offset < string.length()
+ && ((sign = string.charAt(offset)) == '+' || sign == '-')) {
+ ParsePosition position = new ParsePosition(offset + 1);
+ Number result = numberFormat.parse(string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ int hour = result.intValue();
+ int raw = hour * 3600000;
+ int index = position.getIndex();
+ if (index < string.length() && string.charAt(index) == ':') {
+ position.setIndex(index + 1);
+ result = numberFormat.parse(string, position);
+ if (result == null) {
+ return -position.getErrorIndex() - 1;
+ }
+ int minute = result.intValue();
+ raw += minute * 60000;
+ } else if (hour >= 24) {
+ raw = (hour / 100 * 3600000) + (hour % 100 * 60000);
+ }
+ if (sign == '-') {
+ raw = -raw;
+ }
+ calendar.setTimeZone(new SimpleTimeZone(raw, "")); //$NON-NLS-1$
+ return position.getIndex();
+ }
+ if (foundGMT) {
+ calendar.setTimeZone(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$
+ return offset;
+ }
+ for (String[] element : zones) {
+ for (int j = 1; j < 5; j++) {
+ if (string.regionMatches(true, offset, element[j], 0,
+ element[j].length())) {
+ TimeZone zone = TimeZone.getTimeZone(element[0]);
+ if (zone == null) {
+ return -offset - 1;
+ }
+ int raw = zone.getRawOffset();
+ if (j >= 3 && zone.useDaylightTime()) {
+ raw += 3600000;
+ }
+ calendar.setTimeZone(new SimpleTimeZone(raw, "")); //$NON-NLS-1$
+ return offset + element[j].length();
+ }
+ }
+ }
+ return -offset - 1;
+ }
+
+ /**
+ * Sets the Date which is the start of the one hundred year period for two
+ * digits year values.
+ *
+ * @param date
+ * the Date
+ */
+ public void set2DigitYearStart(Date date) {
+ defaultCenturyStart = date;
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(date);
+ creationYear = cal.get(Calendar.YEAR);
+ }
+
+ /**
+ * Sets the DateFormatSymbols used by this SimpleDateFormat.
+ *
+ * @param value
+ * the DateFormatSymbols
+ */
+ public void setDateFormatSymbols(DateFormatSymbols value) {
+ formatData = (DateFormatSymbols) value.clone();
+ }
+
+ /**
+ * Returns the pattern of this SimpleDateFormat using localized pattern
+ * characters.
+ *
+ * @return the localized pattern
+ */
+ public String toLocalizedPattern() {
+ return convertPattern(pattern, patternChars, formatData
+ .getLocalPatternChars(), false);
+ }
+
+ /**
+ * Returns the pattern of this SimpleDateFormat using non-localized pattern
+ * characters.
+ *
+ * @return the non-localized pattern
+ */
+ public String toPattern() {
+ return pattern;
+ }
+
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("defaultCenturyStart", Date.class), //$NON-NLS-1$
+ new ObjectStreamField("formatData", DateFormatSymbols.class), //$NON-NLS-1$
+ new ObjectStreamField("pattern", String.class), //$NON-NLS-1$
+ new ObjectStreamField("serialVersionOnStream", Integer.TYPE), }; //$NON-NLS-1$
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ ObjectOutputStream.PutField fields = stream.putFields();
+ fields.put("defaultCenturyStart", defaultCenturyStart); //$NON-NLS-1$
+ fields.put("formatData", formatData); //$NON-NLS-1$
+ fields.put("pattern", pattern); //$NON-NLS-1$
+ fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
+ stream.writeFields();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream.GetField fields = stream.readFields();
+ int version = fields.get("serialVersionOnStream", 0); //$NON-NLS-1$
+ Date date;
+ if (version > 0) {
+ date = (Date) fields.get("defaultCenturyStart", new Date()); //$NON-NLS-1$
+ } else {
+ date = new Date();
+ }
+ set2DigitYearStart(date);
+ formatData = (DateFormatSymbols) fields.get("formatData", null); //$NON-NLS-1$
+ pattern = (String) fields.get("pattern", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+}
diff --git a/text/src/main/java/java/text/StringCharacterIterator.java b/text/src/main/java/java/text/StringCharacterIterator.java
new file mode 100644
index 0000000..a4d3b68
--- /dev/null
+++ b/text/src/main/java/java/text/StringCharacterIterator.java
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.text;
+
+/**
+ * StringCharacterIterator is an implementation of CharacterIterator for
+ * Strings.
+ */
+public final class StringCharacterIterator implements CharacterIterator {
+
+ String string;
+
+ int start, end, offset;
+
+ /**
+ * Constructs a new StringCharacterIterator on the specified String. The
+ * begin and current indexes are set to the beginning of the String, the end
+ * index is set to the length of the String.
+ *
+ * @param value
+ * the new source String to iterate
+ */
+ public StringCharacterIterator(String value) {
+ string = value;
+ start = offset = 0;
+ end = string.length();
+ }
+
+ /**
+ * Constructs a new StringCharacterIterator on the specified String with the
+ * current index set to the specified value. The begin index is set to the
+ * beginning of the String, the end index is set to the length of the String.
+ *
+ * @param value
+ * the new source String to iterate
+ * @param location
+ * the current index
+ *
+ * @exception IllegalArgumentException
+ * when the current index is less than zero or greater than
+ * the length of the String
+ */
+ public StringCharacterIterator(String value, int location) {
+ string = value;
+ start = 0;
+ end = string.length();
+ if (location < 0 || location > end) {
+ throw new IllegalArgumentException();
+ }
+ offset = location;
+ }
+
+ /**
+ * Constructs a new StringCharacterIterator on the specified String with the
+ * begin, end and current index set to the specified values.
+ *
+ * @param value
+ * the new source String to iterate
+ * @param start
+ * the index of the first character to iterate
+ * @param end
+ * the index one past the last character to iterate
+ * @param location
+ * the current index
+ *
+ * @exception IllegalArgumentException
+ * when the begin index is less than zero, the end index is
+ * greater than the String length, the begin index is greater
+ * than the end index, the current index is less than the
+ * begin index or greater than the end index
+ */
+ public StringCharacterIterator(String value, int start, int end,
+ int location) {
+ string = value;
+ if (start < 0 || end > string.length() || start > end
+ || location < start || location > end) {
+ throw new IllegalArgumentException();
+ }
+ this.start = start;
+ this.end = end;
+ offset = location;
+ }
+
+ /**
+ * Returns a new StringCharacterIterator with the same source String, begin,
+ * end, and current index as this StringCharacterIterator.
+ *
+ * @return a shallow copy of this StringCharacterIterator
+ *
+ * @see java.lang.Cloneable
+ */
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the character at the current index in the source String.
+ *
+ * @return the current character, or DONE if the current index is past the
+ * end
+ */
+ public char current() {
+ if (offset == end) {
+ return DONE;
+ }
+ return string.charAt(offset);
+ }
+
+ /**
+ * Compares the specified object to this StringCharacterIterator and answer
+ * if they are equal. The object must be a StringCharacterIterator iterating
+ * over the same sequence of characters with the same index.
+ *
+ * @param object
+ * the object to compare with this object
+ * @return true if the specified object is equal to this
+ * StringCharacterIterator, false otherwise
+ *
+ * @see #hashCode
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof StringCharacterIterator)) {
+ return false;
+ }
+ StringCharacterIterator it = (StringCharacterIterator) object;
+ return string.equals(it.string) && start == it.start && end == it.end
+ && offset == it.offset;
+ }
+
+ /**
+ * Sets the current position to the begin index and returns the character at
+ * the begin index.
+ *
+ * @return the character at the begin index
+ */
+ public char first() {
+ if (start == end) {
+ return DONE;
+ }
+ offset = start;
+ return string.charAt(offset);
+ }
+
+ /**
+ * Returns the begin index in the source String.
+ *
+ * @return the index of the first character to iterate
+ */
+ public int getBeginIndex() {
+ return start;
+ }
+
+ /**
+ * Returns the end index in the source String.
+ *
+ * @return the index one past the last character to iterate
+ */
+ public int getEndIndex() {
+ return end;
+ }
+
+ /**
+ * Returns the current index in the source String.
+ *
+ * @return the current index
+ */
+ public int getIndex() {
+ return offset;
+ }
+
+ /**
+ * Returns an integer hash code for the receiver. Objects which are equal
+ * answer the same value for this method.
+ *
+ * @return the receiver's hash
+ *
+ * @see #equals
+ */
+ @Override
+ public int hashCode() {
+ return string.hashCode() + start + end + offset;
+ }
+
+ /**
+ * Sets the current position to the end index - 1 and returns the character
+ * at the current position.
+ *
+ * @return the character before the end index
+ */
+ public char last() {
+ if (start == end) {
+ return DONE;
+ }
+ offset = end - 1;
+ return string.charAt(offset);
+ }
+
+ /**
+ * Increments the current index and returns the character at the new index.
+ *
+ * @return the character at the next index, or DONE if the next index is
+ * past the end
+ */
+ public char next() {
+ if (offset >= (end - 1)) {
+ offset = end;
+ return DONE;
+ }
+ return string.charAt(++offset);
+ }
+
+ /**
+ * Decrements the current index and returns the character at the new index.
+ *
+ * @return the character at the previous index, or DONE if the previous
+ * index is past the beginning
+ */
+ public char previous() {
+ if (offset == start) {
+ return DONE;
+ }
+ return string.charAt(--offset);
+ }
+
+ /**
+ * Sets the current index in the source String.
+ *
+ * @return the character at the new index, or DONE if the index is past the
+ * end
+ *
+ * @exception IllegalArgumentException
+ * when the new index is less than the begin index or greater
+ * than the end index
+ */
+ public char setIndex(int location) {
+ if (location < start || location > end) {
+ throw new IllegalArgumentException();
+ }
+ offset = location;
+ if (offset == end) {
+ return DONE;
+ }
+ return string.charAt(offset);
+ }
+
+ /**
+ * Sets the source String to iterate. The begin and end positions are set to
+ * the start and end of this String.
+ *
+ * @param value
+ * the new source String
+ */
+ public void setText(String value) {
+ string = value;
+ start = offset = 0;
+ end = value.length();
+ }
+}
diff --git a/text/src/main/java/java/text/package.html b/text/src/main/java/java/text/package.html
new file mode 100644
index 0000000..2909d52
--- /dev/null
+++ b/text/src/main/java/java/text/package.html
@@ -0,0 +1,16 @@
+<html>
+ <body>
+ <p>
+ The java.text package allows to uncouple the text in the
+ application from a natural language.
+ </p>
+ <p>
+ With this it is possible to write the application in an
+ unlocalized way. Like this a new localization can be provided at any
+ time without having to change anything in the code. Support for
+ localization is given for numbers, messages, dates and also
+ characteristics of a language like the directionality, sorting order or
+ enumeration of characters, words or lines.
+ </p>
+</body>
+</html>
diff --git a/text/src/main/java/org/apache/harmony/text/BidiRun.java b/text/src/main/java/org/apache/harmony/text/BidiRun.java
new file mode 100644
index 0000000..d1033f4
--- /dev/null
+++ b/text/src/main/java/org/apache/harmony/text/BidiRun.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text;
+
+/**
+ * TODO: type description
+ */
+public class BidiRun {
+ private final int start;
+
+ private final int limit;
+
+ private final int level;
+
+ public BidiRun(int start, int limit, int level) {
+ this.start = start;
+ this.limit = limit;
+ this.level = level;
+ }
+
+ public int getLevel() {
+ return level;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o == null || o.getClass() != BidiRun.class ? false
+ : this.start == ((BidiRun) o).start
+ && this.limit == ((BidiRun) o).limit
+ && this.level == ((BidiRun) o).level;
+ }
+}
diff --git a/text/src/main/java/org/apache/harmony/text/BidiWrapper.java b/text/src/main/java/org/apache/harmony/text/BidiWrapper.java
new file mode 100644
index 0000000..240fcdf
--- /dev/null
+++ b/text/src/main/java/org/apache/harmony/text/BidiWrapper.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text;
+
+/**
+ * TODO: type description
+ */
+
+public final class BidiWrapper {
+
+ public static final int UBIDI_DEFAULT_LTR = 0xfe;
+
+ public static final int UBIDI_DEFAULT_RTL = 0xff;
+
+ public static final int UBIDI_MAX_EXPLICIT_LEVEL = 61;
+
+ public static final int UBIDI_LEVEL_OVERRIDE = 0x80;
+
+ public static final int UBIDI_KEEP_BASE_COMBINING = 1;
+
+ public static final int UBIDI_DO_MIRRORING = 2;
+
+ public static final int UBIDI_INSERT_LRM_FOR_NUMERIC = 4;
+
+ public static final int UBIDI_REMOVE_BIDI_CONTROLS = 8;
+
+ public static final int UBIDI_OUTPUT_REVERSE = 16;
+
+ public static final int UBiDiDirection_UBIDI_LTR = 0;
+
+ public static final int UBiDiDirection_UBIDI_RTL = 1;
+
+ public static final int UBiDiDirection_UBIDI_MIXED = 2;
+
+ // Allocate a UBiDi structure.
+ public static native long ubidi_open();
+
+ // ubidi_close() must be called to free the memory associated with a
+ // UBiDi object.
+ public static native void ubidi_close(long pBiDi);
+
+ // Perform the Unicode BiDi algorithm.
+ public static native void ubidi_setPara(long pBiDi, char[] text,
+ int length, byte paraLevel, byte[] embeddingLevels);
+
+ // ubidi_setLine() sets a UBiDi to contain the reordering information,
+ // especially the resolved levels, for all the characters in a line of
+ // text.
+ public static native long ubidi_setLine(final long pParaBiDi, int start,
+ int limit);
+
+ // Get the directionality of the text.
+ public static native int ubidi_getDirection(final long pBiDi);
+
+ // Get the length of the text.
+ public static native int ubidi_getLength(final long pBiDi);
+
+ // Get the paragraph level of the text.
+ public static native byte ubidi_getParaLevel(final long pBiDi);
+
+ // Get an array of levels for each character.
+ public static native byte[] ubidi_getLevels(long pBiDi);
+
+ // Get the number of runs.
+ public static native int ubidi_countRuns(long pBiDi);
+
+ // Get the BidiRuns
+ public static native BidiRun[] ubidi_getRuns(long pBidi);
+
+ // This is a convenience function that does not use a UBiDi object
+ public static native int[] ubidi_reorderVisual(byte[] levels, int length);
+}
diff --git a/text/src/main/java/org/apache/harmony/text/internal/nls/Messages.java b/text/src/main/java/org/apache/harmony/text/internal/nls/Messages.java
new file mode 100644
index 0000000..ed1f532
--- /dev/null
+++ b/text/src/main/java/org/apache/harmony/text/internal/nls/Messages.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.text.internal.nls;
+
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.text.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ private static final String sResource =
+ "org.apache.harmony.text.internal.nls.messages"; //$NON-NLS-1$
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ return MsgHelp.getString(sResource, msg);
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ return MsgHelp.getString(sResource, msg, args);
+ }
+}
diff --git a/text/src/main/java/org/apache/harmony/text/internal/nls/messages.properties b/text/src/main/java/org/apache/harmony/text/internal/nls/messages.properties
new file mode 100644
index 0000000..22221a9
--- /dev/null
+++ b/text/src/main/java/org/apache/harmony/text/internal/nls/messages.properties
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+# messages for EN locale
+text.00=min digits greater than max digits
+text.01=min or max digits negative
+text.02=Unknown attribute
+text.03=Unknown pattern character - '{0}'
+text.04=Unterminated quote
+text.05=Invalid pattern char {0} in {1}
+text.07=Unmatched braces in the pattern
+text.06=Build rules empty
+text.08=one of arguments is null
+text.09=The deserialized date is invalid
+text.0A=Invalid substring range
+text.0B=Cannot add attributes to empty string
+text.0C=cannot resolve subclasses
+text.0E=Illegal date style: {0}
+text.0F=Illegal time style: {0}
+text.0D=Negative textStart value {0}
+text.10=Negative embStart value {0}
+text.11=Negative paragraph length {0}
+text.12=Invalid ranges (start={0}, limit={1}, length={2})
+text.13=Invalid ranges (levels={0}, levelStart={1}, objects={2}, objectStart={3}, count={4})
+text.14=paragraph is null
+text.19=Invalid argument number
+text.15=Missing element format
+text.16=Unknown element format
+text.17=Unknown format
+text.18=Not a valid {0}, subclass should override readResolve()
+text.19=Unparseable date: {0}
+text.1A=position is null
+
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/AllTests.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/AllTests.java
new file mode 100644
index 0000000..cef6191
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/AllTests.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(AllTests.suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(
+ "Suite org.apache.harmony.text.tests.java.text");
+ //$JUnit-BEGIN$
+ suite.addTestSuite(AnnotationTest.class);
+ suite.addTestSuite(AttributedCharacterIteratorAttributeTest.class);
+ suite.addTestSuite(AttributedCharacterIteratorTest.class);
+ suite.addTestSuite(AttributedStringTest.class);
+ suite.addTestSuite(BidiTest.class);
+ suite.addTestSuite(BreakIteratorTest.class);
+ suite.addTestSuite(ChoiceFormatTest.class);
+ suite.addTestSuite(CollationElementIteratorTest.class);
+ suite.addTestSuite(CollationKeyTest.class);
+ suite.addTestSuite(CollatorTest.class);
+ suite.addTestSuite(DataFormatFieldTest.class);
+ suite.addTestSuite(DateFormatSymbolsTest.class);
+ suite.addTestSuite(DateFormatTest.class);
+ suite.addTestSuite(DecimalFormatSymbolsTest.class);
+ suite.addTestSuite(DecimalFormatTest.class);
+ suite.addTestSuite(FieldPositionTest.class);
+ suite.addTestSuite(FormatFieldTest.class);
+ suite.addTestSuite(FormatTest.class);
+ suite.addTestSuite(MessageFormatFieldTest.class);
+ suite.addTestSuite(MessageFormatTest.class);
+ suite.addTestSuite(NumberFormatFieldTest.class);
+ suite.addTestSuite(NumberFormatTest.class);
+ suite.addTestSuite(ParseExceptionTest.class);
+ suite.addTestSuite(ParsePositionTest.class);
+ suite.addTestSuite(RuleBasedCollatorTest.class);
+ suite.addTestSuite(SimpleDateFormatTest.class);
+ suite.addTestSuite(StringCharacterIteratorTest.class);
+ //$JUnit-END$
+ return suite;
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/AnnotationTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/AnnotationTest.java
new file mode 100644
index 0000000..c7d8f84
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/AnnotationTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.Annotation;
+
+import junit.framework.TestCase;
+
+public class AnnotationTest extends TestCase {
+
+ /**
+ * @tests java.text.Annotation(Object)
+ */
+ public void testAnnotation() {
+ assertNotNull(new Annotation(null));
+ assertNotNull(new Annotation("value"));
+ }
+
+ /**
+ * @tests java.text.Annotation.getValue()
+ */
+ public void testGetValue() {
+ Annotation a = new Annotation(null);
+ assertNull(a.getValue());
+ a = new Annotation("value");
+ assertEquals("value", a.getValue());
+ }
+
+ /**
+ * @tests java.text.Annotation.toString()
+ */
+ public void testToString() {
+ Annotation ant = new Annotation("HelloWorld");
+ assertEquals("toString error.",
+ "java.text.Annotation[value=HelloWorld]", ant.toString());
+ assertNotNull(new Annotation(null).toString());
+ assertNotNull(new Annotation("value").toString());
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorAttributeTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorAttributeTest.java
new file mode 100644
index 0000000..968de4c
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorAttributeTest.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.InvalidObjectException;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedCharacterIterator.Attribute;
+import junit.framework.Test;
+
+public class AttributedCharacterIteratorAttributeTest extends
+ junit.framework.TestCase {
+
+ private class MockAttributedCharacterIteratorAttribute extends
+ AttributedCharacterIterator.Attribute {
+
+ private static final long serialVersionUID = 1L;
+
+ public MockAttributedCharacterIteratorAttribute(String name) {
+ super(name);
+ }
+
+ @Override
+ public String getName() {
+ return super.getName();
+ }
+
+ @Override
+ public Object readResolve() throws InvalidObjectException {
+ return super.readResolve();
+ }
+ }
+
+ private class TestAttributedCharacterIteratorAttribute extends
+ AttributedCharacterIterator.Attribute {
+ private static final long serialVersionUID = -2917613373935785179L;
+
+ public TestAttributedCharacterIteratorAttribute(String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#AttributedCharacterIterator.Attribute(java.lang.String)
+ * Test of method
+ * java.text.AttributedCharacterIterator.Attribute#AttributedCharacterIterator.Attribute(java.lang.String).
+ */
+ public void test_Constructor() {
+ try {
+ new MockAttributedCharacterIteratorAttribute("test");
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#equals(java.lang.Object)
+ * Test of method
+ * java.text.AttributedCharacterIterator.Attribute#equals(java.lang.Object).
+ */
+ public void test_equalsLjava_lang_Object() {
+ try {
+ MockAttributedCharacterIteratorAttribute mac1 = new MockAttributedCharacterIteratorAttribute(
+ "test1");
+ MockAttributedCharacterIteratorAttribute mac2 = new MockAttributedCharacterIteratorAttribute(
+ "test2");
+
+ assertFalse("Attributes are equal", mac2.equals(mac1));
+
+ TestAttributedCharacterIteratorAttribute mac3 = new TestAttributedCharacterIteratorAttribute(
+ "test1");
+
+ assertFalse("Attributes are equal", mac3.equals(mac1));
+
+ AttributedCharacterIterator.Attribute mac4 = mac1;
+
+ assertTrue("Attributes are non-equal", mac4.equals(mac1));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#getName() Test of
+ * method java.text.AttributedCharacterIterator.Attribute#getName().
+ */
+ public void test_getName() {
+ try {
+ MockAttributedCharacterIteratorAttribute mac1 = new MockAttributedCharacterIteratorAttribute(
+ "test1");
+ assertEquals("Incorrect attribute name", "test1", mac1.getName());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#hashCode()
+ */
+ public void test_hashCode() {
+ try {
+ MockAttributedCharacterIteratorAttribute mac1 = new MockAttributedCharacterIteratorAttribute(
+ "test1");
+ TestAttributedCharacterIteratorAttribute mac2 = new TestAttributedCharacterIteratorAttribute(
+ "test1");
+
+ assertTrue("The hash codes of same attributes are not equal", mac1
+ .hashCode() == mac2.hashCode());
+
+ MockAttributedCharacterIteratorAttribute mac3 = new MockAttributedCharacterIteratorAttribute(
+ "test2");
+
+ assertTrue("The hash codes of different attributes are equal", mac1
+ .hashCode() != mac3.hashCode());
+
+ AttributedCharacterIterator.Attribute mac4 = mac1;
+
+ assertTrue("The hash codes of same attributes but different hierarchy classes are not equal",
+ mac1.hashCode() == mac4.hashCode());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#readResolve() Test
+ * of method
+ * java.text.AttributedCharacterIterator.Attribute#readResolve().
+ */
+ public void test_readResolve() {
+ MockAttributedCharacterIteratorAttribute mac1 = new MockAttributedCharacterIteratorAttribute(
+ "test");
+ try {
+ mac1.readResolve();
+ fail("InvalidObjectException has not been thrown");
+ } catch (InvalidObjectException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator.Attribute#toString() Test of
+ * method java.text.AttributedCharacterIterator.Attribute#toString().
+ */
+ public void test_toString() {
+ MockAttributedCharacterIteratorAttribute mac1 = new MockAttributedCharacterIteratorAttribute(
+ null);
+ assertEquals("Unexpected class representation string", mac1.toString(),
+ getClass().getName()
+ + "$MockAttributedCharacterIteratorAttribute(null)");
+ TestAttributedCharacterIteratorAttribute mac2 = new TestAttributedCharacterIteratorAttribute(
+ "test1");
+ assertEquals("Unexpected class representation string", mac2.toString(),
+ getClass().getName()
+ + "$TestAttributedCharacterIteratorAttribute(test1)");
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorTest.java
new file mode 100644
index 0000000..76ab2aa
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedCharacterIteratorTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.CharacterIterator;
+
+public class AttributedCharacterIteratorTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#current()
+ */
+ public void test_current() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Wrong first", 'T', it.current());
+ it.next();
+ assertEquals("Wrong second", 'e', it.current());
+ for (int i = 0; i < 9; i++)
+ it.next();
+ assertEquals("Wrong last", 'g', it.current());
+ it.next();
+ assertTrue("Wrong final", it.current() == CharacterIterator.DONE);
+
+ it = attrString.getIterator(null, 2, 8);
+ assertEquals("Wrong first2", 's', it.current());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#first()
+ */
+ public void test_first() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Wrong first1", 'T', it.first());
+ it = attrString.getIterator(null, 0, 3);
+ assertEquals("Wrong first2", 'T', it.first());
+ it = attrString.getIterator(null, 2, 8);
+ assertEquals("Wrong first3", 's', it.first());
+ it = attrString.getIterator(null, 11, 11);
+ assertTrue("Wrong first4", it.first() == CharacterIterator.DONE);
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#getBeginIndex()
+ */
+ public void test_getBeginIndex() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator(null, 2, 6);
+ assertEquals("Wrong begin index", 2, it.getBeginIndex());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#getEndIndex()
+ */
+ public void test_getEndIndex() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator(null, 2, 6);
+ assertEquals("Wrong begin index", 6, it.getEndIndex());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#getIndex()
+ */
+ public void test_getIndex() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Wrong first", 0, it.getIndex());
+ it.next();
+ assertEquals("Wrong second", 1, it.getIndex());
+ for (int i = 0; i < 9; i++)
+ it.next();
+ assertEquals("Wrong last", 10, it.getIndex());
+ it.next();
+ assertEquals("Wrong final", 11, it.getIndex());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#last()
+ */
+ public void test_last() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Wrong last1", 'g', it.last());
+ it = attrString.getIterator(null, 0, 3);
+ assertEquals("Wrong last2", 's', it.last());
+ it = attrString.getIterator(null, 2, 8);
+ assertEquals("Wrong last3", 'r', it.last());
+ it = attrString.getIterator(null, 0, 0);
+ assertTrue("Wrong last4", it.last() == CharacterIterator.DONE);
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#next()
+ */
+ public void test_next() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Wrong first", 'e', it.next());
+ for (int i = 0; i < 8; i++)
+ it.next();
+ assertEquals("Wrong last", 'g', it.next());
+ assertTrue("Wrong final", it.next() == CharacterIterator.DONE);
+
+ it = attrString.getIterator(null, 2, 8);
+ assertEquals("Wrong first2", 't', it.next());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#previous()
+ */
+ public void test_previous() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ it.setIndex(11);
+ assertEquals("Wrong first", 'g', it.previous());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#setIndex(int)
+ */
+ public void test_setIndexI() {
+ String test = "Test 23ring";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ it.setIndex(5);
+ assertEquals("Wrong first", '2', it.current());
+ }
+
+ /**
+ * @tests java.text.AttributedCharacterIterator#getRunLimit(java.text.AttributedCharacterIterator$Attribute)
+ */
+ public void test_getRunLimitLjava_text_AttributedCharacterIterator$Attribute() {
+ AttributedString as = new AttributedString("test");
+ as.addAttribute(AttributedCharacterIterator.Attribute.LANGUAGE, "a", 2,
+ 3);
+ AttributedCharacterIterator it = as.getIterator();
+ assertEquals("non-null value limit",
+ 2, it.getRunLimit(AttributedCharacterIterator.Attribute.LANGUAGE));
+
+ as = new AttributedString("test");
+ as.addAttribute(AttributedCharacterIterator.Attribute.LANGUAGE, null,
+ 2, 3);
+ it = as.getIterator();
+ assertEquals("null value limit",
+ 4, it.getRunLimit(AttributedCharacterIterator.Attribute.LANGUAGE));
+ }
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedStringTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedStringTest.java
new file mode 100644
index 0000000..91f4313
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/AttributedStringTest.java
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.CharacterIterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+
+import junit.framework.Test;
+
+public class AttributedStringTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.AttributedString#AttributedString(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ String test = "Test string";
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ StringBuffer buf = new StringBuffer();
+ buf.append(it.first());
+ char ch;
+ while ((ch = it.next()) != CharacterIterator.DONE)
+ buf.append(ch);
+ assertTrue("Wrong string: " + buf, buf.toString().equals(test));
+ }
+
+ /**
+ * @tests java.text.AttributedString#AttributedString(AttributedCharacterIterator)
+ */
+ public void test_ConstructorLAttributedCharacterIterator() {
+ // Regression for HARMONY-1354
+ assertNotNull(new AttributedString(
+ new testAttributedCharacterIterator()));
+ }
+
+ /**
+ * @tests java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int) Test of method
+ * java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int). Case 1: Try to consruct AttributedString. Case 2: Try
+ * to consruct AttributedString using incorrect beginIndex. Case 3:
+ * Try to consruct AttributedString using incorrect endIndex.
+ */
+ public void test_ConstructorLAttributedCharacterIteratorII() {
+ // Regression for HARMONY-1355
+
+ // case 1: Try to consruct AttributedString.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), 0, 0);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+
+ // case 2: Try to consruct AttributedString using incorrect beginIndex.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), -1, 0);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // case 3: Try to consruct AttributedString using incorrect endIndex.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), 0, -1);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int, AttributedCharacterIterator.Attribute[]) Test of method
+ * java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int, AttributedCharacterIterator.Attribute[]). Case 1: Try to
+ * consruct AttributedString. Case 2: Try to consruct
+ * AttributedString using incorrect beginIndex. Case 3: Try to
+ * consruct AttributedString using incorrect endIndex. Case 4: Try to
+ * consruct AttributedString using specified attributes.
+ */
+ public void test_ConstructorLAttributedCharacterIteratorII$Ljava_text_AttributedCharacterIterator$Attribute() {
+ // case 1: Try to consruct AttributedString.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), 0, 0,
+ null);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+
+ // case 2: Try to consruct AttributedString using incorrect beginIndex.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), -1, 0,
+ null);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // case 3: Try to consruct AttributedString using incorrect endIndex.
+ try {
+ new AttributedString(new testAttributedCharacterIterator(), 0, -1,
+ null);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // case 4: Try to consruct AttributedString using specified attributes.
+ try {
+ AttributedCharacterIterator.Attribute[] attributes = new AttributedCharacterIterator.Attribute[1];
+ attributes[0] = new TestAttributedCharacterIteratorAttribute("test");
+ new AttributedString(new testAttributedCharacterIterator(), 0, 0,
+ attributes);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected expected " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int, Map<? extends AttributedCharacterIterator.Attribute,?>)
+ * Test of method
+ * java.text.AttributedString#AttributedString(AttributedCharacterIterator,
+ * int, int, Map<? extends
+ * AttributedCharacterIterator.Attribute,?>). Case 1: Try to
+ * construct AttributedString. Case 2: Try to construct
+ * AttributedString using 0-length text and not an empty Map
+ * attributes.
+ */
+ public void test_ConstructorLjava_lang_StringLjava_util_Map() {
+ String test = "Test string";
+
+ // case 1: Try to construct AttributedString
+ try {
+ AttributedString attrString = new AttributedString(
+ test,
+ new WeakHashMap<AttributedCharacterIterator.Attribute, String>());
+ AttributedCharacterIterator it = attrString.getIterator();
+ StringBuffer buf = new StringBuffer();
+ buf.append(it.first());
+ char ch;
+ while ((ch = it.next()) != CharacterIterator.DONE)
+ buf.append(ch);
+ assertTrue("Wrong string: " + buf, buf.toString().equals(test));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+
+ // case 2: Try to construct AttributedString using 0-length text and
+ // not an empty Map attributes.
+ try {
+ Map<AttributedCharacterIterator.Attribute, String> whm = new WeakHashMap<AttributedCharacterIterator.Attribute, String>();
+ whm.put(new TestAttributedCharacterIteratorAttribute("test"),
+ "value");
+ new AttributedString("", whm);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+
+ private class TestAttributedCharacterIteratorAttribute extends
+ AttributedCharacterIterator.Attribute {
+ private static final long serialVersionUID = -2917613373935785179L;
+
+ public TestAttributedCharacterIteratorAttribute(String name) {
+ super(name);
+ }
+ }
+
+ private class testAttributedCharacterIterator implements
+ AttributedCharacterIterator {
+ public Set getAllAttributeKeys() {
+ return null;
+ }
+
+ public Object getAttribute(AttributedCharacterIterator.Attribute p) {
+ return null;
+ }
+
+ public Map getAttributes() {
+ return null;
+ }
+
+ public int getRunLimit(Set p) {
+ return 0;
+ }
+
+ public int getRunLimit(AttributedCharacterIterator.Attribute p) {
+ return 0;
+ }
+
+ public int getRunLimit() {
+ return 0;
+ }
+
+ public int getRunStart(Set p) {
+ return 0;
+ }
+
+ public int getRunStart(AttributedCharacterIterator.Attribute p) {
+ return 0;
+ }
+
+ public int getRunStart() {
+ return 0;
+ }
+
+ public Object clone() {
+ return null;
+ }
+
+ public int getIndex() {
+ return 0;
+ }
+
+ public int getEndIndex() {
+ return 0;
+ }
+
+ public int getBeginIndex() {
+ return 0;
+ }
+
+ public char setIndex(int p) {
+ return 'a';
+ }
+
+ public char previous() {
+ return 'a';
+ }
+
+ public char next() {
+ return 'a';
+ }
+
+ public char current() {
+ return 'a';
+ }
+
+ public char last() {
+ return 'a';
+ }
+
+ public char first() {
+ return 'a';
+ }
+ }
+
+ public void test_addAttributeLjava_text_AttributedCharacterIterator$AttributeLjava_lang_ObjectII() {
+ AttributedString as = new AttributedString("test");
+ as.addAttribute(AttributedCharacterIterator.Attribute.LANGUAGE, "a", 2,
+ 3);
+ AttributedCharacterIterator it = as.getIterator();
+ assertEquals("non-null value limit", 2, it
+ .getRunLimit(AttributedCharacterIterator.Attribute.LANGUAGE));
+
+ as = new AttributedString("test");
+ as.addAttribute(AttributedCharacterIterator.Attribute.LANGUAGE, null,
+ 2, 3);
+ it = as.getIterator();
+ assertEquals("null value limit", 4, it
+ .getRunLimit(AttributedCharacterIterator.Attribute.LANGUAGE));
+
+ try {
+ as = new AttributedString("test");
+ as.addAttribute(AttributedCharacterIterator.Attribute.LANGUAGE,
+ null, -1, 3);
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ // regression for Harmony-1244
+ as = new AttributedString("123", new WeakHashMap());
+ try {
+ as.addAttribute(null, new TreeSet(), 0, 1);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ as.addAttribute(null, new TreeSet(), -1, 1);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString.addAttribute(AttributedCharacterIterator,
+ * Object)
+ */
+ public void test_addAttributeLjava_text_AttributedCharacterIterator$AttributeLjava_lang_Object() {
+ // regression for Harmony-1244
+ AttributedString as = new AttributedString("123", new WeakHashMap());
+ try {
+ as.addAttribute(null, new TreeSet());
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ as.addAttribute(null, null);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#addAttributes(Map<? extends
+ * AttributedCharacterIterator.Attribute,?>, int, int) Tests of
+ * method java.text.AttributedString#addAttributes(Map<? extends
+ * AttributedCharacterIterator.Attribute,?>, int, int). Case 1: Try
+ * to add attributes to AttributesString. Case 2: Try to add
+ * null-attributes to AttributesString. Case 3: Try to add attributes
+ * to AttributesString using incorrect index.
+ */
+ public void test_addAttributesLjava_util_MapII() {
+ AttributedString as = new AttributedString("test");
+ Map<AttributedCharacterIterator.Attribute, String> whm = new WeakHashMap<AttributedCharacterIterator.Attribute, String>();
+
+ // case 1: Try to add attributes to AttributesString.
+ try {
+ whm.put(new TestAttributedCharacterIteratorAttribute("test1"),
+ "value1");
+ whm.put(new TestAttributedCharacterIteratorAttribute("test2"),
+ "value2");
+ whm.put(new TestAttributedCharacterIteratorAttribute("test3"),
+ "value3");
+ as.addAttributes(whm, 0, 3);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+
+ // case 2: Try to add null-attributes to AttributesString.
+ try {
+ as.addAttributes(null, 0, 3);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ // case 3: Try to add attributes to AttributesString using incorrect
+ // index.
+ try {
+ as.addAttributes(whm, 0, 0);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#getIterator() Test of method
+ * java.text.AttributedString#getIterator().
+ */
+ public void test_getIterator() {
+ String test = "Test string";
+ try {
+ AttributedString attrString = new AttributedString(test);
+ AttributedCharacterIterator it = attrString.getIterator();
+ assertEquals("Incorrect iteration on AttributedString", it.first(),
+ test.charAt(0));
+ } catch (Exception e) {
+ fail("Unexpected exceptiption " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#getIterator(AttributedCharacterIterator.Attribute[])
+ * Test of method
+ * java.text.AttributedString#getIterator(AttributedCharacterIterator.Attribute[]).
+ */
+ public void test_getIterator$Ljava_text_AttributedCharacterIterator$Attribute() {
+ String test = "Test string";
+ try {
+ Map<AttributedCharacterIterator.Attribute, String> hm = new HashMap<AttributedCharacterIterator.Attribute, String>();
+ AttributedCharacterIterator.Attribute[] aci = new AttributedCharacterIterator.Attribute[3];
+ aci[0] = new TestAttributedCharacterIteratorAttribute("att1");
+ aci[1] = new TestAttributedCharacterIteratorAttribute("att2");
+ aci[2] = new TestAttributedCharacterIteratorAttribute("att3");
+ hm.put(aci[0], "value1");
+ hm.put(aci[1], "value2");
+
+ AttributedString attrString = new AttributedString(test, hm);
+ AttributedCharacterIterator it = attrString.getIterator(aci);
+
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[0]).equals("value1"));
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[1]).equals("value2"));
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[2]) == null);
+ } catch (Exception e) {
+ fail("Unexpected exceptiption " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.AttributedString#getIterator(AttributedCharacterIterator.Attribute[],
+ * int, int) Test of method
+ * java.text.AttributedString#getIterator(AttributedCharacterIterator.Attribute[],
+ * int, int).
+ */
+ public void test_getIterator$Ljava_text_AttributedCharacterIterator$AttributeII() {
+ String test = "Test string";
+ try {
+ Map<AttributedCharacterIterator.Attribute, String> hm = new HashMap<AttributedCharacterIterator.Attribute, String>();
+ AttributedCharacterIterator.Attribute[] aci = new AttributedCharacterIterator.Attribute[3];
+ aci[0] = new TestAttributedCharacterIteratorAttribute("att1");
+ aci[1] = new TestAttributedCharacterIteratorAttribute("att2");
+ aci[2] = new TestAttributedCharacterIteratorAttribute("att3");
+ hm.put(aci[0], "value1");
+ hm.put(aci[1], "value2");
+
+ AttributedString attrString = new AttributedString(test);
+ attrString.addAttributes(hm, 2, 4);
+ AttributedCharacterIterator it = attrString.getIterator(aci, 1, 5);
+
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[0]) == null);
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[1]) == null);
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[2]) == null);
+
+ it.next();
+
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[0]).equals("value1"));
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[1]).equals("value2"));
+ assertTrue("Incorrect iteration on AttributedString", it
+ .getAttribute(aci[2]) == null);
+ } catch (Exception e) {
+ fail("Unexpected exceptiption " + e.toString());
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/BidiTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/BidiTest.java
new file mode 100644
index 0000000..bbe3f1c
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/BidiTest.java
@@ -0,0 +1,994 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.AttributedString;
+import java.text.Bidi;
+import java.util.Arrays;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class BidiTest extends TestCase {
+
+ Bidi bd;
+
+ public static void assertRunArrayEquals(int[][] expected, Bidi bidi) {
+ assertEquals("different length", expected.length, bidi.getRunCount());
+
+ FORRUN: for (int i = 0; i < bidi.getRunCount(); i++) {
+ int[] butWas = new int[] { bidi.getRunStart(i),
+ bidi.getRunLimit(i), bidi.getRunLevel(i) };
+
+ for (int j = 0; j < expected.length; j++) {
+ if (expected[j][0] == butWas[0] && expected[j][1] == butWas[1]
+ && expected[j][2] == butWas[2]) {
+ continue FORRUN;
+ }
+ }
+ fail("expected [" + i + "] " + " start: " + butWas[0] + " limit: "
+ + butWas[1] + " level: " + butWas[2]);
+ }
+ }
+
+ public void testNullPointerConstructor() {
+ try {
+ bd = new Bidi(null, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(null, 0, new byte[] { 0 }, 0, 0,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(null);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ }
+
+ bd = new Bidi("a".toCharArray(), 0, null, 0, 1,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ }
+
+ public void testBadLength() {
+ try {
+ bd = new Bidi("1".toCharArray(), 0, new byte[] { 0 }, 0, 20,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi("1234567".toCharArray(), 0, new byte[] { 0 }, 0, 4,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi("1234567".toCharArray(), 4, new byte[] { 0, 1, 2, 3,
+ 4 }, 0, 5, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi("1234567".toCharArray(), 0, new byte[] { 0, 1, 2, 3,
+ 4 }, 4, 5, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // regression for HARMONY-1031
+ try {
+ bd = new Bidi(new char[] { 't', 't', 't' }, -1,
+ new byte[] { 2, 2 }, 1, 1, 1);
+ fail("should be IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(new char[] { 't', 't', 't' }, 1, new byte[] { 2, 2 },
+ -1, 1, 1);
+ fail("should be IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(new char[] { 't', 't', 't' }, 1, new byte[] { 2, 2 },
+ 1, -1, 1);
+ fail("should be IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(new char[] {}, 5, new byte[] { 2, 2, 2, 2, 2, 2 }, 8,
+ Integer.MAX_VALUE, 5);
+ fail("should be IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ bd = new Bidi(null, 5, null, 8, Integer.MAX_VALUE, 5);
+ fail("should be IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ bd = new Bidi(new char[] { 'o' }, 0, new byte[] { 2, 2 }, 2, 0, 2);
+ }
+
+ public void testEmptyParagraph() {
+ bd = new Bidi("", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(0, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 0, 0 } }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(0, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 0, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+
+ bd = new Bidi("", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(0, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 0, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(0, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 0, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+ }
+
+ public void testSpaceParagraph() {
+ bd = new Bidi(" ", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(" ", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+
+ bd = new Bidi(" ", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(" ", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+ }
+
+ public void testSimpleParagraph() {
+ bd = new Bidi("t", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("t", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("t", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ /**
+ * @tests java.text.Bidi#toString() Test of method java.text.Bidi#toString()
+ */
+ public void testToString() {
+ try {
+ bd = new Bidi("bidi", 173);
+ assertNotNull("Bidi representation is null", bd.toString());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ public void testBadFlags() {
+ bd = new Bidi("", 173);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(0, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 0, 0 }, }, bd);
+ assertTrue(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testBadEmbeddings() {
+ try {
+ bd = new Bidi("".toCharArray(), 0, new byte[] {}, 0, 1,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ public void testOverrideEmbeddings() {
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) -7,
+ (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(7, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 7 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) -1,
+ (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) -1,
+ (byte) -2, (byte) -3 }, 0, 3, Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) -1,
+ (byte) -2, (byte) -3 }, 0, 3, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testDefaultEmbeddings() {
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) 0,
+ (byte) 0, (byte) 0 }, 0, 3, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(2, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 3, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testRelativeEmbeddings() {
+ bd = new Bidi(new char[] { 's', 's', 's' }, 0, new byte[] { (byte) 1,
+ (byte) 2, (byte) 3 }, 0, 3, Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(4, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 2, 2 }, { 2, 3, 4 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testSimpleHebrewParagraph() {
+ bd = new Bidi("\u05D0", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+
+ bd = new Bidi("\u05D0", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+
+ bd = new Bidi("\u05D0", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertFalse(bd.isMixed());
+ assertTrue(bd.isRightToLeft());
+ }
+
+ public void testSimpleBidiParagraph_1() {
+ bd = new Bidi("\u05D0a", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("\u05D0a", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("\u05D0a", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 0 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("\u05D0a", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testSimpleBidiParagraph_2() {
+ bd = new Bidi("a\u05D0", Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, { 1, 2, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("a\u05D0", Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, { 1, 2, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("a\u05D0", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(0, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 0 }, { 1, 2, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi("a\u05D0", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(2, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(2, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 2 }, { 1, 2, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ /*
+ * spec reads: public static final int DIRECTION_RIGHT_TO_LEFT Constant
+ * indicating base direction is right-to-left. according to that, the method
+ * baseIsLeftToRight() here should return false. however, RI doesn't act so.
+ */
+ public void testRIBug_1() {
+ bd = new Bidi("t", Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ // the base level it the essential cause
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ // this is essentially the same bug as Bug_1
+ public void testRIBug_2() {
+ bd = new Bidi("\u05D0", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(1, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(1, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testComplicatedBidi() {
+ bd = new Bidi("a\u05D0a\"a\u05D0\"\u05D0a",
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(9, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(2, bd.getLevelAt(2));
+ assertEquals(2, bd.getLevelAt(3));
+ assertEquals(2, bd.getLevelAt(4));
+ assertEquals(1, bd.getLevelAt(5));
+ assertEquals(1, bd.getLevelAt(6));
+ assertEquals(1, bd.getLevelAt(7));
+ assertEquals(2, bd.getLevelAt(8));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(5, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 2 }, { 1, 2, 1 },
+ { 2, 5, 2 }, { 5, 8, 1 }, { 8, 9, 2 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testComplicatedOverrideBidi() {
+ bd = new Bidi("a\u05D0a\"a\u05D0\"\u05D0a".toCharArray(), 0,
+ new byte[] { 0, 0, 0, -3, -3, 2, 2, 0, 3 }, 0, 9,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(9, bd.getLength());
+ assertEquals(2, bd.getLevelAt(0));
+ assertEquals(1, bd.getLevelAt(1));
+ assertEquals(2, bd.getLevelAt(2));
+ assertEquals(3, bd.getLevelAt(3));
+ assertEquals(3, bd.getLevelAt(4));
+ assertEquals(3, bd.getLevelAt(5));
+ assertEquals(2, bd.getLevelAt(6));
+ assertEquals(1, bd.getLevelAt(7));
+ assertEquals(4, bd.getLevelAt(8));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(7, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 2 }, { 1, 2, 1 },
+ { 2, 3, 2 }, { 3, 6, 3 }, { 6, 7, 2 }, { 7, 8, 1 },
+ { 8, 9, 4 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testRequiresBidi() {
+ try {
+ Bidi.requiresBidi(null, 0, 0);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ assertFalse(Bidi.requiresBidi(null, 0, 1));
+ fail("should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("".toCharArray(), 0, 1));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), -1, 1));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 1, -1));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("\u05D0".toCharArray(), 1, -1));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 1, 0));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 7, 7));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 1,
+ Integer.MAX_VALUE));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(),
+ Integer.MAX_VALUE, 1));
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ assertFalse(Bidi.requiresBidi("".toCharArray(), 0, 0));
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 1, 1));
+ assertFalse(Bidi.requiresBidi("aaa".toCharArray(), 0, 2));
+ assertFalse(Bidi.requiresBidi("\u05D0".toCharArray(), 1, 1));
+ assertTrue(Bidi.requiresBidi("\u05D0".toCharArray(), 0, 1));
+ assertFalse(Bidi.requiresBidi("aa\u05D0a".toCharArray(), 0, 2));
+ assertTrue(Bidi.requiresBidi("aa\u05D0a".toCharArray(), 1, 3));
+ }
+
+ public void testHebrewOverrideEmbeddings() {
+ bd = new Bidi(new char[] { '\u05D0', '\u05D0', '\u05D0' }, 0,
+ new byte[] { (byte) -1, (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { '\u05D0', '\u05D0', '\u05D0' }, 0,
+ new byte[] { (byte) -1, (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { '\u05D0', '\u05D0', '\u05D0' }, 0,
+ new byte[] { (byte) -1, (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_LEFT_TO_RIGHT);
+ assertTrue(bd.baseIsLeftToRight());
+ assertEquals(0, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(0, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+
+ bd = new Bidi(new char[] { '\u05D0', '\u05D0', '\u05D0' }, 0,
+ new byte[] { (byte) -1, (byte) -2, (byte) -3 }, 0, 3,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ assertFalse(bd.baseIsLeftToRight());
+ assertEquals(1, bd.getBaseLevel());
+ assertEquals(3, bd.getLength());
+ assertEquals(1, bd.getLevelAt(0));
+ assertEquals(2, bd.getLevelAt(1));
+ assertEquals(3, bd.getLevelAt(2));
+ assertEquals(1, bd.getLevelAt(1000));
+ assertEquals(3, bd.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 1 }, { 1, 2, 2 },
+ { 2, 3, 3 }, }, bd);
+ assertFalse(bd.isLeftToRight());
+ assertTrue(bd.isMixed());
+ assertFalse(bd.isRightToLeft());
+ }
+
+ public void testCreateLineBidi() {
+ bd = new Bidi("a\u05D0a\na\u05D0\"\u05D0a".toCharArray(), 0,
+ new byte[] { 0, 0, 0, -3, -3, 2, 2, 0, 3 }, 0, 9,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ Bidi line = bd.createLineBidi(2, 7);
+ assertFalse(line.baseIsLeftToRight());
+ assertEquals(1, line.getBaseLevel());
+ assertEquals(5, line.getLength());
+ assertEquals(2, line.getLevelAt(0));
+ assertEquals(1, line.getLevelAt(1));
+ assertEquals(3, line.getLevelAt(2));
+ assertEquals(3, line.getLevelAt(3));
+ assertEquals(2, line.getLevelAt(4));
+ assertEquals(1, line.getLevelAt(1000));
+ assertEquals(4, line.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 1, 2 }, { 1, 2, 1 },
+ { 2, 4, 3 }, { 4, 5, 2 }, }, line);
+ assertFalse(line.isLeftToRight());
+ assertTrue(line.isMixed());
+ assertFalse(line.isRightToLeft());
+ }
+
+ public void testCreateLineBidiInvalid() {
+ // regression for HARMONY-1050
+ Bidi bidi = new Bidi("str", 1);
+ try {
+ bidi.createLineBidi(-1, 1);
+ fail("Expected IAE");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ bidi.createLineBidi(1, -1);
+ fail("Expected IAE");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ bidi.createLineBidi(-1, -1);
+ fail("Expected IAE");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ bidi.createLineBidi(2, 1);
+ fail("Expected IAE");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ bidi.createLineBidi(2, 2);
+
+ try {
+ bidi.createLineBidi(2, 4);
+ fail("Expected IAE");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ public void testIncompatibleLineAlgorithm() {
+ // ICU treat a new line as in the same run, however RI does not
+ bd = new Bidi("aaaaa".toCharArray(), 0,
+ new byte[] { -2, -1, -3, -3, -2 }, 0, 5,
+ Bidi.DIRECTION_RIGHT_TO_LEFT);
+ Bidi line = bd.createLineBidi(1, 4);
+ assertFalse(line.baseIsLeftToRight());
+ assertEquals(1, line.getBaseLevel());
+ assertEquals(3, line.getLength());
+ assertEquals(1, line.getLevelAt(0));
+ assertEquals(1, line.getLevelAt(1));
+ assertEquals(1, line.getLevelAt(2));
+ assertEquals(1, line.getLevelAt(1000));
+ assertEquals(1, line.getRunCount());
+ assertRunArrayEquals(new int[][] { { 0, 3, 1 }, }, line);
+ assertFalse(line.isLeftToRight());
+ assertFalse(line.isMixed());
+ assertTrue(line.isRightToLeft());
+ }
+
+ public void testReorderVisually() {
+ String[] init = new String[] { "a", "b", "c", "d" };
+ String[] s = new String[4];
+
+ System.arraycopy(init, 0, s, 0, s.length);
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 0, s, 0, 4);
+ assertEquals("[c, b, a, d]", Arrays.asList(s).toString());
+
+ System.arraycopy(init, 0, s, 0, s.length);
+ Bidi.reorderVisually(new byte[] { 1, 3 }, 0, s, 1, 2);
+ assertEquals("[a, c, b, d]", Arrays.asList(s).toString());
+
+ System.arraycopy(init, 0, s, 0, s.length);
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 1, s, 1, 2);
+ assertEquals("[a, c, b, d]", Arrays.asList(s).toString());
+
+ System.arraycopy(init, 0, s, 0, s.length);
+ Bidi.reorderVisually(new byte[] { 2, 1, 2, 1 }, 1, s, 0, 3);
+ assertEquals("[c, b, a, d]", Arrays.asList(s).toString());
+
+ System.arraycopy(init, 0, s, 0, s.length);
+ Bidi.reorderVisually(new byte[] { 2, 1, 0, 1 }, 1, s, 0, 3);
+ assertEquals("[a, b, c, d]", Arrays.asList(s).toString());
+ }
+
+ public void testBadReorderVisually() {
+ String[] s = new String[] { "a", "b", "c", "d" };
+
+ try {
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 0, s, 0, 5);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 0, s, -1, 1);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, -1, s, 0, 1);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ Bidi.reorderVisually(null, 0, s, 0, 1);
+ fail("should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 0, null, 0, 1);
+ fail("should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ Bidi.reorderVisually(new byte[] { 2, 1, 3, 0 }, 1, s, 0, -1);
+ fail("should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ }
+
+ public void testGetRuns() {
+ // Regression test for Harmony-1028
+
+ String LTR = "\u0061\u0062";
+ String RTL = "\u05DC\u05DD";
+ String newLine = "\n";
+ String defText = LTR + newLine + RTL + LTR + RTL;
+
+ int[][] expectedRuns = { { 0, 3 }, { 3, 5 }, { 5, 7 }, { 7, 9 }, };
+
+ Bidi bi = new Bidi(defText, 0);
+ final int count = bi.getRunCount();
+ for (int i = 0; i < count; i++) {
+ assertEquals(expectedRuns[i][0], bi.getRunStart(i));
+ assertEquals(expectedRuns[i][1], bi.getRunLimit(i));
+ }
+ }
+
+ public void testGetRunLimit() {
+ bd = new Bidi("text", Bidi.DIRECTION_LEFT_TO_RIGHT);
+ try {
+ assertTrue(4 == bd.getRunLimit(-1));
+ } catch (Exception e) {
+ fail("Unexpected exception: " + e);
+ }
+ }
+
+ public void testBidiConstructor_Iterator() {
+ AttributedString paragraph = new AttributedString("text");
+ bd = new Bidi(paragraph.getIterator());
+ try {
+ assertTrue(4 == bd.getRunLimit(1));
+ } catch (Exception e) {
+ fail("Unexpected exception: " + e);
+ }
+ }
+
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/BreakIteratorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/BreakIteratorTest.java
new file mode 100644
index 0000000..29f2b29
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/BreakIteratorTest.java
@@ -0,0 +1,597 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.BreakIterator;
+import java.text.CharacterIterator;
+import java.util.Collection;
+import java.util.Collections;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class BreakIteratorTest extends TestCase {
+
+ private static final String TEXT = "a\u0308abc def, gh-12i?jkl.mno?";
+
+ BreakIterator iterator;
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ iterator = BreakIterator.getCharacterInstance(Locale.US);
+ }
+
+ public void testConsts() {
+ assertEquals(-1, BreakIterator.DONE);
+ }
+
+ public void testCache() {
+ BreakIterator newOne = BreakIterator.getCharacterInstance(Locale.US);
+ assertNotSame(newOne, iterator);
+ assertEquals(newOne, iterator);
+
+ newOne = BreakIterator.getCharacterInstance();
+ assertEquals(newOne, iterator);
+
+ newOne = BreakIterator.getCharacterInstance(Locale.CHINA);
+ assertEquals(newOne, iterator);
+
+ BreakIterator wordIterator = BreakIterator.getWordInstance();
+ assertFalse(wordIterator.equals(iterator));
+
+ BreakIterator lineIterator = BreakIterator.getLineInstance();
+ assertFalse(lineIterator.equals(iterator));
+
+ BreakIterator senteIterator = BreakIterator.getSentenceInstance();
+ assertFalse(senteIterator.equals(iterator));
+ }
+
+ public void testClone() {
+ BreakIterator cloned = (BreakIterator) iterator.clone();
+ assertNotSame(cloned, iterator);
+ assertEquals(cloned, iterator);
+ }
+
+ public void testCurrent() {
+ assertEquals(0, iterator.current());
+ iterator.setText(TEXT);
+ assertEquals(iterator.first(), iterator.current());
+ }
+
+ /**
+ * @tests java.text.BreakIterator#BreakIterator() Test of method
+ * java.text.BreakIterator#BreakIterator().
+ */
+ public void testConstructor() {
+ try {
+ new MockBreakIterator();
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ public void testFirst() {
+ assertEquals(0, iterator.first());
+ iterator.setText(TEXT);
+ assertEquals(0, iterator.first());
+ }
+
+ public void testFollowing() {
+ try {
+ iterator.following(1);
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ iterator.setText(TEXT);
+ assertEquals(2, iterator.following(1));
+ try {
+ assertEquals(0, iterator.following(-1));
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ iterator.following(TEXT.length());
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testIsBoundary() {
+ try {
+ iterator.isBoundary(2);
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ iterator.setText(TEXT);
+ assertTrue(iterator.isBoundary(2));
+ assertFalse(iterator.isBoundary(1));
+ assertTrue(iterator.isBoundary(0));
+ try {
+ iterator.isBoundary(-1);
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ iterator.isBoundary(TEXT.length());
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testLast() {
+ assertEquals(0, iterator.last());
+ iterator.setText(TEXT);
+ assertEquals(TEXT.length(), iterator.last());
+ }
+
+ /*
+ * Class under test for int next(int)
+ */
+ public void testNextint() {
+ assertEquals(BreakIterator.DONE, iterator.next(3));
+ iterator.setText(TEXT);
+ assertEquals(4, iterator.next(3));
+ assertEquals(24, iterator.next(20));
+ assertEquals(23, iterator.next(-1));
+ assertEquals(-1, iterator.next(TEXT.length()));
+ }
+
+ public void testPreceding() {
+ try {
+ iterator.preceding(2);
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ iterator.setText(TEXT);
+ assertEquals(0, iterator.preceding(2));
+ assertEquals(2, iterator.preceding(3));
+ assertEquals(16, iterator.preceding(17));
+ assertEquals(17, iterator.preceding(18));
+ assertEquals(18, iterator.preceding(19));
+ try {
+ iterator.preceding(-1);
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ iterator.preceding(TEXT.length());
+ fail("should throw illegal argument exception");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testPrevious() {
+ assertEquals(-1, iterator.previous());
+ iterator.setText(TEXT);
+ assertEquals(-1, iterator.previous());
+ iterator.last();
+ assertEquals(TEXT.length() - 1, iterator.previous());
+ }
+
+ /**
+ * @tests java.text.BreakIterator#getAvailableLocales(). Test of method
+ * java.text.BreakIterator#getAvailableLocales().
+ */
+ public void testGetAvailableLocales() {
+ try {
+ Locale[] locales = BreakIterator.getAvailableLocales();
+ assertTrue("Array available locales is null", locales != null);
+ assertTrue("Array available locales is 0-length",
+ (locales != null && locales.length != 0));
+ boolean found = false;
+ for (Locale l : locales) {
+ if (l.equals(Locale.US)) {
+ // expected
+ found = true;
+ }
+ }
+ assertTrue("At least locale " + Locale.US + " must be presented",
+ found);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /*
+ * Class under test for BreakIterator getCharacterInstance()
+ */
+ public void testGetCharacterInstance() {
+ BreakIterator.getCharacterInstance();
+ }
+
+ /*
+ * Class under test for BreakIterator getCharacterInstance(Locale)
+ */
+ public void testGetCharacterInstanceLocale() {
+ BreakIterator it = BreakIterator.getCharacterInstance(Locale.US);
+ BreakIterator it2 = BreakIterator.getCharacterInstance(Locale.CHINA);
+ assertEquals(it, it2);
+ }
+
+ /*
+ * Class under test for BreakIterator getLineInstance()
+ */
+ public void testGetLineInstance() {
+ BreakIterator it = BreakIterator.getLineInstance();
+ assertNotNull(it);
+ }
+
+ /*
+ * @tests java.text.BreakIterator#getLineInstance(Locale) Class under test
+ * for BreakIterator getLineInstance(Locale)
+ */
+ public void testGetLineInstanceLocale() {
+ try {
+ BreakIterator it1 = BreakIterator
+ .getLineInstance(Locale.CANADA_FRENCH);
+ assertTrue("Incorrect BreakIterator", it1 != BreakIterator
+ .getLineInstance());
+ BreakIterator it2 = BreakIterator.getLineInstance(new Locale(
+ "bad locale"));
+ assertTrue("Incorrect BreakIterator", it2 != BreakIterator
+ .getLineInstance());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /*
+ * Class under test for BreakIterator getSentenceInstance()
+ */
+ public void testGetSentenceInstance() {
+ BreakIterator it = BreakIterator.getSentenceInstance();
+ assertNotNull(it);
+ }
+
+ /*
+ * Class under test for BreakIterator getSentenceInstance(Locale)
+ */
+ public void testGetSentenceInstanceLocale() {
+ BreakIterator it = BreakIterator.getSentenceInstance(Locale.US);
+ assertNotNull(it);
+ }
+
+ public void testGetText() {
+ assertEquals(new StringCharacterIterator(""), iterator.getText());
+ iterator.setText(TEXT);
+ assertEquals(new StringCharacterIterator(TEXT), iterator.getText());
+ }
+
+ /*
+ * Class under test for BreakIterator getWordInstance()
+ */
+ public void testGetWordInstance() {
+ BreakIterator it = BreakIterator.getWordInstance();
+ assertNotNull(it);
+ }
+
+ /*
+ * @tests java.text.BreakIterator#getWordInstance(Locale) Class under test
+ * for BreakIterator getWordInstance(Locale)
+ */
+ public void testGetWordInstanceLocale() {
+ try {
+ BreakIterator it1 = BreakIterator
+ .getWordInstance(Locale.CANADA_FRENCH);
+ assertTrue("Incorrect BreakIterator", it1 != BreakIterator
+ .getWordInstance());
+ BreakIterator it2 = BreakIterator.getWordInstance(new Locale(
+ "bad locale"));
+ assertTrue("Incorrect BreakIterator", it2 != BreakIterator
+ .getWordInstance());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /*
+ * Class under test for void setText(CharacterIterator)
+ */
+ public void testSetTextCharacterIterator() {
+ try {
+ iterator.setText((CharacterIterator) null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ CharacterIterator it = new StringCharacterIterator("abc");
+ iterator.setText(it);
+ assertSame(it, iterator.getText());
+ }
+
+ /*
+ * Class under test for void setText(String)
+ */
+ public void testSetTextString() {
+ try {
+ iterator.setText((String) null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ iterator.setText("abc");
+ CharacterIterator it = new StringCharacterIterator("abc");
+ assertEquals(it, iterator.getText());
+ }
+
+ public void test_next() {
+ // Regression test for HARMONY-30
+ BreakIterator bi = BreakIterator.getWordInstance(Locale.US);
+ bi.setText("This is the test, WordInstance");
+ int n = bi.first();
+ n = bi.next();
+ assertEquals("Assert 0: next() returns incorrect value ", 4, n);
+
+ assertEquals(BreakIterator.DONE, iterator.next());
+ iterator.setText(TEXT);
+ assertEquals(2, iterator.next());
+ }
+
+ /**
+ * @tests java.text.BreakIterator.getShort(byte[], int)
+ *
+ */
+ public void test_getShort() {
+ try {
+ MockBreakIterator.publicGetShort(null, 0);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetShort(null, -1);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetShort(new byte[] { 0, 0, 0, 1, 1 }, -1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ try {
+ MockBreakIterator.publicGetShort(new byte[] { 0, 0 }, 1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(0, MockBreakIterator
+ .publicGetShort(new byte[] { 0, 0 }, 0));
+ assertEquals(1, MockBreakIterator
+ .publicGetShort(new byte[] { 0, 1 }, 0));
+ assertEquals(-1, MockBreakIterator.publicGetShort(new byte[] {
+ (byte) 0xff, (byte) 0xff }, 0));
+ assertEquals(1, MockBreakIterator.publicGetShort(new byte[] { 1, 0, 1,
+ 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetShort(new byte[] { 0, 0, 1,
+ 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetShort(new byte[] { 0, 0, 1,
+ 1 }, 1));
+ assertEquals(257, MockBreakIterator.publicGetShort(
+ new byte[] { 0, 1, 1 }, 1));
+
+ // regression for Harmony-944
+ try {
+ MockBreakIterator.publicGetShort(new byte[] { 0, 0 },
+ Integer.MAX_VALUE);
+ fail("should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // expected
+ }
+
+ try {
+ MockBreakIterator.publicGetShort(new byte[] { 0, 0 },
+ Short.MAX_VALUE);
+ fail("should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.BreakIterator.getInt(byte[], int)
+ *
+ */
+ public void test_getInt() {
+ try {
+ MockBreakIterator.publicGetInt(null, 0);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetInt(null, -1);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetInt(new byte[] { 0, 0, 0, 1, 1 }, -1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ try {
+ MockBreakIterator.publicGetInt(new byte[] { 0, 0, 0, 0 }, 1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(0, MockBreakIterator.publicGetInt(
+ new byte[] { 0, 0, 0, 0 }, 0));
+ assertEquals(1, MockBreakIterator.publicGetInt(
+ new byte[] { 0, 0, 0, 1 }, 0));
+ assertEquals(-1, MockBreakIterator.publicGetInt(new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 0));
+ assertEquals(1, MockBreakIterator.publicGetInt(new byte[] { 1, 0, 0, 0,
+ 1, 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetInt(new byte[] { 0, 0, 0, 0,
+ 1, 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetInt(new byte[] { 0, 0, 0, 0,
+ 1, 1 }, 1));
+ assertEquals(257, MockBreakIterator.publicGetInt(new byte[] { 0, 0, 0,
+ 1, 1 }, 1));
+
+ // regression for Harmony-944
+ try {
+ MockBreakIterator.publicGetInt(new byte[] { 0, 0 },
+ Integer.MAX_VALUE);
+ fail("should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.BreakIterator.getLong(byte[], int)
+ *
+ */
+ public void test_getLong() {
+ try {
+ MockBreakIterator.publicGetLong(null, 0);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetLong(null, -1);
+ fail("should throw NPE.");
+ } catch (NullPointerException e) {
+ }
+ try {
+ MockBreakIterator.publicGetLong(
+ new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, -1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ try {
+ MockBreakIterator.publicGetLong(
+ new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, 1);
+ fail("should throw ArrayIndexOutOfBoundsException.");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(0, MockBreakIterator.publicGetLong(new byte[] { 0, 0, 0,
+ 0, 0, 0, 0, 0 }, 0));
+ assertEquals(1, MockBreakIterator.publicGetLong(new byte[] { 0, 0, 0,
+ 0, 0, 0, 0, 1 }, 0));
+ assertEquals(-1, MockBreakIterator.publicGetLong(new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }, 0));
+ assertEquals(1, MockBreakIterator.publicGetLong(new byte[] { 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetLong(new byte[] { 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0 }, 1));
+ assertEquals(1, MockBreakIterator.publicGetLong(new byte[] { 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1 }, 1));
+ assertEquals(257, MockBreakIterator.publicGetLong(new byte[] { 0, 0, 0,
+ 0, 0, 0, 0, 1, 1 }, 1));
+
+ // regression for Harmony-944
+ try {
+ MockBreakIterator.publicGetLong(new byte[] { 0, 1 },
+ Integer.MAX_VALUE);
+ fail("should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.BreakIterator#getCharacterInstance(Locale)
+ */
+ public void testGetCharacterInstanceLocale_NPE() {
+ // Regression for HARMONY-265
+ try {
+ BreakIterator.getCharacterInstance(null);
+ fail("BreakIterator.getCharacterInstance(null); should throw NullPointerException");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ public void testGetLineInstanceLocale_NPE() {
+ try {
+ BreakIterator.getLineInstance(null);
+ fail("BreakIterator.getLineInstance(null); should throw NullPointerException");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ public void testGetSentenceInstanceLocale_NPE() {
+ try {
+ BreakIterator.getSentenceInstance(null);
+ fail("BreakIterator.getSentenceInstance(null); should throw NullPointerException");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ public void testGetWordInstanceLocale_NPE() {
+ try {
+ BreakIterator.getWordInstance(null);
+ fail("BreakIterator.getWordInstance(null); should throw NullPointerException");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ private static class MockBreakIterator extends BreakIterator {
+ public MockBreakIterator() {
+ super();
+ }
+
+ public static int publicGetInt(byte[] buf, int offset) {
+ return BreakIterator.getInt(buf, offset);
+ }
+
+ public static long publicGetLong(byte[] buf, int offset) {
+ return BreakIterator.getLong(buf, offset);
+ }
+
+ public static short publicGetShort(byte[] buf, int offset) {
+ return BreakIterator.getShort(buf, offset);
+ }
+
+ public int current() {
+ return 0;
+ }
+
+ public int first() {
+ return 0;
+ }
+
+ public int following(int offset) {
+ return 0;
+ }
+
+ public CharacterIterator getText() {
+ return null;
+ }
+
+ public int last() {
+ return 0;
+ }
+
+ public int next() {
+ return 0;
+ }
+
+ public int next(int n) {
+ return 0;
+ }
+
+ public int previous() {
+ return 0;
+ }
+
+ public void setText(CharacterIterator newText) {
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/ChoiceFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/ChoiceFormatTest.java
new file mode 100644
index 0000000..3891109
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/ChoiceFormatTest.java
@@ -0,0 +1,477 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.ChoiceFormat;
+import java.text.FieldPosition;
+import java.text.MessageFormat;
+import java.text.ParsePosition;
+
+import junit.framework.TestCase;
+
+public class ChoiceFormatTest extends TestCase {
+
+ double[] limits = new double[] { 0, 1, ChoiceFormat.nextDouble(1),
+ ChoiceFormat.nextDouble(2) };
+
+ String[] formats = new String[] { "Less than one", "one",
+ "Between one and two", "Greater than two" };
+
+ ChoiceFormat f1 = new ChoiceFormat(limits, formats);
+
+ /**
+ * @tests java.text.ChoiceFormat#ChoiceFormat(double[], java.lang.String[])
+ */
+ public void test_Constructor$D$Ljava_lang_String() {
+ // Test for method java.text.ChoiceFormat(double [], java.lang.String
+ // [])
+ String formattedString;
+ double[] appleLimits = { 1, 2, 3, 4, 5 };
+ String[] appleFormats = { "Tiny Apple", "Small Apple", "Medium Apple",
+ "Large Apple", "Huge Apple" };
+ ChoiceFormat cf = new ChoiceFormat(appleLimits, appleFormats);
+
+ formattedString = cf.format(Double.NEGATIVE_INFINITY);
+ assertTrue("a) Incorrect format returned: " + formattedString,
+ formattedString.equals("Tiny Apple"));
+ formattedString = cf.format(0.5d);
+ assertTrue("b) Incorrect format returned: " + formattedString,
+ formattedString.equals("Tiny Apple"));
+ formattedString = cf.format(1d);
+ assertTrue("c) Incorrect format returned: " + formattedString,
+ formattedString.equals("Tiny Apple"));
+ formattedString = cf.format(1.5d);
+ assertTrue("d) Incorrect format returned: " + formattedString,
+ formattedString.equals("Tiny Apple"));
+ formattedString = cf.format(2d);
+ assertTrue("e) Incorrect format returned: " + formattedString,
+ formattedString.equals("Small Apple"));
+ formattedString = cf.format(2.5d);
+ assertTrue("f) Incorrect format returned: " + formattedString,
+ formattedString.equals("Small Apple"));
+ formattedString = cf.format(3d);
+ assertTrue("g) Incorrect format returned: " + formattedString,
+ formattedString.equals("Medium Apple"));
+ formattedString = cf.format(4d);
+ assertTrue("h) Incorrect format returned: " + formattedString,
+ formattedString.equals("Large Apple"));
+ formattedString = cf.format(5d);
+ assertTrue("i) Incorrect format returned: " + formattedString,
+ formattedString.equals("Huge Apple"));
+ formattedString = cf.format(5.5d);
+ assertTrue("j) Incorrect format returned: " + formattedString,
+ formattedString.equals("Huge Apple"));
+ formattedString = cf.format(6.0d);
+ assertTrue("k) Incorrect format returned: " + formattedString,
+ formattedString.equals("Huge Apple"));
+ formattedString = cf.format(Double.POSITIVE_INFINITY);
+ assertTrue("l) Incorrect format returned: " + formattedString,
+ formattedString.equals("Huge Apple"));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#ChoiceFormat(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ // Test for method java.text.ChoiceFormat(java.lang.String)
+ String formattedString;
+ String patternString = "-2#Inverted Orange| 0#No Orange| 0<Almost No Orange| 1#Normal Orange| 2#Expensive Orange";
+ ChoiceFormat cf = new ChoiceFormat(patternString);
+
+ formattedString = cf.format(Double.NEGATIVE_INFINITY);
+ assertTrue("a) Incorrect format returned: " + formattedString,
+ formattedString.equals("Inverted Orange"));
+ formattedString = cf.format(-3);
+ assertTrue("b) Incorrect format returned: " + formattedString,
+ formattedString.equals("Inverted Orange"));
+ formattedString = cf.format(-2);
+ assertTrue("c) Incorrect format returned: " + formattedString,
+ formattedString.equals("Inverted Orange"));
+ formattedString = cf.format(-1);
+ assertTrue("d) Incorrect format returned: " + formattedString,
+ formattedString.equals("Inverted Orange"));
+ formattedString = cf.format(-0);
+ assertTrue("e) Incorrect format returned: " + formattedString,
+ formattedString.equals("No Orange"));
+ formattedString = cf.format(0);
+ assertTrue("f) Incorrect format returned: " + formattedString,
+ formattedString.equals("No Orange"));
+ formattedString = cf.format(0.1);
+ assertTrue("g) Incorrect format returned: " + formattedString,
+ formattedString.equals("Almost No Orange"));
+ formattedString = cf.format(1);
+ assertTrue("h) Incorrect format returned: " + formattedString,
+ formattedString.equals("Normal Orange"));
+ formattedString = cf.format(1.5);
+ assertTrue("i) Incorrect format returned: " + formattedString,
+ formattedString.equals("Normal Orange"));
+ formattedString = cf.format(2);
+ assertTrue("j) Incorrect format returned: " + formattedString,
+ formattedString.equals("Expensive Orange"));
+ formattedString = cf.format(3);
+ assertTrue("k) Incorrect format returned: " + formattedString,
+ formattedString.equals("Expensive Orange"));
+ formattedString = cf.format(Double.POSITIVE_INFINITY);
+ assertTrue("l) Incorrect format returned: " + formattedString,
+ formattedString.equals("Expensive Orange"));
+
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#applyPattern(java.lang.String)
+ */
+ public void test_applyPatternLjava_lang_String() {
+ // Test for method void
+ // java.text.ChoiceFormat.applyPattern(java.lang.String)
+ ChoiceFormat f = (ChoiceFormat) f1.clone();
+ f.applyPattern("0#0|1#1");
+ assertTrue("Incorrect limits", java.util.Arrays.equals(f.getLimits(),
+ new double[] { 0, 1 }));
+ assertTrue("Incorrect formats", java.util.Arrays.equals(f.getFormats(),
+ new String[] { "0", "1" }));
+
+ // Regression for Harmony 540
+ double[] choiceLimits = { -1, 0, 1, ChoiceFormat.nextDouble(1) };
+ String[] choiceFormats = { "is negative", "is zero or fraction",
+ "is one", "is more than 1" };
+
+ f = new ChoiceFormat("");
+ f
+ .applyPattern("-1#is negative|0#is zero or fraction|1#is one|1<is more than 1");
+ assertTrue("Incorrect limits", java.util.Arrays.equals(f.getLimits(),
+ choiceLimits));
+ assertTrue("Incorrect formats", java.util.Arrays.equals(f.getFormats(),
+ choiceFormats));
+
+ f = new ChoiceFormat("");
+ try {
+ f
+ .applyPattern("-1#is negative|0#is zero or fraction|-1#is one|1<is more than 1");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ f = new ChoiceFormat("");
+ try {
+ f
+ .applyPattern("-1is negative|0#is zero or fraction|1#is one|1<is more than 1");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ f = new ChoiceFormat("");
+ f
+ .applyPattern("-1<is negative|0#is zero or fraction|1#is one|1<is more than 1");
+ choiceLimits[0] = ChoiceFormat.nextDouble(-1);
+ assertTrue("Incorrect limits", java.util.Arrays.equals(f.getLimits(),
+ choiceLimits));
+ assertTrue("Incorrect formats", java.util.Arrays.equals(f.getFormats(),
+ choiceFormats));
+
+ f = new ChoiceFormat("");
+ f
+ .applyPattern("-1#is negative|0#is zero or fraction|1#is one|1<is more than 1");
+ String str = "org.apache.harmony.tests.java.text.ChoiceFormat";
+ f.applyPattern(str);
+ String ptrn = f.toPattern();
+ assertEquals("Return value should be empty string for invalid pattern",
+ 0, ptrn.length());
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#clone()
+ */
+ public void test_clone() {
+ // Test for method java.lang.Object java.text.ChoiceFormat.clone()
+ ChoiceFormat f = (ChoiceFormat) f1.clone();
+ assertTrue("Not equal", f.equals(f1));
+ f.setChoices(new double[] { 0, 1, 2 }, new String[] { "0", "1", "2" });
+ assertTrue("Equal", !f.equals(f1));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.ChoiceFormat.equals(java.lang.Object)
+
+ String patternString = "-2#Inverted Orange| 0#No Orange| 0<Almost No Orange| 1#Normal Orange| 2#Expensive Orange";
+ double[] appleLimits = { 1, 2, 3, 4, 5 };
+ String[] appleFormats = { "Tiny Apple", "Small Apple", "Medium Apple",
+ "Large Apple", "Huge Apple" };
+ double[] orangeLimits = { -2, 0, ChoiceFormat.nextDouble(0), 1, 2 };
+ String[] orangeFormats = { "Inverted Orange", "No Orange",
+ "Almost No Orange", "Normal Orange", "Expensive Orange" };
+
+ ChoiceFormat appleChoiceFormat = new ChoiceFormat(appleLimits,
+ appleFormats);
+ ChoiceFormat orangeChoiceFormat = new ChoiceFormat(orangeLimits,
+ orangeFormats);
+ ChoiceFormat orangeChoiceFormat2 = new ChoiceFormat(patternString);
+ ChoiceFormat hybridChoiceFormat = new ChoiceFormat(appleLimits,
+ orangeFormats);
+
+ assertTrue("Apples should not equal oranges", !appleChoiceFormat
+ .equals(orangeChoiceFormat));
+ assertTrue("Different limit list--should not appear as equal",
+ !orangeChoiceFormat.equals(hybridChoiceFormat));
+ assertTrue("Different format list--should not appear as equal",
+ !appleChoiceFormat.equals(hybridChoiceFormat));
+ assertTrue("Should be equal--identical format", appleChoiceFormat
+ .equals(appleChoiceFormat));
+ assertTrue("Should be equals--same limits, same formats",
+ orangeChoiceFormat.equals(orangeChoiceFormat2));
+
+ ChoiceFormat f2 = new ChoiceFormat(
+ "0#Less than one|1#one|1<Between one and two|2<Greater than two");
+ assertTrue("Not equal", f1.equals(f2));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#format(double, java.lang.StringBuffer,
+ * java.text.FieldPosition)
+ */
+ public void test_formatDLjava_lang_StringBufferLjava_text_FieldPosition() {
+ // Test for method java.lang.StringBuffer
+ // java.text.ChoiceFormat.format(double, java.lang.StringBuffer,
+ // java.text.FieldPosition)
+ FieldPosition field = new FieldPosition(0);
+ StringBuffer buf = new StringBuffer();
+ String r = f1.format(-1, buf, field).toString();
+ assertEquals("Wrong choice for -1", "Less than one", r);
+ buf.setLength(0);
+ r = f1.format(0, buf, field).toString();
+ assertEquals("Wrong choice for 0", "Less than one", r);
+ buf.setLength(0);
+ r = f1.format(1, buf, field).toString();
+ assertEquals("Wrong choice for 1", "one", r);
+ buf.setLength(0);
+ r = f1.format(2, buf, field).toString();
+ assertEquals("Wrong choice for 2", "Between one and two", r);
+ buf.setLength(0);
+ r = f1.format(3, buf, field).toString();
+ assertEquals("Wrong choice for 3", "Greater than two", r);
+
+ // Regression test for HARMONY-1081
+ assertEquals(0, new ChoiceFormat("|").format(Double.NaN,
+ new StringBuffer(), new FieldPosition(6)).length());
+ assertEquals(0, new ChoiceFormat("|").format(1, new StringBuffer(),
+ new FieldPosition(6)).length());
+ assertEquals("Less than one", f1.format(Double.NaN, new StringBuffer(),
+ field).toString());
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#format(long, java.lang.StringBuffer,
+ * java.text.FieldPosition)
+ */
+ public void test_formatJLjava_lang_StringBufferLjava_text_FieldPosition() {
+ // Test for method java.lang.StringBuffer
+ // java.text.ChoiceFormat.format(long, java.lang.StringBuffer,
+ // java.text.FieldPosition)
+ FieldPosition field = new FieldPosition(0);
+ StringBuffer buf = new StringBuffer();
+ String r = f1.format(0.5, buf, field).toString();
+ assertEquals("Wrong choice for 0.5", "Less than one", r);
+ buf.setLength(0);
+ r = f1.format(1.5, buf, field).toString();
+ assertEquals("Wrong choice for 1.5", "Between one and two", r);
+ buf.setLength(0);
+ r = f1.format(2.5, buf, field).toString();
+ assertEquals("Wrong choice for 2.5", "Greater than two", r);
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#getFormats()
+ */
+ public void test_getFormats() {
+ // Test for method java.lang.Object []
+ // java.text.ChoiceFormat.getFormats()
+ String[] orgFormats = (String[]) formats.clone();
+ String[] f = (String[]) f1.getFormats();
+ assertTrue("Wrong formats", f.equals(formats));
+ f[0] = "Modified";
+ assertTrue("Formats copied", !f.equals(orgFormats));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#getLimits()
+ */
+ public void test_getLimits() {
+ // Test for method double [] java.text.ChoiceFormat.getLimits()
+ double[] orgLimits = (double[]) limits.clone();
+ double[] l = f1.getLimits();
+ assertTrue("Wrong limits", l.equals(limits));
+ l[0] = 3.14527;
+ assertTrue("Limits copied", !l.equals(orgLimits));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#hashCode()
+ */
+ public void test_hashCode() {
+ // Test for method int java.text.ChoiceFormat.hashCode()
+ ChoiceFormat f2 = new ChoiceFormat(
+ "0#Less than one|1#one|1<Between one and two|2<Greater than two");
+ assertTrue("Different hash", f1.hashCode() == f2.hashCode());
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#nextDouble(double)
+ */
+ public void test_nextDoubleD() {
+ // Test for method double java.text.ChoiceFormat.nextDouble(double)
+ assertTrue("Not greater 5", ChoiceFormat.nextDouble(5) > 5);
+ assertTrue("Not greater 0", ChoiceFormat.nextDouble(0) > 0);
+ assertTrue("Not greater -5", ChoiceFormat.nextDouble(-5) > -5);
+ assertTrue("Not NaN", Double.isNaN(ChoiceFormat.nextDouble(Double.NaN)));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#nextDouble(double, boolean)
+ */
+ public void test_nextDoubleDZ() {
+ // Test for method double java.text.ChoiceFormat.nextDouble(double,
+ // boolean)
+ assertTrue("Not greater 0", ChoiceFormat.nextDouble(0, true) > 0);
+ assertTrue("Not less 0", ChoiceFormat.nextDouble(0, false) < 0);
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#parse(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ public void test_parseLjava_lang_StringLjava_text_ParsePosition() {
+ // Test for method java.lang.Number
+ // java.text.ChoiceFormat.parse(java.lang.String,
+ // java.text.ParsePosition)
+ ChoiceFormat format = new ChoiceFormat("1#one|2#two|3#three");
+ assertEquals("Case insensitive", 0, format.parse("One",
+ new ParsePosition(0)).intValue());
+
+ ParsePosition pos = new ParsePosition(0);
+ Number result = f1.parse("Greater than two", pos);
+ assertTrue("Not a Double1", result instanceof Double);
+ assertTrue("Wrong value ~>2", result.doubleValue() == ChoiceFormat
+ .nextDouble(2));
+ assertEquals("Wrong position ~16", 16, pos.getIndex());
+ pos = new ParsePosition(0);
+ assertTrue("Incorrect result", Double.isNaN(f1.parse("12one", pos)
+ .doubleValue()));
+ assertEquals("Wrong position ~0", 0, pos.getIndex());
+ pos = new ParsePosition(2);
+ result = f1.parse("12one and two", pos);
+ assertTrue("Not a Double2", result instanceof Double);
+ assertEquals("Ignored parse position", 1.0D, result.doubleValue(), 0.0D);
+ assertEquals("Wrong position ~5", 5, pos.getIndex());
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#previousDouble(double)
+ */
+ public void test_previousDoubleD() {
+ // Test for method double java.text.ChoiceFormat.previousDouble(double)
+ assertTrue("Not less 5", ChoiceFormat.previousDouble(5) < 5);
+ assertTrue("Not less 0", ChoiceFormat.previousDouble(0) < 0);
+ assertTrue("Not less -5", ChoiceFormat.previousDouble(-5) < -5);
+ assertTrue("Not NaN", Double.isNaN(ChoiceFormat
+ .previousDouble(Double.NaN)));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#setChoices(double[], java.lang.String[])
+ */
+ public void test_setChoices$D$Ljava_lang_String() {
+ // Test for method void java.text.ChoiceFormat.setChoices(double [],
+ // java.lang.String [])
+ ChoiceFormat f = (ChoiceFormat) f1.clone();
+ double[] l = new double[] { 0, 1 };
+ String[] fs = new String[] { "0", "1" };
+ f.setChoices(l, fs);
+ assertTrue("Limits copied", f.getLimits() == l);
+ assertTrue("Formats copied", f.getFormats() == fs);
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#toPattern()
+ */
+ public void test_toPattern() {
+ // Regression for HARMONY-59
+ ChoiceFormat cf = new ChoiceFormat("");
+ assertEquals("", cf.toPattern());
+
+ cf = new ChoiceFormat("-1#NEGATIVE_ONE|0#ZERO|1#ONE|1<GREATER_THAN_ONE");
+ assertEquals("-1.0#NEGATIVE_ONE|0.0#ZERO|1.0#ONE|1.0<GREATER_THAN_ONE",
+ cf.toPattern());
+
+ MessageFormat mf = new MessageFormat("CHOICE {1,choice}");
+ String ptrn = mf.toPattern();
+ assertEquals("Unused message format returning incorrect pattern",
+ "CHOICE {1,choice,}", ptrn);
+
+ String pattern = f1.toPattern();
+ assertTrue(
+ "Wrong pattern: " + pattern,
+ pattern
+ .equals("0.0#Less than one|1.0#one|1.0<Between one and two|2.0<Greater than two"));
+
+ cf = new ChoiceFormat(
+ "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+|2#is two |2<is more than 2.");
+ String str = "org.apache.harmony.tests.java.lang.share.MyResources2";
+ cf.applyPattern(str);
+ ptrn = cf.toPattern();
+ assertEquals("Return value should be empty string for invalid pattern",
+ 0, ptrn.length());
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#format(long)
+ */
+ public void test_formatL() {
+ ChoiceFormat fmt = new ChoiceFormat(
+ "-1#NEGATIVE_ONE|0#ZERO|1#ONE|1<GREATER_THAN_ONE");
+
+ assertEquals("NEGATIVE_ONE", fmt.format(Long.MIN_VALUE));
+ assertEquals("NEGATIVE_ONE", fmt.format(-1));
+ assertEquals("ZERO", fmt.format(0));
+ assertEquals("ONE", fmt.format(1));
+ assertEquals("GREATER_THAN_ONE", fmt.format(Long.MAX_VALUE));
+ }
+
+ /**
+ * @tests java.text.ChoiceFormat#format(double)
+ */
+ public void test_formatD() {
+ ChoiceFormat fmt = new ChoiceFormat(
+ "-1#NEGATIVE_ONE|0#ZERO|1#ONE|1<GREATER_THAN_ONE");
+ assertEquals("NEGATIVE_ONE", fmt.format(Double.NEGATIVE_INFINITY));
+ assertEquals("NEGATIVE_ONE", fmt.format(-999999999D));
+ assertEquals("NEGATIVE_ONE", fmt.format(-1.1));
+ assertEquals("NEGATIVE_ONE", fmt.format(-1.0));
+ assertEquals("NEGATIVE_ONE", fmt.format(-0.9));
+ assertEquals("ZERO", fmt.format(0.0));
+ assertEquals("ZERO", fmt.format(0.9));
+ assertEquals("ONE", fmt.format(1.0));
+ assertEquals("GREATER_THAN_ONE", fmt.format(1.1));
+ assertEquals("GREATER_THAN_ONE", fmt.format(999999999D));
+ assertEquals("GREATER_THAN_ONE", fmt.format(Double.POSITIVE_INFINITY));
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationElementIteratorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationElementIteratorTest.java
new file mode 100644
index 0000000..fd945bb
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationElementIteratorTest.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.CollationElementIterator;
+import java.text.Collator;
+import java.text.RuleBasedCollator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+/**
+ * Test CollationElementIterator
+ *
+ * Only test normal condition.
+ *
+ */
+public class CollationElementIteratorTest extends TestCase {
+
+ private RuleBasedCollator coll;
+
+ protected void setUp() {
+ coll = (RuleBasedCollator) Collator.getInstance(Locale.US);
+ }
+
+ public void testGetOffset() {
+ String text = "abc";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(text);
+ int[] offsets = { 0, 1, 2, 3 };
+ int offset = iterator.getOffset();
+ int i = 0;
+ assertEquals(offsets[i++], offset);
+ while (offset != text.length()) {
+ iterator.next();
+ offset = iterator.getOffset();
+ assertEquals(offsets[i++], offset);
+ }
+ }
+
+ public void testNext() {
+ String text = "abc";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(text);
+ int[] orders = new int[text.length()];
+ int order = iterator.next();
+ int i = 0;
+ while (order != CollationElementIterator.NULLORDER) {
+ orders[i++] = order;
+ order = iterator.next();
+ }
+
+ int offset = iterator.getOffset();
+ assertEquals(text.length(), offset);
+ order = iterator.previous();
+
+ while (order != CollationElementIterator.NULLORDER) {
+ assertEquals(orders[--i], order);
+ order = iterator.previous();
+ }
+
+ assertEquals(0, iterator.getOffset());
+ }
+
+ /**
+ * @tests java.text.CollationElementIterator#previous() Test of method
+ * java.text.CollationElementIterator#previous().
+ */
+ public void testPrevious() {
+ String text = "abc";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(text);
+ int[] orders = new int[text.length()];
+ int order = iterator.next();
+ int i = 0;
+ while (order != CollationElementIterator.NULLORDER) {
+ orders[i++] = order;
+ order = iterator.next();
+ }
+
+ int offset = iterator.getOffset();
+ assertEquals(text.length(), offset);
+ order = iterator.previous();
+
+ while (order != CollationElementIterator.NULLORDER) {
+ assertEquals(orders[--i], order);
+ order = iterator.previous();
+ }
+
+ assertEquals(0, iterator.getOffset());
+ }
+
+ public void testReset() {
+ String text = "abc";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(text);
+ int[] orders = new int[text.length()];
+ int order = iterator.next();
+ int i = 0;
+ while (order != CollationElementIterator.NULLORDER) {
+ orders[i++] = order;
+ order = iterator.next();
+ }
+
+ int offset = iterator.getOffset();
+ assertEquals(text.length(), offset);
+
+ iterator.reset();
+ assertEquals(0, iterator.getOffset());
+ }
+
+ public void testGetMaxExpansion() {
+ String text = "cha";
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("es", "", "TRADITIONAL"));
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ int order = iterator.next();
+ while (order != CollationElementIterator.NULLORDER) {
+ assertEquals(1, iterator.getMaxExpansion(order));
+ order = iterator.next();
+ }
+
+ }
+
+ public void testPrimaryOrder() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("de", "DE"));
+ String text = "\u00e6";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ int order = iterator.next();
+ int pOrder = CollationElementIterator.primaryOrder(order);
+ CollationElementIterator iterator2 = rbColl
+ .getCollationElementIterator("ae");
+ int order2 = iterator2.next();
+ int pOrder2 = CollationElementIterator.primaryOrder(order2);
+ assertEquals(pOrder, pOrder2);
+ }
+
+ public void testSecondaryOrder() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("fr", "FR"));
+ String text = "a\u00e0";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ int order = iterator.next();
+ int sOrder1 = CollationElementIterator.secondaryOrder(order);
+
+ order = iterator.next();
+ int sOrder2 = CollationElementIterator.secondaryOrder(order);
+
+ assertEquals(sOrder1, sOrder2);
+ }
+
+ public void testTertiaryOrder() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("fr", "FR"));
+ String text = "abAB";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ int order = iterator.next();
+ int tOrder1 = CollationElementIterator.tertiaryOrder(order);
+ order = iterator.next();
+ int tOrder2 = CollationElementIterator.tertiaryOrder(order);
+ assertEquals(tOrder1, tOrder2);
+
+ order = iterator.next();
+ tOrder1 = CollationElementIterator.tertiaryOrder(order);
+ order = iterator.next();
+ tOrder2 = CollationElementIterator.tertiaryOrder(order);
+ assertEquals(tOrder1, tOrder2);
+ }
+
+ public void testSetOffset() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("es", "", "TRADITIONAL"));
+ String text = "cha";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ iterator.setOffset(1);
+ assertEquals(1, iterator.getOffset());
+ }
+
+ /*
+ * Class under test for void setText(java.lang.String)
+ */
+ public void testSetTextString() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("es", "", "TRADITIONAL"));
+ String text = "caa";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ iterator.setOffset(1);
+ assertEquals(1, iterator.getOffset());
+ iterator.setText("cha");
+ iterator.setOffset(1);
+ assertEquals(1, iterator.getOffset());
+ }
+
+ /*
+ * Class under test for void setText(java.text.CharacterIterator)
+ */
+ public void testSetTextCharacterIterator() {
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator
+ .getInstance(new Locale("es", "", "TRADITIONAL"));
+ String text = "caa";
+ CollationElementIterator iterator = rbColl
+ .getCollationElementIterator(text);
+ iterator.setOffset(1);
+ assertEquals(1, iterator.getOffset());
+ iterator.setText(new StringCharacterIterator("cha"));
+ iterator.setOffset(1);
+ assertEquals(1, iterator.getOffset());
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationKeyTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationKeyTest.java
new file mode 100644
index 0000000..b97358a
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollationKeyTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.CollationKey;
+import java.text.Collator;
+import java.text.ParseException;
+import java.text.RuleBasedCollator;
+import java.util.Arrays;
+
+public class CollationKeyTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.CollationKey#compareTo(java.text.CollationKey)
+ */
+ public void test_compareToLjava_text_CollationKey() {
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ CollationKey key1 = collator.getCollationKey("abc");
+ CollationKey key2 = collator.getCollationKey("ABC");
+ assertEquals("Should be equal", 0, key1.compareTo(key2));
+ }
+
+ /**
+ * @tests java.text.CollationKey#compareTo(java.lang.Object)
+ */
+ public void test_compareToLjava_lang_Object() {
+ // Test for method int
+ // java.text.CollationKey.compareTo(java.lang.Object)
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ CollationKey key1 = collator.getCollationKey("abc");
+ CollationKey key2 = collator.getCollationKey("ABC");
+ assertEquals("Should be equal", 0, key1.compareTo(key2));
+ }
+
+ /**
+ * @tests java.text.CollationKey#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ CollationKey key1 = collator.getCollationKey("abc");
+ CollationKey key2 = collator.getCollationKey("ABC");
+ assertTrue("Should be equal", key1.equals(key2));
+ }
+
+ /**
+ * @tests java.text.CollationKey#getSourceString()
+ */
+ public void test_getSourceString() {
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ assertTrue("Wrong source string1", collator.getCollationKey("abc")
+ .getSourceString() == "abc");
+ assertTrue("Wrong source string2", collator.getCollationKey("ABC")
+ .getSourceString() == "ABC");
+ }
+
+ /**
+ * @tests java.text.CollationKey#hashCode()
+ */
+ public void test_hashCode() {
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ CollationKey key1 = collator.getCollationKey("abc");
+ CollationKey key2 = collator.getCollationKey("ABC");
+ assertTrue("Should be equal", key1.hashCode() == key2.hashCode());
+ }
+
+ /**
+ * @tests java.text.CollationKey#toByteArray()
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void failing_test_toByteArray() {
+ // Test for method byte [] java.text.CollationKey.toByteArray()
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ CollationKey key1 = collator.getCollationKey("abc");
+ byte[] bytes = key1.toByteArray();
+ assertTrue("Not enough bytes", bytes.length >= 3);
+
+ try {
+ collator = new RuleBasedCollator("= 1 , 2 ; 3 , 4 < 5 ; 6 , 7");
+ } catch (ParseException e) {
+ fail("ParseException");
+ return;
+ }
+ bytes = collator.getCollationKey("1234567").toByteArray();
+ /*
+ * CollationElementIterator it =
+ * ((RuleBasedCollator)collator).getCollationElementIterator("1234567");
+ * int order; while ((order = it.next()) !=
+ * CollationElementIterator.NULLORDER) {
+ * System.out.println(Integer.toHexString(order)); } for (int i=0; i<bytes.length;
+ * i+=2) { System.out.print(Integer.toHexString(bytes[i]) +
+ * Integer.toHexString(bytes[i+1]) + " "); } System.out.println();
+ */
+ byte[] result = new byte[] { 0, 2, 0, 2, 0, 2, 0, 0, 0, 3, 0, 3, 0, 1,
+ 0, 2, 0, 2, 0, 0, 0, 4, 0, 4, 0, 1, 0, 1, 0, 2 };
+ assertTrue("Wrong bytes", Arrays.equals(bytes, result));
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/CollatorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollatorTest.java
new file mode 100644
index 0000000..d451c37
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/CollatorTest.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.UnsupportedEncodingException;
+import java.text.Collator;
+import java.text.ParseException;
+import java.text.RuleBasedCollator;
+import java.util.Locale;
+
+public class CollatorTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.Collator#clone()
+ */
+ public void test_clone() {
+ Collator c = Collator.getInstance(Locale.GERMAN);
+ Collator c2 = (Collator) c.clone();
+ assertTrue("Clones answered false to equals", c.equals(c2));
+ assertTrue("Clones were equivalent", c != c2);
+ }
+
+ /**
+ * @tests java.text.Collator#compare(java.lang.Object, java.lang.Object)
+ */
+ public void test_compareLjava_lang_ObjectLjava_lang_Object() {
+ Collator c = Collator.getInstance(Locale.FRENCH);
+ Object o, o2;
+
+ c.setStrength(Collator.IDENTICAL);
+ o = "E";
+ o2 = "F";
+ assertTrue("a) Failed on primary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "\u00e9";
+ assertTrue("a) Failed on secondary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "E";
+ assertTrue("a) Failed on tertiary difference", c.compare(o, o2) < 0);
+ o = "\u0001";
+ o2 = "\u0002";
+ assertTrue("a) Failed on identical", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "e";
+ assertEquals("a) Failed on equivalence", 0, c.compare(o, o2));
+ assertTrue("a) Failed on primary expansion",
+ c.compare("\u01db", "v") < 0);
+
+ c.setStrength(Collator.TERTIARY);
+ o = "E";
+ o2 = "F";
+ assertTrue("b) Failed on primary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "\u00e9";
+ assertTrue("b) Failed on secondary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "E";
+ assertTrue("b) Failed on tertiary difference", c.compare(o, o2) < 0);
+ o = "\u0001";
+ o2 = "\u0002";
+ assertEquals("b) Failed on identical", 0, c.compare(o, o2));
+ o = "e";
+ o2 = "e";
+ assertEquals("b) Failed on equivalence", 0, c.compare(o, o2));
+
+ c.setStrength(Collator.SECONDARY);
+ o = "E";
+ o2 = "F";
+ assertTrue("c) Failed on primary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "\u00e9";
+ assertTrue("c) Failed on secondary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "E";
+ assertEquals("c) Failed on tertiary difference", 0, c.compare(o, o2));
+ o = "\u0001";
+ o2 = "\u0002";
+ assertEquals("c) Failed on identical", 0, c.compare(o, o2));
+ o = "e";
+ o2 = "e";
+ assertEquals("c) Failed on equivalence", 0, c.compare(o, o2));
+
+ c.setStrength(Collator.PRIMARY);
+ o = "E";
+ o2 = "F";
+ assertTrue("d) Failed on primary difference", c.compare(o, o2) < 0);
+ o = "e";
+ o2 = "\u00e9";
+ assertEquals("d) Failed on secondary difference", 0, c.compare(o, o2));
+ o = "e";
+ o2 = "E";
+ assertEquals("d) Failed on tertiary difference", 0, c.compare(o, o2));
+ o = "\u0001";
+ o2 = "\u0002";
+ assertEquals("d) Failed on identical", 0, c.compare(o, o2));
+ o = "e";
+ o2 = "e";
+ assertEquals("d) Failed on equivalence", 0, c.compare(o, o2));
+
+ try {
+ c.compare("e", new StringBuffer("Blah"));
+ } catch (ClassCastException e) {
+ // correct
+ return;
+ }
+ fail("Failed to throw ClassCastException");
+ }
+
+ /**
+ * @tests java.text.Collator#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ Collator c = Collator.getInstance(Locale.ENGLISH);
+ Collator c2 = (Collator) c.clone();
+ assertTrue("Cloned collators not equal", c.equals(c2));
+ c2.setStrength(Collator.SECONDARY);
+ assertTrue("Collators with different strengths equal", !c.equals(c2));
+ }
+
+ /**
+ * @tests java.text.Collator#equals(java.lang.String, java.lang.String)
+ */
+ public void test_equalsLjava_lang_StringLjava_lang_String() {
+ Collator c = Collator.getInstance(Locale.FRENCH);
+
+ c.setStrength(Collator.IDENTICAL);
+ assertTrue("a) Failed on primary difference", !c.equals("E", "F"));
+ assertTrue("a) Failed on secondary difference", !c
+ .equals("e", "\u00e9"));
+ assertTrue("a) Failed on tertiary difference", !c.equals("e", "E"));
+ assertTrue("a) Failed on identical", !c.equals("\u0001", "\u0002"));
+ assertTrue("a) Failed on equivalence", c.equals("e", "e"));
+
+ c.setStrength(Collator.TERTIARY);
+ assertTrue("b) Failed on primary difference", !c.equals("E", "F"));
+ assertTrue("b) Failed on secondary difference", !c
+ .equals("e", "\u00e9"));
+ assertTrue("b) Failed on tertiary difference", !c.equals("e", "E"));
+ assertTrue("b) Failed on identical", c.equals("\u0001", "\u0002"));
+ assertTrue("b) Failed on equivalence", c.equals("e", "e"));
+
+ c.setStrength(Collator.SECONDARY);
+ assertTrue("c) Failed on primary difference", !c.equals("E", "F"));
+ assertTrue("c) Failed on secondary difference", !c
+ .equals("e", "\u00e9"));
+ assertTrue("c) Failed on tertiary difference", c.equals("e", "E"));
+ assertTrue("c) Failed on identical", c.equals("\u0001", "\u0002"));
+ assertTrue("c) Failed on equivalence", c.equals("e", "e"));
+
+ c.setStrength(Collator.PRIMARY);
+ assertTrue("d) Failed on primary difference", !c.equals("E", "F"));
+ assertTrue("d) Failed on secondary difference", c.equals("e", "\u00e9"));
+ assertTrue("d) Failed on tertiary difference", c.equals("e", "E"));
+ assertTrue("d) Failed on identical", c.equals("\u0001", "\u0002"));
+ assertTrue("d) Failed on equivalence", c.equals("e", "e"));
+ }
+
+ /**
+ * @tests java.text.Collator#getAvailableLocales()
+ */
+ //FIXME This test fails on Harmony ClassLibrary
+ public void failing_test_getAvailableLocales() {
+ Locale[] locales = Collator.getAvailableLocales();
+ assertTrue("No locales", locales.length > 0);
+ boolean english = false, german = false;
+ for (int i = locales.length; --i >= 0;) {
+ if (locales[i].equals(Locale.ENGLISH))
+ english = true;
+ if (locales[i].equals(Locale.GERMAN))
+ german = true;
+ // Output the working locale to help diagnose a hang
+ Collator c1 = Collator.getInstance(locales[i]);
+ assertTrue("Doesn't work", c1.compare("a", "b") < 0);
+ assertTrue("Wrong decomposition",
+ c1.getDecomposition() == Collator.NO_DECOMPOSITION);
+ assertTrue("Wrong strength", c1.getStrength() == Collator.TERTIARY);
+ if (c1 instanceof RuleBasedCollator) {
+ try {
+ new RuleBasedCollator(((RuleBasedCollator) c1).getRules());
+ } catch (ParseException e) {
+ fail("ParseException");
+ }
+ // assertTrue("Can't recreate: " + locales[i], temp.equals(c1));
+ }
+ }
+ assertTrue("Missing locales", english && german);
+ }
+
+ /**
+ * @tests java.text.Collator#getDecomposition()
+ */
+ //FIXME This test fails on Harmony ClassLibrary
+ public void failing_test_getDecomposition() {
+ RuleBasedCollator collator;
+ try {
+ collator = new RuleBasedCollator("; \u0300 < a, A < b < c < d");
+ } catch (ParseException e) {
+ fail("ParseException");
+ return;
+ }
+ assertTrue("Wrong default",
+ collator.getDecomposition() == Collator.CANONICAL_DECOMPOSITION);
+ }
+
+ /**
+ * @tests java.text.Collator#getInstance()
+ */
+ public void test_getInstance() {
+ Collator c1 = Collator.getInstance();
+ Collator c2 = Collator.getInstance(Locale.getDefault());
+ assertTrue("Wrong locale", c1.equals(c2));
+ }
+
+ /**
+ * @tests java.text.Collator#getInstance(java.util.Locale)
+ */
+ public void test_getInstanceLjava_util_Locale() {
+ assertTrue("Used to test", true);
+ }
+
+ /**
+ * @tests java.text.Collator#getStrength()
+ */
+ public void test_getStrength() {
+ RuleBasedCollator collator;
+ try {
+ collator = new RuleBasedCollator("; \u0300 < a, A < b < c < d");
+ } catch (ParseException e) {
+ fail("ParseException");
+ return;
+ }
+ assertTrue("Wrong default", collator.getStrength() == Collator.TERTIARY);
+ }
+
+ /**
+ * @tests java.text.Collator#setDecomposition(int)
+ */
+ //FIXME This test fails on Harmony ClassLibrary
+ public void failing_test_setDecompositionI() {
+ Collator c = Collator.getInstance(Locale.FRENCH);
+ c.setStrength(Collator.IDENTICAL);
+ c.setDecomposition(Collator.NO_DECOMPOSITION);
+ assertTrue("Collator should not be using decomposition", !c.equals(
+ "\u212B", "\u00C5")); // "ANGSTROM SIGN" and "LATIN CAPITAL
+ // LETTER A WITH RING ABOVE"
+ c.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
+ assertTrue("Collator should be using decomposition", c.equals("\u212B",
+ "\u00C5")); // "ANGSTROM SIGN" and "LATIN CAPITAL LETTER A WITH
+ // RING ABOVE"
+ assertTrue("Should not be equal under canonical decomposition", !c
+ .equals("\u2163", "IV")); // roman number "IV"
+ c.setDecomposition(Collator.FULL_DECOMPOSITION);
+ assertTrue("Should be equal under full decomposition", c.equals(
+ "\u2163", "IV")); // roman number "IV"
+ }
+
+ /**
+ * @tests java.text.Collator#setStrength(int)
+ */
+ public void test_setStrengthI() {
+ assertTrue("Used to test", true);
+ }
+
+
+ // Regression test for Android bug
+ public void test_stackCorruption() {
+ Collator mColl = Collator.getInstance();
+ mColl.setStrength(Collator.PRIMARY);
+ mColl.getCollationKey("2d294f2d3739433565147655394f3762f3147312d3731641452f310");
+ }
+
+ // Test to verify that very large collation keys are not truncated.
+ public void test_collationKeySize() {
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < 1024; i++) {
+ b.append("0123456789ABCDEF");
+ }
+ String sixteen = b.toString();
+ b.append("_THE_END");
+ String sixteenplus = b.toString();
+
+ Collator mColl = Collator.getInstance();
+ mColl.setStrength(Collator.PRIMARY);
+
+ try {
+ byte [] arr = mColl.getCollationKey(sixteen).toByteArray();
+ int len = arr.length;
+ assertTrue("Collation key not 0 terminated", arr[arr.length - 1] == 0);
+ len--;
+ String foo = new String(arr, 0, len, "iso8859-1");
+
+ arr = mColl.getCollationKey(sixteen).toByteArray();
+ len = arr.length;
+ assertTrue("Collation key not 0 terminated", arr[arr.length - 1] == 0);
+ len--;
+ String bar = new String(arr, 0, len, "iso8859-1");
+
+ assertTrue("Collation keys should differ", foo.equals(bar));
+ } catch (UnsupportedEncodingException ex) {
+ fail("UnsupportedEncodingException");
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DataFormatFieldTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DataFormatFieldTest.java
new file mode 100644
index 0000000..9abc8b9
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DataFormatFieldTest.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InvalidObjectException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.text.DateFormat;
+import java.text.DateFormat.Field;
+import java.util.Calendar;
+
+import junit.framework.TestCase;
+
+public class DataFormatFieldTest extends TestCase {
+
+ public void test_ConstructorLjava_lang_StringLjava_lang_String() {
+ // Regression for HARMONY-178
+ MyField field = new MyField("day of month", Calendar.ERA);
+
+ assertEquals("field has wrong name", "day of month", field.getName());
+ assertEquals("field has wrong Calendar field number", Calendar.ERA,
+ field.getCalendarField());
+
+ DateFormat.Field realField = DateFormat.Field
+ .ofCalendarField(Calendar.ERA);
+ assertSame("Modified calendar field with the same field number",
+ DateFormat.Field.ERA, realField);
+
+ DateFormat.Field realField2 = DateFormat.Field
+ .ofCalendarField(Calendar.DAY_OF_MONTH);
+ assertSame("Modified calendar field with the same field number",
+ DateFormat.Field.DAY_OF_MONTH, realField2);
+ }
+
+ static class MyField extends DateFormat.Field {
+ private static final long serialVersionUID = 1L;
+
+ protected MyField(String fieldName, int calendarField) {
+ super(fieldName, calendarField);
+ }
+
+ protected String getName() {
+ return super.getName();
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat$Field#Field(java.lang.String, int)
+ */
+ public void test_ConstructorLjava_lang_StringI() {
+ MyField field = new MyField("a field", Calendar.DAY_OF_WEEK);
+
+ assertEquals("field has wrong name", "a field", field.getName());
+ assertEquals("field has wrong Calendar field number",
+ Calendar.DAY_OF_WEEK, field.getCalendarField());
+
+ DateFormat.Field realField = DateFormat.Field
+ .ofCalendarField(Calendar.DAY_OF_WEEK);
+ assertSame("Modified calendar field with the same field number",
+ DateFormat.Field.DAY_OF_WEEK, realField);
+ }
+
+ /**
+ * @tests java.text.DateFormat$Field#Field(java.lang.String, int)
+ */
+ public void test_Constructor2() {
+ MyField field = new MyField("day of month", Calendar.ERA);
+
+ assertEquals("field has wrong name", "day of month", field.getName());
+ assertEquals("field has wrong Calendar field number", Calendar.ERA,
+ field.getCalendarField());
+
+ DateFormat.Field realField = DateFormat.Field
+ .ofCalendarField(Calendar.ERA);
+ assertSame("Modified calendar field with the same field number",
+ DateFormat.Field.ERA, realField);
+
+ DateFormat.Field realField2 = DateFormat.Field
+ .ofCalendarField(Calendar.DAY_OF_MONTH);
+ assertSame("Modified calendar field with the same field number",
+ DateFormat.Field.DAY_OF_MONTH, realField2);
+ }
+
+ /**
+ * @tests java.text.DateFormat$Field#getCalendarField()
+ */
+ public void test_getCalendarField() {
+ // Test for method int getCalendarField()
+ assertEquals("Field.AM_PM.getCalendarField() returned the wrong value",
+ Calendar.AM_PM, Field.AM_PM.getCalendarField());
+
+ // test special cases
+ assertEquals(
+ "Field.TIME_ZONE.getCalendarField() returned the wrong value",
+ -1, Field.TIME_ZONE.getCalendarField());
+ assertEquals("Field.HOUR0.getCalendarField() returned the wrong value",
+ Calendar.HOUR, Field.HOUR0.getCalendarField());
+ assertEquals("Field.HOUR1.getCalendarField() returned the wrong value",
+ -1, Field.HOUR1.getCalendarField());
+ assertEquals(
+ "Field.HOUR_OF_DAY0.getCalendarField() returned the wrong value",
+ Calendar.HOUR_OF_DAY, Field.HOUR_OF_DAY0.getCalendarField());
+ assertEquals(
+ "Field.HOUR_OF_DAY1.getCalendarField() returned the wrong value",
+ -1, Field.HOUR_OF_DAY1.getCalendarField());
+ }
+
+ /**
+ * @tests java.text.DateFormat$Field#ofCalendarField(int)
+ */
+ public void test_ofCalendarFieldI() {
+ // Test for method static java.text.DateFormat.Field
+ // ofCalendarField(int)
+ assertSame("ofCalendarField(Calendar.AM_PM) returned the wrong value",
+ Field.AM_PM, Field.ofCalendarField(Calendar.AM_PM));
+
+ // test special cases
+ assertSame("ofCalendarField(Calendar.HOUR) returned the wrong value",
+ Field.HOUR0, Field.ofCalendarField(Calendar.HOUR));
+ assertSame(
+ "ofCalendarField(Calendar.HOUR_OF_DAY) returned the wrong value",
+ Field.HOUR_OF_DAY0, Field.ofCalendarField(Calendar.HOUR_OF_DAY));
+
+ // test illegal args
+ try {
+ DateFormat.Field.ofCalendarField(-1);
+ fail("Expected IllegalArgumentException for ofCalendarField(-1)");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ DateFormat.Field.ofCalendarField(Calendar.FIELD_COUNT);
+ fail("Expected IllegalArgumentException for ofCalendarField(Calendar.FIELD_COUNT)");
+ } catch (IllegalArgumentException e) {
+ }
+
+ // test Calendar fields that do not have corresponding DateFormat Fields
+ assertNull(
+ "ofCalendarField(Calendar.DST_OFFSET) returned the wrong value",
+ DateFormat.Field.ofCalendarField(Calendar.DST_OFFSET));
+ assertNull(
+ "ofCalendarField(Calendar.ZONE_OFFSET) returned the wrong value",
+ DateFormat.Field.ofCalendarField(Calendar.ZONE_OFFSET));
+ }
+
+ /**
+ * @tests java.text.DateFormat$Field#readResolve()
+ */
+ public void test_readResolve() {
+ // test for method java.lang.Object readResolve()
+
+ // see serialization stress tests:
+ // implemented in
+ // SerializationStressTest4.test_writeObject_NumberFormat_Field()
+
+ ObjectOutputStream out = null;
+ ObjectInputStream in = null;
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ out = new ObjectOutputStream(bytes);
+
+ DateFormat.Field dfield, dfield2;
+ MyField field;
+
+ // a regular instance of DateFormat.Field
+ dfield = DateFormat.Field.MILLISECOND;
+
+ // a subclass instance with null name
+ field = new MyField(null, Calendar.AM_PM);
+
+ out.writeObject(dfield);
+ out.writeObject(field);
+
+ in = new ObjectInputStream(new ByteArrayInputStream(bytes
+ .toByteArray()));
+
+ try {
+ dfield2 = (Field) in.readObject();
+ assertSame("resolved incorrectly", dfield, dfield2);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException: " + e);
+ }
+
+ try {
+ in.readObject();
+ fail("Expected InvalidObjectException for subclass instance with null name");
+ } catch (InvalidObjectException e) {
+ }
+
+ } catch (IOException e) {
+ fail("unexpected IOException" + e);
+ } catch (ClassNotFoundException e) {
+ fail("unexpected ClassNotFoundException" + e);
+ } finally {
+ try {
+ if (out != null)
+ out.close();
+ if (in != null)
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatSymbolsTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatSymbolsTest.java
new file mode 100644
index 0000000..2bf9dd2
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatSymbolsTest.java
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.DateFormatSymbols;
+import java.util.Arrays;
+import java.util.Locale;
+
+public class DateFormatSymbolsTest extends junit.framework.TestCase {
+
+ private DateFormatSymbols dfs;
+
+ /**
+ * @tests java.text.DateFormatSymbols#DateFormatSymbols()
+ */
+ public void test_Constructor() {
+ // Test for method java.text.DateFormatSymbols()
+ // Used in tests
+ try {
+ new DateFormatSymbols();
+ } catch (Exception e) {
+ fail("Constructor failed.");
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#DateFormatSymbols(java.util.Locale)
+ */
+ public void test_ConstructorLjava_util_Locale() {
+ // Test for method java.text.DateFormatSymbols(java.util.Locale)
+ try {
+ new DateFormatSymbols(new Locale("en", "us"));
+ } catch (Exception e) {
+ fail("Constructor failed.");
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#clone()
+ */
+ public void test_clone() {
+ // Test for method java.lang.Object java.text.DateFormatSymbols.clone()
+ DateFormatSymbols symbols = new DateFormatSymbols();
+ DateFormatSymbols clone = (DateFormatSymbols) symbols.clone();
+ assertTrue("Not equal", symbols.equals(clone));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.DateFormatSymbols.equals(java.lang.Object)
+ assertTrue("Equal object returned true", dfs.equals(dfs.clone()));
+ dfs.setLocalPatternChars("KKKKKKKKK");
+ assertTrue("Un-Equal objects returned false", !dfs
+ .equals(new DateFormatSymbols()));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getAmPmStrings()
+ */
+ public void test_getAmPmStrings() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getAmPmStrings()
+ String[] retVal = dfs.getAmPmStrings();
+ String[] val = { "AM", "PM" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getEras()
+ */
+ public void test_getEras() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getEras()
+ String[] retVal = dfs.getEras();
+ String[] val = { "BC", "AD" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getLocalPatternChars()
+ */
+ public void test_getLocalPatternChars() {
+ // Test for method java.lang.String
+ // java.text.DateFormatSymbols.getLocalPatternChars()
+ String retVal = dfs.getLocalPatternChars();
+
+ String val = "GyMdkHmsSEDFwWahKzZ";
+
+ assertTrue("Returned incorrect pattern string", retVal.equals(val));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getMonths()
+ */
+ public void test_getMonths() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getMonths()
+ String[] retVal = dfs.getMonths();
+ String[] val = { "January", "February", "March", "April", "May",
+ "June", "July", "August", "September", "October", "November",
+ "December", "" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array: " + retVal.length);
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getShortMonths()
+ */
+ public void test_getShortMonths() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getShortMonths()
+ String[] retVal = dfs.getShortMonths();
+ String[] val = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov", "Dec", "" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getShortWeekdays()
+ */
+ public void test_getShortWeekdays() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getShortWeekdays()
+ String[] retVal = dfs.getShortWeekdays();
+ String[] val = { "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getWeekdays()
+ */
+ public void test_getWeekdays() {
+ // Test for method java.lang.String []
+ // java.text.DateFormatSymbols.getWeekdays()
+ String[] retVal = dfs.getWeekdays();
+ String[] val = { "", "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday" };
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Array values do not match", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#getZoneStrings()
+ */
+ public void test_getZoneStrings() {
+ // Test for method java.lang.String [][]
+ // java.text.DateFormatSymbols.getZoneStrings()
+ String[][] val = { { "XX" }, { "YY" } };
+ dfs.setZoneStrings(val);
+ String[][] retVal = dfs.getZoneStrings();
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", Arrays
+ .equals(retVal[i], val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#hashCode()
+ */
+ public void test_hashCode() {
+ // Test for method int java.text.DateFormatSymbols.hashCode()
+ int hc1 = dfs.hashCode();
+ int hc2 = dfs.hashCode();
+ assertTrue("hashCode() returned inconsistent number : " + hc1 + " - "
+ + hc2, hc1 == hc2);
+
+ assertTrue("hashCode() returns different values for equal() objects",
+ dfs.hashCode() == dfs.clone().hashCode());
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setAmPmStrings(java.lang.String[])
+ */
+ public void test_setAmPmStrings$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setAmPmStrings(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setAmPmStrings(val);
+ String[] retVal = dfs.getAmPmStrings();
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setEras(java.lang.String[])
+ */
+ public void test_setEras$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setEras(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setEras(val);
+ String[] retVal = dfs.getEras();
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setLocalPatternChars(java.lang.String)
+ */
+ public void test_setLocalPatternCharsLjava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setLocalPatternChars(java.lang.String)
+ dfs.setLocalPatternChars("GyMZZkHmsSEHHFwWahKz");
+ String retVal = dfs.getLocalPatternChars();
+ String val = "GyMZZkHmsSEHHFwWahKz";
+ assertTrue("Returned incorrect pattern string", retVal.equals(val));
+
+ try {
+ // Regression for HARMONY-466
+ new DateFormatSymbols().setLocalPatternChars(null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setMonths(java.lang.String[])
+ */
+ public void test_setMonths$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setMonths(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setMonths(val);
+ String[] retVal = dfs.getMonths();
+ assertTrue("Return is identical", retVal != dfs.getMonths());
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setShortMonths(java.lang.String[])
+ */
+ public void test_setShortMonths$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setShortMonths(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setShortMonths(val);
+ String[] retVal = dfs.getShortMonths();
+ assertTrue("Return is identical", retVal != dfs.getShortMonths());
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setShortWeekdays(java.lang.String[])
+ */
+ public void test_setShortWeekdays$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setShortWeekdays(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setShortWeekdays(val);
+ String[] retVal = dfs.getShortWeekdays();
+ assertTrue("Return is identical", retVal != dfs.getShortWeekdays());
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setWeekdays(java.lang.String[])
+ */
+ public void test_setWeekdays$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setWeekdays(java.lang.String [])
+ String[] val = { "XX", "YY" };
+ dfs.setWeekdays(val);
+ String[] retVal = dfs.getWeekdays();
+ assertTrue("Return is identical", retVal != dfs.getWeekdays());
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings", retVal[i].equals(val[i]));
+ }
+
+ /**
+ * @tests java.text.DateFormatSymbols#setZoneStrings(java.lang.String[][])
+ */
+ public void test_setZoneStrings$$Ljava_lang_String() {
+ // Test for method void
+ // java.text.DateFormatSymbols.setZoneStrings(java.lang.String [][])
+ String[][] val = { { "XX" }, { "YY" } };
+ dfs.setZoneStrings(val);
+ String[][] retVal = dfs.getZoneStrings();
+ assertTrue("get returns identical", retVal != dfs.getZoneStrings());
+ assertTrue("get[0] returns identical", retVal[0] != dfs
+ .getZoneStrings()[0]);
+ assertTrue("get returned identical", retVal != val);
+ if (retVal.length != val.length)
+ fail("Returned wrong array");
+ for (int i = 0; i < val.length; i++)
+ assertTrue("Failed to set strings: " + retVal[i], Arrays.equals(
+ retVal[i], val[i]));
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+ dfs = new DateFormatSymbols(new Locale("en", "us"));
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatTest.java
new file mode 100644
index 0000000..733812f
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DateFormatTest.java
@@ -0,0 +1,728 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.FieldPosition;
+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.Locale;
+import java.util.TimeZone;
+
+import junit.framework.Test;
+
+public class DateFormatTest extends junit.framework.TestCase {
+
+ private class MockDateFormat extends DateFormat {
+
+ private static final long serialVersionUID = 1L;
+
+ public MockDateFormat() {
+ super();
+ }
+
+ @Override
+ public Date parse(String source, ParsePosition pos) {
+ // it is a fake
+ return null;
+ }
+
+ @Override
+ public StringBuffer format(Date date, StringBuffer toAppendTo,
+ FieldPosition fieldPosition) {
+ // it is a fake
+ return null;
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#DateFormat() Test of method
+ * java.text.DateFormat#DateFormat().
+ */
+ public void test_Constructor() {
+ try {
+ new MockDateFormat();
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#equals(java.lang.Object obj) Test of
+ * java.text.DateFormat#equals(java.lang.Object obj).
+ */
+ public void test_equalsLjava_lang_Object() {
+ try {
+ DateFormat format = DateFormat.getInstance();
+ DateFormat clone = (DateFormat) format.clone();
+ assertTrue("Clone and parent are not equaled", format.equals(clone));
+ assertTrue("Clone is equal to other object", !clone
+ .equals(DateFormat.getTimeInstance()));
+ format.setCalendar(Calendar.getInstance());
+ assertTrue("Clone and parent are not equaled", format.equals(clone));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#format(java.util.Date) Test of method
+ * java.text.DateFormat#format(java.util.Date).
+ */
+ public void test_formatLjava_util_Date() {
+ try {
+ DateFormat format = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT, Locale.US);
+ Date current = new Date();
+ String dtf = format.format(current);
+ SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a");
+ assertTrue("Incorrect date format", sdf.format(current).equals(dtf));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#format(Object, StringBuffer, FieldPosition)
+ * Test of method java.text.DateFormat#format(Object, StringBuffer,
+ * FieldPosition)
+ */
+ public void test_formatLjava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition() {
+ try {
+ DateFormat format = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT, Locale.US);
+ Date current = new Date();
+ StringBuffer toAppend = new StringBuffer();
+ FieldPosition fp = new FieldPosition(DateFormat.YEAR_FIELD);
+ StringBuffer sb = format.format(current, toAppend, fp);
+ SimpleDateFormat sdf = new SimpleDateFormat("M/d/yy h:mm a");
+ assertTrue("Incorrect date format", sdf.format(current).equals(
+ sb.toString()));
+ assertTrue("Incorrect beginIndex of filed position", fp
+ .getBeginIndex() == sb.lastIndexOf("/") + 1);
+ assertTrue("Incorrect endIndex of filed position",
+ fp.getEndIndex() == sb.lastIndexOf("/") + 3);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#clone()
+ */
+ public void test_clone() {
+ DateFormat format = DateFormat.getInstance();
+ DateFormat clone = (DateFormat) format.clone();
+ assertTrue("Clone not equal", format.equals(clone));
+ clone.getNumberFormat().setMinimumFractionDigits(123);
+ assertTrue("Clone shares NumberFormat", !format.equals(clone));
+ }
+
+ /**
+ * @tests java.text.DateFormat#getAvailableLocales()
+ */
+ public void test_getAvailableLocales() {
+ Locale[] locales = DateFormat.getAvailableLocales();
+ assertTrue("No locales", locales.length > 0);
+ boolean english = false, german = false;
+ for (int i = locales.length; --i >= 0;) {
+ if (locales[i].equals(Locale.ENGLISH))
+ english = true;
+ if (locales[i].equals(Locale.GERMAN))
+ german = true;
+ DateFormat f1 = DateFormat.getDateTimeInstance(DateFormat.SHORT,
+ DateFormat.SHORT, locales[i]);
+ assertTrue("Doesn't work",
+ f1.format(new Date()).getClass() == String.class);
+ }
+ assertTrue("Missing locales", english && german);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getCalendar()
+ */
+ public void test_getCalendar() {
+ DateFormat format = DateFormat.getInstance();
+ Calendar cal1 = format.getCalendar();
+ Calendar cal2 = format.getCalendar();
+ assertTrue("Calendars not identical", cal1 == cal2);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateInstance()
+ */
+ public void test_getDateInstance() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat.getDateInstance();
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default", f2.equals(DateFormat.getDateInstance(
+ DateFormat.DEFAULT, Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateInstance(int)
+ */
+ public void test_getDateInstanceI() {
+ assertTrue("Default not medium",
+ DateFormat.DEFAULT == DateFormat.MEDIUM);
+
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat
+ .getDateInstance(DateFormat.SHORT);
+ assertTrue("Wrong class1", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default1", f2.equals(DateFormat.getDateInstance(
+ DateFormat.SHORT, Locale.getDefault())));
+ assertTrue("Wrong symbols1", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work1",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM);
+ assertTrue("Wrong class2", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default2", f2.equals(DateFormat.getDateInstance(
+ DateFormat.MEDIUM, Locale.getDefault())));
+ assertTrue("Wrong symbols2", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work2",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.LONG);
+ assertTrue("Wrong class3", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default3", f2.equals(DateFormat.getDateInstance(
+ DateFormat.LONG, Locale.getDefault())));
+ assertTrue("Wrong symbols3", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work3",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.FULL);
+ assertTrue("Wrong class4", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default4", f2.equals(DateFormat.getDateInstance(
+ DateFormat.FULL, Locale.getDefault())));
+ assertTrue("Wrong symbols4", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work4",
+ f2.format(new Date()).getClass() == String.class);
+
+ // regression test for HARMONY-940
+ try {
+ DateFormat.getDateInstance(77);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateInstance(int, java.util.Locale)
+ */
+ public void test_getDateInstanceILjava_util_Locale() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat.getDateInstance(
+ DateFormat.SHORT, Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.MEDIUM,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.LONG,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.FULL,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ // regression test for HARMONY-940
+ try {
+ DateFormat.getDateInstance(77, Locale.GERMAN);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateTimeInstance()
+ */
+ public void test_getDateTimeInstance() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat
+ .getDateTimeInstance();
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default", f2.equals(DateFormat.getDateTimeInstance(
+ DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ private void testDateTime(int dStyle, int tStyle) {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat
+ .getDateTimeInstance(dStyle, tStyle);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ SimpleDateFormat date = (SimpleDateFormat) DateFormat.getDateInstance(
+ dStyle, Locale.getDefault());
+ SimpleDateFormat time = (SimpleDateFormat) DateFormat.getTimeInstance(
+ tStyle, Locale.getDefault());
+ assertTrue("Wrong default", f2.toPattern().equals(
+ date.toPattern() + " " + time.toPattern()));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateTimeInstance(int, int)
+ */
+ public void test_getDateTimeInstanceII() {
+ testDateTime(DateFormat.SHORT, DateFormat.SHORT);
+ testDateTime(DateFormat.SHORT, DateFormat.MEDIUM);
+ testDateTime(DateFormat.SHORT, DateFormat.LONG);
+ testDateTime(DateFormat.SHORT, DateFormat.FULL);
+
+ testDateTime(DateFormat.MEDIUM, DateFormat.SHORT);
+ testDateTime(DateFormat.MEDIUM, DateFormat.MEDIUM);
+ testDateTime(DateFormat.MEDIUM, DateFormat.LONG);
+ testDateTime(DateFormat.MEDIUM, DateFormat.FULL);
+
+ testDateTime(DateFormat.LONG, DateFormat.SHORT);
+ testDateTime(DateFormat.LONG, DateFormat.MEDIUM);
+ testDateTime(DateFormat.LONG, DateFormat.LONG);
+ testDateTime(DateFormat.LONG, DateFormat.FULL);
+
+ testDateTime(DateFormat.FULL, DateFormat.SHORT);
+ testDateTime(DateFormat.FULL, DateFormat.MEDIUM);
+ testDateTime(DateFormat.FULL, DateFormat.LONG);
+ testDateTime(DateFormat.FULL, DateFormat.FULL);
+
+ // regression test for HARMONY-940
+ try {
+ DateFormat.getDateTimeInstance(77, 66);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ private void testDateTimeLocale(int dStyle, int tStyle) {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat
+ .getDateTimeInstance(dStyle, tStyle, Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ SimpleDateFormat date = (SimpleDateFormat) DateFormat.getDateInstance(
+ dStyle, Locale.GERMAN);
+ SimpleDateFormat time = (SimpleDateFormat) DateFormat.getTimeInstance(
+ tStyle, Locale.GERMAN);
+ assertTrue("Wrong default", f2.toPattern().equals(
+ date.toPattern() + " " + time.toPattern()));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getDateTimeInstance(int, int,
+ * java.util.Locale)
+ */
+ public void test_getDateTimeInstanceIILjava_util_Locale() {
+ testDateTimeLocale(DateFormat.SHORT, DateFormat.SHORT);
+ testDateTimeLocale(DateFormat.SHORT, DateFormat.MEDIUM);
+ testDateTimeLocale(DateFormat.SHORT, DateFormat.LONG);
+ testDateTimeLocale(DateFormat.SHORT, DateFormat.FULL);
+
+ testDateTimeLocale(DateFormat.MEDIUM, DateFormat.SHORT);
+ testDateTimeLocale(DateFormat.MEDIUM, DateFormat.MEDIUM);
+ testDateTimeLocale(DateFormat.MEDIUM, DateFormat.LONG);
+ testDateTimeLocale(DateFormat.MEDIUM, DateFormat.FULL);
+
+ testDateTimeLocale(DateFormat.LONG, DateFormat.SHORT);
+ testDateTimeLocale(DateFormat.LONG, DateFormat.MEDIUM);
+ testDateTimeLocale(DateFormat.LONG, DateFormat.LONG);
+ testDateTimeLocale(DateFormat.LONG, DateFormat.FULL);
+
+ testDateTimeLocale(DateFormat.FULL, DateFormat.SHORT);
+ testDateTimeLocale(DateFormat.FULL, DateFormat.MEDIUM);
+ testDateTimeLocale(DateFormat.FULL, DateFormat.LONG);
+ testDateTimeLocale(DateFormat.FULL, DateFormat.FULL);
+
+ // regression test for HARMONY-940
+ try {
+ DateFormat.getDateTimeInstance(77, 66, Locale.GERMAN);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#getInstance()
+ */
+ public void test_getInstance() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat.getInstance();
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default", f2.equals(DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getNumberFormat()
+ */
+ public void test_getNumberFormat() {
+ DateFormat format = DateFormat.getInstance();
+ NumberFormat nf1 = format.getNumberFormat();
+ NumberFormat nf2 = format.getNumberFormat();
+ assertTrue("NumberFormats not identical", nf1 == nf2);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getTimeInstance()
+ */
+ public void test_getTimeInstance() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat.getTimeInstance();
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default", f2.equals(DateFormat.getTimeInstance(
+ DateFormat.DEFAULT, Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.DateFormat#getTimeInstance(int)
+ */
+ public void test_getTimeInstanceI() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat
+ .getTimeInstance(DateFormat.SHORT);
+ assertTrue("Wrong class1", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default1", f2.equals(DateFormat.getTimeInstance(
+ DateFormat.SHORT, Locale.getDefault())));
+ assertTrue("Wrong symbols1", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work1",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.MEDIUM);
+ assertTrue("Wrong class2", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default2", f2.equals(DateFormat.getTimeInstance(
+ DateFormat.MEDIUM, Locale.getDefault())));
+ assertTrue("Wrong symbols2", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work2",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.LONG);
+ assertTrue("Wrong class3", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default3", f2.equals(DateFormat.getTimeInstance(
+ DateFormat.LONG, Locale.getDefault())));
+ assertTrue("Wrong symbols3", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work3",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.FULL);
+ assertTrue("Wrong class4", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default4", f2.equals(DateFormat.getTimeInstance(
+ DateFormat.FULL, Locale.getDefault())));
+ assertTrue("Wrong symbols4", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work4",
+ f2.format(new Date()).getClass() == String.class);
+
+ // regression test for HARMONY-940
+ try {
+ DateFormat.getTimeInstance(77);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#getTimeInstance(int, java.util.Locale)
+ */
+ public void test_getTimeInstanceILjava_util_Locale() {
+ SimpleDateFormat f2 = (SimpleDateFormat) DateFormat.getTimeInstance(
+ DateFormat.SHORT, Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.MEDIUM,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.LONG,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ f2 = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.FULL,
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ try {
+ DateFormat.getTimeInstance(77, Locale.GERMAN);
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#getTimeZone() Test of method
+ * java.text.DateFormat#getTimeZone().
+ */
+ public void test_getTimeZone() {
+ try {
+ DateFormat format = DateFormat.getInstance();
+ TimeZone tz = format.getTimeZone();
+ //if(1 == 1)
+ // throw new Exception(tz.getClass().getName());
+ // We know we are not sun.util so:
+ assertFalse("Incorrect zone info", tz.getClass().getName().equals(
+ "sun.util.calendar.ZoneInfo"));
+ assertTrue("Incorrect time zone", tz.equals(format.getCalendar()
+ .getTimeZone()));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#hashCode() Test of method
+ * java.text.DateFormat#hashCode().
+ */
+ public void test_hashCode() {
+ try {
+ DateFormat df1 = DateFormat.getInstance();
+ DateFormat df2 = (DateFormat) df1.clone();
+ assertTrue("Hash codes of clones are not equal",
+ df1.hashCode() == df2.hashCode());
+ assertTrue("Hash codes of different objects are the same", df1
+ .hashCode() != DateFormat.getDateInstance().hashCode());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#isLenient() Test of method
+ * java.text.DateFormat#isLenient().
+ */
+ public void test_isLenient() {
+ DateFormat df = DateFormat.getInstance();
+ Calendar c = df.getCalendar();
+ if (df.isLenient()) {
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ c.setLenient(false);
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ } else {
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ c.setLenient(true);
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#setCalendar(java.util.Calendar)
+ */
+ public void test_setCalendarLjava_util_Calendar() {
+ DateFormat format = DateFormat.getInstance();
+ Calendar cal = Calendar.getInstance();
+ format.setCalendar(cal);
+ assertTrue("Not identical Calendar", cal == format.getCalendar());
+ }
+
+ /**
+ * @tests java.text.DateFormat#setNumberFormat(java.text.NumberFormat)
+ */
+ public void test_setNumberFormatLjava_text_NumberFormat() {
+ DateFormat format = DateFormat.getInstance();
+ NumberFormat f1 = NumberFormat.getInstance();
+ format.setNumberFormat(f1);
+ assertTrue("Not identical NumberFormat", f1 == format.getNumberFormat());
+ }
+
+ /**
+ * @tests java.text.DateFormat#parse(String)
+ */
+ public void test_parse_LString() {
+ DateFormat format = DateFormat.getInstance();
+ try {
+ format.parse("not a Date");
+ fail("should throw ParseException first");
+ } catch (ParseException e) {
+ assertNotNull(e.getMessage());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#parseObject(String, ParsePosition) Test of
+ * method java.text.DateFormat#parseObject(String, ParsePosition).
+ * Case 1: Try to parse correct data string. Case 2: Try to parse
+ * partialy correct data string. Case 3: Try to use argument
+ * ParsePosition as null.
+ */
+ public void test_parseObjectLjava_lang_StringLjava_text_ParsePosition() {
+ DateFormat df = DateFormat.getInstance();
+ try {
+ // case 1: Try to parse correct data string.
+ Date current = new Date();
+ ParsePosition pp = new ParsePosition(0);
+ int parseIndex = pp.getIndex();
+ Date result = (Date) df.parseObject(df.format(current), pp);
+ assertTrue("Parse operation return null", result != null);
+ assertTrue("ParseIndex is incorrect", pp.getIndex() != parseIndex);
+
+ // case 2: Try to parse partially correct data string.
+ pp.setIndex(0);
+ char[] cur = df.format(current).toCharArray();
+ cur[cur.length / 2] = 'Z';
+ String partialCorrect = new String(cur);
+ result = (Date) df.parseObject(partialCorrect, pp);
+ assertTrue("Parse operation return not-null", result == null);
+ assertTrue("ParseIndex is incorrect", pp.getIndex() == 0);
+ assertTrue("ParseErrorIndex is incorrect",
+ pp.getErrorIndex() == cur.length / 2);
+
+ // case 3: Try to use argument ParsePosition as null.
+ try {
+ df.parseObject(df.format(current), null);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#setLenient(boolean) Test of method
+ * java.text.DateFormat#setLenient(boolean).
+ */
+ public void test_setLenientZ() {
+ DateFormat df = DateFormat.getInstance();
+ Calendar c = df.getCalendar();
+ try {
+ c.setLenient(true);
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ c.setLenient(false);
+ try {
+ c.set(Calendar.DAY_OF_MONTH, 32);
+ c.get(Calendar.DAY_OF_MONTH);
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ } catch (Exception e) {
+ fail("Uexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DateFormat#setTimeZone(TimeZone) Test of method
+ * java.text.DateFormat#setTimeZone(TimeZone).
+ */
+ public void test_setTimeZoneLjava_util_TimeZone() {
+ try {
+ DateFormat format = DateFormat.getInstance();
+ TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ format.setTimeZone(tz);
+ assertTrue("TimeZone is set incorrectly", tz.equals(format
+ .getTimeZone()));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java
new file mode 100644
index 0000000..4108292
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java
@@ -0,0 +1,536 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Currency;
+import java.util.Locale;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class DecimalFormatSymbolsTest extends TestCase {
+
+ DecimalFormatSymbols dfs;
+
+ DecimalFormatSymbols dfsUS;
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#DecimalFormatSymbols() Test of
+ * method java.text.DecimalFormatSymbols#DecimalFormatSymbols().
+ */
+ public void test_Constructor() {
+ // Test for method java.text.DecimalFormatSymbols()
+ try {
+ new DecimalFormatSymbols();
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#DecimalFormatSymbols(java.util.Locale)
+ */
+ public void test_ConstructorLjava_util_Locale() {
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(new Locale("en",
+ "us"));
+ assertEquals("Returned incorrect symbols", '%', dfs.getPercent());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#clone() Test of method
+ * java.text.DecimalFormatSymbols#clone(). Case 1: Compare of
+ * internal variables of cloned objects. Case 2: Compare of clones.
+ * Case 3: Change the content of the clone.
+ */
+ public void test_clone() {
+ try {
+ // case 1: Compare of internal variables of cloned objects
+ DecimalFormatSymbols fs = new DecimalFormatSymbols(Locale.US);
+ DecimalFormatSymbols fsc = (DecimalFormatSymbols) fs.clone();
+ assertEquals(fs.getCurrency(), fsc.getCurrency());
+
+ // case 2: Compare of clones
+ fs = new DecimalFormatSymbols();
+ DecimalFormatSymbols fsc2 = (DecimalFormatSymbols) (fs.clone());
+ // make sure the objects are equal
+ assertTrue("Object's clone isn't equal!", fs.equals(fsc2));
+
+ // case 3:
+ // change the content of the clone and make sure it's not equal
+ // anymore
+ // verifies that it's data is now distinct from the original
+ fs.setNaN("not-a-number");
+ assertTrue("Object's changed clone should not be equal!", !fs
+ .equals(fsc2));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ assertTrue("Equal objects returned false", dfs.equals(dfs.clone()));
+ dfs.setDigit('B');
+ assertTrue("Un-Equal objects returned true", !dfs
+ .equals(new DecimalFormatSymbols()));
+
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getCurrency()
+ */
+ public void test_getCurrency() {
+ Currency currency = Currency.getInstance("USD");
+ assertTrue("Returned incorrect currency",
+ dfsUS.getCurrency() == currency);
+
+ // BEGIN android-changed
+ // use cs_CZ instead
+ //Currency currK = Currency.getInstance("KRW");
+ Currency currC = Currency.getInstance("CZK");
+ Currency currX = Currency.getInstance("XXX");
+ Currency currE = Currency.getInstance("EUR");
+ // Currency currF = Currency.getInstance("FRF");
+
+ DecimalFormatSymbols dfs1 = new DecimalFormatSymbols(new Locale("cs",
+ "CZ"));
+ assertTrue("Test1: Returned incorrect currency",
+ dfs1.getCurrency() == currC);
+ assertEquals("Test1: Returned incorrect currencySymbol", "K\u010d", dfs1
+ .getCurrencySymbol());
+ assertEquals("Test1: Returned incorrect intlCurrencySymbol", "CZK",
+ dfs1.getInternationalCurrencySymbol());
+
+ dfs1 = new DecimalFormatSymbols(new Locale("", "CZ"));
+ assertTrue("Test2: Returned incorrect currency",
+ dfs1.getCurrency() == currC);
+ assertEquals("Test2: Returned incorrect currencySymbol", "CZK", dfs1
+ .getCurrencySymbol());
+ assertEquals("Test2: Returned incorrect intlCurrencySymbol", "CZK",
+ dfs1.getInternationalCurrencySymbol());
+
+ dfs1 = new DecimalFormatSymbols(new Locale("cs", ""));
+ assertEquals("Test3: Returned incorrect currency",
+ currX, dfs1.getCurrency());
+ assertEquals("Test3: Returned incorrect currencySymbol", "\u00a4", dfs1
+ .getCurrencySymbol());
+ assertEquals("Test3: Returned incorrect intlCurrencySymbol", "XXX",
+ dfs1.getInternationalCurrencySymbol());
+
+ dfs1 = new DecimalFormatSymbols(new Locale("de", "AT"));
+ // END android-changed
+ assertTrue("Test4: Returned incorrect currency",
+ dfs1.getCurrency() == currE);
+ assertEquals("Test4: Returned incorrect currencySymbol", "\u20ac", dfs1
+ .getCurrencySymbol());
+ assertEquals("Test4: Returned incorrect intlCurrencySymbol", "EUR",
+ dfs1.getInternationalCurrencySymbol());
+
+ // RI fails these tests since it doesn't have the PREEURO variant
+ // dfs1 = new DecimalFormatSymbols(new Locale("fr", "FR","PREEURO"));
+ // assertTrue("Test5: Returned incorrect currency", dfs1.getCurrency()
+ // == currF);
+ // assertTrue("Test5: Returned incorrect currencySymbol",
+ // dfs1.getCurrencySymbol().equals("F"));
+ // assertTrue("Test5: Returned incorrect intlCurrencySymbol",
+ // dfs1.getInternationalCurrencySymbol().equals("FRF"));
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getCurrencySymbol()
+ */
+ public void test_getCurrencySymbol() {
+ assertEquals("Returned incorrect currencySymbol", "$", dfsUS
+ .getCurrencySymbol());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getDecimalSeparator()
+ */
+ public void test_getDecimalSeparator() {
+ dfs.setDecimalSeparator('*');
+ assertEquals("Returned incorrect DecimalSeparator symbol", '*', dfs
+ .getDecimalSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getDigit()
+ */
+ public void test_getDigit() {
+ dfs.setDigit('*');
+ assertEquals("Returned incorrect Digit symbol", '*', dfs.getDigit());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getGroupingSeparator()
+ */
+ public void test_getGroupingSeparator() {
+ dfs.setGroupingSeparator('*');
+ assertEquals("Returned incorrect GroupingSeparator symbol", '*', dfs
+ .getGroupingSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getInfinity()
+ */
+ public void test_getInfinity() {
+ dfs.setInfinity("&");
+ assertTrue("Returned incorrect Infinity symbol",
+ dfs.getInfinity() == "&");
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getInternationalCurrencySymbol()
+ */
+ public void test_getInternationalCurrencySymbol() {
+ assertEquals("Returned incorrect InternationalCurrencySymbol", "USD",
+ dfsUS.getInternationalCurrencySymbol());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getMinusSign()
+ */
+ public void test_getMinusSign() {
+ dfs.setMinusSign('&');
+ assertEquals("Returned incorrect MinusSign symbol", '&', dfs
+ .getMinusSign());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getMonetaryDecimalSeparator() Test
+ * of method
+ * java.text.DecimalFormatSymbols#getMonetaryDecimalSeparator().
+ */
+ public void test_getMonetaryDecimalSeparator() {
+ try {
+ dfs.setMonetaryDecimalSeparator(',');
+ assertEquals("Returned incorrect MonetaryDecimalSeparator symbol",
+ ',', dfs.getMonetaryDecimalSeparator());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getNaN()
+ */
+ public void test_getNaN() {
+ dfs.setNaN("NAN!!");
+ assertEquals("Returned incorrect nan symbol", "NAN!!", dfs.getNaN());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getPatternSeparator()
+ */
+ public void test_getPatternSeparator() {
+ dfs.setPatternSeparator('X');
+ assertEquals("Returned incorrect PatternSeparator symbol", 'X', dfs
+ .getPatternSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getPercent()
+ */
+ public void test_getPercent() {
+ dfs.setPercent('*');
+ assertEquals("Returned incorrect Percent symbol", '*', dfs.getPercent());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getPerMill()
+ */
+ public void test_getPerMill() {
+ dfs.setPerMill('#');
+ assertEquals("Returned incorrect PerMill symbol", '#', dfs.getPerMill());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#getZeroDigit()
+ */
+ public void test_getZeroDigit() {
+ dfs.setZeroDigit('*');
+ assertEquals("Returned incorrect ZeroDigit symbol", '*', dfs
+ .getZeroDigit());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#hashCode() Test of method
+ * java.text.DecimalFormatSymbols#hashCode().
+ */
+ public void test_hashCode() {
+ try {
+ DecimalFormatSymbols dfs1 = new DecimalFormatSymbols();
+ DecimalFormatSymbols dfs2 = (DecimalFormatSymbols) dfs1.clone();
+ assertTrue("Hash codes of equal object are equal", dfs2
+ .hashCode() == dfs1.hashCode());
+ dfs1.setInfinity("infinity_infinity");
+ // BEGIN android-changed
+ assertTrue("Hash codes of non-equal objects are equal", dfs2
+ .hashCode() != dfs1.hashCode());
+ // END android-changed
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setCurrency(java.util.Currency)
+ */
+ public void test_setCurrencyLjava_util_Currency() {
+ Locale locale = Locale.CANADA;
+ DecimalFormatSymbols dfs = ((DecimalFormat) NumberFormat
+ .getCurrencyInstance(locale)).getDecimalFormatSymbols();
+
+ try {
+ dfs.setCurrency(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ }
+
+ Currency currency = Currency.getInstance("JPY");
+ dfs.setCurrency(currency);
+
+ assertTrue("Returned incorrect currency", currency == dfs.getCurrency());
+ assertTrue("Returned incorrect currency symbol", currency.getSymbol(
+ locale).equals(dfs.getCurrencySymbol()));
+ assertTrue("Returned incorrect international currency symbol", currency
+ .getCurrencyCode().equals(dfs.getInternationalCurrencySymbol()));
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setCurrencySymbol(java.lang.String)
+ * Test of method
+ * java.text.DecimalFormatSymbols#setCurrencySymbol(java.lang.String).
+ */
+ public void test_setCurrencySymbolLjava_lang_String() {
+ try {
+ dfs.setCurrencySymbol("$");
+ assertEquals("Returned incorrect CurrencySymbol symbol", "$", dfs
+ .getCurrencySymbol());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setDecimalSeparator(char)
+ */
+ public void test_setDecimalSeparatorC() {
+ dfs.setDecimalSeparator('*');
+ assertEquals("Returned incorrect DecimalSeparator symbol", '*', dfs
+ .getDecimalSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setDigit(char)
+ */
+ public void test_setDigitC() {
+ dfs.setDigit('*');
+ assertEquals("Returned incorrect Digit symbol", '*', dfs.getDigit());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setGroupingSeparator(char)
+ */
+ public void test_setGroupingSeparatorC() {
+ dfs.setGroupingSeparator('*');
+ assertEquals("Returned incorrect GroupingSeparator symbol", '*', dfs
+ .getGroupingSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setInfinity(java.lang.String)
+ */
+ public void test_setInfinityLjava_lang_String() {
+ dfs.setInfinity("&");
+ assertTrue("Returned incorrect Infinity symbol",
+ dfs.getInfinity() == "&");
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setInternationalCurrencySymbol(java.lang.String)
+ */
+ public void test_setInternationalCurrencySymbolLjava_lang_String() {
+ Locale locale = Locale.CANADA;
+ DecimalFormatSymbols dfs = ((DecimalFormat) NumberFormat
+ .getCurrencyInstance(locale)).getDecimalFormatSymbols();
+ Currency currency = Currency.getInstance("JPY");
+ dfs.setInternationalCurrencySymbol(currency.getCurrencyCode());
+
+ assertTrue("Test1: Returned incorrect currency", currency == dfs
+ .getCurrency());
+ assertTrue("Test1: Returned incorrect currency symbol", currency
+ .getSymbol(locale).equals(dfs.getCurrencySymbol()));
+ assertTrue("Test1: Returned incorrect international currency symbol",
+ currency.getCurrencyCode().equals(
+ dfs.getInternationalCurrencySymbol()));
+
+ String symbol = dfs.getCurrencySymbol();
+ dfs.setInternationalCurrencySymbol("bogus");
+ assertNull("Test2: Returned incorrect currency", dfs.getCurrency());
+ assertTrue("Test2: Returned incorrect currency symbol", dfs
+ .getCurrencySymbol().equals(symbol));
+ assertEquals("Test2: Returned incorrect international currency symbol",
+ "bogus", dfs.getInternationalCurrencySymbol());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setMinusSign(char)
+ */
+ public void test_setMinusSignC() {
+ dfs.setMinusSign('&');
+ assertEquals("Returned incorrect MinusSign symbol", '&', dfs
+ .getMinusSign());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setMonetaryDecimalSeparator(char)
+ * Test of method
+ * java.text.DecimalFormatSymbols#setMonetaryDecimalSeparator(char).
+ */
+ public void test_setMonetaryDecimalSeparatorC() {
+ try {
+ dfs.setMonetaryDecimalSeparator('#');
+ assertEquals("Returned incorrect MonetaryDecimalSeparator symbol",
+ '#', dfs.getMonetaryDecimalSeparator());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setNaN(java.lang.String)
+ */
+ public void test_setNaNLjava_lang_String() {
+ dfs.setNaN("NAN!!");
+ assertEquals("Returned incorrect nan symbol", "NAN!!", dfs.getNaN());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setPatternSeparator(char)
+ */
+ public void test_setPatternSeparatorC() {
+ dfs.setPatternSeparator('X');
+ assertEquals("Returned incorrect PatternSeparator symbol", 'X', dfs
+ .getPatternSeparator());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setPercent(char)
+ */
+ public void test_setPercentC() {
+ dfs.setPercent('*');
+ assertEquals("Returned incorrect Percent symbol", '*', dfs.getPercent());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setPerMill(char)
+ */
+ public void test_setPerMillC() {
+ dfs.setPerMill('#');
+ assertEquals("Returned incorrect PerMill symbol", '#', dfs.getPerMill());
+ }
+
+ /**
+ * @tests java.text.DecimalFormatSymbols#setZeroDigit(char)
+ */
+ public void test_setZeroDigitC() {
+ dfs.setZeroDigit('*');
+ assertEquals("Set incorrect ZeroDigit symbol", '*', dfs.getZeroDigit());
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+ dfs = new DecimalFormatSymbols();
+ dfsUS = new DecimalFormatSymbols(new Locale("en", "us"));
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ }
+
+ // Test serialization mechanism of DecimalFormatSymbols
+ public void test_serialization() throws Exception {
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.FRANCE);
+ Currency currency = symbols.getCurrency();
+ assertNotNull(currency);
+
+ // serialize
+ ByteArrayOutputStream byteOStream = new ByteArrayOutputStream();
+ ObjectOutputStream objectOStream = new ObjectOutputStream(byteOStream);
+ objectOStream.writeObject(symbols);
+
+ // and deserialize
+ ObjectInputStream objectIStream = new ObjectInputStream(
+ new ByteArrayInputStream(byteOStream.toByteArray()));
+ DecimalFormatSymbols symbolsD = (DecimalFormatSymbols) objectIStream
+ .readObject();
+
+ // The associated currency will not persist
+ currency = symbolsD.getCurrency();
+ assertNotNull(currency);
+ }
+
+ // Use RI to write DecimalFormatSymbols out, use Harmony to read
+ // DecimalFormatSymbols in. The read symbol will be equal with those
+ // instantiated inside Harmony.
+
+ // This assertion will not come into existence the other way around. This is
+ // probably caused by different serialization mechanism used by RI and
+ // Harmony.
+ public void test_RIHarmony_compatible() throws Exception {
+ ObjectInputStream i = null;
+ try {
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols(
+ Locale.FRANCE);
+ i = new ObjectInputStream(
+ getClass()
+ .getClassLoader()
+ .getResourceAsStream(
+ "/serialization/java/text/DecimalFormatSymbols.ser"));
+ DecimalFormatSymbols symbolsD = (DecimalFormatSymbols) i
+ .readObject();
+ assertEquals(symbols, symbolsD);
+ } catch(NullPointerException e) {
+ assertNotNull("Failed to load /serialization/java/text/DecimalFormatSymbols.ser", i);
+ } finally {
+ try {
+ if (i != null) {
+ i.close();
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java
new file mode 100644
index 0000000..f758662
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java
@@ -0,0 +1,1869 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ObjectInputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.AttributedCharacterIterator;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Currency;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+import tests.support.Support_BitSet;
+import tests.support.Support_DecimalFormat;
+
+public class DecimalFormatTest extends TestCase {
+
+ public void testAttributedCharacterIterator() throws Exception {
+ // Regression for http://issues.apache.org/jira/browse/HARMONY-333
+ AttributedCharacterIterator iterator = new DecimalFormat()
+ .formatToCharacterIterator(new Integer(1));
+ assertNotNull(iterator);
+ assertFalse("attributes should exist", iterator.getAttributes()
+ .isEmpty());
+ }
+
+ /*
+ * Test the getter and setter of parseBigDecimal and parseIntegerOnly and
+ * test the default value of them.
+ */
+ public void test_isParseBigDecimalLjava_lang_Boolean_isParseIntegerOnlyLjava_lang_Boolean() {
+
+ // parseBigDecimal default to false
+ DecimalFormat form = (DecimalFormat) DecimalFormat
+ .getInstance(Locale.US);
+ assertFalse(form.isParseBigDecimal());
+ form.setParseBigDecimal(true);
+ assertTrue(form.isParseBigDecimal());
+ form.setParseBigDecimal(false);
+ assertFalse(form.isParseBigDecimal());
+
+ // parseIntegerOnly default to false
+ assertFalse(form.isParseIntegerOnly());
+ }
+
+ // Test the type of the returned object
+
+ public void test_parseLjava_lang_String_Ljava_text_ParsePosition() {
+ DecimalFormat form = (DecimalFormat) DecimalFormat
+ .getInstance(Locale.US);
+ Number number = form.parse("23.1", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // Test parsed object of type double when
+ // parseBigDecimal is set to true
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ number = form.parse("23.1", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ form.setParseBigDecimal(true);
+ number = form.parse("23.1", new ParsePosition(0));
+
+ assertTrue(number instanceof BigDecimal);
+ assertEquals(new BigDecimal("23.1"), number);
+
+ // When parseIntegerOnly set to true, all float numbers will be parsed
+ // into Long.
+ // With the exception that, the value is out of the bound of Long or
+ // some special values such as NaN or Infinity.
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ form.setParseIntegerOnly(true);
+ number = form.parse("23.1f", new ParsePosition(0));
+
+ assertTrue(number instanceof Long);
+
+ number = form.parse("23.0", new ParsePosition(0));
+ assertTrue(number instanceof Long);
+
+ number = form.parse("-0.0", new ParsePosition(0));
+ assertTrue(number instanceof Long);
+ assertTrue(new Long(0).equals(number));
+
+ number = form.parse("-9,223,372,036,854,775,8080.00",
+ new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // Even if parseIntegerOnly is set to true, NaN will be parsed to Double
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ form.setParseIntegerOnly(true);
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ number = form.parse(symbols.getNaN(), new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // Even if parseIntegerOnly is set to true, Infinity will still be
+ // parsed to Double
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ form.setParseIntegerOnly(true);
+ symbols = new DecimalFormatSymbols();
+ number = form.parse(symbols.getInfinity(), new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // ParseBigDecimal take precedence of parseBigInteger
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ form.setParseIntegerOnly(true);
+ form.setParseBigDecimal(true);
+
+ number = form.parse("23.1f", new ParsePosition(0));
+
+ assertTrue(number instanceof BigDecimal);
+
+ number = form.parse("23.0", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ number = form.parse("-9,223,372,036,854,775,8080.00",
+ new ParsePosition(0));
+ assertFalse(number instanceof BigInteger);
+ assertTrue(number instanceof BigDecimal);
+// BEGIN android-added
+ final String doubleMax2 = "359,538,626,972,463,141,629,054,847,463,408,"
+ + "713,596,141,135,051,689,993,197,834,953,606,314,521,560,057,077,"
+ + "521,179,117,265,533,756,343,080,917,907,028,764,928,468,642,653,"
+ + "778,928,365,536,935,093,407,075,033,972,099,821,153,102,564,152,"
+ + "490,980,180,778,657,888,151,737,016,910,267,884,609,166,473,806,"
+ + "445,896,331,617,118,664,246,696,549,595,652,408,289,446,337,476,"
+ + "354,361,838,599,762,500,808,052,368,249,716,736";
+ number = form.parse(doubleMax2, new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+ assertEquals(new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(
+ Double.MAX_VALUE)), number);
+// END android-added
+ // Test whether the parsed object is of type float. (To be specific,
+ // they are of type Double)
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+
+ number = form.parse("23.1f", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ form.setParseBigDecimal(true);
+ number = form.parse("23.1f", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+ assertEquals(new BigDecimal("23.1"), number);
+
+ // Integer will be parsed to Long, unless parseBigDecimal is set to true
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+
+ number = form.parse("123", new ParsePosition(0));
+ assertTrue(number instanceof Long);
+
+ form.setParseBigDecimal(true);
+ number = form.parse("123", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+ assertEquals(new BigDecimal("123"), number);
+
+ // NaN will be parsed to Double, no matter parseBigDecimal set or not.
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ symbols = new DecimalFormatSymbols();
+ number = form.parse(symbols.getNaN() + "", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ form.setParseBigDecimal(true);
+ number = form.parse(symbols.getNaN() + "", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // Infinity will be parsed to Double, no matter parseBigDecimal set or
+ // not.
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ symbols = new DecimalFormatSymbols();
+
+ number = form.parse(symbols.getInfinity(), new ParsePosition(0));
+
+ assertTrue(number instanceof Double);
+ assertEquals("Infinity", number.toString());
+ // When set bigDecimal to true, the result of parsing infinity
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ symbols = new DecimalFormatSymbols();
+ form.setParseBigDecimal(true);
+
+ number = form.parse(symbols.getInfinity(), new ParsePosition(0));
+ assertTrue(number instanceof Double);
+ assertEquals("Infinity", number.toString());
+
+ // Negative infinity will be parsed to double no matter parseBigDecimal
+ // set or not
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ symbols = new DecimalFormatSymbols();
+
+ number = form.parse("-" + symbols.getInfinity(), new ParsePosition(0));
+
+ assertTrue(number instanceof Double);
+ assertEquals("-Infinity", number.toString());
+
+ // When set bigDecimal to true, the result of parsing minus infinity
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+ symbols = new DecimalFormatSymbols();
+ form.setParseBigDecimal(true);
+
+ number = form.parse("-" + symbols.getInfinity(), new ParsePosition(0));
+
+ assertTrue(number instanceof Double);
+ assertEquals("-Infinity", number.toString());
+
+ // -0.0 will be parsed to different type according to the combination of
+ // parseBigDecimal and parseIntegerOnly
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+
+ // parseBigDecimal == true;
+ // parseIntegerOnly == false;
+ form.setParseBigDecimal(true);
+ number = form.parse("-0", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ number = form.parse("-0.0", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ // parseBigDecimal == false;
+ // parseIntegerOnly == true;
+ form.setParseBigDecimal(false);
+ form.setParseIntegerOnly(true);
+ number = form.parse("-0", new ParsePosition(0));
+
+ assertTrue(number instanceof Long);
+
+ number = form.parse("-0.0", new ParsePosition(0));
+ assertTrue(number instanceof Long);
+
+ // parseBigDecimal == false;
+ // parseIntegerOnly == false;
+ form.setParseBigDecimal(false);
+ form.setParseIntegerOnly(false);
+ number = form.parse("-0", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ number = form.parse("-0.0", new ParsePosition(0));
+ assertTrue(number instanceof Double);
+
+ // parseBigDecimal == true;
+ // parseIntegerOnly == true;
+ // parseBigDecimal take precedence of parseBigInteger
+ form.setParseBigDecimal(true);
+ form.setParseIntegerOnly(true);
+ number = form.parse("-0", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ number = form.parse("-0.0", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ number = form.parse("12.4", new ParsePosition(0));
+ assertTrue(number instanceof BigDecimal);
+
+ // When parseBigDecimal is set to false, no matter how massive the
+ // mantissa part of a number is, the number will be parsed into Double
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+
+ number = form.parse("9,223,372,036,854,775,808.00",
+ new ParsePosition(0));
+
+ assertTrue(number instanceof Double);
+ assertEquals("9.223372036854776E18", number.toString());
+
+ number = form.parse("-9,223,372,036,854,775,8080.00",
+ new ParsePosition(0));
+ assertTrue(number instanceof Double);
+ assertEquals("-9.223372036854776E19", number.toString());
+
+ // When parseBigDecimal is set to true, if mantissa part of number
+ // exceeds Long.MAX_VALUE, the number will be parsed into BigDecimal
+
+ form = (DecimalFormat) DecimalFormat.getInstance(Locale.US);
+
+ form.setParseBigDecimal(true);
+ number = form.parse("9,223,372,036,854,775,808.00",
+ new ParsePosition(0));
+
+ assertTrue(number instanceof BigDecimal);
+
+ assertEquals(9.223372036854776E18, number.doubleValue(), 0);
+
+ number = form.parse("-9,223,372,036,854,775,8080.00",
+ new ParsePosition(0));
+
+ assertTrue(number instanceof BigDecimal);
+ assertEquals(-9.223372036854776E19, number.doubleValue(), 0);
+
+ // The minimum value of Long will be parsed to Long when parseBigDecimal
+ // is not set
+
+ ParsePosition pos = new ParsePosition(0);
+ DecimalFormat df = new DecimalFormat();
+ pos = new ParsePosition(0);
+ Number nb = df.parse("" + Long.MIN_VALUE, pos);
+ assertTrue(nb instanceof Long);
+
+ // The maximum value of Long will be parsed to Long when parseBigDecimal
+ // is set
+ pos = new ParsePosition(0);
+ df = new DecimalFormat();
+ pos = new ParsePosition(0);
+ nb = df.parse("" + Long.MAX_VALUE, pos);
+ assertTrue(nb instanceof Long);
+
+ // When parsing invalid string( which is neither consist of digits nor
+ // NaN/Infinity), a null will be returned.
+
+ pos = new ParsePosition(0);
+ df = new DecimalFormat();
+ try {
+ nb = df.parse("invalid", pos);
+ assertNull(nb);
+ } catch (NullPointerException e) {
+ fail("Should not throw NPE");
+ }
+ }
+
+ public void test_getMaximumFractionDigits() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ // getMaximumFractionDigits of NumberFormat default to 3
+ // getMaximumFractionDigits of DecimalFormat default to 3
+ assertEquals(3, nform.getMaximumFractionDigits());
+ assertEquals(3, form.getMaximumFractionDigits());
+
+ // Greater than 340 (critical number used to distinguish
+ // BigInteger and BigDecimal)
+ nform.setMaximumFractionDigits(500);
+ assertEquals(500, nform.getMaximumFractionDigits());
+ assertEquals(500, form.getMaximumFractionDigits());
+
+ form.setMaximumFractionDigits(500);
+ assertEquals(500, nform.getMaximumFractionDigits());
+ assertEquals(500, form.getMaximumFractionDigits());
+
+ form.format(12.3);
+ assertEquals(500, nform.getMaximumFractionDigits());
+ assertEquals(500, form.getMaximumFractionDigits());
+ }
+
+ public void test_getMinimumFractionDigits() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ // getMinimumFractionDigits from NumberFormat (default to 0)
+ // getMinimumFractionDigits from DecimalFormat (default to 0)
+ assertEquals(0, nform.getMinimumFractionDigits());
+ assertEquals(0, form.getMinimumFractionDigits());
+
+ // Greater than 340 (critical number used to distinguish
+ // BigInteger and BigDecimal)
+ nform.setMinimumFractionDigits(500);
+ assertEquals(500, nform.getMinimumFractionDigits());
+ assertEquals(500, form.getMinimumFractionDigits());
+
+ form.setMaximumFractionDigits(400);
+ assertEquals(400, nform.getMinimumFractionDigits());
+ assertEquals(400, form.getMinimumFractionDigits());
+ }
+
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_getMaximumIntegerDigits() {
+ final int maxIntDigit = 309;
+
+ // When use default locale, in this case zh_CN
+ // the returned instance of NumberFormat is a DecimalFormat
+ DecimalFormat form = new DecimalFormat("00.###E0");
+ assertEquals(2, form.getMaximumIntegerDigits());
+
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ form = null;
+ if (nform instanceof DecimalFormat) {
+ form = (DecimalFormat) nform;
+ }
+
+ // Greater than 309 (critical number used to distinguish
+ // BigInteger and BigDecimal)
+ nform.setMaximumIntegerDigits(500);
+ assertEquals(500, nform.getMaximumIntegerDigits());
+ assertEquals(500, form.getMaximumIntegerDigits());
+
+ form = new DecimalFormat("00.###E0");
+ assertEquals(2, form.getMaximumIntegerDigits());
+
+ form.setMaximumIntegerDigits(500);
+ assertEquals(500, nform.getMaximumIntegerDigits());
+ assertEquals(500, form.getMaximumIntegerDigits());
+ form.format(12.3);
+ assertEquals(500, nform.getMaximumIntegerDigits());
+ assertEquals(500, form.getMaximumIntegerDigits());
+
+ nform = DecimalFormat.getInstance(Locale.US);
+ form = null;
+ if (nform instanceof DecimalFormat) {
+ form = (DecimalFormat) nform;
+ }
+ // getMaximumIntegerDigits from NumberFormat default to 309
+ // getMaximumIntegerDigits from DecimalFormat default to 309
+ // the following 2 assertions will fail on RI implementation, since the
+ // implementation of ICU and RI are not identical. RI does not give
+ // DecimalFormat an initial bound about its maximumIntegerDigits
+ // (default to Integer.MAX_VALUE: 2147483647 )
+ assertEquals(maxIntDigit, nform.getMaximumIntegerDigits());
+ assertEquals(maxIntDigit, form.getMaximumIntegerDigits());
+
+ // regression test for HARMONY-878
+ assertTrue(new DecimalFormat("0\t0").getMaximumIntegerDigits() > 0);
+ }
+
+ public void test_getMinimumIntegerDigits() {
+ final int minIntDigit = 1;
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ // getMaximumIntegerDigits from NumberFormat (default to 1)
+ // getMaximumIntegerDigits from DecimalFormat (default to 1)
+ assertEquals(minIntDigit, nform.getMinimumIntegerDigits());
+ assertEquals(minIntDigit, form.getMinimumIntegerDigits());
+
+ // Greater than 309 (critical number used to distinguish
+ // BigInteger and BigDecimal)
+ nform.setMinimumIntegerDigits(500);
+ assertEquals(500, nform.getMinimumIntegerDigits());
+ assertEquals(500, form.getMinimumIntegerDigits());
+
+ form.setMaximumIntegerDigits(400);
+ assertEquals(400, nform.getMinimumIntegerDigits());
+ assertEquals(400, form.getMinimumIntegerDigits());
+
+ }
+
+ public void test_formatLjava_lang_Obj_Ljava_StringBuffer_Ljava_text_FieldPosition() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ // If Object(including null) is not of type Number,
+ // IllegalArgumentException will be thrown out
+ try {
+ form.format(new Object(), new StringBuffer(), new FieldPosition(0));
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ form.format(null, new StringBuffer(), new FieldPosition(0));
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // When StringBuffer == null || FieldPosition == null
+ // NullPointerException will be thrown out.
+ try {
+ form.format(new Double(1.9), null, new FieldPosition(0));
+ fail("Should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ form.format(new Double(1.3), new StringBuffer(), null);
+ fail("Should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ form.format(new Double(1.4), null, null);
+ fail("Should throw NPE");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ form.format(new Object(), null, null);
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ FieldPosition pos;
+ StringBuffer out;
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getInstance(Locale.US);
+
+ // format maxLong
+ pos = new FieldPosition(0);
+ out = format.format(new Long(Long.MAX_VALUE), new StringBuffer(), pos);
+ assertTrue("Wrong result L1: " + out, out.toString().equals(
+ "9,223,372,036,854,775,807"));
+
+ // format minLong
+ pos = new FieldPosition(0);
+ out = format.format(new Long(Long.MIN_VALUE), new StringBuffer(), pos);
+ assertTrue("Wrong result L2: " + out, out.toString().equals(
+ "-9,223,372,036,854,775,808"));
+
+ // format maxLong of type BigInteger
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigInteger(String
+ .valueOf(Long.MAX_VALUE)), new StringBuffer(), pos);
+ assertTrue("Wrong result BI1: " + out, out.toString().equals(
+ "9,223,372,036,854,775,807"));
+
+ // format minLong of type BigInteger
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigInteger(String
+ .valueOf(Long.MIN_VALUE)), new StringBuffer(), pos);
+ assertTrue("Wrong result BI2: " + out, out.toString().equals(
+ "-9,223,372,036,854,775,808"));
+
+ // format maxLong + 1
+ java.math.BigInteger big;
+ pos = new FieldPosition(0);
+ big = new java.math.BigInteger(String.valueOf(Long.MAX_VALUE))
+ .add(new java.math.BigInteger("1"));
+ out = format.format(big, new StringBuffer(), pos);
+ assertTrue("Wrong result BI3: " + out, out.toString().equals(
+ "9,223,372,036,854,775,808"));
+
+ // format minLong - 1
+ pos = new FieldPosition(0);
+ big = new java.math.BigInteger(String.valueOf(Long.MIN_VALUE))
+ .add(new java.math.BigInteger("-1"));
+ out = format.format(big, new StringBuffer(), pos);
+ assertTrue("Wrong result BI4: " + out, out.toString().equals(
+ "-9,223,372,036,854,775,809"));
+
+ // format big decimal
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigDecimal("51.348"),
+ new StringBuffer(), pos);
+ assertTrue("Wrong result BD1: " + out, out.toString().equals("51.348"));
+
+ // format big decimal
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigDecimal("51"), new StringBuffer(),
+ pos);
+ assertTrue("Wrong result BD2: " + out, out.toString().equals("51"));
+
+ // format big decimal Double.MAX_VALUE * 2
+ java.math.BigDecimal bigDecimal;
+ pos = new FieldPosition(0);
+ final String doubleMax2 = "359,538,626,972,463,141,629,054,847,463,408,"
+ + "713,596,141,135,051,689,993,197,834,953,606,314,521,560,057,077,"
+ + "521,179,117,265,533,756,343,080,917,907,028,764,928,468,642,653,"
+ + "778,928,365,536,935,093,407,075,033,972,099,821,153,102,564,152,"
+ + "490,980,180,778,657,888,151,737,016,910,267,884,609,166,473,806,"
+ + "445,896,331,617,118,664,246,696,549,595,652,408,289,446,337,476,"
+ + "354,361,838,599,762,500,808,052,368,249,716,736";
+ bigDecimal = new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(
+ Double.MAX_VALUE));
+ out = format.format(bigDecimal, new StringBuffer(), pos);
+ assertTrue("Wrong result BDmax2: " + out, out.toString().equals(
+ doubleMax2));
+
+ // format big decimal Double.MIN_VALUE + Double.MIN_VALUE
+ // and Double.MIN_VALUE - Double.MIN_VALUE
+ pos = new FieldPosition(0);
+
+ bigDecimal = new BigDecimal(Double.MIN_VALUE).add(new BigDecimal(
+ Double.MIN_VALUE));
+ out = format.format(bigDecimal, new StringBuffer(), pos);
+
+ bigDecimal = new BigDecimal(Float.MAX_VALUE).add(new BigDecimal(
+ Float.MAX_VALUE));
+ out = format.format(bigDecimal, new StringBuffer(), pos);
+ final String BDFloatMax2 = "680,564,693,277,057,719,623,408,366,969,033,850,880";
+ assertTrue("Wrong result BDFloatMax2: " + out, out.toString().equals(
+ BDFloatMax2));
+ // format big decimal Float.MIN_VALUE + Float.MIN_VALUE
+ // and Float.MIN_VALUE - Float.MIN_VALUE
+ bigDecimal = new BigDecimal(Float.MIN_VALUE).add(new BigDecimal(
+ Float.MIN_VALUE));
+ out = format.format(bigDecimal, new StringBuffer(), pos);
+ final String BDFloatMin2 = "0";
+
+ bigDecimal = new BigDecimal(Float.MIN_VALUE).subtract(new BigDecimal(
+ Float.MIN_VALUE));
+ out = format.format(bigDecimal, new StringBuffer(), pos);
+
+ assertTrue("Wrong result BDFloatMax2: " + out, out.toString().equals(
+ BDFloatMin2));
+
+ }
+
+ public void test_setMaximumFractionDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMaximumFractionDigits(-2);
+ assertEquals(0, form.getMaximumFractionDigits());
+
+ form.setMaximumFractionDigits(341);
+ assertEquals(341, form.getMaximumFractionDigits());
+ }
+
+ public void test_setMinimumFractionDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMinimumFractionDigits(-3);
+ assertEquals(0, form.getMinimumFractionDigits());
+
+ form.setMinimumFractionDigits(310);
+ assertEquals(310, form.getMinimumFractionDigits());
+ }
+
+ public void test_setMaximumIntegerDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMaximumIntegerDigits(-3);
+ assertEquals(0, form.getMaximumIntegerDigits());
+
+ form.setMaximumIntegerDigits(310);
+ assertEquals(310, form.getMaximumIntegerDigits());
+ }
+
+ public void test_setMinimumIntegerDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMinimumIntegerDigits(-3);
+ assertEquals(0, form.getMinimumIntegerDigits());
+
+ form.setMinimumIntegerDigits(310);
+ assertEquals(310, form.getMinimumIntegerDigits());
+ }
+
+ // When MaxFractionDigits is set first and less than MinFractionDigits, max
+ // will be changed to min value
+ public void test_setMinimumFactionDigitsLjava_lang_Integer_setMaximumFractionDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMaximumFractionDigits(100);
+ form.setMinimumFractionDigits(200);
+
+ assertEquals(200, form.getMaximumFractionDigits());
+ assertEquals(200, form.getMinimumFractionDigits());
+
+ form.setMaximumIntegerDigits(100);
+ form.setMinimumIntegerDigits(200);
+
+ assertEquals(200, form.getMaximumIntegerDigits());
+ assertEquals(200, form.getMinimumIntegerDigits());
+ }
+
+ // When MinFractionDigits is set first and less than MaxFractionDigits, min
+ // will be changed to max value
+ public void test_setMaximumFactionDigitsLjava_lang_Integer_setMinimumFractionDigitsLjava_lang_Integer() {
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+
+ form.setMinimumFractionDigits(200);
+ form.setMaximumFractionDigits(100);
+
+ assertEquals(100, form.getMaximumFractionDigits());
+ assertEquals(100, form.getMinimumFractionDigits());
+
+ form.setMinimumIntegerDigits(200);
+ form.setMaximumIntegerDigits(100);
+
+ assertEquals(100, form.getMaximumIntegerDigits());
+ assertEquals(100, form.getMinimumIntegerDigits());
+ }
+
+ public void test_equalsLjava_lang_Object() {
+ DecimalFormat format = (DecimalFormat) DecimalFormat
+ .getInstance(Locale.US);
+ DecimalFormat cloned = (DecimalFormat) format.clone();
+ cloned.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
+ assertEquals(format, cloned);
+
+ Currency c = Currency.getInstance(Locale.US);
+ cloned.setCurrency(c);
+
+ assertEquals(format, cloned);
+ }
+
+ public void test_setPositivePrefixLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat();
+ assertEquals("", format.getPositivePrefix());
+ }
+
+ public void test_setPositiveSuffixLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat();
+ assertEquals("", format.getPositiveSuffix());
+ }
+
+ public void test_setNegativePrefixLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat();
+ assertEquals("-", format.getNegativePrefix());
+ }
+
+ public void test_setNegativeSuffixLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat();
+ assertEquals("", format.getNegativeSuffix());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#toLocalizedPattern() Test of method
+ * java.text.DecimalFormat#toLocalizedPattern().
+ */
+ public void test_toLocalizedPattern() {
+ DecimalFormat format = new DecimalFormat();
+ try {
+ format.applyLocalizedPattern("#.#");
+ assertEquals("Wrong pattern 1", "#.;#", format.toLocalizedPattern());
+ format.applyLocalizedPattern("#.");
+ assertEquals("Wrong pattern 2", "#.", format.toLocalizedPattern());
+ format.applyLocalizedPattern("#");
+ assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+ format.applyLocalizedPattern(".#");
+ assertEquals("Wrong pattern 4", ".#", format.toLocalizedPattern());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#toPattern() Test of method
+ * java.text.DecimalFormat#toPattern().
+ */
+ public void test_toPattern() {
+ DecimalFormat format = new DecimalFormat();
+ try {
+ format.applyPattern("#.#");
+ assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+ format.applyPattern("#.");
+ assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+ format.applyPattern("#");
+ assertEquals("Wrong pattern 3", "#", format.toPattern());
+ format.applyPattern(".#");
+ assertEquals("Wrong pattern 4", "#.0", format.toPattern());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ public void test_setGroupingUse() {
+ DecimalFormat format = new DecimalFormat();
+ StringBuffer buf = new StringBuffer();
+ format.setGroupingUsed(false);
+ format.format(new Long(1970), buf, new FieldPosition(0));
+ assertEquals("1970", buf.toString());
+ assertFalse(format.isGroupingUsed());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#DecimalFormat() Test of method
+ * java.text.DecimalFormat#DecimalFormat().
+ */
+ public void test_Constructor() {
+ // Test for method java.text.DecimalFormat()
+ // the constructor form that specifies a pattern is equal to the form
+ // constructed with no pattern and applying that pattern using the
+ // applyPattern call
+ try {
+ DecimalFormat format1 = new DecimalFormat();
+ format1.applyPattern("'$'1000.0000");
+ DecimalFormat format2 = new DecimalFormat();
+ format2.applyPattern("'$'1000.0000");
+ assertTrue(
+ "Constructed format did not match applied format object",
+ format2.equals(format1));
+ DecimalFormat format3 = new DecimalFormat("'$'1000.0000");
+ assertTrue(
+ "Constructed format did not match applied format object",
+ format3.equals(format1));
+ DecimalFormat format4 = new DecimalFormat("'$'8000.0000");
+ assertTrue(
+ "Constructed format did not match applied format object",
+ !format4.equals(format1));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#DecimalFormat(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ // Test for method java.text.DecimalFormat(java.lang.String)
+ // the constructor form that specifies a pattern is equal to the form
+ // constructed with no pattern and applying that pattern using the
+ // applyPattern call
+ DecimalFormat format = new DecimalFormat("'$'0000.0000");
+ DecimalFormat format1 = new DecimalFormat();
+ format1.applyPattern("'$'0000.0000");
+ assertTrue("Constructed format did not match applied format object",
+ format.equals(format1));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#DecimalFormat(java.lang.String,
+ * java.text.DecimalFormatSymbols) Test of method
+ * java.text.DecimalFormat#DecimalFormat(java.lang.String,
+ * java.text.DecimalFormatSymbols). Case 1: Try to construct object
+ * using correct pattern and fromat symbols. Case 2: Try to construct
+ * object using null arguments. Case 3: Try to construct object using
+ * incorrect pattern.
+ */
+ public void test_ConstructorLjava_lang_StringLjava_text_DecimalFormatSymbols() {
+ try {
+ // case 1: Try to construct object using correct pattern and fromat
+ // symbols.
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.CANADA);
+ DecimalFormat format1 = new DecimalFormat("'$'1000.0000", dfs);
+ DecimalFormat format2 = new DecimalFormat();
+ format2.applyPattern("'$'1000.0000");
+ format2.setDecimalFormatSymbols(dfs);
+ assertTrue(
+ "Constructed format did not match applied format object",
+ format2.equals(format1));
+ assertTrue(
+ "Constructed format did not match applied format object",
+ !format1.equals(new DecimalFormat("'$'1000.0000",
+ new DecimalFormatSymbols(Locale.CHINA))));
+
+ // case 2: Try to construct object using null arguments.
+ try {
+ new DecimalFormat("'$'1000.0000", null);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DecimalFormat(null, new DecimalFormatSymbols());
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ new DecimalFormat(null, null);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ // case 3: Try to construct object using incorrect pattern.
+ try {
+ new DecimalFormat("$'", new DecimalFormatSymbols());
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#applyLocalizedPattern(java.lang.String)
+ * Test of method
+ * java.text.DecimalFormat#applyLocalizedPattern(java.lang.String).
+ * Case 1: Try to apply correct variants of pattern. Case 2: Try to
+ * apply malformed patten. Case 3: Try to apply null patern.
+ */
+ public void test_applyLocalizedPatternLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat();
+ try {
+ // case 1: Try to apply correct variants of pattern.
+ format.applyLocalizedPattern("#.#");
+ assertEquals("Wrong pattern 1", "#.;#", format.toLocalizedPattern());
+ format.applyLocalizedPattern("#.");
+ assertEquals("Wrong pattern 2", "#.", format.toLocalizedPattern());
+ format.applyLocalizedPattern("#");
+ assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+ format.applyLocalizedPattern(".#");
+ assertEquals("Wrong pattern 4", ".#", format.toLocalizedPattern());
+
+ // case 2: Try to apply malformed patten.
+ try {
+ format.applyLocalizedPattern("#,##0.0#;(#)");
+ fail("Expected IllegalArgumentException was not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // case 3: Try to apply null patern.
+ try {
+ format.applyLocalizedPattern((String) null);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#applyPattern(java.lang.String)
+ */
+ public void test_applyPatternLjava_lang_String() {
+ DecimalFormat format = new DecimalFormat("#.#");
+ assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+ format = new DecimalFormat("#.");
+ assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+ format = new DecimalFormat("#");
+ assertEquals("Wrong pattern 3", "#", format.toPattern());
+ format = new DecimalFormat(".#");
+ assertEquals("Wrong pattern 4", "#.0", format.toPattern());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#clone()
+ */
+ public void test_clone() {
+ DecimalFormat format = (DecimalFormat) DecimalFormat
+ .getInstance(Locale.US);
+ DecimalFormat cloned = (DecimalFormat) format.clone();
+ assertEquals(cloned.getDecimalFormatSymbols(), format
+ .getDecimalFormatSymbols());
+
+ format = new DecimalFormat("'$'0000.0000");
+ DecimalFormat format1 = (DecimalFormat) (format.clone());
+ // make sure the objects are equal
+ assertTrue("Object's clone isn't equal!", format.equals(format1));
+ // change the content of the clone and make sure it's not equal anymore
+ // verifies that it's data is now distinct from the original
+ format1.applyPattern("'$'0000.####");
+ assertTrue("Object's changed clone should not be equal!", !format
+ .equals(format1));
+ }
+
+ private void compare(String testName, String format, String expected) {
+ assertTrue(testName + " got: " + format + " expected: " + expected,
+ format.equals(expected));
+ }
+
+ private boolean compare(int count, String format, String expected) {
+ boolean result = format.equals(expected);
+ if (!result)
+ System.out.println("Failure test: " + count + " got: " + format
+ + " expected: " + expected);
+ return result;
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#format(double, java.lang.StringBuffer,
+ * java.text.FieldPosition)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_formatDLjava_lang_StringBufferLjava_text_FieldPosition() {
+ new Support_DecimalFormat(
+ "test_formatDLjava_lang_StringBufferLjava_text_FieldPosition")
+ .t_format_with_FieldPosition();
+
+ int failCount = 0;
+ Support_BitSet failures = new Support_BitSet();
+
+ final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+
+ DecimalFormat df = new DecimalFormat("00.0#E0", dfs);
+ compare("00.0#E0: 0.0", df.format(0.0), "00.0E0");
+ compare("00.0#E0: 1.0", df.format(1.0), "10.0E-1");
+ compare("00.0#E0: 12.0", df.format(12.0), "12.0E0");
+ compare("00.0#E0: 123.0", df.format(123.0), "12.3E1");
+ compare("00.0#E0: 1234.0", df.format(1234.0), "12.34E2");
+ compare("00.0#E0: 12346.0", df.format(12346.0), "12.35E3");
+ compare("00.0#E0: 99999.0", df.format(99999.0), "10.0E4");
+ compare("00.0#E0: 1.2", df.format(1.2), "12.0E-1");
+ compare("00.0#E0: 12.3", df.format(12.3), "12.3E0");
+ compare("00.0#E0: 123.4", df.format(123.4), "12.34E1");
+ compare("00.0#E0: 1234.6", df.format(1234.6), "12.35E2");
+ compare("00.0#E0: 9999.9", df.format(9999.9), "10.0E3");
+ compare("00.0#E0: 0.1", df.format(0.1), "10.0E-2");
+ compare("00.0#E0: 0.12", df.format(0.12), "12.0E-2");
+ compare("00.0#E0: 0.123", df.format(0.123), "12.3E-2");
+ compare("00.0#E0: 0.1234", df.format(0.1234), "12.34E-2");
+ compare("00.0#E0: 0.12346", df.format(0.12346), "12.35E-2");
+ compare("00.0#E0: 0.99999", df.format(0.99999), "10.0E-1");
+ compare("00.0#E0: -0.0", df.format(-0.0), "-00.0E0");
+ compare("00.0#E0: -1.0", df.format(-1.0), "-10.0E-1");
+ compare("00.0#E0: -12.0", df.format(-12.0), "-12.0E0");
+ compare("00.0#E0: -123.0", df.format(-123.0), "-12.3E1");
+ compare("00.0#E0: -1234.0", df.format(-1234.0), "-12.34E2");
+ compare("00.0#E0: -12346.0", df.format(-12346.0), "-12.35E3");
+ compare("00.0#E0: -99999.0", df.format(-99999.0), "-10.0E4");
+
+ df = new DecimalFormat("##0.0E0", dfs);
+ compare("##0.0E0: -0.0", df.format(-0.0), "-0.0E0");
+ compare("##0.0E0: 0.0", df.format(0.0), "0.0E0");
+ compare("##0.0E0: 1.0", df.format(1.0), "1.0E0");
+ compare("##0.0E0: 12.0", df.format(12.0), "12E0");
+ compare("##0.0E0: 123.0", df.format(123.0), "123E0");
+ compare("##0.0E0: 1234.0", df.format(1234.0), "1.234E3");
+ compare("##0.0E0: 12346.0", df.format(12346.0), "12.35E3");
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(99999.0), "100E3"))
+ failures.set(failCount);
+ failCount++;
+ compare("##0.0E0: 999999.0", df.format(999999.0), "1.0E6");
+
+ df = new DecimalFormat("#00.0##E0", dfs);
+ compare("#00.0##E0: 0.1", df.format(0.1), ".100E0");
+ compare("#00.0##E0: 0.12", df.format(0.12), ".120E0");
+ compare("#00.0##E0: 0.123", df.format(0.123), ".123E0");
+ compare("#00.0##E0: 0.1234", df.format(0.1234), ".1234E0");
+ compare("#00.0##E0: 0.1234567", df.format(0.1234567), ".123457E0");
+ compare("#00.0##E0: 0.01", df.format(0.01), "10.0E-3");
+ compare("#00.0##E0: 0.012", df.format(0.012), "12.0E-3");
+ compare("#00.0##E0: 0.0123", df.format(0.0123), "12.3E-3");
+ compare("#00.0##E0: 0.01234", df.format(0.01234), "12.34E-3");
+ compare("#00.0##E0: 0.01234567", df.format(0.01234567), "12.3457E-3");
+ compare("#00.0##E0: 0.001", df.format(0.001), "1.00E-3");
+ compare("#00.0##E0: 0.0012", df.format(0.0012), "1.20E-3");
+ compare("#00.0##E0: 0.00123", df.format(0.00123), "1.23E-3");
+ compare("#00.0##E0: 0.001234", df.format(0.001234), "1.234E-3");
+ compare("#00.0##E0: 0.001234567", df.format(0.001234567), "1.23457E-3");
+ compare("#00.0##E0: 0.0001", df.format(0.0001), "100E-6");
+ compare("#00.0##E0: 0.00012", df.format(0.00012), "120E-6");
+ compare("#00.0##E0: 0.000123", df.format(0.000123), "123E-6");
+ compare("#00.0##E0: 0.0001234", df.format(0.0001234), "123.4E-6");
+ compare("#00.0##E0: 0.0001234567", df.format(0.0001234567),
+ "123.457E-6");
+
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.0), "0.00E0"))
+ failures.set(failCount);
+ failCount++;
+ compare("#00.0##E0: 1.0", df.format(1.0), "1.00E0");
+ compare("#00.0##E0: 12.0", df.format(12.0), "12.0E0");
+ compare("#00.0##E0: 123.0", df.format(123.0), "123E0");
+ compare("#00.0##E0: 1234.0", df.format(1234.0), "1.234E3");
+ compare("#00.0##E0: 12345.0", df.format(12345.0), "12.345E3");
+ compare("#00.0##E0: 123456.0", df.format(123456.0), "123.456E3");
+ compare("#00.0##E0: 1234567.0", df.format(1234567.0), "1.23457E6");
+ compare("#00.0##E0: 12345678.0", df.format(12345678.0), "12.3457E6");
+ compare("#00.0##E0: 99999999.0", df.format(99999999.0), "100E6");
+
+ df = new DecimalFormat("#.0E0", dfs);
+ compare("#.0E0: -0.0", df.format(-0.0), "-.0E0");
+ compare("#.0E0: 0.0", df.format(0.0), ".0E0");
+ compare("#.0E0: 1.0", df.format(1.0), ".1E1");
+ compare("#.0E0: 12.0", df.format(12.0), ".12E2");
+ compare("#.0E0: 123.0", df.format(123.0), ".12E3");
+ compare("#.0E0: 1234.0", df.format(1234.0), ".12E4");
+ compare("#.0E0: 9999.0", df.format(9999.0), ".1E5");
+
+ df = new DecimalFormat("0.#E0", dfs);
+ compare("0.#E0: -0.0", df.format(-0.0), "-0E0");
+ compare("0.#E0: 0.0", df.format(0.0), "0E0");
+ compare("0.#E0: 1.0", df.format(1.0), "1E0");
+ compare("0.#E0: 12.0", df.format(12.0), "1.2E1");
+ compare("0.#E0: 123.0", df.format(123.0), "1.2E2");
+ compare("0.#E0: 1234.0", df.format(1234.0), "1.2E3");
+ compare("0.#E0: 9999.0", df.format(9999.0), "1E4");
+
+ df = new DecimalFormat(".0E0", dfs);
+ compare(".0E0: -0.0", df.format(-0.0), "-.0E0");
+ compare(".0E0: 0.0", df.format(0.0), ".0E0");
+ compare(".0E0: 1.0", df.format(1.0), ".1E1");
+ compare(".0E0: 12.0", df.format(12.0), ".1E2");
+ compare(".0E0: 123.0", df.format(123.0), ".1E3");
+ compare(".0E0: 1234.0", df.format(1234.0), ".1E4");
+ compare(".0E0: 9999.0", df.format(9999.0), ".1E5");
+
+ df = new DecimalFormat("0.E0", dfs);
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.0), "0.E0"))
+ failures.set(failCount);
+ failCount++;
+ if (!compare(failCount, df.format(1.0), "1.E0"))
+ failures.set(failCount);
+ failCount++;
+ if (!compare(failCount, df.format(12.0), "1.E1"))
+ failures.set(failCount);
+ failCount++;
+ if (!compare(failCount, df.format(123.0), "1.E2"))
+ failures.set(failCount);
+ failCount++;
+ if (!compare(failCount, df.format(1234.0), "1.E3"))
+ failures.set(failCount);
+ failCount++;
+ if (!compare(failCount, df.format(9999.0), "1.E4"))
+ failures.set(failCount);
+ failCount++;
+
+ df = new DecimalFormat("##0.00#E0", dfs);
+ compare("##0.00#E0: 0.1", df.format(0.1), ".100E0");
+ compare("##0.00#E0: 0.1234567", df.format(0.1234567), ".123457E0");
+ compare("##0.00#E0: 0.9999999", df.format(0.9999999), "1.00E0");
+ compare("##0.00#E0: 0.01", df.format(0.01), "10.0E-3");
+ compare("##0.00#E0: 0.01234567", df.format(0.01234567), "12.3457E-3");
+ compare("##0.00#E0: 0.09999999", df.format(0.09999999), ".100E0");
+ compare("##0.00#E0: 0.001", df.format(0.001), "1.00E-3");
+ compare("##0.00#E0: 0.001234567", df.format(0.001234567), "1.23457E-3");
+ compare("##0.00#E0: 0.009999999", df.format(0.009999999), "10.0E-3");
+ compare("##0.00#E0: 0.0001", df.format(0.0001), "100E-6");
+ compare("##0.00#E0: 0.0001234567", df.format(0.0001234567),
+ "123.457E-6");
+ compare("##0.00#E0: 0.0009999999", df.format(0.0009999999), "1.00E-3");
+
+ df = new DecimalFormat("###0.00#E0", dfs);
+ compare("###0.00#E0: 0.1", df.format(0.1), ".100E0");
+ compare("###0.00#E0: 0.12345678", df.format(0.12345678), ".1234568E0");
+ compare("###0.00#E0: 0.99999999", df.format(0.99999999), "1.00E0");
+ compare("###0.00#E0: 0.01", df.format(0.01), "100E-4");
+ compare("###0.00#E0: 0.012345678", df.format(0.012345678),
+ "123.4568E-4");
+ compare("###0.00#E0: 0.099999999", df.format(0.099999999), ".100E0");
+ compare("###0.00#E0: 0.001", df.format(0.001), "10.0E-4");
+ compare("###0.00#E0: 0.0012345678", df.format(0.0012345678),
+ "12.34568E-4");
+ compare("###0.00#E0: 0.0099999999", df.format(0.0099999999), "100E-4");
+ compare("###0.00#E0: 0.0001", df.format(0.0001), "1.00E-4");
+ compare("###0.00#E0: 0.00012345678", df.format(0.00012345678),
+ "1.234568E-4");
+ compare("###0.00#E0: 0.00099999999", df.format(0.00099999999),
+ "10.0E-4");
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.00001), "1000E-8"))
+ failures.set(failCount);
+ failCount++;
+ compare("###0.00#E0: 0.000012345678", df.format(0.000012345678),
+ "1234.568E-8");
+ compare("###0.00#E0: 0.000099999999", df.format(0.000099999999),
+ "1.00E-4");
+
+ df = new DecimalFormat("###0.0#E0", dfs);
+ compare("###0.0#E0: 0.1", df.format(0.1), ".10E0");
+ compare("###0.0#E0: 0.1234567", df.format(0.1234567), ".123457E0");
+ compare("###0.0#E0: 0.9999999", df.format(0.9999999), "1.0E0");
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.01), "100E-4"))
+ failures.set(failCount);
+ failCount++;
+ compare("###0.0#E0: 0.01234567", df.format(0.01234567), "123.457E-4");
+ compare("###0.0#E0: 0.09999999", df.format(0.09999999), ".10E0");
+ compare("###0.0#E0: 0.001", df.format(0.001), "10E-4");
+ compare("###0.0#E0: 0.001234567", df.format(0.001234567), "12.3457E-4");
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.009999999), "100E-4"))
+ failures.set(failCount);
+ failCount++;
+ compare("###0.0#E0: 0.0001", df.format(0.0001), "1.0E-4");
+ compare("###0.0#E0: 0.0001234567", df.format(0.0001234567),
+ "1.23457E-4");
+ compare("###0.0#E0: 0.0009999999", df.format(0.0009999999), "10E-4");
+ // Fails in JDK 1.2.2
+ if (!compare(failCount, df.format(0.00001), "1000E-8"))
+ failures.set(failCount);
+ failCount++;
+ compare("###0.0#E0: 0.00001234567", df.format(0.00001234567),
+ "1234.57E-8");
+ compare("###0.0#E0: 0.00009999999", df.format(0.00009999999), "1.0E-4");
+
+ assertTrue("Failed " + failures + " of " + failCount,
+ failures.length() == 0);
+
+ String formatString = "##0.#";
+ df = new DecimalFormat(formatString, dfs);
+ df.setMinimumFractionDigits(30);
+ compare(formatString + ": 0.000000000000000000000000000000", df
+ .format(0.0), "0.000000000000000000000000000000");
+ compare(formatString + ": -0.000000000000000000000000000000", df
+ .format(-0.0), "-0.000000000000000000000000000000");
+ compare(formatString + ": 1.000000000000000000000000000000", df
+ .format(1.0), "1.000000000000000000000000000000");
+ compare(formatString + ": -1.000000000000000000000000000000", df
+ .format(-1.0), "-1.000000000000000000000000000000");
+
+ df = new DecimalFormat(formatString);
+ df.setMaximumFractionDigits(30);
+ compare(formatString + ": 0", df.format(0.0), "0");
+ compare(formatString + ": -0", df.format(-0.0), "-0");
+ compare(formatString + ": 1", df.format(1.0), "1");
+ compare(formatString + ": -1", df.format(-1.0), "-1");
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#format(long, java.lang.StringBuffer,
+ * java.text.FieldPosition)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_formatJLjava_lang_StringBufferLjava_text_FieldPosition() {
+ int failCount = 0;
+ Support_BitSet failures = new Support_BitSet();
+
+ final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+
+ DecimalFormat df = new DecimalFormat("00.0#E0", dfs);
+ assertEquals("00.0#E0: 0", "00.0E0", df.format(0));
+ assertEquals("00.0#E0: 1", "10.0E-1", df.format(1));
+ assertEquals("00.0#E0: 12", "12.0E0", df.format(12));
+ assertEquals("00.0#E0: 123", "12.3E1", df.format(123));
+ assertEquals("00.0#E0: 1234", "12.34E2", df.format(1234));
+ assertEquals("00.0#E0: 12346", "12.35E3", df.format(12346));
+ assertEquals("00.0#E0: 99999", "10.0E4", df.format(99999));
+ assertEquals("00.0#E0: -1", "-10.0E-1", df.format(-1));
+ assertEquals("00.0#E0: -12", "-12.0E0", df.format(-12));
+ assertEquals("00.0#E0: -123", "-12.3E1", df.format(-123));
+ assertEquals("00.0#E0: -1234", "-12.34E2", df.format(-1234));
+ assertEquals("00.0#E0: -12346", "-12.35E3", df.format(-12346));
+ assertEquals("00.0#E0: -99999", "-10.0E4", df.format(-99999));
+
+ df = new DecimalFormat("##0.0E0", dfs);
+ assertEquals("##0.0E0: 0", "0.0E0", df.format(0));
+ assertEquals("##0.0E0: 1", "1.0E0", df.format(1));
+ assertEquals("##0.0E0: 12", "12E0", df.format(12));
+ assertEquals("##0.0E0: 123", "123E0", df.format(123));
+ assertEquals("##0.0E0: 1234", "1.234E3", df.format(1234));
+ assertEquals("##0.0E0: 12346", "12.35E3", df.format(12346));
+ // Fails in JDK 1.2.2
+ if (!df.format(99999).equals("100E3"))
+ failures.set(failCount);
+ failCount++;
+ assertEquals("##0.0E0: 999999", "1.0E6", df.format(999999));
+
+ df = new DecimalFormat("#00.0##E0", dfs);
+ // Fails in JDK 1.2.2
+ if (!df.format(0).equals("0.00E0"))
+ failures.set(failCount);
+ failCount++;
+ assertEquals("#00.0##E0: 1", "1.00E0", df.format(1));
+ assertEquals("#00.0##E0: 12", "12.0E0", df.format(12));
+ assertEquals("#00.0##E0: 123", "123E0", df.format(123));
+ assertEquals("#00.0##E0: 1234", "1.234E3", df.format(1234));
+ assertEquals("#00.0##E0: 12345", "12.345E3", df.format(12345));
+ assertEquals("#00.0##E0: 123456", "123.456E3", df.format(123456));
+ assertEquals("#00.0##E0: 1234567", "1.23457E6", df.format(1234567));
+ assertEquals("#00.0##E0: 12345678", "12.3457E6", df.format(12345678));
+ assertEquals("#00.0##E0: 99999999", "100E6", df.format(99999999));
+
+ df = new DecimalFormat("#.0E0", dfs);
+ assertEquals("#.0E0: 0", ".0E0", df.format(0));
+ assertEquals("#.0E0: 1", ".1E1", df.format(1));
+ assertEquals("#.0E0: 12", ".12E2", df.format(12));
+ assertEquals("#.0E0: 123", ".12E3", df.format(123));
+ assertEquals("#.0E0: 1234", ".12E4", df.format(1234));
+ assertEquals("#.0E0: 9999", ".1E5", df.format(9999));
+
+ df = new DecimalFormat("0.#E0", dfs);
+ assertEquals("0.#E0: 0", "0E0", df.format(0));
+ assertEquals("0.#E0: 1", "1E0", df.format(1));
+ assertEquals("0.#E0: 12", "1.2E1", df.format(12));
+ assertEquals("0.#E0: 123", "1.2E2", df.format(123));
+ assertEquals("0.#E0: 1234", "1.2E3", df.format(1234));
+ assertEquals("0.#E0: 9999", "1E4", df.format(9999));
+
+ assertTrue("Failed " + failures + " of " + failCount,
+ failures.length() == 0);
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#formatToCharacterIterator(java.lang.Object)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_formatToCharacterIteratorLjava_lang_Object() {
+
+ try {
+ // Regression for HARMONY-466
+ new DecimalFormat().formatToCharacterIterator(null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ new Support_DecimalFormat(
+ "test_formatToCharacterIteratorLjava_lang_Object")
+ .t_formatToCharacterIterator();
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#format(double)
+ */
+ public void test_formatD() {
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getInstance(Locale.ENGLISH);
+ format.setGroupingUsed(false);
+ format.setMaximumFractionDigits(400);
+ for (int i = 0; i < 309; i++) {
+ String tval = "1";
+ for (int j = 0; j < i; j++)
+ tval += "0";
+ double d = Double.parseDouble(tval);
+ String result = format.format(d);
+ assertEquals(i + ") e:" + tval + " r:" + result, tval, result);
+ }
+ for (int i = 0; i < 322; i++) {
+ String tval = "0.";
+ for (int j = 0; j < i; j++)
+ tval += "0";
+ tval += "1";
+ double d = Double.parseDouble(tval);
+ String result = format.format(d);
+ assertEquals(i + ") e:" + tval + " r:" + result, tval, result);
+ }
+ assertEquals("999999999999999", format.format(999999999999999.));
+ assertEquals("1", "999999999999999.9", format.format(999999999999999.9));
+ assertEquals("2", "99999999999999.98", format.format(99999999999999.99));
+ assertEquals("3", "9999999999999.998", format.format(9999999999999.999));
+ assertEquals("4", "999999999999.9999", format.format(999999999999.9999));
+ assertEquals("5", "99999999999.99998", format.format(99999999999.99999));
+ assertEquals("6", "9999999999.999998", format.format(9999999999.999999));
+ assertEquals("7", "999999999.9999999", format.format(999999999.9999999));
+ assertEquals("8", "99999999.99999999", format.format(99999999.99999999));
+ assertEquals("9", "9999999.999999998", format.format(9999999.999999999));
+ assertEquals("10", "99999.99999999999", format
+ .format(99999.99999999999));
+ assertEquals("11", "9999.999999999998", format
+ .format(9999.999999999999));
+ assertEquals("12", "999.9999999999999", format
+ .format(999.9999999999999));
+ assertEquals("13", "99.99999999999999", format
+ .format(99.99999999999999));
+ assertEquals("14", "9.999999999999998", format
+ .format(9.999999999999999));
+ assertEquals("15", "0.9999999999999999", format
+ .format(.9999999999999999));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getDecimalFormatSymbols()
+ */
+ public void test_getDecimalFormatSymbols() {
+ DecimalFormat df = (DecimalFormat) NumberFormat
+ .getInstance(Locale.ENGLISH);
+ DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
+ assertTrue("Identical symbols", dfs != df.getDecimalFormatSymbols());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getCurrency()
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_getCurrency() {
+ Currency currK = Currency.getInstance("KRW");
+ Currency currX = Currency.getInstance("XXX");
+ Currency currE = Currency.getInstance("EUR");
+ Currency curr01;
+
+ DecimalFormat df = (DecimalFormat) NumberFormat
+ .getCurrencyInstance(new Locale("ko", "KR"));
+ assertTrue("Test1: Returned incorrect currency",
+ df.getCurrency() == currK);
+
+ df = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("",
+ "KR"));
+ assertTrue("Test2: Returned incorrect currency",
+ df.getCurrency() == currK);
+
+ df = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("ko",
+ ""));
+ assertTrue("Test3: Returned incorrect currency",
+ df.getCurrency() == currX);
+
+ df = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("fr",
+ "FR"));
+ assertTrue("Test4: Returned incorrect currency",
+ df.getCurrency() == currE);
+
+ // Regression for HARMONY-1351
+ df = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale(
+ "QWERTY"));
+ assertTrue("Test5: Returned incorrect currency",
+ df.getCurrency() == currX);
+
+ // JDK fails these tests since it doesn't have the PREEURO variant
+ // df = (DecimalFormat)NumberFormat.getCurrencyInstance(new Locale("fr",
+ // "FR","PREEURO"));
+ // assertTrue("Test5: Returned incorrect currency", df.getCurrency() ==
+ // currF);
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getGroupingSize()
+ */
+ public void test_getGroupingSize() {
+ DecimalFormat df = new DecimalFormat("###0.##");
+ assertEquals("Wrong unset size", 0, df.getGroupingSize());
+ df = new DecimalFormat("#,##0.##");
+ assertEquals("Wrong set size", 3, df.getGroupingSize());
+ df = new DecimalFormat("#,###,###0.##");
+ assertEquals("Wrong multiple set size", 4, df.getGroupingSize());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getMultiplier()
+ */
+ public void test_getMultiplier() {
+ final int defaultMultiplier = 1;
+ NumberFormat nform = DecimalFormat.getInstance(Locale.US);
+ DecimalFormat form = (DecimalFormat) nform;
+ assertEquals(defaultMultiplier, form.getMultiplier());
+
+ DecimalFormat df = new DecimalFormat("###0.##");
+ assertEquals("Wrong unset multiplier", 1, df.getMultiplier());
+ df = new DecimalFormat("###0.##%");
+ assertEquals("Wrong percent multiplier", 100, df.getMultiplier());
+ df = new DecimalFormat("###0.##\u2030");
+ assertEquals("Wrong mille multiplier", 1000, df.getMultiplier());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getNegativePrefix() Test of method
+ * java.text.DecimalFormat#getNegativePrefix().
+ */
+ public void test_getNegativePrefix() {
+ DecimalFormat df = new DecimalFormat();
+ try {
+ df.setNegativePrefix("--");
+ assertTrue("Incorrect negative prefix", df.getNegativePrefix()
+ .equals("--"));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getNegativeSuffix() Test of method
+ * java.text.DecimalFormat#getNegativeSuffix().
+ */
+ public void test_getNegativeSuffix() {
+ DecimalFormat df = new DecimalFormat();
+ try {
+ df.setNegativeSuffix("&");
+ assertTrue("Incorrect negative suffix", df.getNegativeSuffix()
+ .equals("&"));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getPositivePrefix() Test of method
+ * java.text.DecimalFormat#getPositivePrefix().
+ */
+ public void test_getPositivePrefix() {
+ DecimalFormat df = new DecimalFormat();
+ try {
+ df.setPositivePrefix("++");
+ assertTrue("Incorrect positive prefix", df.getPositivePrefix()
+ .equals("++"));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#getPositiveSuffix() Test of method
+ * java.text.DecimalFormat#getPositiveSuffix().
+ */
+ public void test_getPositiveSuffix() {
+ DecimalFormat df = new DecimalFormat();
+ try {
+ df.setPositiveSuffix("%");
+ assertTrue("Incorrect positive prefix", df.getPositiveSuffix()
+ .equals("%"));
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#hashCode() Test of method
+ * java.text.DecimalFormat#hashCode().
+ */
+ public void test_hashCode() {
+ try {
+ DecimalFormat df1 = new DecimalFormat();
+ DecimalFormat df2 = (DecimalFormat) df1.clone();
+ assertTrue("Hash codes of equals object are not equal", df2
+ .hashCode() == df1.hashCode());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#isDecimalSeparatorAlwaysShown()
+ */
+ public void test_isDecimalSeparatorAlwaysShown() {
+ DecimalFormat df = new DecimalFormat("###0.##");
+ assertTrue("Wrong unset value", !df.isDecimalSeparatorAlwaysShown());
+ df = new DecimalFormat("###0.00");
+ assertTrue("Wrong unset2 value", !df.isDecimalSeparatorAlwaysShown());
+ df = new DecimalFormat("###0.");
+ assertTrue("Wrong set value", df.isDecimalSeparatorAlwaysShown());
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#parse(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_parseLjava_lang_StringLjava_text_ParsePosition() {
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getNumberInstance(Locale.ENGLISH);
+ ParsePosition pos = new ParsePosition(0);
+ Number result = format.parse("9223372036854775807", pos);
+ assertTrue("Wrong result type for Long.MAX_VALUE",
+ result.getClass() == Long.class);
+ assertEquals("Wrong result Long.MAX_VALUE",
+ Long.MAX_VALUE, result.longValue());
+ pos = new ParsePosition(0);
+ result = format.parse("-9223372036854775808", pos);
+ assertTrue("Wrong result type for Long.MIN_VALUE",
+ result.getClass() == Long.class);
+ assertTrue("Wrong result Long.MIN_VALUE: " + result.longValue(), result
+ .longValue() == Long.MIN_VALUE);
+ pos = new ParsePosition(0);
+ result = format.parse("9223372036854775808", pos);
+ assertTrue("Wrong result type for Long.MAX_VALUE+1",
+ result.getClass() == Double.class);
+ assertEquals("Wrong result Long.MAX_VALUE + 1",
+ (double) Long.MAX_VALUE + 1, result.doubleValue());
+ pos = new ParsePosition(0);
+ result = format.parse("-9223372036854775809", pos);
+ assertTrue("Wrong result type for Long.MIN_VALUE - 1",
+ result.getClass() == Double.class);
+ assertEquals("Wrong result Long.MIN_VALUE - 1",
+ (double) Long.MIN_VALUE - 1, result.doubleValue());
+
+ pos = new ParsePosition(0);
+ result = format.parse("18446744073709551629", pos);
+ assertTrue("Wrong result type for overflow",
+ result.getClass() == Double.class);
+ assertEquals("Wrong result for overflow",
+ 18446744073709551629d, result.doubleValue());
+
+ pos = new ParsePosition(0);
+ result = format.parse("42325917317067571199", pos);
+ assertTrue("Wrong result type for overflow a: " + result, result
+ .getClass() == Double.class);
+ assertTrue("Wrong result for overflow a: " + result, result
+ .doubleValue() == 42325917317067571199d);
+ pos = new ParsePosition(0);
+ result = format.parse("4232591731706757119E1", pos);
+ assertTrue("Wrong result type for overflow b: " + result, result
+ .getClass() == Double.class);
+ assertEquals("Wrong result for overflow b: " + result,
+ 42325917317067571190d, result.doubleValue());
+ pos = new ParsePosition(0);
+ result = format.parse(".42325917317067571199E20", pos);
+ assertTrue("Wrong result type for overflow c: " + result, result
+ .getClass() == Double.class);
+ assertTrue("Wrong result for overflow c: " + result, result
+ .doubleValue() == 42325917317067571199d);
+ pos = new ParsePosition(0);
+ result = format.parse("922337203685477580.9E1", pos);
+ assertTrue("Wrong result type for overflow d: " + result, result
+ .getClass() == Double.class);
+ assertTrue("Wrong result for overflow d: " + result, result
+ .doubleValue() == 9223372036854775809d);
+ pos = new ParsePosition(0);
+ result = format.parse("9.223372036854775809E18", pos);
+ assertTrue("Wrong result type for overflow e: " + result, result
+ .getClass() == Double.class);
+ assertTrue("Wrong result for overflow e: " + result, result
+ .doubleValue() == 9223372036854775809d);
+
+ // test parse with multipliers
+ format.setMultiplier(100);
+ result = format.parse("9223372036854775807", new ParsePosition(0));
+ assertTrue("Wrong result type multiplier 100: " + result, result
+ .getClass() == Long.class);
+ // BEGIN android-changed
+ // RI on windows and linux both answer with a slightly rounded result
+ assertTrue("Wrong result for multiplier 100: " + result, result
+ .longValue() == 92233720368547760L);
+ // END android-changed
+ format.setMultiplier(1000);
+ result = format.parse("9223372036854775807", new ParsePosition(0));
+ assertTrue("Wrong result type multiplier 1000: " + result, result
+ .getClass() == Long.class);
+ assertTrue("Wrong result for multiplier 1000: " + result, result
+ .longValue() == 9223372036854776L);
+
+ format.setMultiplier(10000);
+ result = format.parse("9223372036854775807", new ParsePosition(0));
+ assertTrue("Wrong result type multiplier 10000: " + result, result
+ .getClass() == Double.class);
+ assertTrue("Wrong result for multiplier 10000: " + result, result
+ .doubleValue() == 922337203685477.5807d);
+
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setDecimalFormatSymbols(java.text.DecimalFormatSymbols)
+ */
+ public void test_setDecimalFormatSymbolsLjava_text_DecimalFormatSymbols() {
+ DecimalFormat df = new DecimalFormat("###0.##");
+ DecimalFormatSymbols dfs = new DecimalFormatSymbols();
+ dfs.setDecimalSeparator('@');
+ df.setDecimalFormatSymbols(dfs);
+ assertTrue("Not set", df.getDecimalFormatSymbols().equals(dfs));
+ assertEquals("Symbols not used", "1@2", df.format(1.2));
+
+ // The returned symbols may be cloned in two spots
+ // 1. When set
+ // 2. When returned
+ DecimalFormat format = new DecimalFormat();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ format.setDecimalFormatSymbols(symbols);
+ DecimalFormatSymbols symbolsOut = format.getDecimalFormatSymbols();
+ assertNotSame(symbols, symbolsOut);
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setDecimalSeparatorAlwaysShown(boolean)
+ */
+ public void test_setDecimalSeparatorAlwaysShownZ() {
+ DecimalFormat df = new DecimalFormat("###0.##",
+ new DecimalFormatSymbols(Locale.US));
+ assertEquals("Wrong default result", "5", df.format(5));
+ df.setDecimalSeparatorAlwaysShown(true);
+ assertTrue("Not set", df.isDecimalSeparatorAlwaysShown());
+ assertEquals("Wrong set result", "7.", df.format(7));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setCurrency(java.util.Currency)
+ */
+ public void test_setCurrencyLjava_util_Currency() {
+ Locale locale = Locale.CANADA;
+ DecimalFormat df = ((DecimalFormat) NumberFormat
+ .getCurrencyInstance(locale));
+
+ try {
+ df.setCurrency(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException e) {
+ }
+
+ Currency currency = Currency.getInstance("AED");
+ df.setCurrency(currency);
+ assertTrue("Returned incorrect currency", currency == df.getCurrency());
+ assertTrue("Returned incorrect currency symbol", currency.getSymbol(
+ locale)
+ .equals(df.getDecimalFormatSymbols().getCurrencySymbol()));
+ assertTrue("Returned incorrect international currency symbol", currency
+ .getCurrencyCode().equals(
+ df.getDecimalFormatSymbols()
+ .getInternationalCurrencySymbol()));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setGroupingSize(int)
+ */
+ public void test_setGroupingSizeI() {
+ DecimalFormat df = new DecimalFormat("###0.##",
+ new DecimalFormatSymbols(Locale.ENGLISH));
+ df.setGroupingUsed(true);
+ df.setGroupingSize(2);
+ assertEquals("Value not set", 2, df.getGroupingSize());
+ String result = df.format(123);
+ assertTrue("Invalid format:" + result, result.equals("1,23"));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setMaximumFractionDigits(int)
+ */
+ public void test_setMaximumFractionDigitsI() {
+ DecimalFormat df = new DecimalFormat("###0.##",
+ new DecimalFormatSymbols(Locale.US));
+ df.setMaximumFractionDigits(3);
+ assertEquals("Not set", 3, df.getMaximumFractionDigits());
+ assertEquals("Wrong maximum", "1.235", df.format(1.23456));
+ df.setMinimumFractionDigits(4);
+ assertEquals("Not changed", 4, df.getMaximumFractionDigits());
+ assertEquals("Incorrect fraction", "456.0000", df.format(456));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setMaximumIntegerDigits(int)
+ */
+ public void test_setMaximumIntegerDigitsI() {
+ DecimalFormat df = new DecimalFormat("###0.##");
+ df.setMaximumIntegerDigits(2);
+ assertEquals("Not set", 2, df.getMaximumIntegerDigits());
+ assertEquals("Wrong maximum", "34", df.format(1234));
+ df.setMinimumIntegerDigits(4);
+ assertEquals("Not changed", 4, df.getMaximumIntegerDigits());
+ assertEquals("Incorrect integer", "0026", df.format(26));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setMinimumFractionDigits(int)
+ */
+ public void test_setMinimumFractionDigitsI() {
+ DecimalFormat df = new DecimalFormat("###0.##",
+ new DecimalFormatSymbols(Locale.US));
+ df.setMinimumFractionDigits(4);
+ assertEquals("Not set", 4, df.getMinimumFractionDigits());
+ assertEquals("Wrong minimum", "1.2300", df.format(1.23));
+ df.setMaximumFractionDigits(2);
+ assertEquals("Not changed", 2, df.getMinimumFractionDigits());
+ assertEquals("Incorrect fraction", "456.00", df.format(456));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setMinimumIntegerDigits(int)
+ */
+ public void test_setMinimumIntegerDigitsI() {
+ DecimalFormat df = new DecimalFormat("###0.##",
+ new DecimalFormatSymbols(Locale.US));
+ df.setMinimumIntegerDigits(3);
+ assertEquals("Not set", 3, df.getMinimumIntegerDigits());
+ assertEquals("Wrong minimum", "012", df.format(12));
+ df.setMaximumIntegerDigits(2);
+ assertEquals("Not changed", 2, df.getMinimumIntegerDigits());
+ assertEquals("Incorrect integer", "00.7", df.format(0.7));
+ }
+
+ /**
+ * @tests java.text.DecimalFormat#setMultiplier(int)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void test_setMultiplierI() {
+ DecimalFormat df = new DecimalFormat("###0.##");
+ df.setMultiplier(10);
+ assertEquals("Wrong multiplier", 10, df.getMultiplier());
+ assertEquals("Wrong format", "50", df.format(5));
+ assertEquals("Wrong parse", 5, df.parse("50", new ParsePosition(0))
+ .intValue());
+
+ // regression test for HARMONY-879
+ df.setMultiplier(-1);
+ assertEquals("Wrong multiplier for negative value", -1, df
+ .getMultiplier());
+ }
+
+ /**
+ * @tests serialization/deserialization compatibility.
+ */
+ public void testSerializationSelf() throws Exception {
+ SerializationTest.verifySelf(new DecimalFormat());
+ }
+
+ /**
+ * @tests serialization compatibility with RI
+ */
+ public void test_serializationHarmonyRICompatible() {
+ NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
+
+ DecimalFormat df = null;
+ if (!(nf instanceof DecimalFormat)) {
+ throw new Error("This NumberFormat is not a DecimalFormat");
+
+ }
+ df = (DecimalFormat) nf;
+
+ ObjectInputStream oinput = null;
+
+ DecimalFormat deserializedDF = null;
+
+ try {
+ oinput = new ObjectInputStream(this.getClass().getResource(
+ "/serialization/java/text/DecimalFormat.ser").openStream());
+ deserializedDF = (DecimalFormat) oinput.readObject();
+ } catch (Exception e) {
+ fail("Error occurs during deserialization");
+ } finally {
+ try {
+ if (null != oinput) {
+ oinput.close();
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ assertEquals(df.getNegativePrefix(), deserializedDF.getNegativePrefix());
+ assertEquals(df.getNegativeSuffix(), deserializedDF.getNegativeSuffix());
+ assertEquals(df.getPositivePrefix(), deserializedDF.getPositivePrefix());
+ assertEquals(df.getPositiveSuffix(), deserializedDF.getPositiveSuffix());
+ assertEquals(df.getCurrency(), deserializedDF.getCurrency());
+
+ assertEquals(df.getDecimalFormatSymbols(), deserializedDF
+ .getDecimalFormatSymbols());
+
+ assertEquals(df.getGroupingSize(), df.getGroupingSize());
+ assertEquals(df.getMaximumFractionDigits(), deserializedDF
+ .getMaximumFractionDigits());
+
+ assertEquals(df.getMaximumIntegerDigits(), deserializedDF
+ .getMaximumIntegerDigits());
+
+ assertEquals(df.getMinimumFractionDigits(), deserializedDF
+ .getMinimumFractionDigits());
+ assertEquals(df.getMinimumIntegerDigits(), deserializedDF
+ .getMinimumIntegerDigits());
+ assertEquals(df.getMultiplier(), deserializedDF.getMultiplier());
+
+ // Deliberately omitted this assertion. Since different data resource
+ // will cause the assertion fail.
+ // assertEquals(df, deserializedDF);
+
+ }
+
+ /**
+ * Test whether DecimalFormat can parse Positive infinity correctly
+ */
+ public void testParseInfinityBigDecimalFalse() {
+ // Regression test for HARMONY-106
+ DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ Number number = format.parse(symbols.getInfinity(),
+ new ParsePosition(0));
+ assertTrue(number instanceof Double);
+ assertTrue(Double.isInfinite(number.doubleValue()));
+ }
+
+ /**
+ * Test whether DecimalFormat can parse Negative infinity correctly
+ */
+ public void testParseMinusInfinityBigDecimalFalse() {
+ // Regression test for HARMONY-106
+ DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ Number number = format.parse("-" + symbols.getInfinity(),
+ new ParsePosition(0));
+ assertTrue(number instanceof Double);
+ assertTrue(Double.isInfinite(number.doubleValue()));
+ }
+
+ /**
+ * Test if setDecimalFormatSymbols method wont throw NullPointerException
+ * when it is called with null parameter.
+ */
+ public void testSetDecimalFormatSymbolsAsNull() {
+ // Regression for HARMONY-1070
+ try {
+ DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
+ format.setDecimalFormatSymbols(null);
+ } catch (Exception e) {
+ fail("Unexpected exception caught: " + e);
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/FieldPositionTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/FieldPositionTest.java
new file mode 100644
index 0000000..a1fa81d
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/FieldPositionTest.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+
+public class FieldPositionTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.FieldPosition#FieldPosition(int)
+ */
+ public void test_ConstructorI() {
+ // Test for constructor java.text.FieldPosition(int)
+ FieldPosition fpos = new FieldPosition(DateFormat.MONTH_FIELD);
+ assertEquals("Test1: Constructor failed to set field identifier!",
+ DateFormat.MONTH_FIELD, fpos.getField());
+ assertNull("Constructor failed to set field attribute!", fpos
+ .getFieldAttribute());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#FieldPosition(java.text.Format$Field)
+ */
+ public void test_ConstructorLjava_text_Format$Field() {
+ // Test for constructor java.text.FieldPosition(Format.Field)
+ FieldPosition fpos = new FieldPosition(DateFormat.Field.MONTH);
+ assertSame("Constructor failed to set field attribute!",
+ DateFormat.Field.MONTH, fpos.getFieldAttribute());
+ assertEquals("Test1: Constructor failed to set field identifier!", -1,
+ fpos.getField());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#FieldPosition(java.text.Format$Field, int)
+ */
+ public void test_ConstructorLjava_text_Format$FieldI() {
+ // Test for constructor java.text.FieldPosition(Format.Field, int)
+ FieldPosition fpos = new FieldPosition(DateFormat.Field.MONTH,
+ DateFormat.MONTH_FIELD);
+ assertSame("Constructor failed to set field attribute!",
+ DateFormat.Field.MONTH, fpos.getFieldAttribute());
+ assertEquals("Test1: Constructor failed to set field identifier!",
+ DateFormat.MONTH_FIELD, fpos.getField());
+
+ // test special cases
+ FieldPosition fpos2 = new FieldPosition(DateFormat.Field.HOUR1,
+ DateFormat.HOUR1_FIELD);
+ assertSame("Constructor failed to set field attribute!",
+ DateFormat.Field.HOUR1, fpos2.getFieldAttribute());
+ assertEquals("Test2: Constructor failed to set field identifier!",
+ DateFormat.HOUR1_FIELD, fpos2.getField());
+
+ FieldPosition fpos3 = new FieldPosition(DateFormat.Field.TIME_ZONE,
+ DateFormat.MONTH_FIELD);
+ assertSame("Constructor failed to set field attribute!",
+ DateFormat.Field.TIME_ZONE, fpos3.getFieldAttribute());
+ assertEquals("Test3: Constructor failed to set field identifier!",
+ DateFormat.MONTH_FIELD, fpos3.getField());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.FieldPosition.equals(java.lang.Object)
+ FieldPosition fpos = new FieldPosition(1);
+ FieldPosition fpos1 = new FieldPosition(1);
+ assertTrue("Identical objects were not equal!", fpos.equals(fpos1));
+
+ FieldPosition fpos2 = new FieldPosition(2);
+ assertTrue("Objects with a different ID should not be equal!", !fpos
+ .equals(fpos2));
+
+ fpos.setBeginIndex(1);
+ fpos1.setBeginIndex(2);
+ assertTrue("Objects with a different beginIndex were still equal!",
+ !fpos.equals(fpos1));
+ fpos1.setBeginIndex(1);
+ fpos1.setEndIndex(2);
+ assertTrue("Objects with a different endIndex were still equal!", !fpos
+ .equals(fpos1));
+
+ FieldPosition fpos3 = new FieldPosition(DateFormat.Field.ERA, 1);
+ assertTrue("Objects with a different attribute should not be equal!",
+ !fpos.equals(fpos3));
+ FieldPosition fpos4 = new FieldPosition(DateFormat.Field.AM_PM, 1);
+ assertTrue("Objects with a different attribute should not be equal!",
+ !fpos3.equals(fpos4));
+ }
+
+ /**
+ * @tests java.text.FieldPosition#getBeginIndex()
+ */
+ public void test_getBeginIndex() {
+ // Test for method int java.text.FieldPosition.getBeginIndex()
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setEndIndex(3);
+ fpos.setBeginIndex(2);
+ assertEquals("getBeginIndex should have returned 2", 2, fpos
+ .getBeginIndex());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#getEndIndex()
+ */
+ public void test_getEndIndex() {
+ // Test for method int java.text.FieldPosition.getEndIndex()
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setBeginIndex(2);
+ fpos.setEndIndex(3);
+ assertEquals("getEndIndex should have returned 3", 3, fpos
+ .getEndIndex());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#getField()
+ */
+ public void test_getField() {
+ // Test for method int java.text.FieldPosition.getField()
+ FieldPosition fpos = new FieldPosition(65);
+ assertEquals(
+ "FieldPosition(65) should have caused getField to return 65",
+ 65, fpos.getField());
+ FieldPosition fpos2 = new FieldPosition(DateFormat.Field.MINUTE);
+ assertEquals(
+ "FieldPosition(DateFormat.Field.MINUTE) should have caused getField to return -1",
+ -1, fpos2.getField());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#getFieldAttribute()
+ */
+ public void test_getFieldAttribute() {
+ // Test for method int java.text.FieldPosition.getFieldAttribute()
+ FieldPosition fpos = new FieldPosition(DateFormat.Field.TIME_ZONE);
+ assertTrue(
+ "FieldPosition(DateFormat.Field.TIME_ZONE) should have caused getFieldAttribute to return DateFormat.Field.TIME_ZONE",
+ fpos.getFieldAttribute() == DateFormat.Field.TIME_ZONE);
+
+ FieldPosition fpos2 = new FieldPosition(DateFormat.TIMEZONE_FIELD);
+ assertNull(
+ "FieldPosition(DateFormat.TIMEZONE_FIELD) should have caused getFieldAttribute to return null",
+ fpos2.getFieldAttribute());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#hashCode()
+ */
+ public void test_hashCode() {
+ // Test for method int java.text.FieldPosition.hashCode()
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setBeginIndex(5);
+ fpos.setEndIndex(110);
+ assertEquals("hashCode returned incorrect value", 620, fpos.hashCode());
+
+ FieldPosition fpos2 = new FieldPosition(
+ DateFormat.Field.DAY_OF_WEEK_IN_MONTH);
+ fpos2.setBeginIndex(5);
+ fpos2.setEndIndex(110);
+ assertEquals("hashCode returned incorrect value", 451685956, fpos2
+ .hashCode());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#setBeginIndex(int)
+ */
+ public void test_setBeginIndexI() {
+ // Test for method void java.text.FieldPosition.setBeginIndex(int)
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setBeginIndex(2);
+ fpos.setEndIndex(3);
+ assertEquals("beginIndex should have been set to 2", 2, fpos
+ .getBeginIndex());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#setEndIndex(int)
+ */
+ public void test_setEndIndexI() {
+ // Test for method void java.text.FieldPosition.setEndIndex(int)
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setEndIndex(3);
+ fpos.setBeginIndex(2);
+ assertEquals("EndIndex should have been set to 3", 3, fpos
+ .getEndIndex());
+ }
+
+ /**
+ * @tests java.text.FieldPosition#toString()
+ */
+ public void test_toString() {
+ // Test for method java.lang.String java.text.FieldPosition.toString()
+ FieldPosition fpos = new FieldPosition(1);
+ fpos.setBeginIndex(2);
+ fpos.setEndIndex(3);
+ assertEquals(
+ "ToString returned the wrong value:",
+ "java.text.FieldPosition[attribute=null, field=1, beginIndex=2, endIndex=3]",
+ fpos.toString());
+
+ FieldPosition fpos2 = new FieldPosition(DateFormat.Field.ERA);
+ fpos2.setBeginIndex(4);
+ fpos2.setEndIndex(5);
+ assertEquals("ToString returned the wrong value:",
+ "java.text.FieldPosition[attribute=" + DateFormat.Field.ERA
+ + ", field=-1, beginIndex=4, endIndex=5]", fpos2
+ .toString());
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatFieldTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatFieldTest.java
new file mode 100644
index 0000000..1bc6b39
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatFieldTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.Format;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class FormatFieldTest extends TestCase {
+ private class MockFormatField extends Format.Field {
+
+ private static final long serialVersionUID = 1L;
+
+ public MockFormatField(String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * @tests java.text.Format.Field#FormatField(java.lang.String) Test of
+ * method java.text.Format.Field#FormatField(java.lang.String).
+ */
+ public void test_Constructor() {
+ try {
+ new MockFormatField("test");
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatTest.java
new file mode 100644
index 0000000..83337c0
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/FormatTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.AttributedCharacterIterator;
+import java.text.DecimalFormatSymbols;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+public class FormatTest extends TestCase {
+ private class MockFormat extends Format {
+
+ public StringBuffer format(Object obj, StringBuffer toAppendTo,
+ FieldPosition pos) {
+ // it is a fake
+ if (obj == null)
+ throw new NullPointerException("obj is null");
+ return new StringBuffer("");
+ }
+
+ public Object parseObject(String source, ParsePosition pos) {
+ // it is a fake
+ return null;
+ }
+ }
+
+ /**
+ * @tests java.text.Format#format(Object) Test of method
+ * java.text.Format#format(Object).
+ */
+ public void test_Constructor() {
+ try {
+ new MockFormat();
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.Format#clone() Test of method java.text.Format#clone().
+ * Compare of internal variables of cloned objects.
+ */
+ public void test_clone() {
+ try {
+ // Compare of internal variables of cloned objects
+ Format fm = new MockFormat();
+ Format fmc = (Format) fm.clone();
+ assertEquals(fm.getClass(), fmc.getClass());
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.Format#format(java.lang.Object) Test of method
+ * java.text.Format#format(java.lang.Object).
+ */
+ public void test_formatLjava_lang_Object() {
+ assertTrue("It calls an abstract metod format", true);
+ }
+
+ /**
+ * @tests java.text.Format#formatToCharacterIterator(java.lang.Object) Test
+ * of method
+ * java.text.Format#formatToCharacterIterator(java.lang.Object).
+ */
+ public void test_formatToCharacterIteratorLjava_lang_Object() {
+ assertTrue("It calls an abstract metod format", true);
+ }
+
+ /**
+ * @tests java.text.Format#parseObject(java.lang.String source) Test of
+ * method java.text.Format#parseObject(java.lang.String source).
+ */
+ public void test_parseObjectLjava_lang_String() {
+ assertTrue("It calls an abstract metod parseObject", true);
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatFieldTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatFieldTest.java
new file mode 100644
index 0000000..3b4161d
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatFieldTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.text.MessageFormat;
+
+import junit.framework.TestCase;
+
+public class MessageFormatFieldTest extends TestCase {
+ /**
+ * @tests java.text.MessageFormat$Field#Field(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ // protected constructor
+ String name = "new Message format";
+ MyMessageFormat field = new MyMessageFormat(name);
+ assertEquals("field has wrong name", name, field.getName());
+
+ field = new MyMessageFormat(null);
+ assertEquals("field has wrong name", null, field.getName());
+ }
+
+ /**
+ * @tests java.text.MessageFormat$Field#readResolve()
+ */
+ public void test_readResolve() {
+ // test for method java.lang.Object readResolve()
+
+ // see serialization stress tests:
+ // implemented in
+ // SerializationStressTest4.test_writeObject_MessageFormat_Field()
+ ObjectOutputStream out = null;
+ ObjectInputStream in = null;
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ out = new ObjectOutputStream(bytes);
+
+ MessageFormat.Field mfield, mfield2;
+ MyMessageFormat field;
+
+ mfield = MessageFormat.Field.ARGUMENT;
+
+ field = new MyMessageFormat(null);
+
+ out.writeObject(mfield);
+ out.writeObject(field);
+
+ in = new ObjectInputStream(new ByteArrayInputStream(bytes
+ .toByteArray()));
+
+ try {
+ mfield2 = (MessageFormat.Field) in.readObject();
+ assertSame("resolved incorrectly", mfield, mfield2);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException: " + e);
+ }
+
+ try {
+ in.readObject();
+ fail("Expected InvalidObjectException for subclass instance with null name");
+ } catch (InvalidObjectException e) {
+ }
+
+ } catch (IOException e) {
+ fail("unexpected IOException" + e);
+ } catch (ClassNotFoundException e) {
+ fail("unexpected ClassNotFoundException" + e);
+ } finally {
+ try {
+ if (out != null)
+ out.close();
+ if (in != null)
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ static class MyMessageFormat extends MessageFormat.Field {
+ static final long serialVersionUID = 1L;
+
+ protected MyMessageFormat(String attr) {
+ super(attr);
+ }
+
+ protected String getName() {
+ return super.getName();
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatTest.java
new file mode 100644
index 0000000..6f3022e
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/MessageFormatTest.java
@@ -0,0 +1,1073 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+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 junit.framework.Test;
+import junit.framework.TestCase;
+import tests.support.Support_MessageFormat;
+
+public class MessageFormatTest extends TestCase {
+
+ private MessageFormat format1, format2, format3;
+
+ private Locale defaultLocale;
+
+ private void checkSerialization(MessageFormat format) {
+ try {
+ ByteArrayOutputStream ba = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(ba);
+ out.writeObject(format);
+ out.close();
+ ObjectInputStream in = new ObjectInputStream(
+ new ByteArrayInputStream(ba.toByteArray()));
+ MessageFormat read = (MessageFormat) in.readObject();
+ assertTrue("Not equal: " + format.toPattern(), format.equals(read));
+ } catch (IOException e) {
+ fail("Format: " + format.toPattern() + " caused IOException: " + e);
+ } catch (ClassNotFoundException e) {
+ fail("Format: " + format.toPattern()
+ + " caused ClassNotFoundException: " + e);
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#MessageFormat(java.lang.String,
+ * java.util.Locale)
+ */
+ public void test_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)));
+ }
+
+ /**
+ * @tests java.text.MessageFormat#MessageFormat(java.lang.String)
+ */
+ public void test_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", new Double(1.6), new Double(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]));
+
+ try {
+ result = new MessageFormat("Don't").format(new Object[0]);
+ assertTrue("Should not throw IllegalArgumentException: " + result,
+ "Dont".equals(result));
+ } catch (Exception e) {
+ fail("Unexpected exception: " + e);
+ }
+
+ try {
+ new MessageFormat("Invalid {1,foobar} format descriptor!");
+ fail("Expected test_ConstructorLjava_lang_String to throw IAE.");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ } catch (Throwable ex) {
+ fail("Expected test_ConstructorLjava_lang_String to throw IAE, not a "
+ + ex.getClass().getName());
+ }
+
+ try {
+ new MessageFormat(
+ "Invalid {1,date,invalid-spec} format descriptor!");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ } catch (Throwable ex) {
+ fail("Expected test_ConstructorLjava_lang_String to throw IAE, not a "
+ + ex.getClass().getName());
+ }
+
+ checkSerialization(new MessageFormat(""));
+ checkSerialization(new MessageFormat("noargs"));
+ checkSerialization(new MessageFormat("{0}"));
+ checkSerialization(new MessageFormat("a{0}"));
+ checkSerialization(new MessageFormat("{0}b"));
+ checkSerialization(new MessageFormat("a{0}b"));
+
+ // Regression for HARMONY-65
+ try {
+ new MessageFormat("{0,number,integer");
+ fail("Assert 0: Failed to detect unmatched brackets.");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#applyPattern(java.lang.String)
+ */
+ public void test_applyPatternLjava_lang_String() {
+ // Test for method void
+ // java.text.MessageFormat.applyPattern(java.lang.String)
+ MessageFormat format = new MessageFormat("test");
+ format.applyPattern("xx {0}");
+ assertEquals("Invalid number", "xx 46", format
+ .format(new Object[] { new Integer(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[] { new Integer(2), new Float(3.6) }));
+
+ try {
+ format.applyPattern("WRONG MESSAGE FORMAT {0,number,{}");
+ fail("Expected IllegalArgumentException for invalid pattern");
+ } catch (IllegalArgumentException e) {
+ }
+
+ // 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
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#clone()
+ */
+ public void test_clone() {
+ // Test for method java.lang.Object java.text.MessageFormat.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));
+ }
+
+ /**
+ * @tests java.text.MessageFormat#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.MessageFormat.equals(java.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));
+ }
+
+ /**
+ * @tests java.text.MessageFormat#hashCode()
+ */
+ public void test_hashCode() {
+ // Test for method
+ // int java.text.MessageFormat.hashCode()
+ assertEquals("Should be equal", 3648, new MessageFormat("rr", null)
+ .hashCode());
+ }
+
+ /**
+ * @tests java.text.MessageFormat#formatToCharacterIterator(java.lang.Object)
+ */
+ // FIXME This test fails on Harmony ClassLibrary
+ public void failing_test_formatToCharacterIteratorLjava_lang_Object() {
+ // Test for method formatToCharacterIterator(java.lang.Object)
+ new Support_MessageFormat(
+ "test_formatToCharacterIteratorLjava_lang_Object")
+ .t_formatToCharacterIterator();
+ }
+
+ /**
+ * @tests java.text.MessageFormat#format(java.lang.Object[],
+ * java.lang.StringBuffer, java.text.FieldPosition)
+ */
+ public void test_format$Ljava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition() {
+ // Test for method java.lang.StringBuffer
+ // java.text.MessageFormat.format(java.lang.Object [],
+ // java.lang.StringBuffer, java.text.FieldPosition)
+ MessageFormat format = new MessageFormat("{1,number,integer}");
+ StringBuffer buffer = new StringBuffer();
+ format.format(new Object[] { "0", new Double(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[] { new Double(1.6),
+ new Integer(3), date });
+ assertTrue("Choice not recursive:\n" + expected + "\n" + result,
+ expected.equals(result));
+ }
+
+ /**
+ * @tests java.text.MessageFormat#format(java.lang.Object,
+ * java.lang.StringBuffer, java.text.FieldPosition)
+ */
+ public void test_formatLjava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition() {
+ // Test for method java.lang.StringBuffer
+ // java.text.MessageFormat.format(java.lang.Object,
+ // java.lang.StringBuffer, java.text.FieldPosition)
+ new Support_MessageFormat(
+ "test_formatLjava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition")
+ .t_format_with_FieldPosition();
+ }
+
+ /**
+ * @tests java.text.MessageFormat#format(java.lang.String,
+ * java.lang.Object...) Test of method
+ * java.text.MessageFormat#format(java.lang.String,
+ * java.lang.Object...).
+ */
+ public void test_formatLjava_lang_StringLjava_lang_Object() {
+ int iCurrency = 123;
+ int iInteger = Integer.MIN_VALUE;
+
+ Date date = new Date(12345678);
+ Object[] args = { date, iCurrency, iInteger };
+ String resStr = "Date: Jan 1, 1970 Currency: $" + iCurrency
+ + ".00 Integer: -2,147,483,648";
+ String pattern = "Date: {0,date} Currency: {1, number, currency} Integer: {2, number, integer}";
+ String sFormat = MessageFormat.format(pattern, (Object[]) args);
+ assertEquals(
+ "format(String, Object[]) with valid parameters returns incorrect string: case 1",
+ sFormat, resStr);
+
+ pattern = "abc {4, number, integer} def {3,date} ghi {2,number} jkl {1,choice,0#low|1#high} mnop {0}";
+ resStr = "abc -2,147,483,648 def Jan 1, 1970 ghi -2,147,483,648 jkl high mnop -2,147,483,648";
+ Object[] args_ = { iInteger, 1, iInteger, date, iInteger };
+ sFormat = MessageFormat.format(pattern, args_);
+ assertEquals(
+ "format(String, Object[]) with valid parameters returns incorrect string: case 1",
+ sFormat, resStr);
+
+ try {
+ args = null;
+ MessageFormat.format(null, args);
+ fail("Doesn't throw IllegalArgumentException: null, null");
+ } catch (Exception e) {
+ // expected
+ }
+
+ try {
+ MessageFormat.format("Invalid {1,foobar} format descriptor!",
+ new Object[] {iInteger} );
+ fail("Doesn't throw IllegalArgumentException with invalid pattern as a parameter: case 1");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ }
+
+ try {
+ MessageFormat.format(
+ "Invalid {1,date,invalid-spec} format descriptor!", new Object[]{""});
+ fail("Doesn't throw IllegalArgumentException with invalid pattern as a parameter: case 2");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ }
+
+ try {
+ MessageFormat.format("{0,number,integer", new Object[] {iInteger});
+ fail("Doesn't throw IllegalArgumentException, doesn't detect unmatched brackets");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ }
+
+ try {
+ MessageFormat.format(
+ "Valid {1, date} format {0, number} descriptor!", new Object[]{ "" } );
+ fail("Doesn't throw IllegalArgumentException with invalid Object array");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#getFormats()
+ */
+ public void test_getFormats() {
+ // Test for method java.text.Format []
+ // java.text.MessageFormat.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);
+ }
+
+ /**
+ * @tests java.text.MessageFormat#getFormatsByArgumentIndex()
+ */
+ public void test_getFormatsByArgumentIndex() {
+ // Test for method java.text.Format [] test_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);
+ }
+
+ /**
+ * @tests java.text.MessageFormat#getLocale() Test of method
+ * java.text.MessageFormat#getLocale().
+ */
+ public void test_getLocale() {
+ try {
+ Locale[] l = {
+ Locale.FRANCE,
+ Locale.KOREA,
+ new Locale(Locale.FRANCE.getCountry(), Locale.FRANCE
+ .getLanguage()), new Locale("mk"),
+ new Locale("mk", "MK"), Locale.US,
+ new Locale("#ru", "@31230") };
+
+ String pattern = "getLocale test {0,number,#,####}";
+ MessageFormat mf;
+
+ for (int i = 0; i < 0; i++) {
+ mf = new MessageFormat(pattern, l[i]);
+ Locale result = mf.getLocale();
+ assertEquals("Returned local: " + result + " instead of "
+ + l[i], l[i], result);
+ assertEquals("Returned language: " + result.getLanguage()
+ + " instead of " + l[i].getLanguage(), l[i]
+ .getLanguage(), result.getLanguage());
+ assertEquals("Returned country: " + result.getCountry()
+ + " instead of " + l[i].getCountry(),
+ l[i].getCountry(), result.getCountry());
+ }
+
+ mf = new MessageFormat(pattern);
+ mf.setLocale(null);
+ Locale result = mf.getLocale();
+ assertEquals("Returned local: " + result + " instead of null",
+ null, result);
+ } catch (Exception e) {
+ fail("unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#setFormat(int, Format) Test of method
+ * java.text.MessageFormat#setFormat(int, Format). Case 1: Compare
+ * getFormats() results after calls to setFormat(). Case 2: Try to
+ * call setFormat() using incorrect index.
+ */
+ public void test_setFormatILjava_text_Format() {
+ try {
+ // case 1: Compare getFormats() results after calls to setFormat()
+ MessageFormat f1 = (MessageFormat) format1.clone();
+ f1.setFormat(0, DateFormat.getTimeInstance());
+ f1.setFormat(1, DateFormat.getTimeInstance());
+ f1.setFormat(2, NumberFormat.getInstance());
+ f1.setFormat(3, new ChoiceFormat("0#off|1#on"));
+ f1.setFormat(4, new ChoiceFormat("1#few|2#ok|3#a lot"));
+ f1.setFormat(5, DateFormat.getTimeInstance());
+
+ Format[] formats = f1.getFormats();
+ formats = f1.getFormats();
+
+ Format[] correctFormats = new Format[] {
+ DateFormat.getTimeInstance(), DateFormat.getTimeInstance(),
+ NumberFormat.getInstance(), new ChoiceFormat("0#off|1#on"),
+ new ChoiceFormat("1#few|2#ok|3#a lot"),
+ DateFormat.getTimeInstance() };
+
+ assertEquals("Test1A:Returned wrong number of formats:",
+ correctFormats.length, formats.length);
+ for (int i = 0; i < correctFormats.length; i++) {
+ assertEquals(
+ "Test1B:wrong format for pattern index " + i + ":",
+ correctFormats[i], formats[i]);
+ }
+
+ // case 2: Try to setFormat using incorrect index
+ try {
+ f1.setFormat(-1, DateFormat.getDateInstance());
+ fail("Expected ArrayIndexOutOfBoundsException was not thrown");
+ f1.setFormat(f1.getFormats().length, DateFormat
+ .getDateInstance());
+ fail("Expected ArrayIndexOutOfBoundsException was not thrown");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#setFormatByArgumentIndex(int,
+ * java.text.Format)
+ */
+ public void test_setFormatByArgumentIndexILjava_text_Format() {
+ // test for method setFormatByArgumentIndex(int, 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);
+ }
+
+ /**
+ * @tests java.text.MessageFormat#setFormats(Format[]) Test of method
+ * java.text.MessageFormat#setFormats(Format[]). Case 1: Test with
+ * repeating formats and max argument index < max offset compare
+ * getFormats() results after calls to setFormats(Format[]) Case 2:
+ * Try to pass null argument to setFormats().
+ */
+ public void test_setFormats$Ljava_text_Format() {
+ try {
+ MessageFormat f1 = (MessageFormat) format1.clone();
+
+ // case 1: Test with repeating formats and max argument index < max
+ // offset
+ // compare getFormats() results after calls to setFormats(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.setFormats(correctFormats);
+ Format[] formats = f1.getFormats();
+
+ assertTrue("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]);
+ }
+
+ // case 2: Try to pass null argument to setFormats().
+ try {
+ f1.setFormats(null);
+ fail("Expected exception NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#setFormatsByArgumentIndex(java.text.Format[])
+ */
+ public void test_setFormatsByArgumentIndex$Ljava_text_Format() {
+ // test for method setFormatByArgumentIndex(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);
+
+ }
+
+ /**
+ * @tests java.text.MessageFormat#parse(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ public void test_parseLjava_lang_StringLjava_text_ParsePosition() {
+ // Test for method java.lang.Object []
+ // java.text.MessageFormat.parse(java.lang.String,
+ // java.text.ParsePosition)
+ MessageFormat format = new MessageFormat("date is {0,date,MMM d, yyyy}");
+ ParsePosition pos = new ParsePosition(2);
+ Object[] result = (Object[]) format
+ .parse("xxdate is Feb 28, 1999", pos);
+ assertTrue("No result: " + result.length, result.length >= 1);
+ assertTrue("Wrong answer", ((Date) 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]);
+ }
+
+ /**
+ * @tests java.text.MessageFormat#setLocale(java.util.Locale)
+ */
+ public void test_setLocaleLjava_util_Locale() {
+ // Test for method void
+ // java.text.MessageFormat.setLocale(java.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]);
+ }
+
+ /**
+ * @tests java.text.MessageFormat#toPattern()
+ */
+ public void test_toPattern() {
+ // Test for method java.lang.String java.text.MessageFormat.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();
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+ 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);
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ Locale.setDefault(defaultLocale);
+ }
+
+ /**
+ * @tests java.text.MessageFormat(java.util.Locale)
+ */
+ public void test_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
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#parse(java.lang.String) Test of method
+ * java.text.MessageFormat#parse(java.lang.String).
+ */
+ public void test_parseLjava_lang_String() throws ParseException {
+ 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}";
+ MessageFormat mf = new MessageFormat(pattern);
+ String sToParse = "A $12,345.00 B 9:56:07 AM C 3,200% D 1/15/70 9:56 AM E on F Jan 1, 1970";
+ Object[] result;
+ try {
+ result = mf.parse(sToParse);
+
+ assertTrue("No result: " + result.length, result.length == 5);
+ assertTrue("Object 0 is not date", result[0] instanceof Date);
+ assertEquals("Object 1 is not stringr", result[1].toString(), "1.0");
+ assertTrue("Object 2 is not date", result[2] instanceof Date);
+ assertEquals("Object 3 is not number", result[3].toString(),
+ "12345");
+ assertEquals("Object 4 is not string", result[4].toString(),
+ "1/15/70 9:56 AM");
+
+ } catch (java.text.ParseException pe) {
+ fail("ParseException is thrown for incorrect string " + sToParse);
+ }
+
+ sToParse = "xxdate is Feb 28, 1999";
+ try {
+ result = format1.parse(sToParse);
+ fail("ParseException is thrown for incorrect string " + sToParse);
+ } catch (java.text.ParseException pe) {
+ // expected
+ }
+
+ sToParse = "vm=Test, @3 4 6, 3 ";
+ mf = new MessageFormat("vm={0},{1},{2}");
+ try {
+ result = mf.parse(sToParse);
+ assertTrue("No result: " + result.length, result.length == 3);
+ assertEquals("Object 0 is not string", result[0].toString(), "Test");
+ assertEquals("Object 1 is not string", result[1].toString(),
+ " @3 4 6");
+ assertEquals("Object 2 is not string", result[2].toString(),
+ " 3 ");
+ } catch (java.text.ParseException pe) {
+ fail("ParseException is thrown for correct string " + sToParse);
+ }
+
+ try {
+ result = mf.parse(null);
+ fail("ParseException is not thrown for null " + sToParse);
+ } catch (java.text.ParseException pe) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.MessageFormat#parseObject(java.lang.String,
+ * java.text.ParsePosition) Test of method
+ * java.text.MessageFormat#parseObject(java.lang.String,
+ * java.text.ParsePosition). Case 1: Parsing of correct data string.
+ * Case 2: Parsing of partial correct data string. Case 3: Try to use
+ * argument ParsePosition as null.
+ */
+ public void test_parseObjectLjava_lang_StringLjavajava_text_ParsePosition() {
+ MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
+ try {
+ // case 1: Try to parse correct data string.
+ Object[] objs = { new Double(3.1415) };
+ String result = mf.format(objs);
+ // result now equals "3.14, 3.1"
+ Object[] res = null;
+ ParsePosition pp = new ParsePosition(0);
+ int parseIndex = pp.getIndex();
+ res = (Object[]) mf.parseObject(result, pp);
+ assertTrue("Parse operation return null", res != null);
+ assertTrue("parse operation return array with incorrect length",
+ 1 == res.length);
+ assertTrue("ParseIndex is incorrect", pp.getIndex() != parseIndex);
+ assertTrue("Result object is incorrect", new Double(3.1)
+ .equals(res[0]));
+
+ // case 2: Try to parse partially correct data string.
+ pp.setIndex(0);
+ char[] cur = result.toCharArray();
+ cur[cur.length / 2] = 'Z';
+ String partialCorrect = new String(cur);
+ res = (Object[]) mf.parseObject(partialCorrect, pp);
+ assertTrue("Parse operation return null", res == null);
+ assertTrue("ParseIndex is incorrect", pp.getIndex() == 0);
+ assertTrue("ParseErrorIndex is incorrect",
+ pp.getErrorIndex() == cur.length / 2);
+
+ // case 3: Try to use argument ParsePosition as null.
+ try {
+ mf.parseObject(result, null);
+ fail("Expected NullPointerException was not thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.toString());
+ }
+ }
+
+ public void test_format_Object() {
+ // Regression for HARMONY-1875
+ Locale.setDefault(Locale.CANADA);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+ String pat = "text here {0,date,yyyyyyyyy} and here";
+ Calendar c = Calendar.getInstance();
+ String etalon = "text here 00000" + c.get(Calendar.YEAR) + " and here";
+ MessageFormat obj = new MessageFormat(pat);
+ assertEquals(etalon, obj.format(new Object[] { new Date() }));
+ }
+
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatFieldTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatFieldTest.java
new file mode 100644
index 0000000..8a95a01
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatFieldTest.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.text.*;
+
+public class NumberFormatFieldTest extends junit.framework.TestCase {
+ /**
+ * @tests java.text.NumberFormat$Field#Field(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ // protected constructor
+ String name = "new number format";
+ MyNumberFormat field = new MyNumberFormat(name);
+ assertEquals("field has wrong name", name, field.getName());
+
+ field = new MyNumberFormat(null);
+ assertEquals("field has wrong name", null, field.getName());
+ }
+
+ /**
+ * @tests java.text.NumberFormat$Field#readResolve()
+ */
+ public void test_readResolve() {
+ // test for method java.lang.Object readResolve()
+
+ // see serialization stress tests:
+ // implemented in
+ // SerializationStressTest4.test_writeObject_NumberFormat_Field()
+ ObjectOutputStream out = null;
+ ObjectInputStream in = null;
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ out = new ObjectOutputStream(bytes);
+
+ NumberFormat.Field nfield, nfield2;
+ MyNumberFormat field;
+
+ nfield = NumberFormat.Field.CURRENCY;
+
+ field = new MyNumberFormat(null);
+
+ out.writeObject(nfield);
+ out.writeObject(field);
+
+ in = new ObjectInputStream(new ByteArrayInputStream(bytes
+ .toByteArray()));
+ try {
+ nfield2 = (NumberFormat.Field) in.readObject();
+ assertSame("resolved incorrectly", nfield, nfield2);
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException: " + e);
+ }
+
+ try {
+ in.readObject();
+ fail("Expected InvalidObjectException for subclass instance with null name");
+ } catch (InvalidObjectException e) {
+ }
+
+ } catch (IOException e) {
+ fail("unexpected IOException" + e);
+ } catch (ClassNotFoundException e) {
+ fail("unexpected ClassNotFoundException" + e);
+ } finally {
+ try {
+ if (out != null)
+ out.close();
+ if (in != null)
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ static class MyNumberFormat extends NumberFormat.Field {
+ static final long serialVersionUID = 1L;
+
+ static boolean flag = false;
+
+ protected MyNumberFormat(String attr) {
+ super(attr);
+ }
+
+ protected String getName() {
+ return super.getName();
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java
new file mode 100644
index 0000000..8dd5526
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java
@@ -0,0 +1,1118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.ChoiceFormat;
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Currency;
+import java.util.Locale;
+import junit.framework.TestCase;
+
+public class NumberFormatTest extends TestCase {
+
+ /**
+ * @tests java.text.NumberFormat#format(java.lang.Object,
+ * java.lang.StringBuffer, java.text.FieldPosition)
+ */
+ public void test_formatLjava_lang_ObjectLjava_lang_StringBufferLjava_text_FieldPosition() {
+ FieldPosition pos;
+ StringBuffer out;
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getInstance(Locale.US);
+
+ pos = new FieldPosition(0);
+ out = format.format(new Long(Long.MAX_VALUE), new StringBuffer(), pos);
+ assertEquals("Wrong result L1: " + out, "9,223,372,036,854,775,807",
+ out.toString());
+
+ pos = new FieldPosition(0);
+ out = format.format(new Long(Long.MIN_VALUE), new StringBuffer(), pos);
+ assertEquals("Wrong result L2: " + out, "-9,223,372,036,854,775,808",
+ out.toString());
+
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigInteger(String
+ .valueOf(Long.MAX_VALUE)), new StringBuffer(), pos);
+ assertEquals("Wrong result BI1: " + out, "9,223,372,036,854,775,807",
+ out.toString());
+
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigInteger(String
+ .valueOf(Long.MIN_VALUE)), new StringBuffer(), pos);
+ assertEquals("Wrong result BI2: " + out, "-9,223,372,036,854,775,808",
+ out.toString());
+
+ java.math.BigInteger big;
+ pos = new FieldPosition(0);
+ big = new java.math.BigInteger(String.valueOf(Long.MAX_VALUE))
+ .add(new java.math.BigInteger("1"));
+ out = format.format(big, new StringBuffer(), pos);
+ assertEquals("Wrong result BI3: " + out, "9,223,372,036,854,775,808",
+ out.toString());
+
+ pos = new FieldPosition(0);
+ big = new java.math.BigInteger(String.valueOf(Long.MIN_VALUE))
+ .add(new java.math.BigInteger("-1"));
+ out = format.format(big, new StringBuffer(), pos);
+ assertEquals("Wrong result BI4: " + out, "-9,223,372,036,854,775,809",
+ out.toString());
+
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigDecimal("51.348"),
+ new StringBuffer(), pos);
+ assertEquals("Wrong result BD1: " + out, "51.348", out.toString());
+
+ pos = new FieldPosition(0);
+ out = format.format(new java.math.BigDecimal("51"), new StringBuffer(),
+ pos);
+ assertEquals("Wrong result BD2: " + out, "51", out.toString());
+
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getIntegerInstance()
+ */
+ public void test_getIntegerInstance() throws ParseException {
+ // Test for method java.text.NumberFormat getIntegerInstance()
+ Locale origLocale = Locale.getDefault();
+ Locale.setDefault(Locale.US);
+
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getIntegerInstance();
+
+ assertEquals(
+ "Test1: NumberFormat.getIntegerInstance().toPattern() returned wrong pattern",
+ "#,##0", format.toPattern());
+ assertEquals(
+ "Test2: NumberFormat.getIntegerInstance().format(35.76) returned wrong value",
+ "36", format.format(35.76));
+ assertEquals(
+ "Test3: NumberFormat.getIntegerInstance().parse(\"35.76\") returned wrong number",
+ new Long(35), format.parse("35.76"));
+ assertEquals(
+ "Test4: NumberFormat.getIntegerInstance().parseObject(\"35.76\") returned wrong number",
+ new Long(35), format.parseObject("35.76"));
+ Locale.setDefault(origLocale);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getIntegerInstance(java.util.Locale)
+ */
+ public void test_getIntegerInstanceLjava_util_Locale()
+ throws ParseException {
+ // Test for method java.text.NumberFormat
+ // getIntegerInstance(java.util.Locale)
+ Locale usLocale = Locale.US;
+ // BEGIN android-changed
+ // use de_CH instead
+ // Locale arLocale = new Locale("ar", "AE");
+ Locale chLocale = new Locale("de", "CH");
+ // END android-changed
+
+ DecimalFormat format = (DecimalFormat) NumberFormat
+ .getIntegerInstance(usLocale);
+ assertEquals(
+ "Test1: NumberFormat.getIntegerInstance().toPattern() returned wrong pattern",
+ "#,##0", format.toPattern());
+ assertEquals(
+ "Test2: NumberFormat.getIntegerInstance().format(-35.76) returned wrong value",
+ "-36", format.format(-35.76));
+ assertEquals(
+ "Test3: NumberFormat.getIntegerInstance().parse(\"-36\") returned wrong number",
+ new Long(-36), format.parse("-36"));
+ assertEquals(
+ "Test4: NumberFormat.getIntegerInstance().parseObject(\"-36\") returned wrong number",
+ new Long(-36), format.parseObject("-36"));
+ assertEquals(
+ "Test5: NumberFormat.getIntegerInstance().getMaximumFractionDigits() returned wrong value",
+ 0, format.getMaximumFractionDigits());
+ assertTrue(
+ "Test6: NumberFormat.getIntegerInstance().isParseIntegerOnly() returned wrong value",
+ format.isParseIntegerOnly());
+
+ // try with a locale that has a different integer pattern
+ // BEGIN android-changed
+ // use de_CH instead
+ // format = (DecimalFormat) NumberFormat.getIntegerInstance(arLocale);
+ format = (DecimalFormat) NumberFormat.getIntegerInstance(chLocale);
+ assertEquals(
+ "Test7: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).toPattern() returned wrong pattern",
+ "#,##0", format.toPattern());
+ assertEquals(
+ "Test8: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).format(-35.76) returned wrong value",
+ "-36", format.format(-35.76));
+ assertEquals(
+ "Test9: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).parse(\"-36-\") returned wrong number",
+ new Long(-36), format.parse("-36"));
+ assertEquals(
+ "Test10: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).parseObject(\"36-\") returned wrong number",
+ new Long(-36), format.parseObject("-36"));
+
+ assertEquals(
+ "Test11: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).getMaximumFractionDigits() returned wrong value",
+ 0, format.getMaximumFractionDigits());
+ assertTrue(
+ "Test12: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).isParseIntegerOnly() returned wrong value",
+ format.isParseIntegerOnly());
+ // use de_CH instead
+ /*assertEquals(
+ "Test7: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).toPattern() returned wrong pattern",
+ "#,##0;#,##0-", format.toPattern());
+ assertEquals(
+ "Test8: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).format(-35.76) returned wrong value",
+ "36-", format.format(-35.76));
+ assertEquals(
+ "Test9: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).parse(\"-36-\") returned wrong number",
+ new Long(-36), format.parse("36-"));
+ assertEquals(
+ "Test10: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).parseObject(\"36-\") returned wrong number",
+ new Long(-36), format.parseObject("36-"));
+
+ assertEquals(
+ "Test11: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).getMaximumFractionDigits() returned wrong value",
+ 0, format.getMaximumFractionDigits());
+ assertTrue(
+ "Test12: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).isParseIntegerOnly() returned wrong value",
+ format.isParseIntegerOnly());*/
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getCurrency()
+ */
+ public void test_getCurrency() {
+ // Test for method java.util.Currency getCurrency()
+
+ // a subclass that supports currency formatting
+ Currency currH = Currency.getInstance("HUF");
+ NumberFormat format = NumberFormat.getInstance(new Locale("hu", "HU"));
+ assertSame("Returned incorrect currency", currH, format.getCurrency());
+
+ // a subclass that doesn't support currency formatting
+ ChoiceFormat cformat = new ChoiceFormat(
+ "0#Less than one|1#one|1<Between one and two|2<Greater than two");
+ try {
+ ((NumberFormat) cformat).getCurrency();
+ fail("Expected UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setMaximumIntegerDigits()
+ */
+ public void test_setMaximumIntegerDigits() {
+ NumberFormat format = NumberFormat.getInstance();
+ format.setMaximumIntegerDigits(2);
+ assertEquals("Wrong result: case 1", "23", format.format(123));
+
+ format.setMaximumIntegerDigits(Integer.MIN_VALUE);
+ assertEquals("Wrong result: case 2", "0", format.format(123));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setCurrency(java.util.Currency)
+ */
+ public void test_setCurrencyLjava_util_Currency() {
+ // Test for method void setCurrency(java.util.Currency)
+ // a subclass that supports currency formatting
+ Currency currA = Currency.getInstance("ARS");
+ NumberFormat format = NumberFormat.getInstance(new Locale("hu", "HU"));
+ format.setCurrency(currA);
+ assertSame("Returned incorrect currency", currA, format.getCurrency());
+
+ // a subclass that doesn't support currency formatting
+ ChoiceFormat cformat = new ChoiceFormat(
+ "0#Less than one|1#one|1<Between one and two|2<Greater than two");
+ try {
+ ((NumberFormat) cformat).setCurrency(currA);
+ fail("Expected UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ }
+ }
+
+ /**
+ * @tests java.text.NumberFormat#parseObject(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ public void test_parseObjectLjava_lang_StringLjava_text_ParsePosition() {
+ // regression test for HARMONY-1003
+ assertNull(NumberFormat.getInstance().parseObject("0",
+ new ParsePosition(-1)));
+
+ // Regression for HARMONY-1685
+ try {
+ NumberFormat.getInstance().parseObject("test", null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.NumberFormat#clone()
+ */
+ public void test_clone() {
+
+ int max_digits = 100;
+ NumberFormat nf1 = NumberFormat.getInstance();
+ nf1.setMaximumIntegerDigits(max_digits);
+
+ NumberFormat nf2 = (NumberFormat) nf1.clone();
+ NumberFormat nf3 = (NumberFormat) nf1.clone();
+
+ assertTrue("Clonned object is not equal to object", nf2.equals(nf1));
+ assertTrue("Two clonned objects are not equal", nf2.equals(nf3));
+
+ assertTrue("Max digits value is incorrect for clonned object", nf2
+ .getMaximumIntegerDigits() == max_digits);
+
+ nf1.setMaximumIntegerDigits(10);
+ assertTrue(
+ "Max digits value is incorrect for clonned object after changing this value for object",
+ nf2.getMaximumIntegerDigits() == max_digits);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#equals(Object)
+ */
+ public void test_equals() {
+
+ NumberFormat nf1 = NumberFormat.getInstance();
+ NumberFormat nf2 = NumberFormat.getInstance();
+
+ assertTrue("Objects are not equal", nf1.equals(nf2));
+ assertTrue("THe same Objects are not equal", nf1.equals(nf1));
+
+ nf2.setMaximumIntegerDigits(100);
+ assertFalse("Different NumberFormat are equal", nf1.equals(nf2));
+
+ nf2.setMaximumIntegerDigits(nf1.getMaximumIntegerDigits());
+ assertTrue("THe same Objects are not equal", nf1.equals(nf2));
+
+ nf1 = NumberFormat.getIntegerInstance();
+ nf2 = NumberFormat.getIntegerInstance(Locale.CHINA);
+ assertFalse("Different NumberFormat are equal", nf1.equals(nf2));
+
+ assertFalse("Object is equal null", nf1.equals(null));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#format(double)
+ */
+ public void test_formatLdouble() {
+ // BEGIN android-changed
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ // use de_CH instead
+ // NumberFormat nf2 = NumberFormat.getInstance(new Locale("ar", "AR"));
+ NumberFormat nf2 = NumberFormat.getInstance(new Locale("de", "CH"));
+
+ String out = nf1.format(1234567890.0123456789);
+ assertEquals("Wrong result for double : " + out, "1,234,567,890.012",
+ out.toString());
+
+ out = nf1.format(-1234567890.0123456789);
+ assertEquals("Wrong result for double : " + out, "-1,234,567,890.012",
+ out.toString());
+
+ out = nf2.format(-1234567890.0123456789);
+ // use de_CH instead
+ // assertEquals("Wrong result for double : " + out, "1,234,567,890.012-",
+ // out.toString());
+ assertEquals("Wrong result for double : " + out, "-1'234'567'890.012",
+ out.toString());
+
+ out = nf1.format(1.0001);
+ assertEquals("Wrong result for for double: " + out, "1", out.toString());
+
+ out = nf1.format(5.0);
+ assertEquals("Wrong result for for double: " + out, "5", out.toString());
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#format(long)
+ */
+ public void test_formatLlong() {
+ // BEGIN android-changed
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ // use de_CH instead
+ // NumberFormat nf2 = NumberFormat.getInstance(Locale.CANADA_FRENCH);
+ NumberFormat nf2 = NumberFormat.getInstance(new Locale("de", "CH"));
+
+ String out = nf1.format(Long.MAX_VALUE);
+ assertEquals("Wrong result for double : " + out,
+ "9,223,372,036,854,775,807", out.toString());
+
+ out = nf1.format(Long.MIN_VALUE);
+ assertEquals("Wrong result for double : " + out,
+ "-9,223,372,036,854,775,808", out.toString());
+
+ out = nf2.format(-1234567890);
+ // use de_CH instead
+ // assertEquals("Wrong result for double : " + out, "-1 234 567 890", out
+ // .toString());
+ assertEquals("Wrong result for double : " + out, "-1'234'567'890", out
+ .toString());
+
+ // the Locale data of icu uses \uc2a0
+ out = nf1.format(1);
+ assertEquals("Wrong result for for double: " + out, "1", out.toString());
+
+ out = nf1.format(0);
+ assertEquals("Wrong result for for double: " + out, "0", out.toString());
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getAvailableLocales()
+ */
+ public void test_getAvailableLocales() {
+
+ Locale[] l = NumberFormat.getAvailableLocales();
+ assertFalse("returned Locale array is null", l == null);
+ assertTrue("returned Locale length <= 0", l.length > 0);
+ Locale[] resl = Locale.getAvailableLocales();
+ assertTrue("returned Locale arrays are different",
+ l.length == resl.length);
+ boolean isUS = false;
+ for (int i = 0; i < resl.length; i++) {
+ assertEquals("elements " + i + " are not equal: ", resl[i], l[i]);
+ if (l[i].equals(Locale.US))
+ isUS = true;
+ }
+ assertTrue("there is no Locale.US", isUS);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getCurrencyInstance()
+ */
+ public void test_getCurrencyInstance() {
+
+ NumberFormat format = NumberFormat.getCurrencyInstance();
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getCurrencyInstance().format(35.76) returned wrong value",
+ "$35.76", format.format(35.76));
+ assertEquals(
+ "Test2: NumberFormat.getCurrencyInstance().format(123456.789) returned wrong value",
+ "$123,456.79", format.format(123456.789));
+ assertEquals(
+ "Test3: NumberFormat.getCurrencyInstance().format(0.1) returned wrong value",
+ "$0.10", format.format(0.1));
+ assertEquals(
+ "Test4: NumberFormat.getCurrencyInstance().format(0.999) returned wrong value",
+ "$1.00", format.format(0.999));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getCurrencyInstance(java.util.Locale)
+ */
+ public void test_getCurrencyInstanceLjava_util_Locale() {
+ // BEGIN android-changed
+ Locale usLocale = Locale.US;
+ // use de_AT instead
+ // Locale mkLocale = new Locale("mk", "MK");
+ Locale atLocale = new Locale("de", "AT");
+
+ NumberFormat format = NumberFormat.getCurrencyInstance(usLocale);
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getCurrencyInstance(Locale.US).format(35.76) returned wrong value",
+ "$35.76", format.format(35.76));
+ assertEquals(
+ "Test2: NumberFormat.getCurrencyInstance(Locale.US).format(123456.789) returned wrong value",
+ "$123,456.79", format.format(123456.789));
+ assertEquals(
+ "Test3: NumberFormat.getCurrencyInstance(Locale.US).format(0.1) returned wrong value",
+ "$0.10", format.format(0.1));
+ assertEquals(
+ "Test4: NumberFormat.getCurrencyInstance(Locale.US).format(0.999) returned wrong value",
+ "$1.00", format.format(0.999));
+
+ // use de_AT instead
+ // format = NumberFormat.getCurrencyInstance(mkLocale);
+ format = NumberFormat.getCurrencyInstance(atLocale);
+
+ assertEquals(
+ "Test5: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(35.76) returned wrong value",
+ "\u20ac 35,76", format.format(35.76));
+ assertEquals(
+ "Test6: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(123456.789) returned wrong value",
+ "\u20ac 123.456,79", format.format(123456.789));
+ assertEquals(
+ "Test7: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(0.1) returned wrong value",
+ "\u20ac 0,10", format.format(0.1));
+ assertEquals(
+ "Test8: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(0.999) returned wrong value",
+ "\u20ac 1,00", format.format(0.999));
+ // use de_AT instead
+ /*assertEquals(
+ "Test5: NumberFormat.getCurrencyInstance(new Locale(\"mk\", \"MK\")).format(35.76) returned wrong value",
+ "Den 35,76", format.format(35.76));
+ assertEquals(
+ "Test6: NumberFormat.getCurrencyInstance(new Locale(\"mk\", \"MK\")).format(123456.789) returned wrong value",
+ "Den 123.456,79", format.format(123456.789));
+ assertEquals(
+ "Test7: NumberFormat.getCurrencyInstance(new Locale(\"mk\", \"MK\")).format(0.1) returned wrong value",
+ "Den 0,1", format.format(0.1));
+ assertEquals(
+ "Test8: NumberFormat.getCurrencyInstance(new Locale(\"mk\", \"MK\")).format(0.999) returned wrong value",
+ "Den 1", format.format(0.999));*/
+ try {
+ NumberFormat.getCurrencyInstance(null);
+ fail("java.lang.NullPointerException is not thrown");
+ } catch (java.lang.NullPointerException npe) {
+ // expested
+ }
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getInstance()
+ */
+ public void test_getInstance() {
+ Locale.setDefault(Locale.US);
+ NumberFormat format = NumberFormat.getInstance();
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getInstance().format(1234567890.0987654321) returned wrong value",
+ "1,234,567,890.099", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getInstance()).toPattern returned wrong value",
+ "#,##0.###", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getInstance().format(123456789) returned wrong value",
+ "123,456,789", format.format(123456789));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getInstance(Locale)
+ */
+ public void test_getInstanceLjava_util_Locale() {
+ // BEGIN android-changed
+ Locale.setDefault(Locale.US);
+ // use de_CH instead
+ // NumberFormat format = NumberFormat.getInstance(new Locale("ar", "AR"));
+ NumberFormat format = NumberFormat.getInstance(new Locale("de", "CH"));
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getInstance().format(1234567890.0987654321) returned wrong value",
+ "1'234'567'890.099", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getInstance()).toPattern returned wrong value",
+ "#,##0.###", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getInstance().format(123456789) returned wrong value",
+ "123'456'789", format.format(123456789));
+ // use de_CH instead
+ /*assertEquals(
+ "Test1: NumberFormat.getInstance().format(1234567890.0987654321) returned wrong value",
+ "1,234,567,890.099", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getInstance()).toPattern returned wrong value",
+ "#,##0.###;#,##0.###-", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getInstance().format(123456789) returned wrong value",
+ "123,456,789", format.format(123456789));*/
+ try {
+ NumberFormat.getInstance(null);
+ fail("java.lang.NullPointerException is not thrown");
+ } catch (java.lang.NullPointerException npe) {
+ // expested
+ }
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getNumberInstance()
+ */
+ public void test_getNumberInstance() {
+ Locale.setDefault(Locale.US);
+ NumberFormat format = NumberFormat.getNumberInstance();
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getNumberInstance().format(1234567890.0987654321) returned wrong value",
+ "1,234,567,890.099", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getNumberInstance()).toPattern returned wrong value",
+ "#,##0.###", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getNumberInstance().format(123456789) returned wrong value",
+ "123,456,789", format.format(123456789));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getNumberInstance(Locale)
+ */
+ public void test_getNumberInstanceLjava_util_Locale() {
+ // BEGIN android-changed
+ Locale.setDefault(Locale.US);
+ // use de_CH instead
+ NumberFormat format = NumberFormat.getNumberInstance(new Locale("de",
+ "CH"));
+ // NumberFormat format = NumberFormat.getNumberInstance(new Locale("ar",
+ // "AR"));
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getNumberInstance().format(-1234567890.0987654321) returned wrong value",
+ "-1'234'567'890.099", format.format(-1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getNumberInstance()).toPattern returned wrong value",
+ "#,##0.###", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getNumberInstance().format(123456789) returned wrong value",
+ "123'456'789", format.format(123456789));
+ // use de_CH instead
+ /*assertEquals(
+ "Test1: NumberFormat.getNumberInstance().format(-1234567890.0987654321) returned wrong value",
+ "1,234,567,890.099-", format.format(-1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getNumberInstance()).toPattern returned wrong value",
+ "#,##0.###;#,##0.###-", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getNumberInstance().format(123456789) returned wrong value",
+ "123,456,789", format.format(123456789));*/
+ try {
+ NumberFormat.getInstance(null);
+ fail("java.lang.NullPointerException is not thrown");
+ } catch (java.lang.NullPointerException npe) {
+ // expested
+ }
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getPercentInstance()
+ */
+ public void test_getPercentInstance() {
+ Locale.setDefault(Locale.US);
+ NumberFormat format = NumberFormat.getPercentInstance();
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getPercentInstance().format(1234567890.0987654321) returned wrong value",
+ "123,456,789,010%", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getPercentInstance()).toPattern returned wrong value",
+ "#,##0%", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getPercentInstance().format(123456789) returned wrong value",
+ "12,345,678,900%", format.format(123456789));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getPercentInstance(Locale)
+ */
+ public void test_getPercentInstanceLjava_util_Locale() {
+ Locale.setDefault(Locale.US);
+ NumberFormat format = NumberFormat.getPercentInstance(new Locale("ar",
+ "AR"));
+
+ assertNotSame("Instance is null", null, format);
+ assertTrue("Object is not instance of NumberFormat",
+ format instanceof NumberFormat);
+
+ assertEquals(
+ "Test1: NumberFormat.getPercentInstance().format(1234567890.0987654321) returned wrong value",
+ "123,456,789,010%", format.format(1234567890.0987654321));
+ assertEquals(
+ "Test2: ((DecimalFormat) NumberFormat.getPercentInstance()).toPattern returned wrong value",
+ "#,##0%", ((DecimalFormat) format).toPattern());
+ assertEquals(
+ "Test3: NumberFormat.getPercentInstance().format(123456789) returned wrong value",
+ "12,345,678,900%", format.format(123456789));
+ try {
+ NumberFormat.getInstance(null);
+ fail("java.lang.NullPointerException is not thrown");
+ } catch (java.lang.NullPointerException npe) {
+ // expested
+ }
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getMaximumFractionDigits()
+ */
+ public void test_getMaximumFractionDigits() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+
+ nf1.setMaximumFractionDigits(Integer.MAX_VALUE);
+ int result = nf1.getMaximumFractionDigits();
+ assertTrue("getMaximumFractionDigits returns " + result
+ + " instead of: " + Integer.MAX_VALUE,
+ result == Integer.MAX_VALUE);
+
+ nf1.setMaximumFractionDigits(0);
+ result = nf1.getMaximumFractionDigits();
+ assertTrue("getMaximumFractionDigits returns " + result
+ + " instead of 0", result == 0);
+
+ nf1.setMinimumFractionDigits(Integer.MAX_VALUE);
+ result = nf1.getMaximumFractionDigits();
+ assertTrue("getMaximumFractionDigits returns " + result
+ + " instead of Integer.MAX_VALUE", result == Integer.MAX_VALUE);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getMinimumFractionDigits()
+ */
+ public void test_getMinimumFractionDigits() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ nf1.setMinimumFractionDigits(Integer.MAX_VALUE);
+ int result = nf1.getMinimumFractionDigits();
+ assertTrue("getMinimumFractionDigits returns " + result
+ + " instead of: " + Integer.MAX_VALUE,
+ result == Integer.MAX_VALUE);
+
+ nf1.setMaximumFractionDigits(0);
+ result = nf1.getMinimumFractionDigits();
+ assertTrue("getMinimumFractionDigits returns " + result
+ + " instead of 0", result == 0);
+
+ nf1.setMinimumFractionDigits(52);
+ result = nf1.getMinimumFractionDigits();
+ assertTrue("getMinimumFractionDigits returns " + result
+ + " instead of 52", result == 52);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getMaximumIntegerDigits()
+ */
+ public void test_getMaximumIntegerDigits() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ nf1.setMaximumIntegerDigits(Integer.MAX_VALUE);
+ int result = nf1.getMaximumIntegerDigits();
+ assertTrue("getMaximumIntegerDigits returns " + result
+ + " instead of: " + Integer.MAX_VALUE,
+ result == Integer.MAX_VALUE);
+
+ nf1.setMaximumIntegerDigits(0);
+ result = nf1.getMaximumIntegerDigits();
+ assertTrue("getMaximumIntegerDigits returns " + result
+ + " instead of 0", result == 0);
+
+ nf1.setMinimumIntegerDigits(Integer.MAX_VALUE);
+ result = nf1.getMaximumIntegerDigits();
+ assertTrue("getMaximumIntegerigits returns " + result
+ + " instead of Integer.MAX_VALUE", result == Integer.MAX_VALUE);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#getMinimumIntegerDigits()
+ */
+ public void test_getMinimumIntegernDigits() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ nf1.setMinimumIntegerDigits(Integer.MAX_VALUE);
+ int result = nf1.getMinimumIntegerDigits();
+ assertTrue("getMinimumIntegerDigits returns " + result
+ + " instead of: " + Integer.MAX_VALUE,
+ result == Integer.MAX_VALUE);
+
+ nf1.setMaximumIntegerDigits(0);
+ result = nf1.getMinimumIntegerDigits();
+ assertTrue("getMinimumIntegerDigits returns " + result
+ + " instead of 0", result == 0);
+
+ nf1.setMinimumIntegerDigits(0x12034);
+ result = nf1.getMinimumIntegerDigits();
+ assertTrue("getMinimumIntegerDigits returns " + result
+ + " instead of 5148", result == 73780);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#hashCode()
+ */
+ public void test_hashCode() {
+
+ NumberFormat nf1 = NumberFormat.getInstance();
+ NumberFormat nf11 = NumberFormat.getInstance();
+ NumberFormat nf2 = NumberFormat.getInstance(Locale.US);
+ NumberFormat nf3 = NumberFormat.getPercentInstance();
+ NumberFormat nf4 = NumberFormat.getCurrencyInstance();
+ NumberFormat nf5 = NumberFormat
+ .getNumberInstance(new Locale("mk", "MK"));
+ NumberFormat nf6 = NumberFormat.getInstance(Locale.US);
+
+ assertTrue("Hash codes are not equal: case 1", nf1.hashCode() == nf2
+ .hashCode());
+ assertTrue("Hash codes are not equal: case 2", nf1.hashCode() == nf11
+ .hashCode());
+ assertTrue("Hash codes are not equal: case 3", nf1.hashCode() == nf3
+ .hashCode());
+ assertFalse("Hash codes are equal: case 4", nf3.hashCode() == nf4
+ .hashCode());
+ assertFalse("Hash codes are equal: case 5", nf4.hashCode() == nf5
+ .hashCode());
+ assertTrue("Hash codes are not equal: case 6", nf5.hashCode() == nf6
+ .hashCode());
+
+ nf1.setMaximumFractionDigits(0);
+ assertTrue("Hash codes are not equal: case 7", nf1.hashCode() == nf11
+ .hashCode());
+ }
+
+ /**
+ * @tests java.text.NumberFormat#isGroupingUsed()
+ */
+ public void test_isGroupingUsed() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ assertTrue("grouping is not used for NumberFormat.getInstance", nf1
+ .isGroupingUsed());
+
+ nf1.setGroupingUsed(false);
+ assertFalse(
+ "grouping is used for NumberFormat.getInstance after setting false",
+ nf1.isGroupingUsed());
+
+ nf1.setGroupingUsed(true);
+ assertTrue(
+ "grouping is not used for NumberFormat.getInstance after setting true",
+ nf1.isGroupingUsed());
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setGroupingUsed(boolean)
+ */
+ public void test_setGroupingUsed() {
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ nf1.setGroupingUsed(false);
+
+ assertEquals("grouping is not used for 1234567890.1", "1234567890.1",
+ nf1.format(1234567890.1));
+
+ assertEquals("grouping is not used for -1234567890.1", "-1234567890.1",
+ nf1.format(-1234567890.1));
+
+ nf1.setGroupingUsed(false);
+
+ assertEquals("grouping is not used for 1234567890.1", "1234567890.1",
+ nf1.format(1234567890.1));
+
+ assertEquals("grouping is not used for -1234567890.1", "-1234567890.1",
+ nf1.format(-1234567890.1));
+
+ nf1.setGroupingUsed(true);
+
+ assertEquals("grouping is not used for 1234567890.1",
+ "1,234,567,890.1", nf1.format(1234567890.1));
+
+ assertEquals("grouping is not used for -1234567890.1",
+ "-1,234,567,890.1", nf1.format(-1234567890.1));
+
+ NumberFormat nf2 = NumberFormat.getPercentInstance(new Locale("ar",
+ "AR"));
+ nf2.setGroupingUsed(false);
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for 1234567890.1",
+ "123456789010%", nf2.format(1234567890.1));
+
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for -1234567890.1",
+ "-123456789010%", nf2.format(-1234567890.1));
+ assertEquals("grouping is not used for 1234567890.1",
+ "1,234,567,890.1", nf1.format(1234567890.1));
+
+ nf2.setGroupingUsed(true);
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for 1234567890.1",
+ "123,456,789,010%", nf2.format(1234567890.1));
+
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for -1234567890.1",
+ "-123,456,789,010%", nf2.format(-1234567890.1));
+
+ nf2.setGroupingUsed(true);
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for 1234567890.1",
+ "123,456,789,010%", nf2.format(1234567890.1));
+
+ assertEquals(
+ "Locale(\"ar\", \"AR\"): grouping is not used for -1234567890.1",
+ "-123,456,789,010%", nf2.format(-1234567890.1));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#isParseIntegerOnly()
+ */
+ public void test_isParseIntegerOnly() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ assertTrue("ParseIntegerOnly is not used for NumberFormat.getInstance",
+ nf1.isGroupingUsed());
+
+ nf1.setParseIntegerOnly(false);
+ assertFalse(
+ "ParseIntegerOnly is used for NumberFormat.getInstance after setting false",
+ nf1.isParseIntegerOnly());
+
+ nf1.setParseIntegerOnly(true);
+ assertTrue(
+ "ParseIntegerOnly is not used for NumberFormat.getInstance after setting true",
+ nf1.isParseIntegerOnly());
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setParseIntegerOnly(boolean)
+ */
+ public void test_setParseIntegerOnly() {
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ nf1.setParseIntegerOnly(true);
+
+ assertEquals("ParseIntegerOnly is not used for 1234567890.1",
+ "1,234,567,890.1", nf1.format(1234567890.1));
+ assertEquals("ParseIntegerOnly is not used for -1234567890.1",
+ "-1,234,567,890.1", nf1.format(-1234567890.1));
+ assertEquals("ParseIntegerOnly is not used for -1234567890.",
+ "-1,234,567,890", nf1.format(-1234567890.));
+
+ nf1.setParseIntegerOnly(false);
+
+ assertEquals("ParseIntegerOnly is not used for 1234567890.1",
+ "1,234,567,890.1", nf1.format(1234567890.1));
+ assertEquals("ParseIntegerOnly is not used for -1234567890.1",
+ "-1,234,567,890.1", nf1.format(-1234567890.1));
+ assertEquals("ParseIntegerOnly is not used for -1234567890.",
+ "-1,234,567,890", nf1.format(-1234567890.));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setMaximumFractionDigits(int)
+ */
+ public void test_setMaximumFractionDigits() {
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ nf1.setMaximumFractionDigits(Integer.MAX_VALUE);
+ int result = nf1.getMaximumFractionDigits();
+ assertTrue("setMaximumFractionDigits set " + result
+ + " instead of Integer.MAX_VALUE", result == Integer.MAX_VALUE);
+ nf1.setMaximumFractionDigits(0);
+ result = nf1.getMaximumFractionDigits();
+ assertTrue("setMaximumFractionDigits set " + result + " instead of 0",
+ result == 0);
+ assertEquals("format of 1234567890.0987654321 returns incorrect value",
+ "1,234,567,890", nf1.format(1234567890.0987654321));
+ nf1.setMaximumFractionDigits(5);
+ result = nf1.getMaximumFractionDigits();
+ assertTrue("setMaximumFractionDigits set " + result + " instead of 5",
+ result == 5);
+ assertEquals(
+ "format of 1234567890.0987654321 returns incorrect value with MaximumFractionDigits = 5",
+ "1,234,567,890.09877", nf1.format(1234567890.0987654321));
+ assertEquals(
+ "format of -1234567890 returns incorrect value with MaximumFractionDigits = 5",
+ "-1,234,567,890", nf1.format(-1234567890));
+ nf1.setMaximumFractionDigits(Integer.MIN_VALUE);
+ result = nf1.getMaximumFractionDigits();
+ assertTrue("setMaximumFractionDigits set " + result
+ + " instead of Integer.MIN_VALUE", result == 0);
+ assertEquals(
+ "format of 1234567890.0987654321 returns incorrect value with MaximumFractionDigits = 5",
+ "1,234,567,890", nf1.format(1234567890.0987654321));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setMinimumFractionDigits(int)
+ */
+ public void test_setMinimumFractionDigits() {
+
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ nf1.setMinimumFractionDigits(Integer.MAX_VALUE);
+ int result = nf1.getMinimumFractionDigits();
+ assertTrue("setMinimumFractionDigits set " + result
+ + " instead of Integer.MAX_VALUE", result == Integer.MAX_VALUE);
+ nf1.setMinimumFractionDigits(0);
+ result = nf1.getMinimumFractionDigits();
+ assertTrue("setMinimumFractionDigits set " + result + " instead of 0",
+ result == 0);
+ nf1.setMinimumFractionDigits(5);
+ result = nf1.getMinimumFractionDigits();
+ assertTrue("setMinimumFractionDigits set " + result + " instead of 5",
+ result == 5);
+ assertEquals(
+ "format of 1234567890.0987654321 returns incorrect value with MinimumFractionDigits = 5",
+ "1,234,567,890.09000", nf1.format(1234567890.09));
+ assertEquals(
+ "format of -1234567890 returns incorrect value with MinimumFractionDigits = 5",
+ "-1,234,567,890.00000", nf1.format(-1234567890));
+ nf1.setMinimumFractionDigits(Integer.MIN_VALUE);
+ result = nf1.getMinimumFractionDigits();
+ assertTrue("setMinimumFractionDigits set " + result
+ + " instead of Integer.MIN_VALUE", result == 0);
+ assertEquals(
+ "format of 1234567890.098 returns incorrect value with MinimumFractionDigits = 5",
+ "1,234,567,890.098", nf1.format(1234567890.098));
+ }
+
+ /**
+ * @tests java.text.NumberFormat#setMinimumIntegerDigits(int)
+ */
+ public void test_setMinimumIntegerDigits() {
+
+ NumberFormat nf1 = NumberFormat.getInstance(Locale.US);
+ nf1.setMinimumIntegerDigits(Integer.MAX_VALUE);
+ int result = nf1.getMinimumIntegerDigits();
+ assertTrue("setMinimumIntegerDigits set " + result
+ + " instead of Integer.MAX_VALUE", result == Integer.MAX_VALUE);
+ nf1.setMinimumIntegerDigits(0);
+ result = nf1.getMinimumIntegerDigits();
+ assertTrue("setMinimumIntegerDigits set " + result + " instead of 0",
+ result == 0);
+ nf1.setMinimumIntegerDigits(5);
+ result = nf1.getMinimumIntegerDigits();
+ assertTrue("setMinimumIntegerDigits set " + result + " instead of 5",
+ result == 5);
+ assertEquals(
+ "format of 123.09 returns incorrect value with MinimumIntegerDigits = 5",
+ "00,123.09", nf1.format(123.09));
+ assertEquals(
+ "format of -123 returns incorrect value with MinimumIntegerDigits = 5",
+ "-00,123", nf1.format(-123));
+ nf1.setMinimumIntegerDigits(Integer.MIN_VALUE);
+ result = nf1.getMinimumIntegerDigits();
+ assertTrue("setMinimumIntegerDigits set " + result
+ + " instead of Integer.MIN_VALUE", result == 0);
+ }
+
+ /**
+ * @tests java.text.NumberFormat#parse(String)
+ */
+ public void test_parseLjava_lang_String() {
+ NumberFormat nf1 = NumberFormat.getInstance();
+ try {
+ assertEquals(
+ "Test1: NumberFormat.getInstance().parse(\"1234567890.1\") returned wrong number",
+ new Double(1234567890.1), nf1.parse("1234567890.1"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for 1234567890.1");
+ }
+
+ try {
+ assertEquals(
+ "Test2: NumberFormat.getInstance().parse(\"-1234567890.1\") returned wrong number",
+ new Double(-1234567890.1), nf1.parse("-1,234,567,890.1"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for -1,234,567,890.1");
+ }
+
+ try {
+ nf1.parse("@1,234,567,8901");
+ fail("java.text.ParseException is not thrown for 1,234,567,890z1");
+ } catch (java.text.ParseException pe) {
+ // expected
+ }
+
+ nf1 = NumberFormat.getPercentInstance();
+ try {
+ assertEquals(
+ "Test3: NumberFormat.getPercentInstance().parse(\"-123%\") returned wrong number",
+ new Double(-1.23), nf1.parse("-123%"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for -123%");
+ }
+
+ nf1 = NumberFormat.getCurrencyInstance();
+ try {
+ assertEquals(
+ "Test4: NumberFormat.getCurrencyInstance().parse(\"$123\") returned wrong number",
+ new Long(123), nf1.parse("$123"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for $123");
+ }
+
+ try {
+ assertEquals(
+ "Test4: NumberFormat.getCurrencyInstance().parse(\"$123abc\") returned wrong number",
+ new Long(123), nf1.parse("$123abc"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for $123");
+ }
+
+ nf1 = NumberFormat.getIntegerInstance();
+ try {
+ assertEquals(
+ "Test5: NumberFormat.getIntegerInstance().parse(\"-123.123\") returned wrong number",
+ nf1.parseObject("-123.123"), nf1.parse("-123.123"));
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for $123");
+ }
+ }
+
+ /**
+ * @tests java.text.NumberFormat#NumberFormat()
+ */
+ public void test_constructor() {
+ MyNumberFormat mf = new MyNumberFormat();
+ assertFalse("Greated NumberFormat object is null", mf == null);
+ assertTrue(
+ "Greated NumberFormat object is not instance of NumberFormat",
+ mf instanceof NumberFormat);
+ }
+
+ class MyNumberFormat extends NumberFormat {
+ static final long serialVersionUID = 1L;
+
+ public MyNumberFormat() {
+ super();
+ }
+
+ public StringBuffer format(double number, StringBuffer toAppendTo,
+ FieldPosition pos) {
+
+ return new StringBuffer();
+ }
+
+ public Number parse(String source, ParsePosition parsePosition) {
+
+ return new Double(0);
+ }
+
+ public StringBuffer format(long number, StringBuffer toAppendTo,
+ FieldPosition pos) {
+ return new StringBuffer();
+ }
+
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/ParseExceptionTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/ParseExceptionTest.java
new file mode 100644
index 0000000..5e2fa88
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/ParseExceptionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+
+public class ParseExceptionTest extends junit.framework.TestCase {
+
+ /**
+ * @tests java.text.ParseException#ParseException(java.lang.String, int)
+ */
+ public void test_ConstructorLjava_lang_StringI() {
+ // Test for method java.text.ParseException(java.lang.String, int)
+ // SM
+ try {
+ DateFormat df = DateFormat.getInstance();
+ df.parse("HelloWorld");
+ } catch (ParseException e) {
+ return;
+ }
+ fail("ParseException not created/thrown.");
+ }
+
+ /**
+ * @tests java.text.ParseException#getErrorOffset()
+ */
+ public void test_getErrorOffset() {
+ // Test for method int java.text.ParseException.getErrorOffset()
+ // SM
+ try {
+ DateFormat df = DateFormat.getInstance();
+ df.parse("1999HelloWorld");
+ } catch (ParseException e) {
+ assertEquals("getErrorOffsetFailed.", 4, e.getErrorOffset());
+ }
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/ParsePositionTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/ParsePositionTest.java
new file mode 100644
index 0000000..b8b2983
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/ParsePositionTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.ParsePosition;
+
+public class ParsePositionTest extends junit.framework.TestCase {
+
+ ParsePosition pp;
+
+ /**
+ * @tests java.text.ParsePosition#ParsePosition(int)
+ */
+ public void test_ConstructorI() {
+ // Test for method java.text.ParsePosition(int)
+ try {
+ ParsePosition pp1 = new ParsePosition(Integer.MIN_VALUE);
+ assertTrue("Initialization failed.",
+ pp1.getIndex() == Integer.MIN_VALUE);
+ assertEquals("Initialization failed.", -1, pp1.getErrorIndex());
+ } catch (Exception e) {
+ fail("Constructor failed.");
+ }
+
+ }
+
+ /**
+ * @tests java.text.ParsePosition#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.ParsePosition.equals(java.lang.Object)
+ ParsePosition pp2 = new ParsePosition(43);
+ pp2.setErrorIndex(56);
+ assertTrue("equals failed.", !pp.equals(pp2));
+ pp.setErrorIndex(56);
+ pp.setIndex(43);
+ assertTrue("equals failed.", pp.equals(pp2));
+ }
+
+ /**
+ * @tests java.text.ParsePosition#getErrorIndex()
+ */
+ public void test_getErrorIndex() {
+ // Test for method int java.text.ParsePosition.getErrorIndex()
+ pp.setErrorIndex(56);
+ assertEquals("getErrorIndex failed.", 56, pp.getErrorIndex());
+ }
+
+ /**
+ * @tests java.text.ParsePosition#getIndex()
+ */
+ public void test_getIndex() {
+ // Test for method int java.text.ParsePosition.getIndex()
+ assertTrue("getIndex failed.", pp.getIndex() == Integer.MAX_VALUE);
+ }
+
+ /**
+ * @tests java.text.ParsePosition#hashCode()
+ */
+ public void test_hashCode() {
+ // Test for method int java.text.ParsePosition.hashCode()
+ assertTrue("Wrong hashCode returned", (pp.hashCode() == pp.getIndex()
+ + pp.getErrorIndex()));
+ }
+
+ /**
+ * @tests java.text.ParsePosition#setErrorIndex(int)
+ */
+ public void test_setErrorIndexI() {
+ // Test for method void java.text.ParsePosition.setErrorIndex(int)
+ pp.setErrorIndex(4564);
+ assertEquals("setErrorIndex failed.", 4564, pp.getErrorIndex());
+ }
+
+ /**
+ * @tests java.text.ParsePosition#setIndex(int)
+ */
+ public void test_setIndexI() {
+ // Test for method void java.text.ParsePosition.setIndex(int)
+ pp.setIndex(4564);
+ assertEquals("setErrorIndex failed.", 4564, pp.getIndex());
+ }
+
+ /**
+ * @tests java.text.ParsePosition#toString()
+ */
+ public void test_toString() {
+ // Test for method java.lang.String java.text.ParsePosition.toString()
+ assertEquals("toString failed.",
+ "java.text.ParsePosition[index=2147483647, errorIndex=-1]", pp
+ .toString());
+ }
+
+ /**
+ * Sets up the fixture, for example, open a network connection. This method
+ * is called before a test is executed.
+ */
+ protected void setUp() {
+
+ pp = new ParsePosition(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Tears down the fixture, for example, close a network connection. This
+ * method is called after a test is executed.
+ */
+ protected void tearDown() {
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/RuleBasedCollatorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/RuleBasedCollatorTest.java
new file mode 100644
index 0000000..1960892
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/RuleBasedCollatorTest.java
@@ -0,0 +1,350 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.CharacterIterator;
+import java.text.CollationElementIterator;
+import java.text.CollationKey;
+import java.text.Collator;
+import java.text.ParseException;
+import java.text.RuleBasedCollator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+public class RuleBasedCollatorTest extends TestCase {
+
+ /**
+ * @tests java.text.RuleBasedCollator#RuleBasedCollator(String)
+ */
+ public void test_constrLRuleBasedCollatorLjava_lang_String() {
+ RuleBasedCollator rbc;
+ try {
+ rbc = new RuleBasedCollator("<a< b< c< d");
+ assertNotSame("RuleBasedCollator object is null", null, rbc);
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for correct string");
+ }
+
+ try {
+ rbc = new RuleBasedCollator("<a< '&'b< \u0301< d");
+ assertNotSame("RuleBasedCollator object is null", null, rbc);
+ } catch (java.text.ParseException pe) {
+ fail("java.text.ParseException is thrown for correct string");
+ }
+
+ try {
+ new RuleBasedCollator(null);
+ fail("No Exception is thrown for correct string");
+ } catch (java.text.ParseException pe) {
+ fail("java.lang.NullPointerException is not thrown for correct string");
+ } catch (java.lang.NullPointerException npe) {
+
+ }
+
+ try {
+ new RuleBasedCollator("");
+ fail("java.text.ParseException is not thrown for empty string");
+ } catch (java.text.ParseException pe) {
+ }
+
+ try {
+ new RuleBasedCollator("1234567%$#845");
+ fail("java.text.ParseException is not thrown for wrong rules");
+ } catch (java.text.ParseException pe) {
+ }
+ }
+
+ public void test_getCollationKeyLjava_lang_String() {
+ // Regression test for HARMONY-28
+ String source = null;
+ RuleBasedCollator rbc = null;
+ try {
+ String Simple = "< a< b< c< d";
+ rbc = new RuleBasedCollator(Simple);
+ } catch (ParseException e) {
+ fail("Assert 0: Unexpected format exception " + e);
+ }
+ CollationKey ck = rbc.getCollationKey(source);
+ assertNull("Assert 1: getCollationKey (null) does not return null", ck);
+ }
+
+ public void testHashCode() throws ParseException {
+ {
+ String rule = "< a < b < c < d";
+ RuleBasedCollator coll = new RuleBasedCollator(rule);
+ assertEquals(rule.hashCode(), coll.hashCode());
+ }
+
+ {
+ String rule = "< a < b < c < d < e";
+ RuleBasedCollator coll = new RuleBasedCollator(rule);
+ assertEquals(rule.hashCode(), coll.hashCode());
+ }
+
+ }
+
+ public void testClone() throws ParseException {
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(Locale.US);
+ RuleBasedCollator clone = (RuleBasedCollator) coll.clone();
+ assertNotSame(coll, clone);
+ assertEquals(coll.getRules(), clone.getRules());
+ assertEquals(coll.getDecomposition(), clone.getDecomposition());
+ assertEquals(coll.getStrength(), clone.getStrength());
+ }
+
+ /*
+ * Class under test for boolean equals(java.lang.Object)
+ */
+ public void testEqualsObject() throws ParseException {
+ String rule = "< a < b < c < d < e";
+ RuleBasedCollator coll = new RuleBasedCollator(rule);
+
+ assertEquals(Collator.TERTIARY, coll.getStrength());
+ assertEquals(Collator.NO_DECOMPOSITION, coll.getDecomposition());
+ RuleBasedCollator other = new RuleBasedCollator(rule);
+ assertTrue(coll.equals(other));
+
+ coll.setStrength(Collator.PRIMARY);
+ assertFalse(coll.equals(other));
+
+ coll.setStrength(Collator.TERTIARY);
+ coll.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
+ assertFalse(coll.equals(other));
+ }
+
+ /*
+ * Class under test for int compare(java.lang.String, java.lang.String)
+ */
+ public void testCompareStringString() throws ParseException {
+ String rule = "< c < b < a";
+ RuleBasedCollator coll = new RuleBasedCollator(rule);
+ assertEquals(-1, coll.compare("c", "a"));
+ }
+
+ public void testGetCollationKey() {
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(Locale.GERMAN);
+ String source = "abc";
+ CollationKey key1 = coll.getCollationKey(source);
+ assertEquals(source, key1.getSourceString());
+ String source2 = "abb";
+ CollationKey key2 = coll.getCollationKey(source2);
+ assertEquals(source2, key2.getSourceString());
+ assertTrue(key1.compareTo(key2) > 0);
+ assertTrue(coll.compare(source, source2) > 0);
+
+ }
+
+ public void testGetRules() throws ParseException {
+ String rule = "< a = b < c";
+ RuleBasedCollator coll = new RuleBasedCollator(rule);
+ assertEquals(rule, coll.getRules());
+ }
+
+ /*
+ * Class under test for java.text.CollationElementIterator
+ * getCollationElementIterator(java.lang.String)
+ */
+ public void testGetCollationElementIteratorString() throws Exception {
+ {
+ Locale locale = new Locale("es", "", "TRADITIONAL");
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(locale);
+ String source = "cha";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(source);
+ int[] e_offset = { 0, 2, 3 };
+ int offset = iterator.getOffset();
+ int i = 0;
+ assertEquals(e_offset[i++], offset);
+ while (offset != source.length()) {
+ iterator.next();
+ offset = iterator.getOffset();
+ assertEquals(e_offset[i++], offset);
+ }
+ }
+
+ {
+ Locale locale = new Locale("de", "DE");
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(locale);
+ String source = "\u00E6b";
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(source);
+ int[] e_offset = { 0, 1, 1, 2 };
+ int offset = iterator.getOffset();
+ int i = 0;
+ assertEquals(e_offset[i++], offset);
+ while (offset != source.length()) {
+ iterator.next();
+ offset = iterator.getOffset();
+ assertEquals(e_offset[i++], offset);
+ }
+ }
+ // Regression for HARMONY-1352
+ try {
+ new RuleBasedCollator("< a< b< c< d").getCollationElementIterator((String)null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /*
+ * Class under test for java.text.CollationElementIterator
+ * getCollationElementIterator(java.text.CharacterIterator)
+ */
+ public void testGetCollationElementIteratorCharacterIterator() throws Exception {
+ {
+ Locale locale = new Locale("es", "", "TRADITIONAL");
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(locale);
+ String text = "cha";
+ StringCharacterIterator source = new StringCharacterIterator(text);
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(source);
+ int[] e_offset = { 0, 2, 3 };
+ int offset = iterator.getOffset();
+ int i = 0;
+ assertEquals(e_offset[i++], offset);
+ while (offset != text.length()) {
+ iterator.next();
+ offset = iterator.getOffset();
+ // System.out.println(offset);
+ assertEquals(e_offset[i++], offset);
+ }
+ }
+
+ {
+ Locale locale = new Locale("de", "DE");
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(locale);
+ String text = "\u00E6b";
+ StringCharacterIterator source = new StringCharacterIterator(text);
+ CollationElementIterator iterator = coll
+ .getCollationElementIterator(source);
+ int[] e_offset = { 0, 1, 1, 2 };
+ int offset = iterator.getOffset();
+ int i = 0;
+ assertEquals(e_offset[i++], offset);
+ while (offset != text.length()) {
+ iterator.next();
+ offset = iterator.getOffset();
+ assertEquals(e_offset[i++], offset);
+ }
+ }
+ // Regression for HARMONY-1352
+ try {
+ new RuleBasedCollator("< a< b< c< d").getCollationElementIterator((CharacterIterator)null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ public void testStrength() {
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(Locale.US);
+ for (int i = 0; i < 4; i++) {
+ coll.setStrength(i);
+ assertEquals(i, coll.getStrength());
+ }
+
+ }
+
+ public void testDecomposition() {
+ RuleBasedCollator coll = (RuleBasedCollator) Collator
+ .getInstance(Locale.US);
+ for (int i = 0; i < 2; i++) {
+ coll.setDecomposition(i);
+ assertEquals(i, coll.getDecomposition());
+ }
+ }
+
+ public void testCollator_GetInstance() {
+ Collator coll = Collator.getInstance();
+ Object obj1 = "a";
+ Object obj2 = "b";
+ assertEquals(-1, coll.compare(obj1, obj2));
+
+ Collator.getInstance();
+ assertFalse(coll.equals("A", "\uFF21"));
+ }
+
+ public void testGetAvaiableLocales() {
+ // Locale[] locales = Collator.getAvailableLocales();
+ // for (int i = 0; i < locales.length; i++) {
+ // Locale locale = locales[i];
+ // }
+ }
+
+ // Test CollationKey
+ public void testCollationKey() {
+ Collator coll = Collator.getInstance(Locale.US);
+ String text = "abc";
+ CollationKey key = coll.getCollationKey(text);
+ key.hashCode();
+
+ CollationKey key2 = coll.getCollationKey("abc");
+
+ assertEquals(0, key.compareTo(key2));
+ }
+
+ /**
+ * @tests java.text.RuleBasedCollator.RuleBasedCollator(java.lang.String)
+ */
+ public void testNullPointerException() throws Exception {
+ // Regression for HARMONY-241
+ try {
+ new RuleBasedCollator(null);
+ fail("Constructor RuleBasedCollator(null) "
+ + "should throw NullPointerException");
+ } catch (NullPointerException e) {}
+ }
+
+ /**
+ * @tests java.text.RuleBasedCollator.compare(java.lang.String, java.lang.String)
+ */
+ public void testCompareNull() throws Exception {
+ // Regression for HARMONY-836
+ try {
+ new RuleBasedCollator("< a").compare(null, null);
+ fail("RuleBasedCollator.compare(null, null) "
+ + "should throw NullPointerException");
+ } catch (NullPointerException e) {}
+ }
+
+ /**
+ * @tests java.text.RuleBasedCollator.RuleBasedCollator(java.lang.String)
+ */
+ public void testEmptyStringException() {
+ // Regression for HARMONY-241
+ try {
+ new RuleBasedCollator("");
+ fail("Constructor RuleBasedCollator(\"\") "
+ + "should throw ParseException");
+ } catch (ParseException e) {
+ assertEquals("java.text.ParseException", e.getClass().getName());
+ assertEquals(0, e.getErrorOffset());
+ }
+ }
+
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/SimpleDateFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/SimpleDateFormatTest.java
new file mode 100644
index 0000000..c5e94e1
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/SimpleDateFormatTest.java
@@ -0,0 +1,964 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.FieldPosition;
+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.SimpleTimeZone;
+import java.util.TimeZone;
+
+import tests.support.Support_SimpleDateFormat;
+
+public class SimpleDateFormatTest extends junit.framework.TestCase {
+
+ static SimpleDateFormat format = new SimpleDateFormat("", Locale.ENGLISH);
+
+ static SimpleDateFormat pFormat = new SimpleDateFormat("", Locale.ENGLISH);
+
+ static class TestFormat extends junit.framework.TestCase {
+ boolean testsFailed = false;
+
+ public TestFormat(String name) {
+ super(name);
+ }
+
+ public void test(String pattern, Calendar cal, String expected,
+ int field) {
+ StringBuffer buffer = new StringBuffer();
+ FieldPosition position = new FieldPosition(field);
+ format.applyPattern(pattern);
+ format.format(cal.getTime(), buffer, position);
+ String result = buffer.toString();
+ if (!System.getProperty("java.vendor", "None").substring(0, 3)
+ .equals("Sun")) {
+ assertTrue("Wrong format: \"" + pattern + "\" expected: "
+ + expected + " result: " + result, result
+ .equals(expected));
+ assertTrue("Wrong begin position: " + pattern + " expected: "
+ + expected + " field: " + field, position
+ .getBeginIndex() == 1);
+ assertTrue("Wrong end position: " + pattern + " expected: "
+ + expected + " field: " + field,
+ position.getEndIndex() == result.length());
+ } else {
+ // Print the failure but don't use assert as this
+ // will stop subsequent tests from running
+ if (!result.equals(expected)) {
+ System.out
+ .println("Wrong format: \"" + pattern
+ + "\" expected: " + expected + " result: "
+ + result);
+ testsFailed = true;
+ }
+ }
+ }
+
+ public boolean testsFailed() {
+ return testsFailed;
+ }
+
+ public void parse(String pattern, String input, Date expected,
+ int start, int end) {
+ pFormat.applyPattern(pattern);
+ ParsePosition position = new ParsePosition(start);
+ Date result = pFormat.parse(input, position);
+ assertTrue("Wrong result: " + pattern + " input: " + input
+ + " expected: " + expected + " result: " + result, expected
+ .equals(result));
+ assertTrue("Wrong end position: " + pattern + " input: " + input,
+ position.getIndex() == end);
+ }
+
+ public void verifyFormatTimezone(String timeZoneId, String expected1,
+ String expected2, Date date) {
+ format.setTimeZone(SimpleTimeZone.getTimeZone(timeZoneId));
+ format.applyPattern("z, zzzz");
+ assertEquals("Test z for TimeZone : " + timeZoneId, expected1,
+ format.format(date));
+
+ format.applyPattern("Z, ZZZZ");
+ assertEquals("Test Z for TimeZone : " + timeZoneId, expected2,
+ format.format(date));
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#SimpleDateFormat()
+ */
+ public void test_Constructor() {
+ // Test for method java.text.SimpleDateFormat()
+ SimpleDateFormat f2 = new SimpleDateFormat();
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertTrue("Wrong default", f2.equals(DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#SimpleDateFormat(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ // Test for method java.text.SimpleDateFormat(java.lang.String)
+ SimpleDateFormat f2 = new SimpleDateFormat("yyyy");
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertEquals("Wrong pattern", "yyyy", f2.toPattern());
+ assertTrue("Wrong locale", f2.equals(new SimpleDateFormat("yyyy",
+ Locale.getDefault())));
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols()));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+
+ // Invalid constructor value.
+ try {
+ new SimpleDateFormat(
+ "this is an invalid simple date format");
+ fail("Expected test_ConstructorLjava_lang_String to throw IAE.");
+ } catch (IllegalArgumentException ex) {
+ // expected
+ } catch (Throwable ex) {
+ fail("Expected test_ConstructorLjava_lang_String to throw IAE, not "
+ + ex.getClass().getName());
+ }
+
+ // Null string value
+ try {
+ new SimpleDateFormat(null);
+ fail("Expected test_ConstructorLjava_lang_String to throw NPE.");
+ } catch (NullPointerException ex) {
+ // expected
+ } catch (Throwable ex) {
+ fail("Expected test_ConstructorLjava_lang_String to throw NPE, not "
+ + ex.getClass().getName());
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#SimpleDateFormat(java.lang.String,
+ * java.text.DateFormatSymbols)
+ */
+ public void test_ConstructorLjava_lang_StringLjava_text_DateFormatSymbols() {
+ // Test for method java.text.SimpleDateFormat(java.lang.String,
+ // java.text.DateFormatSymbols)
+ DateFormatSymbols symbols = new DateFormatSymbols(Locale.ENGLISH);
+ symbols.setEras(new String[] { "Before", "After" });
+ SimpleDateFormat f2 = new SimpleDateFormat("y'y'yy", symbols);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertEquals("Wrong pattern", "y'y'yy", f2.toPattern());
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(symbols));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#SimpleDateFormat(java.lang.String,
+ * java.util.Locale)
+ */
+ public void test_ConstructorLjava_lang_StringLjava_util_Locale() {
+ // Test for method java.text.SimpleDateFormat(java.lang.String,
+ // java.util.Locale)
+ SimpleDateFormat f2 = new SimpleDateFormat("'yyyy' MM yy",
+ Locale.GERMAN);
+ assertTrue("Wrong class", f2.getClass() == SimpleDateFormat.class);
+ assertEquals("Wrong pattern", "'yyyy' MM yy", f2.toPattern());
+ assertTrue("Wrong symbols", f2.getDateFormatSymbols().equals(
+ new DateFormatSymbols(Locale.GERMAN)));
+ assertTrue("Doesn't work",
+ f2.format(new Date()).getClass() == String.class);
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#applyLocalizedPattern(java.lang.String)
+ */
+ public void test_applyLocalizedPatternLjava_lang_String() {
+ // Test for method void
+ // java.text.SimpleDateFormat.applyLocalizedPattern(java.lang.String)
+ SimpleDateFormat f2 = new SimpleDateFormat("y", new Locale("de", "CH"));
+ // BEGIN android-removed
+ // This test doesn't work like this. The cause lies inside of icu
+ // that doesn't support localized pattern characters anymore. So this
+ // test fails because the pattern template contains characters that are
+ // not part of the standard pattern returned for every locale.
+ // The default pattern characters are: GyMdkHmsSEDFwWahKzZ
+ //
+ // f2.applyLocalizedPattern("GuMtkHmsSEDFwWahKz");
+ // String pattern = f2.toPattern();
+ // assertTrue("Wrong pattern: " + pattern, pattern
+ // .equals("GyMdkHmsSEDFwWahKz"));
+ //
+ // test the new "Z" pattern char
+ // f2 = new SimpleDateFormat("y", new Locale("de", "CH"));
+ // f2.applyLocalizedPattern("G u M t Z");
+ // pattern = f2.toPattern();
+ // assertTrue("Wrong pattern: " + pattern, pattern.equals("G y M d Z"));
+ // END android-removed
+
+ // test invalid patterns
+ try {
+ f2.applyLocalizedPattern("b");
+ fail("Expected IllegalArgumentException for pattern with invalid pattern letter: b");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ // BEGIN android-canged
+ f2.applyLocalizedPattern("u");
+ fail("Expected IllegalArgumentException for pattern with invalid pattern letter: u");
+ // END android-changed
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ f2.applyLocalizedPattern("a '");
+ fail("Expected IllegalArgumentException for pattern with unterminated quote: a '");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ f2.applyLocalizedPattern(null);
+ fail("Expected NullPointerException for null pattern");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#applyPattern(java.lang.String)
+ */
+ public void test_applyPatternLjava_lang_String() {
+ // Test for method void
+ // java.text.SimpleDateFormat.applyPattern(java.lang.String)
+ SimpleDateFormat f2 = new SimpleDateFormat("y", new Locale("de", "CH"));
+ // BEGIN android-changed
+ f2.applyPattern("GyMdkHmsSEDFwWahKzZ");
+ assertEquals("Wrong pattern", "GyMdkHmsSEDFwWahKzZ", f2.toPattern());
+ // END android-changed
+
+ // test invalid patterns
+ try {
+ f2.applyPattern("b");
+ fail("Expected IllegalArgumentException for pattern with invalid patter letter: b");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ f2.applyPattern("u");
+ fail("Expected IllegalArgumentException for pattern with invalid patter letter: u");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ f2.applyPattern("a '");
+ fail("Expected IllegalArgumentException for pattern with unterminated quote: a '");
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ f2.applyPattern(null);
+ fail("Expected NullPointerException for null pattern");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#clone()
+ */
+ public void test_clone() {
+ // Test for method java.lang.Object java.text.SimpleDateFormat.clone()
+ SimpleDateFormat f2 = new SimpleDateFormat();
+ SimpleDateFormat clone = (SimpleDateFormat) f2.clone();
+ assertTrue("Invalid clone", f2.equals(clone));
+ clone.applyPattern("y");
+ assertTrue("Format modified", !f2.equals(clone));
+ clone = (SimpleDateFormat) f2.clone();
+ // Date date = clone.get2DigitYearStart();
+ // date.setTime(0);
+ // assertTrue("Equal after date change: " +
+ // f2.get2DigitYearStart().getTime() + " " +
+ // clone.get2DigitYearStart().getTime(), !f2.equals(clone));
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#equals(java.lang.Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ // Test for method boolean
+ // java.text.SimpleDateFormat.equals(java.lang.Object)
+ SimpleDateFormat format = (SimpleDateFormat) DateFormat.getInstance();
+ SimpleDateFormat clone = (SimpleDateFormat) format.clone();
+ assertTrue("clone not equal", format.equals(clone));
+ format.format(new Date());
+ assertTrue("not equal after format", format.equals(clone));
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#hashCode()
+ */
+ public void test_hashCode() {
+ SimpleDateFormat format = (SimpleDateFormat) DateFormat.getInstance();
+ SimpleDateFormat clone = (SimpleDateFormat) format.clone();
+ assertTrue("clone has not equal hash code", clone.hashCode() == format
+ .hashCode());
+ format.format(new Date());
+ assertTrue("clone has not equal hash code after format", clone
+ .hashCode() == format.hashCode());
+ DateFormatSymbols symbols = new DateFormatSymbols(Locale.ENGLISH);
+ symbols.setEras(new String[] { "Before", "After" });
+ SimpleDateFormat format2 = new SimpleDateFormat("y'y'yy", symbols);
+ assertFalse("objects has equal hash code", format2.hashCode() == format
+ .hashCode());
+ }
+
+ public void test_equals_afterFormat() {
+ // Regression test for HARMONY-209
+ SimpleDateFormat df = new SimpleDateFormat();
+ df.format(new Date());
+ assertEquals(df, new SimpleDateFormat());
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#formatToCharacterIterator(java.lang.Object)
+ */
+ public void test_formatToCharacterIteratorLjava_lang_Object() {
+
+ try {
+ // Regression for HARMONY-466
+ new SimpleDateFormat().formatToCharacterIterator(null);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ // Test for method formatToCharacterIterator(java.lang.Object)
+ new Support_SimpleDateFormat(
+ "test_formatToCharacterIteratorLjava_lang_Object")
+ .t_formatToCharacterIterator();
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#format(java.util.Date,
+ * java.lang.StringBuffer, java.text.FieldPosition)
+ */
+ public void test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition() {
+ // Test for method java.lang.StringBuffer
+ // java.text.SimpleDateFormat.format(java.util.Date,
+ // java.lang.StringBuffer, java.text.FieldPosition)
+
+ new Support_SimpleDateFormat(
+ "test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition")
+ .t_format_with_FieldPosition();
+
+ TestFormat test = new TestFormat(
+ "test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition");
+
+ Calendar cal = new GregorianCalendar(1999, Calendar.JUNE, 2, 15, 3, 6);
+ test.test(" G", cal, " AD", DateFormat.ERA_FIELD);
+ test.test(" GG", cal, " AD", DateFormat.ERA_FIELD);
+ test.test(" GGG", cal, " AD", DateFormat.ERA_FIELD);
+ test.test(" G", new GregorianCalendar(-1999, Calendar.JUNE, 2), " BC",
+ DateFormat.ERA_FIELD);
+
+ test.test(" y", cal, " 99", DateFormat.YEAR_FIELD);
+ test.test(" yy", cal, " 99", DateFormat.YEAR_FIELD);
+ test.test(" yy", new GregorianCalendar(2001, Calendar.JUNE, 2), " 01",
+ DateFormat.YEAR_FIELD);
+ test.test(" yy", new GregorianCalendar(2000, Calendar.JUNE, 2), " 00",
+ DateFormat.YEAR_FIELD);
+ test.test(" yyy", new GregorianCalendar(2000, Calendar.JUNE, 2), " 00",
+ DateFormat.YEAR_FIELD);
+ test.test(" yyy", cal, " 99", DateFormat.YEAR_FIELD);
+ test.test(" yyyy", cal, " 1999", DateFormat.YEAR_FIELD);
+ test.test(" yyyyy", cal, " 01999", DateFormat.YEAR_FIELD);
+
+ test.test(" M", cal, " 6", DateFormat.MONTH_FIELD);
+ test.test(" M", new GregorianCalendar(1999, Calendar.NOVEMBER, 2),
+ " 11", DateFormat.MONTH_FIELD);
+ test.test(" MM", cal, " 06", DateFormat.MONTH_FIELD);
+ test.test(" MMM", cal, " Jun", DateFormat.MONTH_FIELD);
+ test.test(" MMMM", cal, " June", DateFormat.MONTH_FIELD);
+ test.test(" MMMMM", cal, " June", DateFormat.MONTH_FIELD);
+
+ test.test(" d", cal, " 2", DateFormat.DATE_FIELD);
+ test.test(" d", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
+ " 12", DateFormat.DATE_FIELD);
+ test.test(" dd", cal, " 02", DateFormat.DATE_FIELD);
+ test.test(" dddd", cal, " 0002", DateFormat.DATE_FIELD);
+
+ test.test(" h", cal, " 3", DateFormat.HOUR1_FIELD);
+ test.test(" h", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
+ " 12", DateFormat.HOUR1_FIELD);
+ test.test(" hh", cal, " 03", DateFormat.HOUR1_FIELD);
+ test.test(" hhhh", cal, " 0003", DateFormat.HOUR1_FIELD);
+
+ test.test(" H", cal, " 15", DateFormat.HOUR_OF_DAY0_FIELD);
+ test.test(" H",
+ new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 4, 0), " 4",
+ DateFormat.HOUR_OF_DAY0_FIELD);
+ test.test(" H", new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 12,
+ 0), " 12", DateFormat.HOUR_OF_DAY0_FIELD);
+ test.test(" H", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
+ " 0", DateFormat.HOUR_OF_DAY0_FIELD);
+ test.test(" HH", cal, " 15", DateFormat.HOUR_OF_DAY0_FIELD);
+ test.test(" HHHH", cal, " 0015", DateFormat.HOUR_OF_DAY0_FIELD);
+
+ test.test(" m", cal, " 3", DateFormat.MINUTE_FIELD);
+ test.test(" m", new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 4,
+ 47), " 47", DateFormat.MINUTE_FIELD);
+ test.test(" mm", cal, " 03", DateFormat.MINUTE_FIELD);
+ test.test(" mmmm", cal, " 0003", DateFormat.MINUTE_FIELD);
+
+ test.test(" s", cal, " 6", DateFormat.SECOND_FIELD);
+ test.test(" s", new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 4,
+ 47, 13), " 13", DateFormat.SECOND_FIELD);
+ test.test(" ss", cal, " 06", DateFormat.SECOND_FIELD);
+ test.test(" ssss", cal, " 0006", DateFormat.SECOND_FIELD);
+
+ test.test(" S", cal, " 0", DateFormat.MILLISECOND_FIELD);
+ Calendar temp = new GregorianCalendar();
+ temp.set(Calendar.MILLISECOND, 961);
+
+ test.test(" SS", temp, " 961", DateFormat.MILLISECOND_FIELD);
+ test.test(" SSSS", cal, " 0000", DateFormat.MILLISECOND_FIELD);
+
+ test.test(" SS", cal, " 00", DateFormat.MILLISECOND_FIELD);
+
+ test.test(" E", cal, " Wed", DateFormat.DAY_OF_WEEK_FIELD);
+ test.test(" EE", cal, " Wed", DateFormat.DAY_OF_WEEK_FIELD);
+ test.test(" EEE", cal, " Wed", DateFormat.DAY_OF_WEEK_FIELD);
+ test.test(" EEEE", cal, " Wednesday", DateFormat.DAY_OF_WEEK_FIELD);
+ test.test(" EEEEE", cal, " Wednesday", DateFormat.DAY_OF_WEEK_FIELD);
+
+ test.test(" D", cal, " 153", DateFormat.DAY_OF_YEAR_FIELD);
+ test.test(" DD", cal, " 153", DateFormat.DAY_OF_YEAR_FIELD);
+ test.test(" DDDD", cal, " 0153", DateFormat.DAY_OF_YEAR_FIELD);
+
+ test.test(" F", cal, " 1", DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD);
+ test.test(" F", new GregorianCalendar(1999, Calendar.NOVEMBER, 14),
+ " 2", DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD);
+ test.test(" FF", cal, " 01", DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD);
+ test.test(" FFFF", cal, " 0001", DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD);
+
+ test.test(" w", cal, " 23", DateFormat.WEEK_OF_YEAR_FIELD);
+ test.test(" ww", cal, " 23", DateFormat.WEEK_OF_YEAR_FIELD);
+ test.test(" wwww", cal, " 0023", DateFormat.WEEK_OF_YEAR_FIELD);
+
+ test.test(" W", cal, " 1", DateFormat.WEEK_OF_MONTH_FIELD);
+ test.test(" W", new GregorianCalendar(1999, Calendar.NOVEMBER, 14),
+ " 3", DateFormat.WEEK_OF_MONTH_FIELD);
+ test.test(" WW", cal, " 01", DateFormat.WEEK_OF_MONTH_FIELD);
+ test.test(" WWWW", cal, " 0001", DateFormat.WEEK_OF_MONTH_FIELD);
+
+ test.test(" a", cal, " PM", DateFormat.AM_PM_FIELD);
+ test.test(" a", new GregorianCalendar(1999, Calendar.NOVEMBER, 14),
+ " AM", DateFormat.AM_PM_FIELD);
+ test.test(" a", new GregorianCalendar(1999, Calendar.NOVEMBER, 14, 12,
+ 0), " PM", DateFormat.AM_PM_FIELD);
+ test.test(" aa", cal, " PM", DateFormat.AM_PM_FIELD);
+ test.test(" aaa", cal, " PM", DateFormat.AM_PM_FIELD);
+ test.test(" aaaa", cal, " PM", DateFormat.AM_PM_FIELD);
+ test.test(" aaaaa", cal, " PM", DateFormat.AM_PM_FIELD);
+
+ test.test(" k", cal, " 15", DateFormat.HOUR_OF_DAY1_FIELD);
+ test.test(" k",
+ new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 4, 0), " 4",
+ DateFormat.HOUR_OF_DAY1_FIELD);
+ test.test(" k", new GregorianCalendar(1999, Calendar.NOVEMBER, 12, 12,
+ 0), " 12", DateFormat.HOUR_OF_DAY1_FIELD);
+ test.test(" k", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
+ " 24", DateFormat.HOUR_OF_DAY1_FIELD);
+ test.test(" kk", cal, " 15", DateFormat.HOUR_OF_DAY1_FIELD);
+ test.test(" kkkk", cal, " 0015", DateFormat.HOUR_OF_DAY1_FIELD);
+
+ test.test(" K", cal, " 3", DateFormat.HOUR0_FIELD);
+ test.test(" K", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
+ " 0", DateFormat.HOUR0_FIELD);
+ test.test(" KK", cal, " 03", DateFormat.HOUR0_FIELD);
+ test.test(" KKKK", cal, " 0003", DateFormat.HOUR0_FIELD);
+
+ format.setTimeZone(TimeZone.getTimeZone("EST"));
+ test.test(" z", cal, " EDT", DateFormat.TIMEZONE_FIELD);
+ Calendar temp2 = new GregorianCalendar(1999, Calendar.JANUARY, 12);
+ test.test(" z", temp2, " EST", DateFormat.TIMEZONE_FIELD);
+ test.test(" zz", cal, " EDT", DateFormat.TIMEZONE_FIELD);
+ test.test(" zzz", cal, " EDT", DateFormat.TIMEZONE_FIELD);
+ test.test(" zzzz", cal, " Eastern Daylight Time",
+ DateFormat.TIMEZONE_FIELD);
+ test.test(" zzzz", temp2, " Eastern Standard Time",
+ DateFormat.TIMEZONE_FIELD);
+ test.test(" zzzzz", cal, " Eastern Daylight Time",
+ DateFormat.TIMEZONE_FIELD);
+
+ format.setTimeZone(new SimpleTimeZone(60000, "ONE MINUTE"));
+ test.test(" z", cal, " GMT+00:01", DateFormat.TIMEZONE_FIELD);
+ test.test(" zzzz", cal, " GMT+00:01", DateFormat.TIMEZONE_FIELD);
+ format.setTimeZone(new SimpleTimeZone(5400000, "ONE HOUR, THIRTY"));
+ test.test(" z", cal, " GMT+01:30", DateFormat.TIMEZONE_FIELD);
+ format
+ .setTimeZone(new SimpleTimeZone(-5400000,
+ "NEG ONE HOUR, THIRTY"));
+ test.test(" z", cal, " GMT-01:30", DateFormat.TIMEZONE_FIELD);
+
+ format.applyPattern("'Mkz''':.@5");
+ assertEquals("Wrong output", "Mkz':.@5", format.format(new Date()));
+
+ assertTrue("Tests failed", !test.testsFailed());
+
+ // Test invalid args to format.
+ SimpleDateFormat dateFormat = new SimpleDateFormat();
+ try {
+ dateFormat.format(null, new StringBuffer(), new FieldPosition(1));
+ fail("Expected test to throw NPE.");
+ } catch (NullPointerException ex) {
+ // expected
+ } catch (Throwable ex) {
+ fail("Expected test to throw NPE, not " + ex.getClass().getName());
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#format(java.util.Date)
+ */
+ public void test_timeZoneFormatting() {
+ // tests specific to formatting of timezones
+ Date summerDate = new GregorianCalendar(1999, Calendar.JUNE, 2, 15, 3,
+ 6).getTime();
+ Date winterDate = new GregorianCalendar(1999, Calendar.JANUARY, 12)
+ .getTime();
+
+ TestFormat test = new TestFormat(
+ "test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition");
+
+ test.verifyFormatTimezone("PST", "PDT, Pacific Daylight Time",
+ "-0700, -0700", summerDate);
+ test.verifyFormatTimezone("PST", "PST, Pacific Standard Time",
+ "-0800, -0800", winterDate);
+
+ test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00",
+ "-0700, -0700", summerDate);
+ test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00",
+ "-0700, -0700", winterDate);
+
+ // Pacific/Kiritimati is one of the timezones supported only in mJava
+ test.verifyFormatTimezone("Pacific/Kiritimati", "LINT, Line Is. Time",
+ "+1400, +1400", summerDate);
+ test.verifyFormatTimezone("Pacific/Kiritimati", "LINT, Line Is. Time",
+ "+1400, +1400", winterDate);
+
+ test.verifyFormatTimezone("EST", "EDT, Eastern Daylight Time",
+ "-0400, -0400", summerDate);
+ test.verifyFormatTimezone("EST", "EST, Eastern Standard Time",
+ "-0500, -0500", winterDate);
+
+ test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00",
+ "+1400, +1400", summerDate);
+ test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00",
+ "+1400, +1400", winterDate);
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#get2DigitYearStart()
+ */
+ public void test_get2DigitYearStart() {
+ // Test for method java.util.Date
+ // java.text.SimpleDateFormat.get2DigitYearStart()
+ SimpleDateFormat f1 = new SimpleDateFormat("y");
+ Date date = f1.get2DigitYearStart();
+ Calendar cal = new GregorianCalendar();
+ int year = cal.get(Calendar.YEAR);
+ cal.setTime(date);
+ assertTrue("Wrong default year start",
+ cal.get(Calendar.YEAR) == (year - 80));
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#getDateFormatSymbols()
+ */
+ public void test_getDateFormatSymbols() {
+ // Test for method java.text.DateFormatSymbols
+ // java.text.SimpleDateFormat.getDateFormatSymbols()
+ SimpleDateFormat df = (SimpleDateFormat) DateFormat.getInstance();
+ DateFormatSymbols dfs = df.getDateFormatSymbols();
+ assertTrue("Symbols identical", dfs != df.getDateFormatSymbols());
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#parse(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ public void test_parseLjava_lang_StringLjava_text_ParsePosition() {
+ // Test for method java.util.Date
+ // java.text.SimpleDateFormat.parse(java.lang.String,
+ // java.text.ParsePosition)
+ TestFormat test = new TestFormat(
+ "test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition");
+
+ Calendar cal = new GregorianCalendar(1970, Calendar.JANUARY, 1);
+ Date time = cal.getTime();
+ test.parse("h", " 12", time, 1, 3);
+ test.parse("H", " 0", time, 1, 2);
+ test.parse("k", " 24", time, 1, 3);
+ test.parse("K", " 0", time, 1, 2);
+
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1, 1, 0);
+ time = cal.getTime();
+ test.parse("h", "1", time, 0, 1);
+ test.parse("H", "1 ", time, 0, 1);
+ test.parse("k", "1", time, 0, 1);
+ test.parse("K", "1", time, 0, 1);
+
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1, 11, 0);
+ time = cal.getTime();
+ test.parse("h", "0011 ", time, 0, 4);
+ test.parse("K", "11", time, 0, 2);
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1, 23, 0);
+ time = cal.getTime();
+ test.parse("H", "23", time, 0, 2);
+ test.parse("k", "23", time, 0, 2);
+
+ test.parse("h a", " 3 AM", new GregorianCalendar(1970,
+ Calendar.JANUARY, 1, 3, 0).getTime(), 1, 5);
+ test.parse("K a", " 3 pm ", new GregorianCalendar(1970,
+ Calendar.JANUARY, 1, 15, 0).getTime(), 1, 5);
+ test.parse("m:s", "0:59 ", new GregorianCalendar(1970,
+ Calendar.JANUARY, 1, 0, 0, 59).getTime(), 0, 4);
+ test.parse("m:s", "59:0", new GregorianCalendar(1970, Calendar.JANUARY,
+ 1, 0, 59, 0).getTime(), 0, 4);
+ test.parse("ms", "059", new GregorianCalendar(1970, Calendar.JANUARY,
+ 1, 0, 0, 59).getTime(), 0, 3);
+
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1);
+ test.parse("S", "0", cal.getTime(), 0, 1);
+ cal.setTimeZone(TimeZone.getTimeZone("HST"));
+ cal.set(Calendar.MILLISECOND, 999);
+ test.parse("S z", "999 HST", cal.getTime(), 0, 7);
+
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1);
+ cal.set(Calendar.ERA, GregorianCalendar.BC);
+ test.parse("G", "Bc ", cal.getTime(), 0, 2);
+
+ test.parse("y", "00", new GregorianCalendar(2000, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("y", "99", new GregorianCalendar(1999, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("y", "1", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 1);
+ test.parse("y", "-1", new GregorianCalendar(-1, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("y", "001", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 3);
+ test.parse("y", "2005",
+ new GregorianCalendar(2005, Calendar.JANUARY, 1).getTime(), 0,
+ 4);
+ test.parse("yy", "00", new GregorianCalendar(2000, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yy", "99", new GregorianCalendar(1999, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yy", "1", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 1);
+ test.parse("yy", "-1", new GregorianCalendar(-1, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yy", "001", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 3);
+ test.parse("yy", "2005", new GregorianCalendar(2005, Calendar.JANUARY,
+ 1).getTime(), 0, 4);
+ test.parse("yyy", "99", new GregorianCalendar(99, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yyy", "1", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 1);
+ test.parse("yyy", "-1", new GregorianCalendar(-1, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yyy", "001", new GregorianCalendar(1, Calendar.JANUARY, 1)
+ .getTime(), 0, 3);
+ test.parse("yyy", "2005", new GregorianCalendar(2005, Calendar.JANUARY,
+ 1).getTime(), 0, 4);
+ test.parse("yyyy", "99", new GregorianCalendar(99, Calendar.JANUARY, 1)
+ .getTime(), 0, 2);
+ test.parse("yyyy", " 1999", new GregorianCalendar(1999,
+ Calendar.JANUARY, 1).getTime(), 2, 6);
+ test.parse("MM'M'", "4M",
+ new GregorianCalendar(1970, Calendar.APRIL, 1).getTime(), 0, 2);
+ test.parse("MMM", "Feb", new GregorianCalendar(1970, Calendar.FEBRUARY,
+ 1).getTime(), 0, 3);
+ test.parse("MMMM d", "April 14 ", new GregorianCalendar(1970,
+ Calendar.APRIL, 14).getTime(), 0, 8);
+ test.parse("MMMMd", "April14 ", new GregorianCalendar(1970,
+ Calendar.APRIL, 14).getTime(), 0, 7);
+ test.parse("E w", "Mon 12", new GregorianCalendar(1970, Calendar.MARCH,
+ 16).getTime(), 0, 6);
+ test.parse("Ew", "Mon12", new GregorianCalendar(1970, Calendar.MARCH,
+ 16).getTime(), 0, 5);
+ test.parse("M EE ''W", "5 Tue '2", new GregorianCalendar(1970,
+ Calendar.MAY, 5).getTime(), 0, 8);
+ test.parse("MEE''W", "5Tue'2", new GregorianCalendar(1970,
+ Calendar.MAY, 5).getTime(), 0, 6);
+ test.parse("MMM EEE F", " JUL Sunday 3", new GregorianCalendar(1970,
+ Calendar.JULY, 19).getTime(), 1, 13);
+ test.parse("MMMEEEF", " JULSunday3", new GregorianCalendar(1970,
+ Calendar.JULY, 19).getTime(), 1, 11);
+
+ cal = new GregorianCalendar(1970, Calendar.JANUARY, 1);
+ cal.setTimeZone(TimeZone.getTimeZone("GMT+0:1"));
+ cal.set(Calendar.DAY_OF_YEAR, 243);
+ test.parse("D z", "243 GMT+0:0", cal.getTime(), 0, 11);
+ cal.setTimeZone(TimeZone.getTimeZone("EST"));
+ cal.set(1970, Calendar.JANUARY, 1, 4, 30);
+ test.parse("h:m z", "4:30 GMT-5 ", cal.getTime(), 0, 10);
+ test.parse("h z", "14 GMT-24 ", new Date(51840000), 0, 9);
+ test.parse("h z", "14 GMT-23 ", new Date(133200000), 0, 9);
+ test.parse("h z", "14 GMT-0001 ", new Date(54000000), 0, 11);
+ test.parse("h z", "14 GMT+24 ", new Date(48960000), 0, 9);
+ test.parse("h z", "14 GMT+23 ", new Date(-32400000), 0, 9);
+ test.parse("h z", "14 GMT+0001 ", new Date(46800000), 0, 11);
+ test.parse("h z", "14 +0001 ", new Date(46800000), 0, 8);
+ test.parse("h z", "14 -0001 ", new Date(54000000), 0, 8);
+
+ test.parse("yyyyMMddHHmmss", "19990913171901", new GregorianCalendar(
+ 1999, Calendar.SEPTEMBER, 13, 17, 19, 01).getTime(), 0, 14);
+
+ Date d = new Date(1015822800000L);
+ SimpleDateFormat df = new SimpleDateFormat("", new Locale("en", "US"));
+ df.setTimeZone(TimeZone.getTimeZone("EST"));
+
+ try {
+ df.applyPattern("dd MMMM yyyy EEEE");
+ String output = df.format(d);
+ Date date = df.parse(output);
+ assertTrue("Invalid result 1: " + date, d.equals(date));
+
+ df.applyPattern("dd MMMM yyyy F");
+ output = df.format(d);
+ date = df.parse(output);
+ assertTrue("Invalid result 2: " + date, d.equals(date));
+
+ df.applyPattern("dd MMMM yyyy w");
+ output = df.format(d);
+ date = df.parse(output);
+ assertTrue("Invalid result 3: " + date, d.equals(date));
+
+ df.applyPattern("dd MMMM yyyy W");
+ output = df.format(d);
+ date = df.parse(output);
+ assertTrue("Invalid result 4: " + date, d.equals(date));
+
+ df.applyPattern("dd MMMM yyyy D");
+ date = df.parse("5 January 2002 70");
+ assertTrue("Invalid result 5: " + date, d.equals(date));
+
+ df.applyPattern("W w dd MMMM yyyy EEEE");
+ output = df.format(d);
+ date = df.parse("3 12 5 March 2002 Monday");
+ assertTrue("Invalid result 6: " + date, d.equals(date));
+
+ df.applyPattern("w W dd MMMM yyyy EEEE");
+ output = df.format(d);
+ date = df.parse("12 3 5 March 2002 Monday");
+ assertTrue("Invalid result 6a: " + date, d.equals(date));
+
+ df.applyPattern("F dd MMMM yyyy EEEE");
+ output = df.format(d);
+ date = df.parse("2 5 March 2002 Monday");
+ assertTrue("Invalid result 7: " + date, d.equals(date));
+
+ df.applyPattern("w dd MMMM yyyy EEEE");
+ output = df.format(d);
+ date = df.parse("11 5 January 2002 Monday");
+ assertTrue("Invalid result 8: " + date, d.equals(date));
+
+ df.applyPattern("w dd yyyy EEEE MMMM");
+ output = df.format(d);
+ date = df.parse("11 5 2002 Monday January");
+ assertTrue("Invalid result 9: " + date, d.equals(date));
+
+ df.applyPattern("w yyyy EEEE MMMM dd");
+ output = df.format(d);
+ date = df.parse("17 2002 Monday March 11");
+ assertTrue("Invalid result 10: " + date, d.equals(date));
+
+ df.applyPattern("dd D yyyy MMMM");
+ output = df.format(d);
+ date = df.parse("5 70 2002 January");
+ assertTrue("Invalid result 11: " + date, d.equals(date));
+
+ df.applyPattern("D dd yyyy MMMM");
+ output = df.format(d);
+ date = df.parse("240 11 2002 March");
+ assertTrue("Invalid result 12: " + date, d.equals(date));
+ } catch (ParseException e) {
+ fail("unexpected: " + e);
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#set2DigitYearStart(java.util.Date)
+ */
+ public void test_set2DigitYearStartLjava_util_Date() {
+ // Test for method void
+ // java.text.SimpleDateFormat.set2DigitYearStart(java.util.Date)
+ SimpleDateFormat f1 = new SimpleDateFormat("yy");
+ f1.set2DigitYearStart(new GregorianCalendar(1950, Calendar.JANUARY, 1)
+ .getTime());
+ Calendar cal = new GregorianCalendar();
+ try {
+ cal.setTime(f1.parse("49"));
+ assertEquals("Incorrect year 2049", 2049, cal.get(Calendar.YEAR));
+ cal.setTime(f1.parse("50"));
+ int year = cal.get(Calendar.YEAR);
+ assertTrue("Incorrect year 1950: " + year, year == 1950);
+ f1.applyPattern("y");
+ cal.setTime(f1.parse("00"));
+ assertEquals("Incorrect year 2000", 2000, cal.get(Calendar.YEAR));
+ f1.applyPattern("yyy");
+ cal.setTime(f1.parse("50"));
+ assertEquals("Incorrect year 50", 50, cal.get(Calendar.YEAR));
+ } catch (ParseException e) {
+ fail("ParseException");
+ }
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#setDateFormatSymbols(java.text.DateFormatSymbols)
+ */
+ public void test_setDateFormatSymbolsLjava_text_DateFormatSymbols() {
+ // Test for method void
+ // java.text.SimpleDateFormat.setDateFormatSymbols(java.text.DateFormatSymbols)
+ SimpleDateFormat f1 = new SimpleDateFormat("a");
+ DateFormatSymbols symbols = new DateFormatSymbols();
+ symbols.setAmPmStrings(new String[] { "morning", "night" });
+ f1.setDateFormatSymbols(symbols);
+ DateFormatSymbols newSym = f1.getDateFormatSymbols();
+ assertTrue("Set incorrectly", newSym.equals(symbols));
+ assertTrue("Not a clone", f1.getDateFormatSymbols() != symbols);
+ String result = f1.format(new GregorianCalendar(1999, Calendar.JUNE,
+ 12, 3, 0).getTime());
+ assertEquals("Incorrect symbols used", "morning", result);
+ symbols.setEras(new String[] { "before", "after" });
+ assertTrue("Identical symbols", !f1.getDateFormatSymbols().equals(
+ symbols));
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#toLocalizedPattern()
+ */
+ public void test_toLocalizedPattern() {
+ // BEGIN android-changed
+ // Test for method java.lang.String
+ // java.text.SimpleDateFormat.toLocalizedPattern()
+ SimpleDateFormat f2 = new SimpleDateFormat("GyMdkHmsSEDFwWahKzZ",
+ new Locale("de", "CH"));
+ String pattern = f2.toLocalizedPattern();
+ // the default localized pattern characters are the same for all locales
+ // since icu has droped support for this. the default pattern characters
+ // are these: GyMdkHmsSEDFwWahKz
+ //
+ // assertTrue("Wrong pattern: " + pattern, pattern
+ // .equals("GuMtkHmsSEDFwWahKz"));
+ assertTrue("Wrong pattern: " + pattern, pattern
+ .equals("GyMdkHmsSEDFwWahKzZ"));
+
+
+ // test the new "Z" pattern char
+ f2 = new SimpleDateFormat("G y M d Z", new Locale("de", "CH"));
+ pattern = f2.toLocalizedPattern();
+ // assertTrue("Wrong pattern: " + pattern, pattern.equals("G u M t Z"));
+ assertTrue("Wrong pattern: " + pattern, pattern.equals("G y M d Z"));
+ // END android-changed
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#toPattern()
+ */
+ public void test_toPattern() {
+ String pattern = "yyyy mm dd";
+ SimpleDateFormat f = new SimpleDateFormat(pattern);
+ assertEquals("Wrong pattern: " + pattern, pattern, f.toPattern());
+
+ pattern = "GyMdkHmsSEDFwWahKz";
+ f = new SimpleDateFormat("GyMdkHmsSEDFwWahKz", new Locale("de", "CH"));
+ assertTrue("Wrong pattern: " + pattern, f.toPattern().equals(pattern));
+
+ pattern = "G y M d Z";
+ f = new SimpleDateFormat(pattern, new Locale("de", "CH"));
+ pattern = f.toPattern();
+ assertTrue("Wrong pattern: " + pattern, f.toPattern().equals(pattern));
+ }
+
+ /**
+ * @tests java.text.SimpleDateFormat#parse(java.lang.String,
+ * java.text.ParsePosition)
+ */
+ public void test_parse_with_spaces() {
+ // Regression for HARMONY-502
+ SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
+ df.setLenient(false);
+
+ char allowed_chars[] = { 0x9, 0x20 };
+ String allowed_char_names[] = { "tab", "space" };
+ for (int i = 0; i < allowed_chars.length; i++) {
+ Date expected = new GregorianCalendar(1970, Calendar.JANUARY, 1, 9,
+ 7, 6).getTime();
+ ParsePosition pp = new ParsePosition(0);
+ Date d = df.parse(allowed_chars[i] + "9:07:06", pp);
+ assertNotNull("hour may be prefixed by " + allowed_char_names[i], d);
+ assertEquals(expected, d);
+
+ pp = new ParsePosition(0);
+ d = df.parse("09:" + allowed_chars[i] + "7:06", pp);
+ assertNotNull("minute may be prefixed by " + allowed_char_names[i],
+ d);
+ assertEquals(expected, d);
+
+ pp = new ParsePosition(0);
+ d = df.parse("09:07:" + allowed_chars[i] + "6", pp);
+ assertNotNull("second may be prefixed by " + allowed_char_names[i],
+ d);
+ assertEquals(expected, d);
+ }
+
+ char not_allowed_chars[] = {
+ // whitespace
+ 0x1c, 0x1d, 0x1e, 0x1f, 0xa, 0xb, 0xc, 0xd, 0x2001, 0x2002,
+ 0x2003, 0x2004, 0x2005, 0x2006, 0x2008, 0x2009, 0x200a, 0x200b,
+ 0x2028, 0x2029, 0x3000,
+ // non-breaking space
+ 0xA0, 0x2007, 0x202F };
+
+ for (int i = 0; i < not_allowed_chars.length; i++) {
+
+ ParsePosition pp = new ParsePosition(0);
+ Date d = df.parse(not_allowed_chars[i] + "9:07", pp);
+ assertNull(d);
+
+ pp = new ParsePosition(0);
+ d = df.parse("09:" + not_allowed_chars[i] + "7", pp);
+ assertNull(d);
+
+ pp = new ParsePosition(0);
+ d = df.parse("09:07:" + not_allowed_chars[i] + "6", pp);
+ assertNull(d);
+ }
+ }
+}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/StringCharacterIteratorTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/StringCharacterIteratorTest.java
new file mode 100644
index 0000000..68293fb
--- /dev/null
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/StringCharacterIteratorTest.java
@@ -0,0 +1,521 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.harmony.text.tests.java.text;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+import junit.framework.TestCase;
+
+public class StringCharacterIteratorTest extends TestCase {
+
+ /**
+ * @tests java.text.StringCharacterIterator.StringCharacterIterator(String,
+ * int)
+ */
+ public void test_ConstructorI() {
+ assertNotNull(new StringCharacterIterator("value", 0));
+ assertNotNull(new StringCharacterIterator("value", "value".length()));
+ assertNotNull(new StringCharacterIterator("", 0));
+ try {
+ new StringCharacterIterator(null, 0);
+ fail("Assert 0: no null pointer");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ new StringCharacterIterator("value", -1);
+ fail("Assert 1: no illegal argument");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ new StringCharacterIterator("value", "value".length() + 1);
+ fail("Assert 2: no illegal argument");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator(String, int, int, int)
+ */
+ public void test_ConstructorIII() {
+ assertNotNull(new StringCharacterIterator("value", 0, "value".length(),
+ 0));
+ assertNotNull(new StringCharacterIterator("value", 0, "value".length(),
+ 1));
+ assertNotNull(new StringCharacterIterator("", 0, 0, 0));
+
+ try {
+ new StringCharacterIterator(null, 0, 0, 0);
+ fail("no null pointer");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", -1, "value".length(), 0);
+ fail("no illegal argument: invalid begin");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", 0, "value".length() + 1, 0);
+ fail("no illegal argument: invalid end");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", 2, 1, 0);
+ fail("no illegal argument: start greater than end");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", 2, 1, 2);
+ fail("no illegal argument: start greater than end");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", 2, 4, 1);
+ fail("no illegal argument: location greater than start");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ try {
+ new StringCharacterIterator("value", 0, 2, 3);
+ fail("no illegal argument: location greater than start");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.equals(Object)
+ */
+ public void test_equalsLjava_lang_Object() {
+ StringCharacterIterator sci0 = new StringCharacterIterator("fixture");
+ assertEquals(sci0, sci0);
+ assertFalse(sci0.equals(null));
+ assertFalse(sci0.equals("fixture"));
+
+ StringCharacterIterator sci1 = new StringCharacterIterator("fixture");
+ assertEquals(sci0, sci1);
+
+ sci1.next();
+ assertFalse(sci0.equals(sci1));
+ sci0.next();
+ assertEquals(sci0, sci1);
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ StringCharacterIterator it2 = new StringCharacterIterator("xxstinx", 2,
+ 6, 4);
+ assertTrue("Range is equal", !it1.equals(it2));
+ StringCharacterIterator it3 = new StringCharacterIterator("testing", 2,
+ 6, 2);
+ it3.setIndex(4);
+ assertTrue("Not equal", it1.equals(it3));
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.clone()
+ */
+ public void test_clone() {
+ StringCharacterIterator sci0 = new StringCharacterIterator("fixture");
+ assertSame(sci0, sci0);
+ StringCharacterIterator sci1 = (StringCharacterIterator) sci0.clone();
+ assertNotSame(sci0, sci1);
+ assertEquals(sci0, sci1);
+
+ StringCharacterIterator it = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ StringCharacterIterator clone = (StringCharacterIterator) it.clone();
+ assertTrue("Clone not equal", it.equals(clone));
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.current()
+ */
+ public void test_current() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals('f', fixture.current());
+ fixture.next();
+ assertEquals('i', fixture.current());
+
+ StringCharacterIterator it = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong current char", 'i', it.current());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.first()
+ */
+ public void test_first() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals('f', fixture.first());
+ fixture.next();
+ assertEquals('f', fixture.first());
+ fixture = new StringCharacterIterator("fixture", 1);
+ assertEquals('f', fixture.first());
+ fixture = new StringCharacterIterator("fixture", 1, "fixture".length(),
+ 2);
+ assertEquals('i', fixture.first());
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong first char", 's', it1.first());
+ assertEquals("Wrong next char", 't', it1.next());
+ it1 = new StringCharacterIterator("testing", 2, 2, 2);
+ assertTrue("Not DONE", it1.first() == CharacterIterator.DONE);
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.getBeginIndex()
+ */
+ public void test_getBeginIndex() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals(0, fixture.getBeginIndex());
+ fixture = new StringCharacterIterator("fixture", 1);
+ assertEquals(0, fixture.getBeginIndex());
+ fixture = new StringCharacterIterator("fixture", 1, "fixture".length(),
+ 2);
+ assertEquals(1, fixture.getBeginIndex());
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong begin index 2", 2, it1.getBeginIndex());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.getEndIndex()
+ */
+ public void test_getEndIndex() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals("fixture".length(), fixture.getEndIndex());
+ fixture = new StringCharacterIterator("fixture", 1);
+ assertEquals("fixture".length(), fixture.getEndIndex());
+ fixture = new StringCharacterIterator("fixture", 1, "fixture".length(),
+ 2);
+ assertEquals("fixture".length(), fixture.getEndIndex());
+ fixture = new StringCharacterIterator("fixture", 1, 4, 2);
+ assertEquals(4, fixture.getEndIndex());
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong end index 6", 6, it1.getEndIndex());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.getIndex()
+ */
+ public void testGetIndex() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals(0, fixture.getIndex());
+ fixture = new StringCharacterIterator("fixture", 1);
+ assertEquals(1, fixture.getIndex());
+ fixture = new StringCharacterIterator("fixture", 1, "fixture".length(),
+ 2);
+ assertEquals(2, fixture.getIndex());
+ fixture = new StringCharacterIterator("fixture", 1, 4, 2);
+ assertEquals(2, fixture.getIndex());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.last()
+ */
+ public void testLast() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals('e', fixture.last());
+ fixture.next();
+ assertEquals('e', fixture.last());
+ fixture = new StringCharacterIterator("fixture", 1);
+ assertEquals('e', fixture.last());
+ fixture = new StringCharacterIterator("fixture", 1, "fixture".length(),
+ 2);
+ assertEquals('e', fixture.last());
+ fixture = new StringCharacterIterator("fixture", 1, 4, 2);
+ assertEquals('t', fixture.last());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.next()
+ */
+ public void test_next() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals(0, fixture.getIndex());
+ assertEquals('i', fixture.next());
+ assertEquals(1, fixture.getIndex());
+ assertEquals('x', fixture.next());
+ assertEquals(2, fixture.getIndex());
+ assertEquals('t', fixture.next());
+ assertEquals(3, fixture.getIndex());
+ assertEquals('u', fixture.next());
+ assertEquals(4, fixture.getIndex());
+ assertEquals('r', fixture.next());
+ assertEquals(5, fixture.getIndex());
+ assertEquals('e', fixture.next());
+ assertEquals(6, fixture.getIndex());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(7, fixture.getIndex());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(7, fixture.getIndex());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(7, fixture.getIndex());
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 3);
+ char result = it1.next();
+ assertEquals("Wrong next char1", 'i', result);
+ assertEquals("Wrong next char2", 'n', it1.next());
+ assertTrue("Wrong next char3", it1.next() == CharacterIterator.DONE);
+ assertTrue("Wrong next char4", it1.next() == CharacterIterator.DONE);
+ int index = it1.getIndex();
+ assertEquals("Wrong index", 6, index);
+ assertTrue("Wrong current char",
+ it1.current() == CharacterIterator.DONE);
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.previous()
+ */
+ public void test_previous() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ assertEquals(CharacterIterator.DONE, fixture.previous());
+ assertEquals('i', fixture.next());
+ assertEquals('x', fixture.next());
+ assertEquals('t', fixture.next());
+ assertEquals('u', fixture.next());
+ assertEquals('r', fixture.next());
+ assertEquals('e', fixture.next());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(CharacterIterator.DONE, fixture.next());
+ assertEquals(7, fixture.getIndex());
+ assertEquals('e', fixture.previous());
+ assertEquals(6, fixture.getIndex());
+ assertEquals('r', fixture.previous());
+ assertEquals(5, fixture.getIndex());
+ assertEquals('u', fixture.previous());
+ assertEquals(4, fixture.getIndex());
+ assertEquals('t', fixture.previous());
+ assertEquals(3, fixture.getIndex());
+ assertEquals('x', fixture.previous());
+ assertEquals(2, fixture.getIndex());
+ assertEquals('i', fixture.previous());
+ assertEquals(1, fixture.getIndex());
+ assertEquals('f', fixture.previous());
+ assertEquals(0, fixture.getIndex());
+ assertEquals(CharacterIterator.DONE, fixture.previous());
+ assertEquals(0, fixture.getIndex());
+
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong previous char1", 't', it1.previous());
+ assertEquals("Wrong previous char2", 's', it1.previous());
+ assertTrue("Wrong previous char3",
+ it1.previous() == CharacterIterator.DONE);
+ assertTrue("Wrong previous char4",
+ it1.previous() == CharacterIterator.DONE);
+ assertEquals("Wrong index", 2, it1.getIndex());
+ assertEquals("Wrong current char", 's', it1.current());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.setIndex(int)
+ */
+ public void test_setIndex() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ while (fixture.next() != CharacterIterator.DONE) {
+ // empty
+ }
+ assertEquals("fixture".length(), fixture.getIndex());
+ fixture.setIndex(0);
+ assertEquals(0, fixture.getIndex());
+ assertEquals('f', fixture.current());
+ fixture.setIndex("fixture".length() - 1);
+ assertEquals('e', fixture.current());
+ try {
+ fixture.setIndex(-1);
+ fail("no illegal argument");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ fixture.setIndex("fixture".length() + 1);
+ fail("no illegal argument");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator.setText(String)
+ */
+ public void test_setText() {
+ StringCharacterIterator fixture = new StringCharacterIterator("fixture");
+ fixture.setText("fix");
+ assertEquals('f', fixture.current());
+ assertEquals('x', fixture.last());
+
+ try {
+ fixture.setText(null);
+ fail("no null pointer");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#StringCharacterIterator(java.lang.String)
+ */
+ public void test_ConstructorLjava_lang_String() {
+ assertNotNull(new StringCharacterIterator("value"));
+ assertNotNull(new StringCharacterIterator(""));
+ try {
+ new StringCharacterIterator(null);
+ fail("Assert 0: no null pointer");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ StringCharacterIterator it = new StringCharacterIterator("testing");
+ assertEquals("Wrong begin index", 0, it.getBeginIndex());
+ assertEquals("Wrong end index", 7, it.getEndIndex());
+ assertEquals("Wrong current index", 0, it.getIndex());
+ assertEquals("Wrong current char", 't', it.current());
+ assertEquals("Wrong next char", 'e', it.next());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#StringCharacterIterator(java.lang.String,
+ * int)
+ */
+ public void test_ConstructorLjava_lang_StringI() {
+ StringCharacterIterator it = new StringCharacterIterator("testing", 3);
+ assertEquals("Wrong begin index", 0, it.getBeginIndex());
+ assertEquals("Wrong end index", 7, it.getEndIndex());
+ assertEquals("Wrong current index", 3, it.getIndex());
+ assertEquals("Wrong current char", 't', it.current());
+ assertEquals("Wrong next char", 'i', it.next());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#StringCharacterIterator(java.lang.String,
+ * int, int, int)
+ */
+ public void test_ConstructorLjava_lang_StringIII() {
+ StringCharacterIterator it = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong begin index", 2, it.getBeginIndex());
+ assertEquals("Wrong end index", 6, it.getEndIndex());
+ assertEquals("Wrong current index", 4, it.getIndex());
+ assertEquals("Wrong current char", 'i', it.current());
+ assertEquals("Wrong next char", 'n', it.next());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#getIndex()
+ */
+ public void test_getIndex() {
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong index 4", 4, it1.getIndex());
+ it1.next();
+ assertEquals("Wrong index 5", 5, it1.getIndex());
+ it1.last();
+ assertEquals("Wrong index 4/2", 5, it1.getIndex());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#hashCode()
+ */
+ public void test_hashCode() {
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ StringCharacterIterator it2 = new StringCharacterIterator("xxstinx", 2,
+ 6, 4);
+ assertTrue("Hash is equal", it1.hashCode() != it2.hashCode());
+ StringCharacterIterator it3 = new StringCharacterIterator("testing", 2,
+ 6, 2);
+ assertTrue("Hash equal1", it1.hashCode() != it3.hashCode());
+ it3 = new StringCharacterIterator("testing", 0, 6, 4);
+ assertTrue("Hash equal2", it1.hashCode() != it3.hashCode());
+ it3 = new StringCharacterIterator("testing", 2, 5, 4);
+ assertTrue("Hash equal3", it1.hashCode() != it3.hashCode());
+ it3 = new StringCharacterIterator("froging", 2, 6, 4);
+ assertTrue("Hash equal4", it1.hashCode() != it3.hashCode());
+
+ StringCharacterIterator sci0 = new StringCharacterIterator("fixture");
+ assertEquals(sci0.hashCode(), sci0.hashCode());
+
+ StringCharacterIterator sci1 = new StringCharacterIterator("fixture");
+ assertEquals(sci0.hashCode(), sci1.hashCode());
+
+ sci1.next();
+ sci0.next();
+ assertEquals(sci0.hashCode(), sci1.hashCode());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#last()
+ */
+ public void test_last() {
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 3);
+ assertEquals("Wrong last char", 'n', it1.last());
+ assertEquals("Wrong previous char", 'i', it1.previous());
+ it1 = new StringCharacterIterator("testing", 2, 2, 2);
+ assertTrue("Not DONE", it1.last() == CharacterIterator.DONE);
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#setIndex(int)
+ */
+ public void test_setIndexI() {
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ assertEquals("Wrong result1", 's', it1.setIndex(2));
+ char result = it1.next();
+ assertTrue("Wrong next char: " + result, result == 't');
+ assertTrue("Wrong result2", it1.setIndex(6) == CharacterIterator.DONE);
+ assertEquals("Wrong previous char", 'n', it1.previous());
+ }
+
+ /**
+ * @tests java.text.StringCharacterIterator#setText(java.lang.String)
+ */
+ public void test_setTextLjava_lang_String() {
+ StringCharacterIterator it1 = new StringCharacterIterator("testing", 2,
+ 6, 4);
+ it1.setText("frog");
+ assertEquals("Wrong begin index", 0, it1.getBeginIndex());
+ assertEquals("Wrong end index", 4, it1.getEndIndex());
+ assertEquals("Wrong current index", 0, it1.getIndex());
+ }
+}
diff --git a/text/src/test/java/tests/text/AllTests.java b/text/src/test/java/tests/text/AllTests.java
new file mode 100644
index 0000000..7162c4d
--- /dev/null
+++ b/text/src/test/java/tests/text/AllTests.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 tests.text;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all tests for the Text project.
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(AllTests.suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite("All Text test suites");
+ // $JUnit-BEGIN$
+ suite.addTest(org.apache.harmony.text.tests.java.text.AllTests.suite());
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/text/src/test/resources/serialization/java/text/DecimalFormat.ser b/text/src/test/resources/serialization/java/text/DecimalFormat.ser
new file mode 100644
index 0000000..c20fa78
--- /dev/null
+++ b/text/src/test/resources/serialization/java/text/DecimalFormat.ser
Binary files differ
diff --git a/text/src/test/resources/serialization/java/text/DecimalFormatSymbols.ser b/text/src/test/resources/serialization/java/text/DecimalFormatSymbols.ser
new file mode 100644
index 0000000..6e086af
--- /dev/null
+++ b/text/src/test/resources/serialization/java/text/DecimalFormatSymbols.ser
Binary files differ