diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java index ff31589a0..92d33b847 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TAbstractList.java @@ -42,15 +42,23 @@ public abstract class TAbstractList extends TAbstractCollection implements private int index; private int modCount = TAbstractList.this.modCount; private int size = size(); + private int removeIndex = -1; @Override public boolean hasNext() { return index < size; } @Override public E next() { checkConcurrentModification(); + removeIndex = index; return get(index++); } @Override public void remove() { + if (removeIndex < 0) { + throw new TIllegalStateException(); + } TAbstractList.this.remove(index - 1); + modCount = TAbstractList.this.modCount; + --index; + removeIndex = -1; } private void checkConcurrentModification() { if (modCount < TAbstractList.this.modCount) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TDictionary.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TDictionary.java new file mode 100644 index 000000000..16993c71f --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TDictionary.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.java.util; + +import org.teavm.classlib.java.lang.TObject; + +public abstract class TDictionary extends TObject { + public TDictionary() { + super(); + } + + public abstract TEnumeration elements(); + + public abstract V get(Object key); + + public abstract boolean isEmpty(); + + public abstract TEnumeration keys(); + + public abstract V put(K key, V value); + + public abstract V remove(Object key); + + public abstract int size(); +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/THashtable.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/THashtable.java new file mode 100644 index 000000000..aec216a5d --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/THashtable.java @@ -0,0 +1,773 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.java.util; + +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneNotSupportedException; +import org.teavm.classlib.java.lang.TCloneable; +import org.teavm.classlib.java.lang.TNullPointerException; +import org.teavm.classlib.java.lang.TUnsupportedOperationException; + +public class THashtable extends TDictionary implements TMap, + TCloneable, TSerializable { + + transient int elementCount; + + transient Entry[] elementData; + + private float loadFactor; + + private int threshold; + + transient int firstSlot; + + transient int lastSlot = -1; + + transient int modCount; + + private static final TEnumeration EMPTY_ENUMERATION = new TEnumeration() { + @Override + public boolean hasMoreElements() { + return false; + } + + @Override + public Object nextElement() { + throw new TNoSuchElementException(); + } + }; + + private static final TIterator EMPTY_ITERATOR = new TIterator() { + + @Override + public boolean hasNext() { + return false; + } + + @Override + public Object next() { + throw new TNoSuchElementException(); + } + + @Override + public void remove() { + throw new IllegalStateException(); + } + }; + + private static Entry newEntry(K key, V value, @SuppressWarnings("unused") int hash) { + return new Entry<>(key, value); + } + + private static class Entry extends TMapEntry { + Entry next; + + final int hashcode; + + Entry(K theKey, V theValue) { + super(theKey, theValue); + hashcode = theKey.hashCode(); + } + + @Override + @SuppressWarnings("unchecked") + public Object clone() { + Entry entry = (Entry) super.clone(); + if (next != null) { + entry.next = (Entry) next.clone(); + } + return entry; + } + + @Override + public V setValue(V object) { + if (object == null) { + throw new NullPointerException(); + } + V result = value; + value = object; + return result; + } + + public int getKeyHash() { + return key.hashCode(); + } + + public boolean equalsKey(Object aKey, @SuppressWarnings("unused") int hash) { + return hashcode == aKey.hashCode() && key.equals(aKey); + } + + @Override + public String toString() { + return key + "=" + value; + } + } + + private class HashIterator implements TIterator { + int position, expectedModCount; + + final TMapEntry.Type type; + + Entry lastEntry; + + int lastPosition; + + boolean canRemove = false; + + HashIterator(TMapEntry.Type value) { + type = value; + position = lastSlot; + expectedModCount = modCount; + } + + @Override + public boolean hasNext() { + if (lastEntry != null && lastEntry.next != null) { + return true; + } + while (position >= firstSlot) { + if (elementData[position] == null) { + position--; + } else { + return true; + } + } + return false; + } + + @Override + public E next() { + if (expectedModCount == modCount) { + if (lastEntry != null) { + lastEntry = lastEntry.next; + } + if (lastEntry == null) { + while (position >= firstSlot + && (lastEntry = elementData[position]) == null) { + position--; + } + if (lastEntry != null) { + lastPosition = position; + // decrement the position so we don't find the same slot + // next time + position--; + } + } + if (lastEntry != null) { + canRemove = true; + return type.get(lastEntry); + } + throw new TNoSuchElementException(); + } + throw new TConcurrentModificationException(); + } + + @Override + public void remove() { + if (expectedModCount == modCount) { + if (canRemove) { + canRemove = false; + synchronized (THashtable.this) { + boolean removed = false; + Entry entry = elementData[lastPosition]; + if (entry == lastEntry) { + elementData[lastPosition] = entry.next; + removed = true; + } else { + while (entry != null && entry.next != lastEntry) { + entry = entry.next; + } + if (entry != null) { + entry.next = lastEntry.next; + removed = true; + } + } + if (removed) { + modCount++; + elementCount--; + expectedModCount++; + return; + } + // the entry must have been (re)moved outside of the + // iterator + // but this condition wasn't caught by the modCount + // check + // throw ConcurrentModificationException() outside of + // synchronized block + } + } else { + throw new IllegalStateException(); + } + } + throw new TConcurrentModificationException(); + } + } + + public THashtable() { + this(11); + } + + public THashtable(int capacity) { + if (capacity >= 0) { + elementCount = 0; + elementData = newElementArray(capacity == 0 ? 1 : capacity); + firstSlot = elementData.length; + loadFactor = 0.75f; + computeMaxSize(); + } else { + throw new IllegalArgumentException(); + } + } + + public THashtable(int capacity, float loadFactor) { + if (capacity >= 0 && loadFactor > 0) { + elementCount = 0; + firstSlot = capacity; + elementData = newElementArray(capacity == 0 ? 1 : capacity); + this.loadFactor = loadFactor; + computeMaxSize(); + } else { + throw new IllegalArgumentException(); + } + } + + public THashtable(TMap map) { + this(map.size() < 6 ? 11 : (map.size() * 4 / 3) + 11); + putAll(map); + } + + @SuppressWarnings("unchecked") + private Entry[] newElementArray(int size) { + return new Entry[size]; + } + + @Override + public synchronized void clear() { + elementCount = 0; + Arrays.fill(elementData, null); + modCount++; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized Object clone() { + try { + THashtable hashtable = (THashtable) super.clone(); + hashtable.elementData = new Entry[elementData.length]; + Entry entry; + for (int i = elementData.length; --i >= 0;) { + if ((entry = elementData[i]) != null) { + hashtable.elementData[i] = (Entry) entry.clone(); + } + } + return hashtable; + } catch (TCloneNotSupportedException e) { + return null; + } + } + + private void computeMaxSize() { + threshold = (int) (elementData.length * loadFactor); + } + + public synchronized boolean contains(Object value) { + if (value == null) { + throw new TNullPointerException(); + } + + for (int i = elementData.length; --i >= 0;) { + Entry entry = elementData[i]; + while (entry != null) { + if (entry.value.equals(value)) { + return true; + } + entry = entry.next; + } + } + return false; + } + + @Override + public synchronized boolean containsKey(Object key) { + return getEntry(key) != null; + } + + @Override + public boolean containsValue(Object value) { + return contains(value); + } + + @Override + @SuppressWarnings("unchecked") + public synchronized TEnumeration elements() { + if (elementCount == 0) { + return (TEnumeration) EMPTY_ENUMERATION; + } + return new HashEnumIterator<>(new TMapEntry.Type() { + @Override + public V get(TMapEntry entry) { + return entry.value; + } + }, true); + } + + @Override + public TSet> entrySet() { + return new TAbstractSet>() { + @Override + public int size() { + return elementCount; + } + + @Override + public void clear() { + THashtable.this.clear(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean remove(Object object) { + if (contains(object)) { + THashtable.this.remove(((TMap.Entry) object) + .getKey()); + return true; + } + return false; + } + + @Override + @SuppressWarnings("unchecked") + public boolean contains(Object object) { + Entry entry = getEntry(((TMap.Entry) object) + .getKey()); + return object.equals(entry); + } + + @Override + public TIterator> iterator() { + return new HashIterator<>( + new TMapEntry.Type, K, V>() { + @Override + public TMap.Entry get( + TMapEntry entry) { + return entry; + } + }); + } + }; + } + + @Override + public synchronized boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof TMap) { + TMap map = (TMap) object; + if (size() != map.size()) { + return false; + } + + TSet> entries = entrySet(); + for (TIterator> iter = map.entrySet().iterator(); iter.hasNext();) { + TMap.Entry e = iter.next(); + if (!entries.contains(e)) { + return false; + } + } + return true; + } + return false; + } + + @Override + public synchronized V get(Object key) { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + Entry entry = elementData[index]; + while (entry != null) { + if (entry.equalsKey(key, hash)) { + return entry.value; + } + entry = entry.next; + } + return null; + } + + Entry getEntry(Object key) { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + Entry entry = elementData[index]; + while (entry != null) { + if (entry.equalsKey(key, hash)) { + return entry; + } + entry = entry.next; + } + return null; + } + + @Override + public synchronized int hashCode() { + int result = 0; + TIterator> it = entrySet().iterator(); + while (it.hasNext()) { + TMap.Entry entry = it.next(); + Object key = entry.getKey(); + if (key == this) { + continue; + } + Object value = entry.getValue(); + if (value == this) { + continue; + } + int hash = (key != null ? key.hashCode() : 0) + ^ (value != null ? value.hashCode() : 0); + result += hash; + } + return result; + } + + @Override + public synchronized boolean isEmpty() { + return elementCount == 0; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized TEnumeration keys() { + if (elementCount == 0) { + return (TEnumeration) EMPTY_ENUMERATION; + } + return new HashEnumIterator<>(new TMapEntry.Type() { + @Override + public K get(TMapEntry entry) { + return entry.key; + } + }, true); + } + + @Override + public TSet keySet() { + return new TAbstractSet() { + @Override + public boolean contains(Object object) { + return containsKey(object); + } + + @Override + public int size() { + return elementCount; + } + + @Override + public void clear() { + THashtable.this.clear(); + } + + @Override + public boolean remove(Object key) { + if (containsKey(key)) { + THashtable.this.remove(key); + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + @Override + public TIterator iterator() { + if (this.size() == 0) { + return (TIterator) EMPTY_ITERATOR; + } + return new HashEnumIterator<>(new TMapEntry.Type() { + @Override + public K get(TMapEntry entry) { + return entry.key; + } + }); + } + }; + } + + class HashEnumIterator extends HashIterator implements TEnumeration { + + private boolean isEnumeration = false; + + int start; + + Entry entry; + + HashEnumIterator(TMapEntry.Type value) { + super(value); + } + + HashEnumIterator(TMapEntry.Type value, boolean isEnumeration) { + super(value); + this.isEnumeration = isEnumeration; + start = lastSlot + 1; + } + + @Override + public boolean hasMoreElements() { + if (isEnumeration) { + if (entry != null) { + return true; + } + while (start > firstSlot) { + if (elementData[--start] != null) { + entry = elementData[start]; + return true; + } + } + return false; + } + // iterator + return super.hasNext(); + } + + @Override + public boolean hasNext() { + if (isEnumeration) { + return hasMoreElements(); + } + // iterator + return super.hasNext(); + } + + @Override + public E next() { + if (isEnumeration) { + if (expectedModCount == modCount) { + return nextElement(); + } else { + throw new TConcurrentModificationException(); + } + } + // iterator + return super.next(); + } + + @Override + @SuppressWarnings("unchecked") + public E nextElement() { + if (isEnumeration) { + if (hasMoreElements()) { + Object result = type.get(entry); + entry = entry.next; + return (E) result; + } + throw new TNoSuchElementException(); + } + // iterator + return super.next(); + } + + @Override + public void remove() { + if (isEnumeration) { + throw new TUnsupportedOperationException(); + } else { + super.remove(); + } + } + } + + @Override + public synchronized V put(K key, V value) { + if (key != null && value != null) { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + Entry entry = elementData[index]; + while (entry != null && !entry.equalsKey(key, hash)) { + entry = entry.next; + } + if (entry == null) { + modCount++; + if (++elementCount > threshold) { + rehash(); + index = (hash & 0x7FFFFFFF) % elementData.length; + } + if (index < firstSlot) { + firstSlot = index; + } + if (index > lastSlot) { + lastSlot = index; + } + entry = newEntry(key, value, hash); + entry.next = elementData[index]; + elementData[index] = entry; + return null; + } + V result = entry.value; + entry.value = value; + return result; + } + throw new NullPointerException(); + } + + @Override + public synchronized void putAll(TMap map) { + for (TIterator> iter = map.entrySet().iterator(); + iter.hasNext();) { + TMap.Entry entry = iter.next(); + put(entry.getKey(), entry.getValue()); + } + } + + protected void rehash() { + int length = (elementData.length << 1) + 1; + if (length == 0) { + length = 1; + } + int newFirst = length; + int newLast = -1; + Entry[] newData = newElementArray(length); + for (int i = lastSlot + 1; --i >= firstSlot;) { + Entry entry = elementData[i]; + while (entry != null) { + int index = (entry.getKeyHash() & 0x7FFFFFFF) % length; + if (index < newFirst) { + newFirst = index; + } + if (index > newLast) { + newLast = index; + } + Entry next = entry.next; + entry.next = newData[index]; + newData[index] = entry; + entry = next; + } + } + firstSlot = newFirst; + lastSlot = newLast; + elementData = newData; + computeMaxSize(); + } + + @Override + public synchronized V remove(Object key) { + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % elementData.length; + Entry last = null; + Entry entry = elementData[index]; + while (entry != null && !entry.equalsKey(key, hash)) { + last = entry; + entry = entry.next; + } + if (entry != null) { + modCount++; + if (last == null) { + elementData[index] = entry.next; + } else { + last.next = entry.next; + } + elementCount--; + V result = entry.value; + entry.value = null; + return result; + } + return null; + } + + @Override + public synchronized int size() { + return elementCount; + } + + @Override + public synchronized String toString() { + if (isEmpty()) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(size() * 28); + buffer.append('{'); + for (int i = lastSlot; i >= firstSlot; i--) { + Entry entry = elementData[i]; + while (entry != null) { + if (entry.key != this) { + buffer.append(entry.key); + } else { + buffer.append("(this Map)"); + } + buffer.append('='); + if (entry.value != this) { + buffer.append(entry.value); + } else { + buffer.append("(this Map)"); + } + buffer.append(", "); //$NON-NLS-1$ + entry = entry.next; + } + } + // Remove the last ", " + if (elementCount > 0) { + buffer.setLength(buffer.length() - 2); + } + buffer.append('}'); + return buffer.toString(); + } + + @Override + public TCollection values() { + return new TAbstractCollection() { + @Override + public boolean contains(Object object) { + return THashtable.this.contains(object); + } + + @Override + public int size() { + return elementCount; + } + + @Override + public void clear() { + THashtable.this.clear(); + } + + @Override + public TIterator iterator() { + return new HashIterator<>( + new TMapEntry.Type() { + @Override + public V get(TMapEntry entry) { + return entry.value; + } + }); + } + }; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TVector.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TVector.java new file mode 100644 index 000000000..ebe4e2ff3 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TVector.java @@ -0,0 +1,552 @@ +/* + * 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. + */ +/* + * 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.teavm.classlib.java.util; + +import java.lang.reflect.Array; +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneNotSupportedException; +import org.teavm.classlib.java.lang.TCloneable; + +public class TVector extends TAbstractList implements TList, TRandomAccess, TCloneable, TSerializable { + protected int elementCount; + protected Object[] elementData; + protected int capacityIncrement; + private static final int DEFAULT_SIZE = 10; + + public TVector() { + this(DEFAULT_SIZE, 0); + } + + public TVector(int capacity) { + this(capacity, 0); + } + + public TVector(int capacity, int capacityIncrement) { + if (capacity < 0) { + throw new IllegalArgumentException(); + } + elementData = newElementArray(capacity); + elementCount = 0; + this.capacityIncrement = capacityIncrement; + } + + public TVector(TCollection collection) { + this(collection.size(), 0); + TIterator it = collection.iterator(); + while (it.hasNext()) { + elementData[elementCount++] = it.next(); + } + } + + @SuppressWarnings("unchecked") + private E[] newElementArray(int size) { + return (E[]) new Object[size]; + } + + @Override + public void add(int location, E object) { + insertElementAt(object, location); + } + + @Override + public synchronized boolean add(E object) { + if (elementCount == elementData.length) { + growByOne(); + } + elementData[elementCount++] = object; + modCount++; + return true; + } + + @Override + public synchronized boolean addAll(int location, TCollection collection) { + if (0 <= location && location <= elementCount) { + int size = collection.size(); + if (size == 0) { + return false; + } + int required = size - (elementData.length - elementCount); + if (required > 0) { + growBy(required); + } + int count = elementCount - location; + if (count > 0) { + System.arraycopy(elementData, location, elementData, location + size, count); + } + TIterator it = collection.iterator(); + while (it.hasNext()) { + elementData[location++] = it.next(); + } + elementCount += size; + modCount++; + return true; + } + throw new ArrayIndexOutOfBoundsException(location); + } + + @Override + public synchronized boolean addAll(TCollection collection) { + return addAll(elementCount, collection); + } + + public synchronized void addElement(E object) { + if (elementCount == elementData.length) { + growByOne(); + } + elementData[elementCount++] = object; + modCount++; + } + + public synchronized int capacity() { + return elementData.length; + } + + @Override + public void clear() { + removeAllElements(); + } + + @Override + @SuppressWarnings("unchecked") + public synchronized Object clone() { + try { + TVector vector = (TVector) super.clone(); + vector.elementData = elementData.clone(); + return vector; + } catch (TCloneNotSupportedException e) { + return null; + } + } + + @Override + public boolean contains(Object object) { + return indexOf(object, 0) != -1; + } + + @Override + public synchronized boolean containsAll(TCollection collection) { + return super.containsAll(collection); + } + + public synchronized void copyInto(Object[] elements) { + System.arraycopy(elementData, 0, elements, 0, elementCount); + } + + @SuppressWarnings("unchecked") + public synchronized E elementAt(int location) { + if (location < elementCount) { + return (E) elementData[location]; + } + throw new ArrayIndexOutOfBoundsException(location); + } + + public TEnumeration elements() { + return new TEnumeration() { + int pos = 0; + + @Override + public boolean hasMoreElements() { + return pos < elementCount; + } + + @Override + @SuppressWarnings("unchecked") + public E nextElement() { + synchronized (TVector.this) { + if (pos < elementCount) { + return (E) elementData[pos++]; + } + } + throw new TNoSuchElementException(); + } + }; + } + + public synchronized void ensureCapacity(int minimumCapacity) { + if (elementData.length < minimumCapacity) { + int next = (capacityIncrement <= 0 ? elementData.length : capacityIncrement) + elementData.length; + grow(minimumCapacity > next ? minimumCapacity : next); + } + } + + @Override + public synchronized boolean equals(Object object) { + if (this == object) { + return true; + } + if (object instanceof TList) { + TList list = (TList) object; + if (list.size() != elementCount) { + return false; + } + + int index = 0; + TIterator it = list.iterator(); + while (it.hasNext()) { + Object e1 = elementData[index++], e2 = it.next(); + if (!(e1 == null ? e2 == null : e1.equals(e2))) { + return false; + } + } + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + public synchronized E firstElement() { + if (elementCount > 0) { + return (E) elementData[0]; + } + throw new TNoSuchElementException(); + } + + @Override + public E get(int location) { + return elementAt(location); + } + + private void grow(int newCapacity) { + E[] newData = newElementArray(newCapacity); + // Assumes elementCount is <= newCapacity + assert elementCount <= newCapacity; + System.arraycopy(elementData, 0, newData, 0, elementCount); + elementData = newData; + } + + /** + * JIT optimization + */ + private void growByOne() { + int adding = 0; + if (capacityIncrement <= 0) { + if ((adding = elementData.length) == 0) { + adding = 1; + } + } else { + adding = capacityIncrement; + } + + E[] newData = newElementArray(elementData.length + adding); + System.arraycopy(elementData, 0, newData, 0, elementCount); + elementData = newData; + } + + private void growBy(int required) { + int adding = 0; + if (capacityIncrement <= 0) { + if ((adding = elementData.length) == 0) { + adding = required; + } + while (adding < required) { + adding += adding; + } + } else { + adding = (required / capacityIncrement) * capacityIncrement; + if (adding < required) { + adding += capacityIncrement; + } + } + E[] newData = newElementArray(elementData.length + adding); + System.arraycopy(elementData, 0, newData, 0, elementCount); + elementData = newData; + } + + @Override + public synchronized int hashCode() { + int result = 1; + for (int i = 0; i < elementCount; i++) { + result = (31 * result) + (elementData[i] == null ? 0 : elementData[i].hashCode()); + } + return result; + } + + @Override + public int indexOf(Object object) { + return indexOf(object, 0); + } + + public synchronized int indexOf(Object object, int location) { + if (location < 0) { + throw new ArrayIndexOutOfBoundsException(); + } + if (object != null) { + for (int i = location; i < elementCount; i++) { + if (object.equals(elementData[i])) { + return i; + } + } + } else { + for (int i = location; i < elementCount; i++) { + if (elementData[i] == null) { + return i; + } + } + } + return -1; + } + + public synchronized void insertElementAt(E object, int location) { + if (0 <= location && location <= elementCount) { + if (elementCount == elementData.length) { + growByOne(); + } + int count = elementCount - location; + if (count > 0) { + System.arraycopy(elementData, location, elementData, location + 1, count); + } + elementData[location] = object; + elementCount++; + modCount++; + } else { + throw new ArrayIndexOutOfBoundsException(location); + } + } + + @Override + public synchronized boolean isEmpty() { + return elementCount == 0; + } + + @SuppressWarnings("unchecked") + public synchronized E lastElement() { + if (isEmpty()) { + throw new TNoSuchElementException(); + } + return (E) elementData[elementCount - 1]; + } + + @Override + public synchronized int lastIndexOf(Object object) { + return lastIndexOf(object, elementCount - 1); + } + + public synchronized int lastIndexOf(Object object, int location) { + if (location < 0) { + return -1; + } else if (location < elementCount) { + if (object != null) { + for (int i = location; i >= 0; i--) { + if (object.equals(elementData[i])) { + return i; + } + } + } else { + for (int i = location; i >= 0; i--) { + if (elementData[i] == null) { + return i; + } + } + } + return -1; + } + throw new ArrayIndexOutOfBoundsException(location); + } + + @SuppressWarnings("unchecked") + @Override + public synchronized E remove(int location) { + if (location < elementCount && location >= 0) { + E result = (E) elementData[location]; + elementCount--; + int size = elementCount - location; + if (size > 0) { + System.arraycopy(elementData, location + 1, elementData, location, size); + } + elementData[elementCount] = null; + modCount++; + return result; + } + throw new ArrayIndexOutOfBoundsException(location); + } + + @Override + public boolean remove(Object object) { + return removeElement(object); + } + + @Override + public synchronized boolean removeAll(TCollection collection) { + return super.removeAll(collection); + } + + public synchronized void removeAllElements() { + for (int i = 0; i < elementCount; i++) { + elementData[i] = null; + } + modCount++; + elementCount = 0; + } + + public synchronized boolean removeElement(Object object) { + int index; + if ((index = indexOf(object, 0)) == -1) { + return false; + } + removeElementAt(index); + return true; + } + + public synchronized void removeElementAt(int location) { + if (0 <= location && location < elementCount) { + elementCount--; + int size = elementCount - location; + if (size > 0) { + System.arraycopy(elementData, location + 1, elementData, location, size); + } + elementData[elementCount] = null; + modCount++; + } else { + throw new ArrayIndexOutOfBoundsException(location); + } + } + + @Override + protected void removeRange(int start, int end) { + if (start >= 0 && start <= end && end <= elementCount) { + if (start == end) { + return; + } + if (end != elementCount) { + System.arraycopy(elementData, end, elementData, start, elementCount - end); + int newCount = elementCount - (end - start); + Arrays.fill(elementData, newCount, elementCount, null); + elementCount = newCount; + } else { + Arrays.fill(elementData, start, elementCount, null); + elementCount = start; + } + modCount++; + } else { + throw new IndexOutOfBoundsException(); + } + } + + @Override + public synchronized boolean retainAll(TCollection collection) { + return super.retainAll(collection); + } + + @SuppressWarnings("unchecked") + @Override + public synchronized E set(int location, E object) { + if (location >= 0 && location < elementCount) { + E result = (E) elementData[location]; + elementData[location] = object; + return result; + } + throw new ArrayIndexOutOfBoundsException(location); + } + + public synchronized void setElementAt(E object, int location) { + if (location < elementCount && location >= 0) { + elementData[location] = object; + } else { + throw new ArrayIndexOutOfBoundsException(location); + } + } + + public synchronized void setSize(int length) { + if (length < 0) { + throw new ArrayIndexOutOfBoundsException(); + } + if (length == elementCount) { + return; + } + ensureCapacity(length); + if (elementCount > length) { + Arrays.fill(elementData, length, elementCount, null); + } + elementCount = length; + modCount++; + } + + @Override + public synchronized int size() { + return elementCount; + } + + @Override + public synchronized Object[] toArray() { + Object[] result = new Object[elementCount]; + System.arraycopy(elementData, 0, result, 0, elementCount); + return result; + } + + @Override + @SuppressWarnings("unchecked") + public synchronized T[] toArray(T[] contents) { + if (elementCount > contents.length) { + Class ct = contents.getClass().getComponentType(); + contents = (T[]) Array.newInstance(ct, elementCount); + } + System.arraycopy(elementData, 0, contents, 0, elementCount); + if (elementCount < contents.length) { + contents[elementCount] = null; + } + return contents; + } + + @Override + public synchronized String toString() { + if (elementCount == 0) { + return "[]"; //$NON-NLS-1$ + } + int length = elementCount - 1; + StringBuilder buffer = new StringBuilder(elementCount * 16); + buffer.append('['); + for (int i = 0; i < length; i++) { + if (elementData[i] == this) { + buffer.append("(this Collection)"); + } else { + buffer.append(elementData[i]); + } + buffer.append(", "); + } + if (elementData[length] == this) { + buffer.append("(this Collection)"); + } else { + buffer.append(elementData[length]); + } + buffer.append(']'); + return buffer.toString(); + } + + public synchronized void trimToSize() { + if (elementData.length != elementCount) { + grow(elementCount); + } + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/HashtableTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/HashtableTest.java new file mode 100644 index 000000000..95a5581bb --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/HashtableTest.java @@ -0,0 +1,719 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.java.util; + +import static org.junit.Assert.*; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.TreeMap; +import java.util.Vector; +import org.junit.Test; +import org.teavm.classlib.support.Support_MapTest2; +import org.teavm.classlib.support.Support_UnmodifiableCollectionTest; + +public class HashtableTest { + + private Hashtable ht10; + + private Hashtable ht100; + + private Hashtable htfull; + + private Vector keyVector; + + private Vector elmVector; + + public HashtableTest() { + ht10 = new Hashtable<>(10); + ht100 = new Hashtable<>(100); + htfull = new Hashtable<>(10); + keyVector = new Vector<>(10); + elmVector = new Vector<>(10); + + for (int i = 0; i < 10; i++) { + ht10.put("Key " + i, "Val " + i); + keyVector.addElement("Key " + i); + elmVector.addElement("Val " + i); + } + + for (int i = 0; i < 7; i++) + htfull.put("FKey " + i, "FVal " + i); + } + + @Test + public void test_Constructor() { + // Test for method java.util.Hashtable() + new Support_MapTest2(new Hashtable()).runTest(); + + Hashtable h = new Hashtable<>(); + + assertEquals("Created incorrect hashtable", 0, h.size()); + } + + @Test + public void test_ConstructorI() { + // Test for method java.util.Hashtable(int) + Hashtable h = new Hashtable<>(9); + + assertEquals("Created incorrect hashtable", 0, h.size()); + + Hashtable empty = new Hashtable<>(0); + assertNull("Empty hashtable access", empty.get("nothing")); + empty.put("something", "here"); + assertEquals("cannot get element", "here", empty.get("something")); + } + + @Test + public void test_ConstructorIF() { + // Test for method java.util.Hashtable(int, float) + Hashtable h = new Hashtable<>(10, 0.5f); + assertEquals("Created incorrect hashtable", 0, h.size()); + + Hashtable empty = new Hashtable<>(0, 0.75f); + assertNull("Empty hashtable access", empty.get("nothing")); + empty.put("something", "here"); + assertEquals("cannot get element", "here", empty.get("something")); + } + + @Test + public void test_ConstructorLjava_util_Map() { + // Test for method java.util.Hashtable(java.util.Map) + Map map = new TreeMap<>(); + Object firstVal = "Gabba"; + Object secondVal = new Integer(5); + map.put("Gah", firstVal); + map.put("Ooga", secondVal); + Hashtable ht = new Hashtable<>(map); + assertSame("a) Incorrect Hashtable constructed", firstVal, ht.get("Gah")); + assertSame("b) Incorrect Hashtable constructed", secondVal, ht.get("Ooga")); + } + + public void test_HashTable_Constructor() { + Hashtable, Set>> hashTable = new Hashtable<>(); + hashTable.put(hashTable, hashTable.keySet()); + new Hashtable<>(hashTable); + } + + @Test + public void test_clear() { + // Test for method void java.util.Hashtable.clear() + Hashtable h = hashtableClone(htfull); + h.clear(); + assertEquals("Hashtable was not cleared", 0, h.size()); + Enumeration el = h.elements(); + Enumeration keys = h.keys(); + assertTrue("Hashtable improperly cleared", !el.hasMoreElements() && !(keys.hasMoreElements())); + } + + @Test + public void test_clone() { + // Test for method java.lang.Object java.util.Hashtable.clone() + + @SuppressWarnings("unchecked") + Hashtable h = (Hashtable) htfull.clone(); + assertTrue("Clone different size than original", h.size() == htfull.size()); + + Enumeration org = htfull.keys(); + Enumeration cpy = h.keys(); + + String okey, ckey; + while (org.hasMoreElements()) { + assertTrue("Key comparison failed", (okey = org.nextElement()).equals(ckey = cpy.nextElement())); + assertTrue("Value comparison failed", (htfull.get(okey)).equals(h.get(ckey))); + } + assertTrue("Copy has more keys than original", !cpy.hasMoreElements()); + } + + @Test + public void test_containsLjava_lang_Object() { + // Test for method boolean + // java.util.Hashtable.contains(java.lang.Object) + assertTrue("Element not found", ht10.contains("Val 7")); + assertTrue("Invalid element found", !ht10.contains("ZZZZZZZZZZZZZZZZ")); + } + + @Test + public void test_containsKeyLjava_lang_Object() { + // Test for method boolean + // java.util.Hashtable.containsKey(java.lang.Object) + + assertTrue("Failed to find key", htfull.containsKey("FKey 4")); + assertTrue("Failed to find key", !htfull.containsKey("FKey 99")); + } + + @Test + public void test_containsValueLjava_lang_Object() { + // Test for method boolean + // java.util.Hashtable.containsValue(java.lang.Object) + Enumeration e = elmVector.elements(); + while (e.hasMoreElements()) + assertTrue("Returned false for valid value", ht10.containsValue(e.nextElement())); + assertTrue("Returned true for invalid value", !ht10.containsValue(new Object())); + } + + @Test + public void test_elements() { + // Test for method java.util.Enumeration java.util.Hashtable.elements() + Enumeration elms = ht10.elements(); + while (elms.hasMoreElements()) { + String s = elms.nextElement(); + assertTrue("Missing key from enumeration", elmVector.contains(s)); + } + + assertEquals("All keys not retrieved", 10, ht10.size()); + + // cast Enumeration to Iterator + @SuppressWarnings("unchecked") + Iterator iterator = (Iterator) elms; + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + } + + @Test + public void test_elements_subtest0() { + // this is the reference implementation behavior + final Hashtable ht = new Hashtable<>(7); + ht.put("1", "a"); + // these three elements hash to the same bucket in a 7 element Hashtable + ht.put("2", "b"); + ht.put("9", "c"); + ht.put("12", "d"); + // Hashtable looks like: + // 0: "1" + // 1: "12" -> "9" -> "2" + Enumeration en = ht.elements(); + // cache the first entry + en.hasMoreElements(); + ht.remove("12"); + ht.remove("9"); + } + + @Test + public void test_entrySet() { + // Test for method java.util.Set java.util.Hashtable.entrySet() + Set> s = ht10.entrySet(); + Set s2 = new HashSet<>(); + for (Map.Entry entry : s) { + s2.add(entry.getValue()); + } + Enumeration e = elmVector.elements(); + while (e.hasMoreElements()) + assertTrue("Returned incorrect entry set", s2.contains(e.nextElement())); + + boolean exception = false; + try { + (ht10.entrySet().iterator().next()).setValue(null); + } catch (NullPointerException e1) { + exception = true; + } + assertTrue("Should not be able to assign null to a Hashtable entrySet() Map.Entry", exception); + } + + @Test + public void test_equalsLjava_lang_Object() { + // Test for method boolean java.util.Hashtable.equals(java.lang.Object) + Hashtable h = hashtableClone(ht10); + assertTrue("Returned false for equal tables", ht10.equals(h)); + assertTrue("Returned true for unequal tables", !ht10.equals(htfull)); + } + + @Test + public void test_getLjava_lang_Object() { + // Test for method java.lang.Object + // java.util.Hashtable.get(java.lang.Object) + Hashtable h = hashtableClone(htfull); + assertEquals("Could not retrieve element", "FVal 2", h.get("FKey 2")); + + // Regression for HARMONY-262 + ReusableKey k = new ReusableKey(); + Hashtable h2 = new Hashtable<>(); + k.setKey(1); + h2.put(k, "value1"); + + k.setKey(13); + assertNull(h2.get(k)); + + k.setKey(12); + assertNull(h2.get(k)); + } + + @Test + public void test_hashCode() { + // Test for method int java.util.Hashtable.hashCode() + Set> entrySet = ht10.entrySet(); + Iterator> iterator = entrySet.iterator(); + int expectedHash; + for (expectedHash = 0; iterator.hasNext(); expectedHash += iterator.next().hashCode()) { + // do nothing + } + assertTrue("Incorrect hashCode returned. Wanted: " + expectedHash + " got: " + ht10.hashCode(), + expectedHash == ht10.hashCode()); + } + + @Test + public void test_isEmpty() { + // Test for method boolean java.util.Hashtable.isEmpty() + + assertTrue("isEmpty returned incorrect value", !ht10.isEmpty()); + assertTrue("isEmpty returned incorrect value", new Hashtable().isEmpty()); + } + + @Test + public void test_keys() { + // Test for method java.util.Enumeration java.util.Hashtable.keys() + + Enumeration keys = ht10.keys(); + while (keys.hasMoreElements()) { + String s = keys.nextElement(); + assertTrue("Missing key from enumeration", keyVector.contains(s)); + } + + assertEquals("All keys not retrieved", 10, ht10.size()); + + // cast Enumeration to Iterator + @SuppressWarnings("unchecked") + Iterator iterator = (Iterator) keys; + assertFalse(iterator.hasNext()); + try { + iterator.next(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + } + + @Test + public void test_keys_subtest0() { + // this is the reference implementation behavior + final Hashtable ht = new Hashtable<>(3); + ht.put("initial", ""); + Enumeration en = ht.keys(); + en.hasMoreElements(); + ht.remove("initial"); + boolean exception = false; + try { + Object result = en.nextElement(); + assertTrue("unexpected: " + result, "initial".equals(result)); + } catch (NoSuchElementException e) { + exception = true; + } + assertTrue("unexpected NoSuchElementException", !exception); + } + + @Test + public void test_keySet() { + // Test for method java.util.Set java.util.Hashtable.keySet() + Set s = ht10.keySet(); + Enumeration e = keyVector.elements(); + while (e.hasMoreElements()) + assertTrue("Returned incorrect key set", s.contains(e.nextElement())); + + Map map = new Hashtable<>(101); + map.put(new Integer(1), "1"); + map.put(new Integer(102), "102"); + map.put(new Integer(203), "203"); + Iterator it = map.keySet().iterator(); + Integer remove1 = it.next(); + it.remove(); + Integer remove2 = it.next(); + it.remove(); + ArrayList list = new ArrayList<>(Arrays.asList(new Integer[] { 1, 102, 203 })); + list.remove(remove1); + list.remove(remove2); + assertTrue("Wrong result", it.next().equals(list.get(0))); + assertEquals("Wrong size", 1, map.size()); + assertTrue("Wrong contents", map.keySet().iterator().next().equals(list.get(0))); + + Map map2 = new Hashtable<>(101); + map2.put(new Integer(1), "1"); + map2.put(new Integer(4), "4"); + Iterator it2 = map2.keySet().iterator(); + Integer remove3 = it2.next(); + Integer next; + if (remove3.intValue() == 1) + next = new Integer(4); + else + next = new Integer(1); + it2.hasNext(); + it2.remove(); + assertTrue("Wrong result 2", it2.next().equals(next)); + assertEquals("Wrong size 2", 1, map2.size()); + assertTrue("Wrong contents 2", map2.keySet().iterator().next().equals(next)); + + // cast Iterator to Enumeration + @SuppressWarnings("unchecked") + Enumeration enumeration = (Enumeration) s.iterator(); + assertTrue(enumeration.hasMoreElements()); + } + + @Test + public void test_keySet_subtest0() { + Set s1 = ht10.keySet(); + assertTrue("should contain key", s1.remove("Key 0")); + assertTrue("should not contain key", !s1.remove("Key 0")); + } + + @Test + public void test_keySet_subtest1() { + // this is the reference implementation behavior + final Hashtable ht = new Hashtable<>(7); + ht.put("1", "a"); + // these three elements hash to the same bucket in a 7 element Hashtable + ht.put("2", "b"); + ht.put("9", "c"); + ht.put("12", "d"); + // Hashtable looks like: + // 0: "1" + // 1: "12" -> "9" -> "2" + Enumeration en = ht.elements(); + // cache the first entry + en.hasMoreElements(); + Iterator it = ht.keySet().iterator(); + // this is mostly a copy of the test in test_elements_subtest0() + // test removing with the iterator does not null the values + while (it.hasNext()) { + String key = it.next(); + if ("1".equals(key)) { + it.remove(); + } + } + boolean exception = false; + try { + // cached "12" + Set iteratorElements = new HashSet<>(); + iteratorElements.add(en.nextElement()); + iteratorElements.add(en.nextElement()); + iteratorElements.add(en.nextElement()); + assertTrue(iteratorElements.contains("b")); + assertTrue(iteratorElements.contains("c")); + assertTrue(iteratorElements.contains("d")); + } catch (NoSuchElementException e) { + exception = true; + } + assertTrue("unexpected NoSuchElementException", !exception); + } + + @Test + public void test_putLjava_lang_ObjectLjava_lang_Object() { + // Test for method java.lang.Object + // java.util.Hashtable.put(java.lang.Object, java.lang.Object) + Hashtable h = hashtableClone(ht100); + Integer key = new Integer(100); + h.put("Value 100", key); + assertTrue("Key/Value not inserted", h.size() == 1 && (h.contains(key))); + } + + @Test + public void test_putAllLjava_util_Map() { + // Test for method void java.util.Hashtable.putAll(java.util.Map) + Hashtable h = new Hashtable<>(); + h.putAll(ht10); + Enumeration e = keyVector.elements(); + while (e.hasMoreElements()) { + Object x = e.nextElement(); + assertTrue("Failed to put all elements", h.get(x).equals(ht10.get(x))); + } + } + + @Test + public void test_removeLjava_lang_Object() { + // Test for method java.lang.Object + // java.util.Hashtable.remove(java.lang.Object) + Hashtable h = hashtableClone(htfull); + Object k = h.remove("FKey 0"); + assertTrue("Remove failed", !h.containsKey("FKey 0") || k == null); + } + + @Test + public void test_HashTable_remove_scenario1() { + Hashtable, Set>> hashTable = new Hashtable<>(); + Set> keySet = hashTable.keySet(); + hashTable.put(hashTable, keySet); + hashTable.remove(hashTable); + } + + @Test + public void test_HashTable_remove_scenario2() { + Hashtable, Hashtable> hashTable = new Hashtable<>(); + hashTable.keySet(); + hashTable.put(hashTable, hashTable); + hashTable.remove(hashTable); + } + + @Test + public void test_HashTable_remove_scenario3() { + Hashtable, Hashtable>, Hashtable> hashTable = new Hashtable<>(); + Hashtable, Hashtable> keyHashTable = new Hashtable<>(); + keyHashTable.put(hashTable, keyHashTable); + hashTable.put(keyHashTable, hashTable); + hashTable.remove(keyHashTable); + } + + @Test + public void test_size() { + // Test for method int java.util.Hashtable.size() + assertTrue("Returned invalid size", ht10.size() == 10 && (ht100.size() == 0)); + } + + @Test + public void test_toString() { + // Test for method java.lang.String java.util.Hashtable.toString() + Hashtable h = new Hashtable<>(); + assertEquals("Incorrect toString for Empty table", "{}", h.toString()); + + h.put("one", "1"); + h.put("two", h); + h.put(h, "3"); + h.put(h, h); + String result = h.toString(); + assertTrue("should contain self ref", result.indexOf("(this") > -1); + } + + @Test + public void test_values() { + // Test for method java.util.Collection java.util.Hashtable.values() + Collection c = ht10.values(); + Enumeration e = elmVector.elements(); + while (e.hasMoreElements()) + assertTrue("Returned incorrect values", c.contains(e.nextElement())); + + Hashtable myHashtable = new Hashtable<>(); + for (int i = 0; i < 100; i++) + myHashtable.put(new Integer(i), new Integer(i)); + Collection values = myHashtable.values(); + new Support_UnmodifiableCollectionTest(values).runTest(); + values.remove(new Integer(0)); + assertTrue("Removing from the values collection should remove from the original map", + !myHashtable.containsValue(new Integer(0))); + } + + @Test + public void test_entrySet_remove() { + Hashtable hashtable = new Hashtable<>(); + hashtable.put("my.nonexistent.prop", "AAA"); + hashtable.put("parse.error", "BBB"); + Iterator> iterator = hashtable.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + final Object value = entry.getValue(); + if (value.equals("AAA")) { + iterator.remove(); + } + } + assertFalse(hashtable.containsKey("my.nonexistent.prop")); + } + + @Test + @SuppressWarnings("unchecked") + public void test_keys_elements_keySet_Exceptions() { + Hashtable hashTable = new Hashtable<>(); + String key = "key"; + String value = "value"; + hashTable.put(key, value); + + Iterator iterator = (Iterator) hashTable.keys(); + assertTrue(iterator.hasNext()); + try { + iterator.remove(); + fail("should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // Expected + } + iterator.next(); + try { + iterator.remove(); + fail("should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // Expected + } + assertFalse(iterator.hasNext()); + + iterator = (Iterator) hashTable.elements(); + assertTrue(iterator.hasNext()); + try { + iterator.remove(); + fail("should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // Expected + } + iterator.next(); + try { + iterator.remove(); + fail("should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // Expected + } + assertFalse(iterator.hasNext()); + + iterator = hashTable.keySet().iterator(); + assertTrue(iterator.hasNext()); + try { + iterator.remove(); + fail("should throw IllegalStateException"); + } catch (IllegalStateException e) { + // Expected + } + iterator.next(); + iterator.remove(); + assertFalse(iterator.hasNext()); + + hashTable.clear(); + for (int i = 0; i < 10; i++) { + hashTable.put(key + i, value + i); + } + + // cast Enumeration to Iterator + Enumeration enumeration = hashTable.keys(); + iterator = (Iterator) enumeration; + assertTrue(enumeration.hasMoreElements()); + assertTrue(iterator.hasNext()); + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + enumeration.nextElement(); + } else { + iterator.next(); + } + } + assertFalse(enumeration.hasMoreElements()); + assertFalse(iterator.hasNext()); + try { + enumeration.nextElement(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + try { + iterator.next(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + + // cast Enumeration to Iterator + enumeration = hashTable.elements(); + iterator = (Iterator) enumeration; + assertTrue(enumeration.hasMoreElements()); + assertTrue(iterator.hasNext()); + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + enumeration.nextElement(); + } else { + iterator.next(); + } + } + assertFalse(enumeration.hasMoreElements()); + assertFalse(iterator.hasNext()); + try { + enumeration.nextElement(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + try { + iterator.next(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + + // cast Iterator to Enumeration + enumeration = (Enumeration) hashTable.keySet().iterator(); + iterator = (Iterator) enumeration; + assertTrue(enumeration.hasMoreElements()); + assertTrue(iterator.hasNext()); + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + enumeration.nextElement(); + } else { + iterator.next(); + } + } + assertFalse(enumeration.hasMoreElements()); + assertFalse(iterator.hasNext()); + try { + enumeration.nextElement(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + try { + iterator.next(); + fail("should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + } + + @SuppressWarnings("unchecked") + protected Hashtable hashtableClone(Hashtable s) { + return (Hashtable) s.clone(); + } + + static class ReusableKey { + private int key = 0; + + public void setKey(int key) { + this.key = key; + } + + @Override + public int hashCode() { + return key; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ReusableKey)) { + return false; + } + return key == ((ReusableKey) o).key; + } + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/VectorTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/VectorTest.java new file mode 100644 index 000000000..9eaee9e96 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/VectorTest.java @@ -0,0 +1,1059 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.java.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.util.*; +import org.junit.Test; +import org.teavm.classlib.support.Support_ListTest; + +public class VectorTest { + + private Vector tVector = new Vector<>(); + + Object[] objArray; + + private String vString = "[Test 0, Test 1, Test 2, Test 3, Test 4, Test 5, Test 6, Test 7, Test 8, Test 9, Test 10, Test 11, Test 12, Test 13, Test 14, Test 15, Test 16, Test 17, Test 18, Test 19, Test 20, Test 21, Test 22, Test 23, Test 24, Test 25, Test 26, Test 27, Test 28, Test 29, Test 30, Test 31, Test 32, Test 33, Test 34, Test 35, Test 36, Test 37, Test 38, Test 39, Test 40, Test 41, Test 42, Test 43, Test 44, Test 45, Test 46, Test 47, Test 48, Test 49, Test 50, Test 51, Test 52, Test 53, Test 54, Test 55, Test 56, Test 57, Test 58, Test 59, Test 60, Test 61, Test 62, Test 63, Test 64, Test 65, Test 66, Test 67, Test 68, Test 69, Test 70, Test 71, Test 72, Test 73, Test 74, Test 75, Test 76, Test 77, Test 78, Test 79, Test 80, Test 81, Test 82, Test 83, Test 84, Test 85, Test 86, Test 87, Test 88, Test 89, Test 90, Test 91, Test 92, Test 93, Test 94, Test 95, Test 96, Test 97, Test 98, Test 99]"; + + public VectorTest() { + for (int i = 0; i < 100; i++) { + tVector.addElement("Test " + i); + } + objArray = new Object[100]; + for (int i = 0; i < 100; i++) { + objArray[i] = "Test " + i; + } + } + + @Test + public void test_Constructor() { + // Test for method java.util.Vector() + + Vector tv = new Vector<>(100); + for (int i = 0; i < 100; i++) + tv.addElement(i); + new Support_ListTest(tv).runTest(); + + tv = new Vector<>(200); + for (int i = -50; i < 150; i++) + tv.addElement(i); + new Support_ListTest(tv.subList(50, 150)).runTest(); + + Vector v = new Vector<>(); + assertEquals("Vector creation failed", 0, v.size()); + assertEquals("Wrong capacity", 10, v.capacity()); + } + + @Test + public void test_ConstructorI() { + // Test for method java.util.Vector(int) + + Vector v = new Vector<>(100); + assertEquals("Vector creation failed", 0, v.size()); + assertEquals("Wrong capacity", 100, v.capacity()); + } + + @Test + public void test_ConstructorII() { + // Test for method java.util.Vector(int, int) + + Vector v = new Vector<>(2, 10); + v.addElement(new Object()); + v.addElement(new Object()); + v.addElement(new Object()); + + assertEquals("Failed to inc capacity by proper amount", 12, v.capacity()); + + Vector grow = new Vector<>(3, -1); + grow.addElement("one"); + grow.addElement("two"); + grow.addElement("three"); + grow.addElement("four"); + assertEquals("Wrong size", 4, grow.size()); + assertEquals("Wrong capacity", 6, grow.capacity()); + + Vector emptyVector = new Vector<>(0, 0); + emptyVector.addElement("one"); + assertEquals("Wrong size", 1, emptyVector.size()); + emptyVector.addElement("two"); + emptyVector.addElement("three"); + assertEquals("Wrong size", 3, emptyVector.size()); + + try { + new Vector<>(-1, 0); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Excepted + } + } + + @Test + public void test_ConstructorLjava_util_Collection() { + // Test for method java.util.Vector(java.util.Collection) + Collection l = new LinkedList<>(); + for (int i = 0; i < 100; i++) + l.add("Test " + i); + Vector myVector = new Vector<>(l); + assertTrue("Vector is not correct size", myVector.size() == objArray.length); + for (int counter = 0; counter < objArray.length; counter++) + assertTrue("Vector does not contain correct elements", myVector.contains(((List) l).get(counter))); + } + + @Test + public void test_addILjava_lang_Object() { + // Test for method void java.util.Vector.add(int, java.lang.Object) + Object o = new Object(); + Object prev = tVector.get(45); + tVector.add(45, o); + assertTrue("Failed to add Object", tVector.get(45) == o); + assertTrue("Failed to fix-up existing indices", tVector.get(46) == prev); + assertEquals("Wrong size after add", 101, tVector.size()); + + prev = tVector.get(50); + tVector.add(50, null); + assertNull("Failed to add null", tVector.get(50)); + assertTrue("Failed to fix-up existing indices after adding null", tVector.get(51) == prev); + assertEquals("Wrong size after add", 102, tVector.size()); + } + + @Test + public void test_addLjava_lang_Object() { + // Test for method boolean java.util.Vector.add(java.lang.Object) + Object o = new Object(); + tVector.add(o); + assertTrue("Failed to add Object", tVector.lastElement() == o); + assertEquals("Wrong size after add", 101, tVector.size()); + + tVector.add(null); + assertNull("Failed to add null", tVector.lastElement()); + assertEquals("Wrong size after add", 102, tVector.size()); + } + + @Test + public void test_addAllILjava_util_Collection() { + // Test for method boolean java.util.Vector.addAll(int, + // java.util.Collection) + Collection l = new LinkedList<>(); + for (int i = 0; i < 100; i++) + l.add("Test " + i); + Vector v = new Vector<>(); + tVector.addAll(50, l); + for (int i = 50; i < 100; i++) + assertTrue("Failed to add all elements", tVector.get(i) == ((List) l).get(i - 50)); + v = new Vector<>(); + v.add("one"); + int r = 0; + try { + v.addAll(3, Arrays.asList(new String[] { "two", "three" })); + } catch (ArrayIndexOutOfBoundsException e) { + r = 1; + } catch (IndexOutOfBoundsException e) { + r = 2; + } + assertTrue("Invalid add: " + r, r == 1); + l = new LinkedList<>(); + l.add(null); + l.add("gah"); + l.add(null); + tVector.addAll(50, l); + assertNull("Wrong element at position 50--wanted null", tVector.get(50)); + assertEquals("Wrong element at position 51--wanted 'gah'", "gah", tVector.get(51)); + assertNull("Wrong element at position 52--wanted null", tVector.get(52)); + + try { + v.addAll(0, null); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // Excepted + } + + try { + v.addAll(-1, null); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_addAllLjava_util_Collection() { + // Test for method boolean java.util.Vector.addAll(java.util.Collection) + Vector v = new Vector<>(); + Collection l = new LinkedList<>(); + for (int i = 0; i < 100; i++) + l.add("Test " + i); + v.addAll(l); + assertTrue("Failed to add all elements", tVector.equals(v)); + + v.addAll(l); + int vSize = tVector.size(); + for (int counter = vSize - 1; counter >= 0; counter--) + assertTrue("Failed to add elements correctly", v.get(counter) == v.get(counter + vSize)); + + l = new LinkedList<>(); + l.add(null); + l.add("gah"); + l.add(null); + tVector.addAll(l); + assertNull("Wrong element at 3rd last position--wanted null", tVector.get(vSize)); + assertEquals("Wrong element at 2nd last position--wanted 'gah'", "gah", tVector.get(vSize + 1)); + assertNull("Wrong element at last position--wanted null", tVector.get(vSize + 2)); + + try { + v.addAll(null); + fail("Should throw NullPointerException"); + } catch (NullPointerException e) { + // Excepted + } + } + + @Test + public void test_addElementLjava_lang_Object() { + // Test for method void java.util.Vector.addElement(java.lang.Object) + Vector v = vectorClone(tVector); + v.addElement("Added Element"); + assertTrue("Failed to add element", v.contains("Added Element")); + assertEquals("Added Element to wrong slot", "Added Element", v.elementAt(100)); + v.addElement(null); + assertTrue("Failed to add null", v.contains(null)); + assertNull("Added null to wrong slot", v.elementAt(101)); + } + + @Test + public void test_addElementLjava_lang_Object_subtest0() { + // Test for method void java.util.Vector.addElement(java.lang.Object) + Vector v = vectorClone(tVector); + v.addElement("Added Element"); + assertTrue("Failed to add element", v.contains("Added Element")); + assertEquals("Added Element to wrong slot", "Added Element", v.elementAt(100)); + v.addElement(null); + assertTrue("Failed to add null", v.contains(null)); + assertNull("Added null to wrong slot", v.elementAt(101)); + } + + @Test + public void test_capacity() { + // Test for method int java.util.Vector.capacity() + + Vector v = new Vector<>(9); + assertEquals("Incorrect capacity returned", 9, v.capacity()); + } + + @Test + public void test_clear() { + // Test for method void java.util.Vector.clear() + Vector orgVector = vectorClone(tVector); + tVector.clear(); + assertEquals("a) Cleared Vector has non-zero size", 0, tVector.size()); + Enumeration e = orgVector.elements(); + while (e.hasMoreElements()) + assertTrue("a) Cleared vector contained elements", !tVector.contains(e.nextElement())); + + tVector.add(null); + tVector.clear(); + assertEquals("b) Cleared Vector has non-zero size", 0, tVector.size()); + e = orgVector.elements(); + while (e.hasMoreElements()) + assertTrue("b) Cleared vector contained elements", !tVector.contains(e.nextElement())); + } + + @Test + public void test_clone() { + // Test for method java.lang.Object java.util.Vector.clone() + tVector.add(25, null); + tVector.add(75, null); + @SuppressWarnings("unchecked") + Vector v = (Vector) tVector.clone(); + Enumeration orgNum = tVector.elements(); + Enumeration cnum = v.elements(); + + while (orgNum.hasMoreElements()) { + assertTrue("Not enough elements copied", cnum.hasMoreElements()); + assertTrue("Vector cloned improperly, elements do not match", orgNum.nextElement() == cnum.nextElement()); + } + assertTrue("Not enough elements copied", !cnum.hasMoreElements()); + + } + + @Test + public void test_containsLjava_lang_Object() { + // Test for method boolean java.util.Vector.contains(java.lang.Object) + assertTrue("Did not find element", tVector.contains("Test 42")); + assertTrue("Found bogus element", !tVector.contains("Hello")); + assertTrue("Returned true looking for null in vector without null element", !tVector.contains(null)); + tVector.insertElementAt(null, 20); + assertTrue("Returned false looking for null in vector with null element", tVector.contains(null)); + } + + @Test + public void test_containsAllLjava_util_Collection() { + // Test for method boolean + // java.util.Vector.containsAll(java.util.Collection) + Collection s = new HashSet<>(); + for (int i = 0; i < 100; i++) + s.add("Test " + i); + + assertTrue("Returned false for valid collection", tVector.containsAll(s)); + s.add(null); + assertTrue("Returned true for invlaid collection containing null", !tVector.containsAll(s)); + tVector.add(25, null); + assertTrue("Returned false for valid collection containing null", tVector.containsAll(s)); + s = new HashSet<>(); + s.add(new Object()); + assertTrue("Returned true for invalid collection", !tVector.containsAll(s)); + } + + @Test + public void test_copyInto$Ljava_lang_Object() { + // Test for method void java.util.Vector.copyInto(java.lang.Object []) + + Object[] a = new Object[100]; + tVector.setElementAt(null, 20); + tVector.copyInto(a); + + for (int i = 0; i < 100; i++) + assertTrue("copyInto failed", a[i] == tVector.elementAt(i)); + } + + @Test + public void test_elementAtI() { + // Test for method java.lang.Object java.util.Vector.elementAt(int) + assertEquals("Incorrect element returned", "Test 18", tVector.elementAt(18)); + tVector.setElementAt(null, 20); + assertNull("Incorrect element returned--wanted null", tVector.elementAt(20)); + + } + + @Test + public void test_elements() { + // Test for method java.util.Enumeration java.util.Vector.elements() + tVector.insertElementAt(null, 20); + Enumeration e = tVector.elements(); + int i = 0; + while (e.hasMoreElements()) { + assertTrue("Enumeration returned incorrect element at pos: " + i, e.nextElement() == tVector.elementAt(i)); + i++; + } + assertTrue("Invalid enumeration", i == tVector.size()); + } + + @Test + public void test_ensureCapacityI() { + // Test for method void java.util.Vector.ensureCapacity(int) + + Vector v = new Vector<>(9); + v.ensureCapacity(20); + assertEquals("ensureCapacity failed to set correct capacity", 20, v.capacity()); + v = new Vector<>(100); + assertEquals("ensureCapacity reduced capacity", 100, v.capacity()); + + v.ensureCapacity(150); + assertEquals("ensuieCapacity failed to set to be twice the old capacity", 200, v.capacity()); + + v = new Vector<>(9, -1); + v.ensureCapacity(20); + assertEquals("ensureCapacity failed to set to be minCapacity", 20, v.capacity()); + v.ensureCapacity(15); + assertEquals("ensureCapacity reduced capacity", 20, v.capacity()); + v.ensureCapacity(35); + assertEquals("ensuieCapacity failed to set to be twice the old capacity", 40, v.capacity()); + + v = new Vector<>(9, 4); + v.ensureCapacity(11); + assertEquals("ensureCapacity failed to set correct capacity", 13, v.capacity()); + v.ensureCapacity(5); + assertEquals("ensureCapacity reduced capacity", 13, v.capacity()); + v.ensureCapacity(20); + assertEquals("ensuieCapacity failed to set to be twice the old capacity", 20, v.capacity()); + } + + @Test + public void test_equalsLjava_lang_Object() { + // Test for method boolean java.util.Vector.equals(java.lang.Object) + Vector v = new Vector<>(); + for (int i = 0; i < 100; i++) + v.addElement("Test " + i); + assertTrue("a) Equal vectors returned false", tVector.equals(v)); + v.addElement(null); + assertTrue("b) UnEqual vectors returned true", !tVector.equals(v)); + tVector.addElement(null); + assertTrue("c) Equal vectors returned false", tVector.equals(v)); + tVector.removeElementAt(22); + assertTrue("d) UnEqual vectors returned true", !tVector.equals(v)); + assertTrue("e) Equal vectors returned false", tVector.equals(tVector)); + assertFalse("f) UnEqual vectors returned true", tVector.equals(new Object())); + assertFalse("g) Unequal vectors returned true", tVector.equals(null)); + } + + @Test + public void test_firstElement() { + // Test for method java.lang.Object java.util.Vector.firstElement() + assertEquals("Returned incorrect firstElement", "Test 0", tVector.firstElement()); + tVector.insertElementAt(null, 0); + assertNull("Returned incorrect firstElement--wanted null", tVector.firstElement()); + + Vector v = new Vector<>(); + try { + v.firstElement(); + fail("Should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Excepted + } + } + + @Test + public void test_getI() { + // Test for method java.lang.Object java.util.Vector.get(int) + assertEquals("Get returned incorrect object", "Test 80", tVector.get(80)); + tVector.add(25, null); + assertNull("Returned incorrect element--wanted null", tVector.get(25)); + } + + @Test + public void test_hashCode() { + // Test for method int java.util.Vector.hashCode() + int hashCode = 1; // one + tVector.insertElementAt(null, 20); + for (int i = 0; i < tVector.size(); i++) { + Object obj = tVector.elementAt(i); + hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); + } + assertTrue("Incorrect hashCode returned. Wanted: " + hashCode + " got: " + tVector.hashCode(), + tVector.hashCode() == hashCode); + } + + @Test + public void test_indexOfLjava_lang_Object() { + // Test for method int java.util.Vector.indexOf(java.lang.Object) + assertEquals("Incorrect index returned", 10, tVector.indexOf("Test 10")); + assertEquals("Index returned for invalid Object", -1, tVector.indexOf("XXXXXXXXXXX")); + tVector.setElementAt(null, 20); + tVector.setElementAt(null, 40); + assertTrue("Incorrect indexOf returned for null: " + tVector.indexOf(null), tVector.indexOf(null) == 20); + } + + @Test + public void test_indexOfLjava_lang_ObjectI() { + // Test for method int java.util.Vector.indexOf(java.lang.Object, int) + assertEquals("Failed to find correct index", tVector.indexOf("Test 98", 50), 98); + assertTrue("Found index of bogus element", (tVector.indexOf("Test 1001", 50) == -1)); + tVector.setElementAt(null, 20); + tVector.setElementAt(null, 40); + tVector.setElementAt(null, 60); + assertTrue("a) Incorrect indexOf returned for null: " + tVector.indexOf(null, 25), + tVector.indexOf(null, 25) == 40); + assertTrue("b) Incorrect indexOf returned for null: " + tVector.indexOf(null, 20), + tVector.indexOf(null, 20) == 20); + try { + tVector.indexOf("Test 98", -1); + fail("should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + + } + assertEquals(-1, tVector.indexOf("Test 98", 1000)); + assertEquals(-1, tVector.indexOf("Test 98", Integer.MAX_VALUE)); + assertEquals(-1, tVector.indexOf("Test 98", tVector.size())); + assertEquals(98, tVector.indexOf("Test 98", 0)); + try { + tVector.indexOf("Test 98", Integer.MIN_VALUE); + fail("should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + + } + } + + @Test + public void test_insertElementAtLjava_lang_ObjectI() { + // Test for method void + // java.util.Vector.insertElementAt(java.lang.Object, int) + Vector v = vectorClone(tVector); + String prevElement = (String) v.elementAt(99); + v.insertElementAt("Inserted Element", 99); + assertEquals("Element not inserted", "Inserted Element", v.elementAt(99)); + assertTrue("Elements shifted incorrectly", ((String) v.elementAt(100)).equals(prevElement)); + v.insertElementAt(null, 20); + assertNull("null not inserted", v.elementAt(20)); + + try { + tVector.insertElementAt("Inserted Element", -1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.insertElementAt(null, -1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.insertElementAt("Inserted Element", tVector.size() + 1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.insertElementAt(null, tVector.size() + 1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_isEmpty() { + // Test for method boolean java.util.Vector.isEmpty()Vector + Vector v = new Vector<>(); + assertTrue("Empty vector returned false", v.isEmpty()); + v.addElement(new Object()); + assertTrue("non-Empty vector returned true", !v.isEmpty()); + } + + @Test + public void test_lastElement() { + // Test for method java.lang.Object java.util.Vector.lastElement() + assertEquals("Incorrect last element returned", "Test 99", tVector.lastElement()); + tVector.addElement(null); + assertNull("Incorrect last element returned--wanted null", tVector.lastElement()); + + Vector vector = new Vector<>(); + try { + vector.lastElement(); + fail("Should throw NoSuchElementException"); + } catch (NoSuchElementException e) { + // Excepted + } + } + + @Test + public void test_lastIndexOfLjava_lang_Object() { + // Test for method int java.util.Vector.lastIndexOf(java.lang.Object) + Vector v = new Vector<>(9); + for (int i = 0; i < 9; i++) + v.addElement("Test"); + v.addElement("z"); + assertEquals("Failed to return correct index", 8, v.lastIndexOf("Test")); + tVector.setElementAt(null, 20); + tVector.setElementAt(null, 40); + assertTrue("Incorrect lastIndexOf returned for null: " + tVector.lastIndexOf(null), + tVector.lastIndexOf(null) == 40); + } + + @Test + public void test_lastIndexOfLjava_lang_ObjectI() { + // Test for method int java.util.Vector.lastIndexOf(java.lang.Object, + // int) + assertEquals("Failed to find object", 0, tVector.lastIndexOf("Test 0", 0)); + assertTrue("Found Object outside of index", (tVector.lastIndexOf("Test 0", 10) > -1)); + tVector.setElementAt(null, 20); + tVector.setElementAt(null, 40); + tVector.setElementAt(null, 60); + assertTrue("Incorrect lastIndexOf returned for null: " + tVector.lastIndexOf(null, 15), + tVector.lastIndexOf(null, 15) == -1); + assertTrue("Incorrect lastIndexOf returned for null: " + tVector.lastIndexOf(null, 45), + tVector.lastIndexOf(null, 45) == 40); + + assertEquals(-1, tVector.lastIndexOf("Test 98", -1)); + assertEquals(-1, tVector.lastIndexOf("Test 98", 0)); + try { + assertEquals(-1, tVector.lastIndexOf("Test 98", 1000)); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + } + try { + assertEquals(-1, tVector.lastIndexOf("Test 98", Integer.MAX_VALUE)); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + } + try { + tVector.lastIndexOf("Test 98", tVector.size()); + fail("should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + } + try { + tVector.indexOf("Test 98", Integer.MIN_VALUE); + fail("should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + } + } + + @Test + public void test_removeI() { + // Test for method java.lang.Object java.util.Vector.remove(int) + Object removeElement = tVector.get(36); + Object result = tVector.remove(36); + assertFalse("Contained element after remove", tVector.contains("Test 36")); + assertEquals("Should return the element that was removed", removeElement, result); + assertEquals("Failed to decrement size after remove", 99, tVector.size()); + tVector.add(20, null); + removeElement = tVector.get(19); + result = tVector.remove(19); + assertNull("Didn't move null element over", tVector.get(19)); + assertEquals("Should return the element that was removed", removeElement, result); + removeElement = tVector.get(19); + result = tVector.remove(19); + assertNotNull("Didn't remove null element", tVector.get(19)); + assertEquals("Should return the element that was removed", removeElement, result); + assertEquals("Failed to decrement size after removing null", 98, tVector.size()); + + try { + tVector.remove(-1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.remove(tVector.size()); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_removeLjava_lang_Object() { + // Test for method boolean java.util.Vector.remove(java.lang.Object) + tVector.remove("Test 0"); + assertTrue("Contained element after remove", !tVector.contains("Test 0")); + assertEquals("Failed to decrement size after remove", 99, tVector.size()); + tVector.add(null); + tVector.remove(null); + assertTrue("Contained null after remove", !tVector.contains(null)); + assertEquals("Failed to decrement size after removing null", 99, tVector.size()); + } + + @Test + public void test_removeAllLjava_util_Collection() { + // Test for method boolean + // java.util.Vector.removeAll(java.util.Collection) + Vector v = new Vector<>(); + Collection l = new LinkedList<>(); + for (int i = 0; i < 5; i++) + l.add("Test " + i); + v.addElement(l); + + Collection s = new HashSet<>(); + Object o; + s.add(o = v.firstElement()); + v.removeAll(s); + assertTrue("Failed to remove items in collection", !v.contains(o)); + v.removeAll(l); + assertTrue("Failed to remove all elements", v.isEmpty()); + + v.add(null); + v.add(null); + v.add("Boom"); + v.removeAll(s); + assertEquals("Should not have removed any elements", 3, v.size()); + l = new LinkedList<>(); + l.add(null); + v.removeAll(l); + assertEquals("Should only have one element", 1, v.size()); + assertEquals("Element should be 'Boom'", "Boom", v.firstElement()); + } + + @Test + public void test_removeAllElements() { + // Test for method void java.util.Vector.removeAllElements() + Vector v = vectorClone(tVector); + v.removeAllElements(); + assertEquals("Failed to remove all elements", 0, v.size()); + } + + @Test + public void test_removeElementLjava_lang_Object() { + // Test for method boolean + // java.util.Vector.removeElement(java.lang.Object) + Vector v = vectorClone(tVector); + v.removeElement("Test 98"); + assertEquals("Element not removed", "Test 99", v.elementAt(98)); + assertTrue("Vector is wrong size after removal: " + v.size(), v.size() == 99); + tVector.addElement(null); + v.removeElement(null); + assertTrue("Vector is wrong size after removing null: " + v.size(), v.size() == 99); + } + + @Test + public void test_removeElementAtI() { + // Test for method void java.util.Vector.removeElementAt(int) + Vector v = vectorClone(tVector); + int size = v.size(); + v.removeElementAt(50); + assertEquals("Failed to remove element", -1, v.indexOf("Test 50", 0)); + assertEquals("Test 51", v.get(50)); + assertEquals(size - 1, v.size()); + + tVector.insertElementAt(null, 60); + assertNull(tVector.get(60)); + size = tVector.size(); + tVector.removeElementAt(60); + assertNotNull("Element at 60 should not be null after removal", tVector.elementAt(60)); + assertEquals(size - 1, tVector.size()); + + try { + tVector.removeElementAt(-1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.removeElementAt(tVector.size()); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_removeRange() { + MockVector myVector = new MockVector<>(); + myVector.removeRange(0, 0); + + try { + myVector.removeRange(0, 1); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // Excepted + } + + int[] data = { 1, 2, 3, 4 }; + for (int i = 0; i < data.length; i++) { + myVector.add(i, data[i]); + } + + myVector.removeRange(0, 2); + assertEquals(data[2], myVector.get(0)); + assertEquals(data[3], myVector.get(1)); + + try { + myVector.removeRange(-1, 1); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // Excepted + } + + try { + myVector.removeRange(0, -1); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // Excepted + } + + try { + myVector.removeRange(1, 0); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // Excepted + } + + try { + myVector.removeRange(2, 1); + fail("Should throw IndexOutOfBoundsException"); + } catch (IndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_retainAllLjava_util_Collection() { + // Test for method boolean + // java.util.Vector.retainAll(java.util.Collection) + Object o = tVector.firstElement(); + tVector.add(null); + Collection s = new HashSet<>(); + s.add(o); + s.add(null); + tVector.retainAll(s); + assertTrue("Retained items other than specified", + tVector.size() == 2 && tVector.contains(o) && tVector.contains(null)); + } + + @Test + public void test_setILjava_lang_Object() { + // Test for method java.lang.Object java.util.Vector.set(int, + // java.lang.Object) + Object o = new Object(); + Object previous = tVector.get(23); + Object result = tVector.set(23, o); + assertEquals("Should return the element previously at the specified position", previous, result); + assertTrue("Failed to set Object", tVector.get(23) == o); + + previous = tVector.get(0); + result = tVector.set(0, null); + assertEquals("Should return the element previously at the specified position", previous, result); + assertNull("Failed to set Object", tVector.get(0)); + + try { + tVector.set(-1, o); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.set(-1, null); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.set(tVector.size(), o); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + tVector.set(tVector.size(), null); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_setElementAtLjava_lang_ObjectI() { + // Test for method void java.util.Vector.setElementAt(java.lang.Object, + // int) + Vector v = vectorClone(tVector); + v.setElementAt("Inserted Element", 99); + assertEquals("Element not set", "Inserted Element", v.elementAt(99)); + + v.setElementAt(null, 0); + assertNull("Null element not set", v.elementAt(0)); + + try { + v.setElementAt("Inserted Element", -1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + v.setElementAt(null, -1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + v.setElementAt("Inserted Element", v.size()); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + + try { + v.setElementAt(null, v.size()); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_setSizeI() { + // Test for method void java.util.Vector.setSize(int) + Vector v = vectorClone(tVector); + int oldSize = v.size(); + Object preElement = v.get(10); + v.setSize(10); + assertEquals("Failed to set size", 10, v.size()); + assertEquals("All components at index newSize and greater should be discarded", -1, v.indexOf(preElement)); + try { + v.get(oldSize - 1); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted; + } + + oldSize = v.size(); + v.setSize(20); + assertEquals("Failed to set size", 20, v.size()); + for (int i = oldSize; i < v.size(); i++) { + assertNull(v.get(i)); + } + + try { + v.setSize(-1); + fail("Should throw ArrayIndexOutOfBoundsException"); + } catch (ArrayIndexOutOfBoundsException e) { + // Excepted + } + } + + @Test + public void test_size() { + // Test for method int java.util.Vector.size() + assertEquals("Returned incorrect size", 100, tVector.size()); + } + + @Test + public void test_subListII() { + // Test for method java.util.List java.util.Vector.subList(int, int) + List sl = tVector.subList(10, 25); + assertEquals("Returned sublist of incorrect size", 15, sl.size()); + for (int i = 10; i < 25; i++) + assertTrue("Returned incorrect sublist", sl.contains(tVector.get(i))); + + } + + @Test + public void test_toArray() { + // Test for method java.lang.Object [] java.util.Vector.toArray() + assertTrue("Returned incorrect array", Arrays.equals(objArray, tVector.toArray())); + } + + @Test + public void test_toArray$Ljava_lang_Object() { + // Test for method java.lang.Object [] + // java.util.Vector.toArray(java.lang.Object []) + Object[] o = new Object[1000]; + Object f = new Object(); + for (int i = 0; i < o.length; i++) + o[i] = f; + tVector.toArray(o); + assertNull("Failed to set slot to null", o[100]); + for (int i = 0; i < tVector.size(); i++) + assertTrue("Returned incorrect array", tVector.elementAt(i) == o[i]); + } + + class SubVector extends Vector { + + private static final long serialVersionUID = 1L; + + public SubVector() { + super(); + } + + @Override + public synchronized boolean add(E obj) { + super.addElement(obj); + return true; + } + + @Override + public synchronized void addElement(E obj) { + super.add(obj); + } + + /** + * @tests java.util.Vector#add(Object) + */ + @SuppressWarnings("nls") + public void test_add() { + SubVector subvector = new SubVector<>(); + subvector.add("foo"); + subvector.addElement("bar"); + assertEquals("Expected two elements in vector", 2, subvector.size()); + } + + } + + @Test + public void test_toString() { + // Ensure toString works with self-referencing elements. + Vector vec = new Vector<>(3); + vec.add(null); + vec.add(new Object()); + vec.add(vec); + assertNotNull(vec.toString()); + + // Test for method java.lang.String java.util.Vector.toString() + assertTrue("Incorrect String returned", tVector.toString().equals(vString)); + + Vector v = new Vector<>(); + v.addElement("one"); + v.addElement(v); + v.addElement("3"); + // test last element + v.addElement(v); + String result = v.toString(); + assertTrue("should contain self ref", result.indexOf("(this") > -1); + } + + @Test + public void test_override_size() throws Exception { + Vector v = new Vector<>(); + Vector testv = new MockVector<>(); + // though size is overriden, it should passed without exception + testv.add(1); + testv.add(2); + testv.clear(); + + testv.add(1); + testv.add(2); + v.add(1); + v.add(2); + // RI's bug here + assertTrue(testv.equals(v)); + } + + @Test + public void test_trimToSize() { + // Test for method void java.util.Vector.trimToSize() + Vector v = new Vector<>(10); + v.addElement(new Object()); + v.trimToSize(); + assertEquals("Failed to trim capacity", 1, v.capacity()); + } + + @SuppressWarnings("unchecked") + protected Vector vectorClone(Vector s) { + return (Vector) s.clone(); + } + + public class MockVector extends Vector { + private static final long serialVersionUID = -8036311869188435980L; + + @Override + public synchronized int size() { + return 0; + } + + @Override + public void removeRange(int start, int end) { + super.removeRange(start, end); + } + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_CollectionTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_CollectionTest.java new file mode 100644 index 000000000..5a3339857 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_CollectionTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.support; + +import static org.junit.Assert.*; +import java.util.Collection; +import java.util.TreeSet; + +/** + * @tests java.util.Collection + */ +public class Support_CollectionTest { + + Collection col; // must contain the Integers 0 to 99 + + public Support_CollectionTest() { + } + + public Support_CollectionTest(Collection c) { + col = c; + } + + public void runTest() { + new Support_UnmodifiableCollectionTest(col).runTest(); + + // setup + Collection myCollection = new TreeSet<>(); + myCollection.add(new Integer(101)); + myCollection.add(new Integer(102)); + myCollection.add(new Integer(103)); + + // add + assertTrue("CollectionTest - a) add did not work", col.add(new Integer(101))); + assertTrue("CollectionTest - b) add did not work", col.contains(new Integer(101))); + + // remove + assertTrue("CollectionTest - a) remove did not work", col.remove(new Integer(101))); + assertTrue("CollectionTest - b) remove did not work", !col.contains(new Integer(101))); + + // addAll + assertTrue("CollectionTest - a) addAll failed", col.addAll(myCollection)); + assertTrue("CollectionTest - b) addAll failed", col.containsAll(myCollection)); + + // containsAll + assertTrue("CollectionTest - a) containsAll failed", col.containsAll(myCollection)); + col.remove(new Integer(101)); + assertTrue("CollectionTest - b) containsAll failed", !col.containsAll(myCollection)); + + // removeAll + assertTrue("CollectionTest - a) removeAll failed", col.removeAll(myCollection)); + assertTrue("CollectionTest - b) removeAll failed", !col.removeAll(myCollection)); + assertTrue("CollectionTest - c) removeAll failed", !col.contains(new Integer(102))); + assertTrue("CollectionTest - d) removeAll failed", !col.contains(new Integer(103))); + + // retianAll + col.addAll(myCollection); + assertTrue("CollectionTest - a) retainAll failed", col.retainAll(myCollection)); + assertTrue("CollectionTest - b) retainAll failed", !col.retainAll(myCollection)); + assertTrue("CollectionTest - c) retainAll failed", col.containsAll(myCollection)); + assertTrue("CollectionTest - d) retainAll failed", !col.contains(new Integer(0))); + assertTrue("CollectionTest - e) retainAll failed", !col.contains(new Integer(50))); + + // clear + col.clear(); + assertTrue("CollectionTest - a) clear failed", col.isEmpty()); + assertTrue("CollectionTest - b) clear failed", !col.contains(new Integer(101))); + + } + +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_ListTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_ListTest.java new file mode 100644 index 000000000..f7f6239a7 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_ListTest.java @@ -0,0 +1,200 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.support; + +import static org.junit.Assert.*; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +public class Support_ListTest { + List list; // must contain the Integers 0 to 99 in order + + public Support_ListTest() { + } + + public Support_ListTest(List l) { + list = l; + } + + public void runTest() { + int hashCode = 1; + for (int counter = 0; counter < 100; counter++) { + Object elem; + elem = list.get(counter); + hashCode = 31 * hashCode + elem.hashCode(); + assertTrue("ListTest - get failed", elem.equals(new Integer(counter))); + } + assertTrue("ListTest - hashCode failed", hashCode == list.hashCode()); + + list.add(50, new Integer(1000)); + assertTrue("ListTest - a) add with index failed--did not insert", list.get(50).equals(new Integer(1000))); + assertTrue("ListTest - b) add with index failed--did not move following elements", + list.get(51).equals(new Integer(50))); + assertTrue("ListTest - c) add with index failed--affected previous elements", + list.get(49).equals(new Integer(49))); + + list.set(50, new Integer(2000)); + assertTrue("ListTest - a) set failed--did not set", list.get(50).equals(new Integer(2000))); + assertTrue("ListTest - b) set failed--affected following elements", list.get(51).equals(new Integer(50))); + assertTrue("ListTest - c) set failed--affected previous elements", list.get(49).equals(new Integer(49))); + + list.remove(50); + assertTrue("ListTest - a) remove with index failed--did not remove", list.get(50).equals(new Integer(50))); + assertTrue("ListTest - b) remove with index failed--did not move following elements", + list.get(51).equals(new Integer(51))); + assertTrue("ListTest - c) remove with index failed--affected previous elements", + list.get(49).equals(new Integer(49))); + + List myList = new LinkedList<>(); + myList.add(new Integer(500)); + myList.add(new Integer(501)); + myList.add(new Integer(502)); + + list.addAll(50, myList); + assertTrue("ListTest - a) addAll with index failed--did not insert", list.get(50).equals(new Integer(500))); + assertTrue("ListTest - b) addAll with index failed--did not insert", list.get(51).equals(new Integer(501))); + assertTrue("ListTest - c) addAll with index failed--did not insert", list.get(52).equals(new Integer(502))); + assertTrue("ListTest - d) addAll with index failed--did not move following elements", + list.get(53).equals(new Integer(50))); + assertTrue("ListTest - e) addAll with index failed--affected previous elements", + list.get(49).equals(new Integer(49))); + + List mySubList = list.subList(50, 53); + assertEquals(3, mySubList.size()); + assertTrue("ListTest - a) sublist Failed--does not contain correct elements", + mySubList.get(0).equals(new Integer(500))); + assertTrue("ListTest - b) sublist Failed--does not contain correct elements", + mySubList.get(1).equals(new Integer(501))); + assertTrue("ListTest - c) sublist Failed--does not contain correct elements", + mySubList.get(2).equals(new Integer(502))); + + t_listIterator(mySubList); + + mySubList.clear(); + assertEquals("ListTest - Clearing the sublist did not remove the appropriate elements from the original list", + 100, list.size()); + + t_listIterator(list); + ListIterator li = list.listIterator(); + for (int counter = 0; li.hasNext(); counter++) { + Object elem; + elem = li.next(); + assertTrue("ListTest - listIterator failed", elem.equals(new Integer(counter))); + } + + new Support_CollectionTest(list).runTest(); + + } + + public void t_listIterator(List list) { + ListIterator li = list.listIterator(1); + assertTrue("listIterator(1)", li.next() == list.get(1)); + + int orgSize = list.size(); + li = list.listIterator(); + for (int i = 0; i <= orgSize; i++) { + if (i == 0) { + assertTrue("list iterator hasPrevious(): " + i, !li.hasPrevious()); + } else { + assertTrue("list iterator hasPrevious(): " + i, li.hasPrevious()); + } + if (i == list.size()) { + assertTrue("list iterator hasNext(): " + i, !li.hasNext()); + } else { + assertTrue("list iterator hasNext(): " + i, li.hasNext()); + } + assertTrue("list iterator nextIndex(): " + i, li.nextIndex() == i); + assertTrue("list iterator previousIndex(): " + i, li.previousIndex() == i - 1); + boolean exception = false; + try { + assertTrue("list iterator next(): " + i, li.next() == list.get(i)); + } catch (NoSuchElementException e) { + exception = true; + } + if (i == list.size()) { + assertTrue("list iterator next() exception: " + i, exception); + } else { + assertTrue("list iterator next() exception: " + i, !exception); + } + } + + for (int i = orgSize - 1; i >= 0; i--) { + assertTrue("list iterator previous(): " + i, li.previous() == list.get(i)); + assertTrue("list iterator nextIndex()2: " + i, li.nextIndex() == i); + assertTrue("list iterator previousIndex()2: " + i, li.previousIndex() == i - 1); + if (i == 0) { + assertTrue("list iterator hasPrevious()2: " + i, !li.hasPrevious()); + } else { + assertTrue("list iterator hasPrevious()2: " + i, li.hasPrevious()); + } + assertTrue("list iterator hasNext()2: " + i, li.hasNext()); + } + boolean exception = false; + try { + li.previous(); + } catch (NoSuchElementException e) { + exception = true; + } + assertTrue("list iterator previous() exception", exception); + + Integer add1 = new Integer(600); + Integer add2 = new Integer(601); + li.add(add1); + assertTrue("list iterator add(), size()", list.size() == (orgSize + 1)); + assertEquals("list iterator add(), nextIndex()", 1, li.nextIndex()); + assertEquals("list iterator add(), previousIndex()", 0, li.previousIndex()); + Object next = li.next(); + assertTrue("list iterator add(), next(): " + next, next == list.get(1)); + li.add(add2); + Object previous = li.previous(); + assertTrue("list iterator add(), previous(): " + previous, previous == add2); + assertEquals("list iterator add(), nextIndex()2", 2, li.nextIndex()); + assertEquals("list iterator add(), previousIndex()2", 1, li.previousIndex()); + + li.remove(); + assertTrue("list iterator remove(), size()", list.size() == (orgSize + 1)); + assertEquals("list iterator remove(), nextIndex()", 2, li.nextIndex()); + assertEquals("list iterator remove(), previousIndex()", 1, li.previousIndex()); + assertTrue("list iterator previous()2", li.previous() == list.get(1)); + assertTrue("list iterator previous()3", li.previous() == list.get(0)); + assertTrue("list iterator next()2", li.next() == list.get(0)); + li.remove(); + assertTrue("list iterator hasPrevious()3", !li.hasPrevious()); + assertTrue("list iterator hasNext()3", li.hasNext()); + assertTrue("list iterator size()", list.size() == orgSize); + assertEquals("list iterator nextIndex()3", 0, li.nextIndex()); + assertEquals("list iterator previousIndex()3", -1, li.previousIndex()); + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_MapTest2.java b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_MapTest2.java index 283824838..3d0093f55 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_MapTest2.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_MapTest2.java @@ -1,3 +1,18 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -14,6 +29,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.teavm.classlib.support; import static org.junit.Assert.*; @@ -37,9 +53,12 @@ public class Support_MapTest2 { assertEquals("size should be one", 1, map.size()); map.clear(); assertEquals("size should be zero", 0, map.size()); - assertTrue("Should not have entries", !map.entrySet().iterator().hasNext()); - assertTrue("Should not have keys", !map.keySet().iterator().hasNext()); - assertTrue("Should not have values", !map.values().iterator().hasNext()); + assertTrue("Should not have entries", !map.entrySet().iterator() + .hasNext()); + assertTrue("Should not have keys", !map.keySet().iterator() + .hasNext()); + assertTrue("Should not have values", !map.values().iterator() + .hasNext()); } catch (UnsupportedOperationException e) { } @@ -48,9 +67,12 @@ public class Support_MapTest2 { assertEquals("size should be one", 1, map.size()); map.remove("one"); assertEquals("size should be zero", 0, map.size()); - assertTrue("Should not have entries", !map.entrySet().iterator().hasNext()); - assertTrue("Should not have keys", !map.keySet().iterator().hasNext()); - assertTrue("Should not have values", !map.values().iterator().hasNext()); + assertTrue("Should not have entries", !map.entrySet().iterator() + .hasNext()); + assertTrue("Should not have keys", !map.keySet().iterator() + .hasNext()); + assertTrue("Should not have values", !map.values().iterator() + .hasNext()); } catch (UnsupportedOperationException e) { } } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_UnmodifiableCollectionTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_UnmodifiableCollectionTest.java new file mode 100644 index 000000000..5d7e0d7a5 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/support/Support_UnmodifiableCollectionTest.java @@ -0,0 +1,121 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * 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.teavm.classlib.support; + +import static org.junit.Assert.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; + +public class Support_UnmodifiableCollectionTest { + + Collection col; + + + public Support_UnmodifiableCollectionTest() { + } + + public Support_UnmodifiableCollectionTest(Collection c) { + col = c; + } + + public void runTest() { + + // contains + assertTrue("UnmodifiableCollectionTest - should contain 0", col + .contains(new Integer(0))); + assertTrue("UnmodifiableCollectionTest - should contain 50", col + .contains(new Integer(50))); + assertTrue("UnmodifiableCollectionTest - should not contain 100", !col + .contains(new Integer(100))); + + // containsAll + HashSet hs = new HashSet<>(); + hs.add(new Integer(0)); + hs.add(new Integer(25)); + hs.add(new Integer(99)); + assertTrue( + "UnmodifiableCollectionTest - should contain set of 0, 25, and 99", + col.containsAll(hs)); + hs.add(new Integer(100)); + assertTrue( + "UnmodifiableCollectionTest - should not contain set of 0, 25, 99 and 100", + !col.containsAll(hs)); + + // isEmpty + assertTrue("UnmodifiableCollectionTest - should not be empty", !col + .isEmpty()); + + // iterator + Iterator it = col.iterator(); + SortedSet ss = new TreeSet<>(); + while (it.hasNext()) { + ss.add(it.next()); + } + it = ss.iterator(); + for (int counter = 0; it.hasNext(); counter++) { + int nextValue = it.next().intValue(); + assertTrue( + "UnmodifiableCollectionTest - Iterator returned wrong value. Wanted: " + + counter + " got: " + nextValue, + nextValue == counter); + } + + // size + assertTrue( + "UnmodifiableCollectionTest - returned wrong size. Wanted 100, got: " + + col.size(), col.size() == 100); + + // toArray + Object[] objArray; + objArray = col.toArray(); + for (int counter = 0; it.hasNext(); counter++) { + assertTrue( + "UnmodifiableCollectionTest - toArray returned incorrect array", + objArray[counter] == it.next()); + } + + // toArray (Object[]) + objArray = new Object[100]; + col.toArray(objArray); + for (int counter = 0; it.hasNext(); counter++) { + assertTrue( + "UnmodifiableCollectionTest - toArray(Object) filled array incorrectly", + objArray[counter] == it.next()); + } + + } + +}