Add tests for ArraySet (newly made public in mnc).
Also fixed mistake in ArrayMap.dump(ArrayMap, ArrayMap).
Change-Id: Ifda100e2a2cd22846873a8f0f904018f622f6cb5
diff --git a/tests/tests/util/src/android/util/cts/ArrayMapTest.java b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
index 7fdd0da..130b354 100644
--- a/tests/tests/util/src/android/util/cts/ArrayMapTest.java
+++ b/tests/tests/util/src/android/util/cts/ArrayMapTest.java
@@ -310,7 +310,7 @@
private static void dump(ArrayMap map1, ArrayMap map2) {
Log.e("test", "ArrayMap of " + map1.size() + " entries:");
- for (int i=0; i<map2.size(); i++) {
+ for (int i=0; i<map1.size(); i++) {
Log.e("test", " " + map1.keyAt(i) + " -> " + map1.valueAt(i));
}
Log.e("test", "ArrayMap of " + map2.size() + " entries:");
diff --git a/tests/tests/util/src/android/util/cts/ArraySetTest.java b/tests/tests/util/src/android/util/cts/ArraySetTest.java
new file mode 100644
index 0000000..112459c
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/ArraySetTest.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.cts;
+
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+// As is the case with ArraySet itself, ArraySetTest borrows heavily from ArrayMapTest.
+
+public class ArraySetTest extends AndroidTestCase {
+ private static final String TAG = "ArraySetTest";
+
+ private static final boolean DEBUG = false;
+
+ private static final int OP_ADD = 1;
+ private static final int OP_REM = 2;
+
+ private static int[] OPS = new int[] {
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+ OP_ADD, OP_ADD, OP_ADD,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+ OP_REM, OP_REM, OP_REM,
+ OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+ };
+
+ private static int[] KEYS = new int[] {
+ // General adding and removing.
+ -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900,
+ 2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400,
+ 600, -1, 1900, 600, 300, 2100, 200, 800, 800,
+ 1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900,
+
+ // Shrink when removing item from end.
+ 100, 200, 300, 400, 500, 600, 700, 800, 900,
+ 900, 800, 700, 600, 500, 400, 300, 200, 100,
+
+ // Shrink when removing item from middle.
+ 100, 200, 300, 400, 500, 600, 700, 800, 900,
+ 900, 800, 700, 600, 500, 400, 200, 300, 100,
+
+ // Shrink when removing item from front.
+ 100, 200, 300, 400, 500, 600, 700, 800, 900,
+ 900, 800, 700, 600, 500, 400, 100, 200, 300,
+
+ // Test hash collisions.
+ 105, 106, 108, 104, 102, 102, 107, 5, 205,
+ 4, 202, 203, 3, 5, 101, 109, 200, 201,
+ 0, -1, 100,
+ 106, 108, 104, 102, 103, 105, 107, 101, 109,
+ -1, 100, 0,
+ 4, 5, 3, 5, 200, 203, 202, 201, 205,
+ };
+
+ public static class ControlledHash {
+ final int mValue;
+
+ ControlledHash(int value) {
+ mValue = value;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ return mValue == ((ControlledHash)o).mValue;
+ }
+
+ @Override
+ public final int hashCode() {
+ return mValue/100;
+ }
+
+ @Override
+ public final String toString() {
+ return Integer.toString(mValue);
+ }
+ }
+
+ private static boolean compare(Object v1, Object v2) {
+ if (v1 == null) {
+ return v2 == null;
+ }
+ if (v2 == null) {
+ return false;
+ }
+ return v1.equals(v2);
+ }
+
+ private static <E> void compareSets(HashSet<E> set, ArraySet<E> array) {
+ assertEquals("Bad size", set.size(), array.size());
+
+ // Check that every entry in HashSet is in ArraySet.
+ for (E entry : set) {
+ assertTrue("ArraySet missing value: " + entry, array.contains(entry));
+ }
+
+ // Check that every entry in ArraySet is in HashSet using ArraySet.iterator().
+ for (E entry : array) {
+ assertTrue("ArraySet (via iterator) has unexpected value: " + entry,
+ set.contains(entry));
+ }
+
+ // Check that every entry in ArraySet is in HashSet using ArraySet.valueAt().
+ for (int i = 0; i < array.size(); ++i) {
+ E entry = array.valueAt(i);
+ assertTrue("ArraySet (via valueAt) has unexpected value: " + entry,
+ set.contains(entry));
+ }
+
+ if (set.hashCode() != array.hashCode()) {
+ assertEquals("Set hash codes differ", set.hashCode(), array.hashCode());
+ }
+
+ assertTrue("HashSet.equals(ArraySet) failed", set.equals(array));
+ assertTrue("ArraySet.equals(HashSet) failed", array.equals(set));
+
+ assertTrue("HashSet.containsAll(ArraySet) failed", set.containsAll(array));
+ assertTrue("ArraySet.containsAll(HashSet) failed", array.containsAll(set));
+ }
+
+ private static <E> void compareArraySetAndRawArray(ArraySet<E> arraySet, Object[] rawArray) {
+ assertEquals("Bad size", arraySet.size(), rawArray.length);
+ for (int i = 0; i < rawArray.length; ++i) {
+ assertEquals("ArraySet<E> and raw array unequal at index " + i,
+ arraySet.valueAt(i), rawArray[i]);
+ }
+ }
+
+ private static <E> void validateArraySet(ArraySet<E> array) {
+ int index = 0;
+ Iterator<E> iter = array.iterator();
+ while (iter.hasNext()) {
+ E value = iter.next();
+ E realValue = array.valueAt(index);
+ if (!compare(realValue, value)) {
+ fail("Bad array set entry: expected " + realValue
+ + ", got " + value + " at index " + index);
+ }
+ index++;
+ }
+
+ assertEquals("Length of iteration was unequal to size()", array.size(), index);
+ }
+
+ private static <E> void dump(HashSet<E> set, ArraySet<E> array) {
+ Log.e(TAG, "HashSet of " + set.size() + " entries:");
+ for (E entry : set) {
+ Log.e(TAG, " " + entry);
+ }
+ Log.e(TAG, "ArraySet of " + array.size() + " entries:");
+ for (int i = 0; i < array.size(); i++) {
+ Log.e(TAG, " " + array.valueAt(i));
+ }
+ }
+
+ private static void dump(ArraySet set1, ArraySet set2) {
+ Log.e(TAG, "ArraySet of " + set1.size() + " entries:");
+ for (int i = 0; i < set1.size(); i++) {
+ Log.e(TAG, " " + set1.valueAt(i));
+ }
+ Log.e(TAG, "ArraySet of " + set2.size() + " entries:");
+ for (int i = 0; i < set2.size(); i++) {
+ Log.e(TAG, " " + set2.valueAt(i));
+ }
+ }
+
+ public void testTest() {
+ assertEquals("OPS and KEYS must be equal length", OPS.length, KEYS.length);
+ }
+
+ public void testBasicArraySet() {
+ HashSet<ControlledHash> hashSet = new HashSet<ControlledHash>();
+ ArraySet<ControlledHash> arraySet = new ArraySet<ControlledHash>();
+
+ for (int i = 0; i < OPS.length; i++) {
+ ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
+ String strKey = KEYS[i] < 0 ? null : Integer.toString(KEYS[i]);
+ switch (OPS[i]) {
+ case OP_ADD:
+ if (DEBUG) Log.i(TAG, "Adding key: " + key);
+ boolean hashAdded = hashSet.add(key);
+ boolean arrayAdded = arraySet.add(key);
+ assertEquals("Adding key " + key + " was not symmetric in HashSet and "
+ + "ArraySet", hashAdded, arrayAdded);
+ break;
+ case OP_REM:
+ if (DEBUG) Log.i(TAG, "Removing key: " + key);
+ boolean hashRemoved = hashSet.remove(key);
+ boolean arrayRemoved = arraySet.remove(key);
+ assertEquals("Removing key " + key + " was not symmetric in HashSet and "
+ + "ArraySet", hashRemoved, arrayRemoved);
+ break;
+ default:
+ fail("Bad operation " + OPS[i] + " @ " + i);
+ return;
+ }
+ if (DEBUG) dump(hashSet, arraySet);
+
+ try {
+ validateArraySet(arraySet);
+ } catch (Throwable e) {
+ Log.e(TAG, e.getMessage());
+ dump(hashSet, arraySet);
+ throw e;
+ }
+
+ try {
+ compareSets(hashSet, arraySet);
+ } catch (Throwable e) {
+ Log.e(TAG, e.getMessage());
+ dump(hashSet, arraySet);
+ throw e;
+ }
+ }
+
+ // Check to see if HashSet.iterator().remove() works as expected.
+ arraySet.add(new ControlledHash(50000));
+ ControlledHash lookup = new ControlledHash(50000);
+ Iterator<ControlledHash> it = arraySet.iterator();
+ while (it.hasNext()) {
+ if (it.next().equals(lookup)) {
+ it.remove();
+ }
+ }
+ if (arraySet.contains(lookup)) {
+ String msg = "Bad ArraySet iterator: didn't remove test key";
+ Log.e(TAG, msg);
+ dump(hashSet, arraySet);
+ fail(msg);
+ }
+
+ Log.e(TAG, "Test successful; printing final map.");
+ dump(hashSet, arraySet);
+ }
+
+ public void testCopyArraySet() {
+ // set copy constructor test
+ ArraySet newSet = new ArraySet<Integer>();
+ for (int i = 0; i < 10; ++i) {
+ newSet.add(i);
+ }
+
+ ArraySet copySet = new ArraySet(newSet);
+ if (!compare(copySet, newSet)) {
+ String msg = "ArraySet copy constructor failure: expected " +
+ newSet + ", got " + copySet;
+ Log.e(TAG, msg);
+ dump(newSet, copySet);
+ fail(msg);
+ return;
+ }
+ }
+
+ public void testEqualsArrayMap() {
+ ArraySet<Integer> set1 = new ArraySet<Integer>();
+ ArraySet<Integer> set2 = new ArraySet<Integer>();
+ HashSet<Integer> set3 = new HashSet<Integer>();
+ if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) {
+ fail("ArraySet equals failure for empty sets " + set1 + ", " +
+ set2 + ", " + set3);
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ set1.add(i);
+ set2.add(i);
+ set3.add(i);
+ }
+ if (!compare(set1, set2) || !compare(set1, set3) || !compare(set3, set2)) {
+ fail("ArraySet equals failure for populated sets " + set1 + ", " +
+ set2 + ", " + set3);
+ }
+
+ set1.remove(0);
+ if (compare(set1, set2) || compare(set1, set3) || compare(set3, set1)) {
+ fail("ArraySet equals failure for set size " + set1 + ", " +
+ set2 + ", " + set3);
+ }
+ }
+
+ public void testIsEmpty() {
+ ArraySet<Integer> set = new ArraySet<Integer>();
+ assertEquals("New ArraySet should have size==0", 0, set.size());
+ assertTrue("New ArraySet should be isEmptry", set.isEmpty());
+
+ set.add(3);
+ assertEquals("ArraySet has incorrect size", 1, set.size());
+ assertFalse("ArraySet should not be isEmptry", set.isEmpty());
+
+ set.remove(3);
+ assertEquals("ArraySet should have size==0", 0, set.size());
+ assertTrue("ArraySet should be isEmptry", set.isEmpty());
+ }
+
+ public void testRemoveAt() {
+ ArraySet<Integer> set = new ArraySet<Integer>();
+
+ for (int i = 0; i < 10; ++i) {
+ set.add(i * 10);
+ }
+
+ int indexToDelete = 6;
+ assertEquals(10, set.size());
+ assertEquals(indexToDelete * 10, set.valueAt(indexToDelete).intValue());
+ assertEquals(indexToDelete * 10, set.removeAt(indexToDelete).intValue());
+ assertEquals(9, set.size());
+
+ for (int i = 0; i < 9; ++i) {
+ int expectedValue = ((i >= indexToDelete) ? (i + 1) : i) * 10;
+ assertEquals(expectedValue, set.valueAt(i).intValue());
+ }
+
+ for (int i = 9; i > 0; --i) {
+ set.removeAt(0);
+ assertEquals(i - 1, set.size());
+ }
+
+ assertTrue(set.isEmpty());
+
+ try {
+ set.removeAt(0);
+ fail("Expected ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException expected) {
+ // expected
+ }
+ }
+
+ public void testIndexOf() {
+ ArraySet<Integer> set = new ArraySet<Integer>();
+
+ for (int i = 0; i < 10; ++i) {
+ set.add(i * 10);
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ assertEquals("indexOf(" + (i * 10) + ")", i, set.indexOf(i * 10));
+ }
+ }
+
+ public void testAddAll() {
+ ArraySet<Integer> arraySet = new ArraySet<Integer>();
+ ArraySet<Integer> testArraySet = new ArraySet<Integer>();
+ ArrayList<Integer> testArrayList = new ArrayList<Integer>();
+
+ for (int i = 0; i < 10; ++i) {
+ testArraySet.add(i * 10);
+ testArrayList.add(i * 10);
+ }
+
+ assertTrue(arraySet.isEmpty());
+
+ // addAll(ArraySet) has no return value.
+ arraySet.addAll(testArraySet);
+ assertTrue("ArraySet.addAll(ArraySet) failed", arraySet.containsAll(testArraySet));
+
+ arraySet.clear();
+ assertTrue(arraySet.isEmpty());
+
+ // addAll(Collection) returns true if any items were added.
+ assertTrue(arraySet.addAll(testArrayList));
+ assertTrue("ArraySet.addAll(Container) failed", arraySet.containsAll(testArrayList));
+ assertTrue("ArraySet.addAll(Container) failed", arraySet.containsAll(testArraySet));
+ // Adding the same Collection should return false.
+ assertFalse(arraySet.addAll(testArrayList));
+ assertTrue("ArraySet.addAll(Container) failed", arraySet.containsAll(testArrayList));
+ }
+
+ public void testRemoveAll() {
+ ArraySet<Integer> arraySet = new ArraySet<Integer>();
+ ArraySet<Integer> arraySetToRemove = new ArraySet<Integer>();
+ ArrayList<Integer> arrayListToRemove = new ArrayList<Integer>();
+
+ for (int i = 0; i < 10; ++i) {
+ arraySet.add(i * 10);
+ }
+
+ for (int i = 6; i < 15; ++i) {
+ arraySetToRemove.add(i * 10);
+ }
+
+ for (int i = 3; i > -3; --i) {
+ arrayListToRemove.add(i * 10);
+ }
+
+ assertEquals(10, arraySet.size());
+
+ // Remove [6,14] (really [6,9]) via another ArraySet.
+ assertTrue(arraySet.removeAll(arraySetToRemove));
+ assertEquals(6, arraySet.size());
+ assertFalse(arraySet.removeAll(arraySetToRemove));
+ assertEquals(6, arraySet.size());
+
+ // Remove [-2,3] (really [0,3]) via an ArrayList (ie Collection).
+ assertTrue(arraySet.removeAll(arrayListToRemove));
+ assertEquals(2, arraySet.size());
+ assertFalse(arraySet.removeAll(arrayListToRemove));
+ assertEquals(2, arraySet.size());
+
+ // Remove the rest of the items.
+ ArraySet<Integer> copy = new ArraySet<Integer>(arraySet);
+ assertTrue(arraySet.removeAll(copy));
+ assertEquals(0, arraySet.size());
+ assertFalse(arraySet.removeAll(copy));
+ assertEquals(0, arraySet.size());
+ }
+
+ public void testRetainAll() {
+ ArraySet<Integer> arraySet = new ArraySet<Integer>();
+ ArrayList<Integer> arrayListToRetain = new ArrayList<Integer>();
+
+ for (int i = 0; i < 10; ++i) {
+ arraySet.add(i * 10);
+ }
+
+ arrayListToRetain.add(30);
+ arrayListToRetain.add(50);
+ arrayListToRetain.add(51); // bogus value
+
+ assertEquals(10, arraySet.size());
+
+ assertTrue(arraySet.retainAll(arrayListToRetain));
+ assertEquals(2, arraySet.size());
+
+ assertTrue(arraySet.contains(30));
+ assertTrue(arraySet.contains(50));
+ assertFalse(arraySet.contains(51));
+
+ // Nothing should change.
+ assertFalse(arraySet.retainAll(arrayListToRetain));
+ assertEquals(2, arraySet.size());
+ }
+
+ public void testToArray() {
+ ArraySet<Integer> arraySet = new ArraySet<Integer>();
+ for (int i = 0; i < 10; ++i) {
+ arraySet.add(i * 10);
+ }
+
+ // Allocate a new array with the right type given a zero-length ephemeral array.
+ Integer[] copiedArray = arraySet.toArray(new Integer[0]);
+ compareArraySetAndRawArray(arraySet, copiedArray);
+
+ // Allocate a new array with the right type given an undersized array.
+ Integer[] undersizedArray = new Integer[5];
+ copiedArray = arraySet.toArray(undersizedArray);
+ compareArraySetAndRawArray(arraySet, copiedArray);
+ assertNotSame(undersizedArray, copiedArray);
+
+ // Use the passed array that is large enough to hold the ArraySet.
+ Integer[] rightSizedArray = new Integer[10];
+ copiedArray = arraySet.toArray(rightSizedArray);
+ compareArraySetAndRawArray(arraySet, copiedArray);
+ assertSame(rightSizedArray, copiedArray);
+
+ // Create a new Object[] array.
+ Object[] objectArray = arraySet.toArray();
+ compareArraySetAndRawArray(arraySet, objectArray);
+ }
+}