Revision: 8342
Author: [email protected]
Date: Wed Jun 30 08:59:28 2010
Log: Set and MutableSet. Bytecode implementation.

Review at http://gwt-code-reviews.appspot.com/636801

Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=8342

Added:
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/MutableSet.java /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Relation.java /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Set.java /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetAdapterTest.java /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetTest.java
Modified:
/branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java

=======================================
--- /dev/null
+++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/MutableSet.java Wed Jun 30 08:59:28 2010
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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 com.google.gwt.collections;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A {...@link Set} whose content can change over time.
+ *
+ * Elements in {...@code this} Set are indexed by Strings. For each object in the + * Set, the index String is computed by an "adapter" {...@link Relation} provided
+ * when creating the Set with
+ * {...@link CollectionFactory#createMutableSet(Relation)}.
+ *
+ * Calls to {...@link Relation#applyTo(Object)} should return {...@code null} 
for
+ * any object that cannot be a member of the Set. For any two objects to be
+ * stored in the Set, {...@code a} and {...@code b} the adapter must meet
+ * the condition that {...@code adapt(a) == adapt(b)} iff.
+ * {...@code a.equals(b)}.
+ *
+ * For example, suppose we need to store Foo objects uniquely identified by an
+ * index property provided by {...@code Foo.getIndex()}. The following adapter
+ * would provide support for these objects in a Set:
+ *
+ * <pre class="code">
+ * <code>
+ * public class FooRelation implements Relation&lt;Object, String&gt; {
+ *   public String applyTo(Object value) {
+ *     return (value instanceof Foo) ? ((Foo) value).getIndex() : null;
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * The default adapter is used when creating a Set with
+ * {...@link CollectionFactory#createMutableSet()}. This adapter uses
+ * {...@link Object#toString()} to obtain the index string for any value.
+ * {...@code null} values are not supported (i.e. the adapter returns
+ * {...@code null}).
+ *
+ * Methods that require comparing one set to another implicitly require testing + * membership of elements of one set into another. Adapters used in each set may
+ * differ. For a method of {...@code this} set that receives a set
+ * {...@code source} as parameter, the calls will succeed as long as the
+ * following conditions are met:
+ *
+ * <ul>
+ * <li>For {...@link MutableSet#addAll(Set)}, all elements {...@code e} in
+ * {...@code source} must be such that {...@code this.adapt(e) != null}</li>
+ *
+ * <li>For {...@link Set#containsAll}, {...@link Set#containsSome(Set)},
+ * {...@link Set#isEqual(Set)} and MutableSet#removeAll(Set)}, all elements
+ * {...@code e} in {...@code source} must be such that
+ * {...@code this.adapt(e)} will complete successfully</li>
+ *
+ * <li>For {...@link MutableSet#keepAll(Set)}, all elements {...@code e} in
+ * {...@code this} must be such that {...@code source.adapt(e)} will
+ * complete successfully</li>
+ * </ul>
+ *
+ * @param <E> The type stored in the set elements
+ */
+public final class MutableSet<E> extends Set<E> {
+
+  /**
+   * Adds an {...@code element} to this set. {...@code element} must be a value
+   * accepted by the underlying adapter; that is, a call to {...@code
+   * adapt(element)} produces a non-null result.
+   *
+   * @param element element to add
+   */
+  public void add(E element) {
+    String key = adapt(element);
+    assert key != null : Assertions.ACCESS_UNSUPPORTED_VALUE;
+    elements.put(key, element);
+  }
+
+  /**
+ * Adds all elements from {...@code source}. This set will contain the union of
+   * {...@code this} and {...@code source} sets.
+   *
+   * @param source a set whose contents will be added to this Set
+   * @exception NullPointerException if {...@code source} is {...@code null}
+   */
+  public void addAll(Set<E> source) {
+    if (source == null) {
+      throw new NullPointerException("source == null");
+    }
+
+    HashMap<String, E> sourceElems = source.elements;
+    Iterator<String> i = sourceElems.keySet().iterator();
+
+    while (i.hasNext()) {
+      add(sourceElems.get(i.next()));
+    }
+  }
+
+  @Override
+  public boolean contains(Object element) {
+    String key = adapt(element);
+    if (key == null) {
+      return false;
+    }
+    return elements.containsKey(key);
+  }
+
+  @Override
+  public boolean containsAll(Set<E> source) {
+    if (source == null) {
+      throw new NullPointerException("source == null");
+    }
+
+    HashMap<String, E> sourceElems = source.elements;
+    Iterator<String> i = sourceElems.keySet().iterator();
+
+    while (i.hasNext()) {
+      if (!contains(sourceElems.get(i.next()))) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public boolean containsSome(Set<E> source) {
+    if (source == null) {
+      throw new NullPointerException("source == null");
+    }
+
+    HashMap<String, E> sourceElems = source.elements;
+    Iterator<String> i = sourceElems.keySet().iterator();
+
+    while (i.hasNext()) {
+      if (contains(sourceElems.get(i.next()))) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return elements.isEmpty();
+  }
+
+  @Override
+  public boolean isEqual(Set<E> source) {
+    return source != null
+      && source.elements.size() == elements.size()
+      && containsAll(source);
+  }
+
+  /**
+ * Removes all elements not in the {...@code source} set. This set will keep the
+   * intersection of {...@code this} and {...@code source} sets.
+   *
+   * @param source set of elements to keep
+   * @exception NullPointerException if {...@code source} is {...@code null}
+   */
+  public void keepAll(Set<E> source) {
+    if (source == null) {
+      throw new NullPointerException("source == null");
+    }
+
+    Iterator<String> i = elements.keySet().iterator();
+
+    while (i.hasNext()) {
+      if (!source.contains(elements.get(i.next()))) {
+        i.remove();
+      }
+    }
+  }
+
+  /**
+ * Removes an {...@code element} from this set. {...@code element} must be a value
+   * accepted by the underlying adapter; that is, a call to {...@code
+   * adapt(element)} produces a non-null result.
+   *
+   * @param element element to remove
+   */
+  public void remove(E element) {
+    String key = adapt(element);
+    if (key == null) {
+      return;
+    }
+    elements.remove(key);
+  }
+
+  /**
+ * Removes all elements contained in {...@code source} from this set. The result
+   * will be the subtraction of {...@code source} from {...@code this} set.
+   *
+   * @param source a set whose contents will be removed from this set
+   * @exception NullPointerException if {...@code source} is {...@code null}
+   */
+  public void removeAll(Set<E> source) {
+    if (source == null) {
+      throw new NullPointerException("source == null");
+    }
+
+    HashMap<String, E> sourceElems = source.elements;
+    Iterator<String> i = sourceElems.keySet().iterator();
+
+    while (i.hasNext()) {
+      remove(sourceElems.get(i.next()));
+    }
+  }
+
+  /**
+   * Sets the {...@link Relation} to use to translate elements of the Set into
+   * Strings.
+   *
+   * @param adapter {...@link Relation} from Object to String
+ * @exception IllegalStateException if an adapter has already been set or this
+   *            set is not empty
+   * @exception NullPointerException if {...@code adapter} is {...@code null}
+   */
+  void setAdapter(Relation<Object, String> adapter) {
+    // TODO Consider allowing re-indexing the set
+    assert this.adapter == null : Assertions.INIT_ADAPTER_TWICE;
+
+    if (adapter == null) {
+      throw new NullPointerException("adapter == null");
+    }
+
+    if (this.adapter != null) {
+      throw new IllegalStateException("Adapter already set");
+    }
+
+    if (!isEmpty()) {
+      throw new IllegalStateException("Adapter set on non-empty set");
+    }
+
+    this.adapter = adapter;
+  }
+
+}
=======================================
--- /dev/null
+++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Relation.java Wed Jun 30 08:59:28 2010
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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 com.google.gwt.collections;
+
+/**
+ * Encapsulates a single parameter function. Primarily used by {...@code
+ * com.gwt.collections} in the form {...@code Relation<Object, String>} to obtain a
+ * {...@code String} that represents an {...@code Object} stored in a
+ * {...@link MutableSet} or a {...@link MutableMap}.
+ *
+ * @see MutableSet
+ * @see MutableMap
+ *
+ * @param <I> relation domain type
+ * @param <O> relation range type
+ */
+public interface Relation<I, O> {
+  /**
+   * Applies a function to the {...@code element} passed as a parameter.
+ * @return the result of the function. {...@code null} if {...@code element} is not
+   * valid as an input to the function represented by this {...@code Relation}
+   */
+  O applyTo(I element);
+}
=======================================
--- /dev/null
+++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Set.java Wed Jun 30 08:59:28 2010
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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 com.google.gwt.collections;
+
+import java.util.HashMap;
+
+/**
+ * The root Set type that provides read-access to an set that might still be
+ * mutable by another actor.
+ *
+ * See {...@link MutableSet} for a description of the role
+ * {...@link Set#adapt(Object)} plays in the behavior of this class.
+ *
+ * @param <E> The type stored in the array elements
+ */
+public abstract class Set<E> {
+
+  /**
+ * Encapsulates the logic to transform <E> typed elements into String. This is
+   * used to index into the set elements into a Map.
+   */
+  protected Relation<Object, String> adapter;
+
+  /**
+   * Backing store for the set elements.
+   */
+  HashMap<String, E> elements = new HashMap<String, E>();
+
+  /**
+ * Tests element membership. {...@code element} can take any value accepted by
+   * {...@link Set#adapt(Object)}.
+   *
+   * @param element element to test for membership
+   * @return true if the element is a member of this set
+   */
+  public abstract boolean contains(Object element);
+
+  /**
+   * Tests whether {...@code source} is a subset of this set.
+   *
+   * @param source set containing elements to test for membership
+   * @return true if all elements in {...@code source} are in this set
+   * @exception NullPointerException if {...@code source} is {...@code null}
+   */
+  public abstract boolean containsAll(Set<E> source);
+
+  /**
+ * Tests whether the intersection of {...@code source} and this set is not empty.
+   *
+   * @param source set containing elements to test for membership
+   * @return true if at least one elements in {...@code source} is in this set
+   * @exception NullPointerException if {...@code source} is {...@code null}
+   */
+  public abstract boolean containsSome(Set<E> source);
+
+  /**
+   * Tests whether this set contains any element.
+   *
+   * @return {...@code true} if the set contains at least one element
+   */
+  public abstract boolean isEmpty();
+
+  /**
+   * Tests whether {...@code source} and {...@code this} set contain the same
+   * elements.
+   *
+   * @param source set containing elements to test for membership
+   * @return {...@code true} if source != null, all elements in {...@code 
source}
+ * are in {...@code this} set and all elements in {...@code this} set are
+   *         contained in {...@code source}; {...@code false} otherwise
+   */
+  public abstract boolean isEqual(Set<E> source);
+
+  /**
+   * Translates the Set domain into String. Actually calls {...@code
+   * adapter.applyTo(Object)}.
+   *
+   * @see MutableSet
+   * @param value to adapt
+   * @return a String uniquely representing the {...@code value}. {...@code 
null}
+   *         if the {...@code value} cannot be represented as a String
+   */
+  protected final String adapt(Object value) {
+    return adapter.applyTo(value);
+  }
+
+}
=======================================
--- /dev/null
+++ /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetAdapterTest.java Wed Jun 30 08:59:28 2010
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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 com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests MutableSet when used providing a {...@link Relation} with
+ * custom {...@link MutableSet#setAdapter(Relation)} adapters.
+ */
+public class MutableSetAdapterTest extends GWTTestCase {
+
+  private boolean assertionsEnabled;
+
+ private Relation<Object, String> adapter1 = new Relation<Object, String>() {
+    public String applyTo(Object element) {
+      if (!(element instanceof Integer) || (Integer) element >= 0) {
+        return null;
+      }
+      return "__" + ((Integer) element).toString();
+    }
+  };
+
+ private Relation<Object, String> adapter2 = new Relation<Object, String>() {
+    public String applyTo(Object element) {
+      if (!(element instanceof Integer) || (Integer) element >= 0) {
+        return null;
+      }
+      return "_$_" + ((Integer) element).toString();
+    }
+  };
+
+  public void gwtSetUp() {
+    assertionsEnabled = this.getClass().desiredAssertionStatus();
+  }
+
+  public void testAdd() {
+    MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+
+    ms.add(-1);
+    assertTrue(ms.contains(-1));
+
+    // Do not test undefined behavior without assertions
+    if (!assertionsEnabled) {
+      return;
+    }
+    try {
+      ms.add(null);
+      fail("Should have triggered an assertion");
+    } catch (AssertionError e) {
+      // Good
+      assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+    }
+    try {
+      ms.add(1);
+      fail("Should have triggered an assertion");
+    } catch (AssertionError e) {
+      // Good
+      assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+    }
+  }
+
+  public void testAddAll() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.add(-3);
+
+    msB.addAll(msA);
+
+    assertTrue(msB.isEqual(msA));
+    try {
+      msA.addAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+
+    // Test different adapters
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+    msC.addAll(msA);
+
+    assertTrue(msC.isEqual(msA));
+  }
+
+  public void testContains() {
+    MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+    ms.add(-1);
+
+    assertTrue(ms.contains(-1));
+    assertFalse(ms.contains(-2));
+
+    assertFalse(ms.contains(null));
+  }
+
+  public void testContainsAll() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msEmpty = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.add(-3);
+
+    msB.add(-1);
+    msB.add(-2);
+
+    assertTrue(msA.containsAll(msB));
+    assertFalse(msB.containsAll(msA));
+    assertTrue(msA.containsAll(msEmpty));
+    try {
+      msA.containsAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+
+    // Test different adapters
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+
+    msC.add(-1);
+    msC.add(-2);
+
+    assertTrue(msA.containsAll(msC));
+    assertFalse(msC.containsAll(msA));
+  }
+
+  public void testContainsSome() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+ MutableSet<Integer> msEmpty = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.add(-3);
+
+    msB.add(-4);
+    msB.add(-5);
+    msB.add(-1);
+
+    assertTrue(msA.containsSome(msB));
+    msB.remove(-1);
+    assertFalse(msB.containsSome(msA));
+    assertFalse(msA.containsSome(msEmpty));
+    try {
+      msA.containsSome(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+
+    // Test different adapters
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter2);
+    msC.add(-4);
+    msC.add(-5);
+    msC.add(-1);
+
+    assertTrue(msA.containsSome(msC));
+    msC.remove(-1);
+    assertFalse(msC.containsSome(msA));
+  }
+
+  public void testIsEmpty() {
+    MutableSet<Integer> ms = CollectionFactory.createMutableSet(adapter1);
+
+    assertTrue(ms.isEmpty());
+    ms.add(-1);
+    assertFalse(ms.isEmpty());
+  }
+
+  public void testIsEqual() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+    assertTrue(msA.isEqual(msB));
+    msA.add(-1);
+    assertFalse(msA.isEqual(msB));
+    msB.add(-1);
+    assertTrue(msA.isEqual(msB));
+    msB.add(-2);
+    assertFalse(msA.isEqual(msB));
+    assertFalse(msA.isEqual(null));
+
+    // Test different adapters
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+    assertTrue(msC.isEqual(msD));
+    msC.add(-1);
+    assertFalse(msC.isEqual(msD));
+    msD.add(-1);
+    assertTrue(msC.isEqual(msD));
+    msD.add(-2);
+    assertFalse(msC.isEqual(msD));
+  }
+
+  public void testKeepAll() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.add(-3);
+
+    msB.add(-1);
+    msB.add(-2);
+    msB.add(-4);
+
+    msC.add(-1);
+    msC.add(-2);
+
+    msA.keepAll(msB);
+    assertTrue(msC.isEqual(msA));
+    try {
+      msA.keepAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+
+    // Test different adapters
+    MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+    msD.add(-1);
+    msD.add(-2);
+    msD.add(-3);
+
+    msD.keepAll(msB);
+
+    assertTrue(msC.isEqual(msD));
+  }
+
+  public void testRemove() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.remove(-1);
+    msB.add(-2);
+    assertTrue(msA.isEqual(msB));
+    msA.remove(-3);
+    assertTrue(msA.isEqual(msB));
+    msA.remove(null);
+    assertTrue(msA.isEqual(msB));
+    msA.remove(-2);
+    assertTrue(msA.isEmpty());
+  }
+
+  public void testRemoveAll() {
+    MutableSet<Integer> msA = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msB = CollectionFactory.createMutableSet(adapter1);
+    MutableSet<Integer> msC = CollectionFactory.createMutableSet(adapter1);
+
+    msA.add(-1);
+    msA.add(-2);
+    msA.add(-3);
+
+    msB.add(-1);
+    msB.add(-3);
+    msB.add(-4);
+
+    msC.add(-2);
+
+    msA.removeAll(msB);
+    assertTrue(msC.isEqual(msA));
+    msA.removeAll(msC);
+    assertTrue(msA.isEmpty());
+    try {
+      msA.removeAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+
+    // Test different adapters
+    MutableSet<Integer> msD = CollectionFactory.createMutableSet(adapter2);
+
+    msD.add(-1);
+    msD.add(-2);
+    msD.add(-3);
+
+    msD.removeAll(msB);
+    assertTrue(msC.isEqual(msD));
+    msD.removeAll(msC);
+    assertTrue(msD.isEmpty());
+}
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+}
=======================================
--- /dev/null
+++ /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/MutableSetTest.java Wed Jun 30 08:59:28 2010
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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 com.google.gwt.collections;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests MutableSet when used without providing a {...@link Relation} with
+ * {...@link MutableSet#setAdapter(Relation)}.
+ */
+public class MutableSetTest extends GWTTestCase {
+
+  private boolean assertionsEnabled;
+
+  public void gwtSetUp() {
+    assertionsEnabled = this.getClass().desiredAssertionStatus();
+  }
+
+  public void testAdd() {
+    MutableSet<String> ms = CollectionFactory.createMutableSet();
+
+    ms.add("peach");
+    assertTrue(ms.contains("peach"));
+
+    // Do not test undefined behavior without assertions
+    if (!assertionsEnabled) {
+      return;
+    }
+    try {
+      ms.add(null);
+      fail("Should have triggered an assertion");
+    } catch (AssertionError e) {
+      // Good
+      assertEquals(Assertions.ACCESS_UNSUPPORTED_VALUE, e.getMessage());
+    }
+  }
+
+  public void testAddAll() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.add("prune");
+
+    msB.addAll(msA);
+
+    assertTrue(msB.isEqual(msA));
+    try {
+      msA.addAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+    assertTrue(msB.isEqual(msA));
+  }
+
+  public void testContains() {
+    MutableSet<String> ms = CollectionFactory.createMutableSet();
+    ms.add("peach");
+
+    assertTrue(ms.contains("peach"));
+    assertFalse(ms.contains("lemon"));
+
+    assertFalse(ms.contains(null));
+  }
+
+  public void testContainsAll() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+    MutableSet<String> msEmpty = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.add("prune");
+
+    msB.add("peach");
+    msB.add("prune");
+
+    assertTrue(msA.containsAll(msB));
+    assertFalse(msB.containsAll(msA));
+    assertTrue(msA.containsAll(msEmpty));
+    try {
+      msA.containsAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+  }
+
+  public void testContainsSome() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+    MutableSet<String> msEmpty = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.add("prune");
+
+    msB.add("lemon");
+    msB.add("orange");
+    msB.add("peach");
+
+    assertTrue(msA.containsSome(msB));
+    msB.remove("peach");
+    assertFalse(msB.containsSome(msA));
+    assertFalse(msA.containsSome(msEmpty));
+    try {
+      msA.containsSome(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+  }
+
+  public void testIsEmpty() {
+    MutableSet<String> ms = CollectionFactory.createMutableSet();
+
+    assertTrue(ms.isEmpty());
+    ms.add("peach");
+    assertFalse(ms.isEmpty());
+  }
+
+  public void testIsEqual() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+    assertTrue(msA.isEqual(msB));
+    msA.add("peach");
+    assertFalse(msA.isEqual(msB));
+    msB.add("peach");
+    assertTrue(msA.isEqual(msB));
+    msB.add("apricot");
+    assertFalse(msA.isEqual(msB));
+    assertFalse(msA.isEqual(null));
+  }
+
+  public void testKeepAll() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+    MutableSet<String> msC = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.add("prune");
+
+    msB.add("peach");
+    msB.add("prune");
+    msB.add("orange");
+
+    msC.add("peach");
+    msC.add("prune");
+
+    msA.keepAll(msB);
+    assertTrue(msC.isEqual(msA));
+    try {
+      msA.keepAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+  }
+
+  public void testRemove() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.remove("peach");
+    msB.add("apricot");
+    assertTrue(msA.isEqual(msB));
+    msA.remove("blue_berry");
+    assertTrue(msA.isEqual(msB));
+    msA.remove(null);
+    assertTrue(msA.isEqual(msB));
+    msA.remove("apricot");
+    assertTrue(msA.isEmpty());
+  }
+
+  public void testRemoveAll() {
+    MutableSet<String> msA = CollectionFactory.createMutableSet();
+    MutableSet<String> msB = CollectionFactory.createMutableSet();
+    MutableSet<String> msC = CollectionFactory.createMutableSet();
+
+    msA.add("peach");
+    msA.add("apricot");
+    msA.add("prune");
+
+    msB.add("peach");
+    msB.add("prune");
+    msB.add("orange");
+
+    msC.add("apricot");
+
+    msA.removeAll(msB);
+    assertTrue(msC.isEqual(msA));
+    msA.removeAll(msC);
+    assertTrue(msA.isEmpty());
+    try {
+      msA.removeAll(null);
+      fail();
+    } catch (NullPointerException e) {
+      // Expected behavior
+    }
+  }
+
+  @Override
+  public String getModuleName() {
+    return null;
+  }
+
+}
=======================================
--- /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java Mon Jun 14 06:05:16 2010 +++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Assertions.java Wed Jun 30 08:59:28 2010
@@ -20,12 +20,25 @@
  */
 class Assertions {

+  /**
+ * Message produced when asserting that access into a set or map uses a value
+   * not in the domain.
+   */
+  static final String ACCESS_UNSUPPORTED_VALUE = "Unsupported value";
+
   /**
* Message for asserting that access to an empty array is an illegal operation.
    */
   public static final String ACCESS_EMPTY_ARRAY_MESSAGE =
     "Attempt to access an element in an empty array";

+  /**
+   * Message for asserting that adapters can only be set inly once after
+   * creation.
+   */
+  public static final String INIT_ADAPTER_TWICE = "Attempt to call " +
+    "setAdapter(Relation) a second time";
+
static void assertIndexInRange(int index, int minInclusive, int maxExclusive) {
     assert minInclusive < maxExclusive : ACCESS_EMPTY_ARRAY_MESSAGE;
assert (index >= minInclusive && index < maxExclusive) : "Index " + index
=======================================
--- /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java Mon Jun 14 11:58:23 2010 +++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/CollectionFactory.java Wed Jun 30 08:59:28 2010
@@ -20,6 +20,16 @@
  * isn't.
  */
 public class CollectionFactory {
+
+  static final Relation<Object, String> defaultAdapter =
+      new Relation<Object, String>() {
+    public String applyTo(Object value) {
+      if (value == null) {
+        return null;
+      }
+      return (String) value;
+    }
+  };

   /**
    * Creates an empty {...@link MutableArray}.
@@ -56,6 +66,27 @@
     r.setSize(size, fillValue);
     return r;
   }
+
+  /**
+   * Creates an empty {...@link MutableSet}.
+   * @param <E> type of elements in the map
+   * @return an empty {...@code MutableSet}
+   */
+  public static <E> MutableSet<E> createMutableSet() {
+    return createMutableSet(defaultAdapter);
+  }
+
+  /**
+   * Creates an empty {...@link MutableSet} that uses a specific adapter.
+   * @param <E> type of elements in the map
+   * @return an empty {...@code MutableSet}
+   */
+  public static <E> MutableSet<E> createMutableSet(
+      Relation<Object, String> adapter) {
+    MutableSet<E> set = new MutableSet<E>();
+    set.setAdapter(adapter);
+    return set;
+  }

   /**
    * Creates an empty {...@link MutableStringMap}.
=======================================
--- /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java Tue Jun 22 12:49:14 2010 +++ /branches/lwc-gwt-migration/bikeshed/src/com/google/gwt/collections/Map.java Wed Jun 30 08:59:28 2010
@@ -39,7 +39,7 @@
    * Determines if a key is in the set of keys contained in the map.
    *
    * @param key to use for testing membership
-   * @return <code>true</code> if the key is contained in the map
+   * @return {...@code true} if the key is contained in the map
    */
   public abstract boolean containsKey(K key);

@@ -51,12 +51,12 @@
    * containsKey(K)} to determine key membership.
    *
    * @param key index to use for retrieval.
-   * @return value associated to the key or <code>null</code> otherwise.
+   * @return value associated to the key or {...@code null} otherwise.
    */
   public abstract V get(K key);

   /**
-   * @return <code>true</code> if the map contains no entries.
+   * @return {...@code true} if the map contains no entries.
    */
   public abstract boolean isEmpty();

=======================================
--- /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java Mon Jun 14 06:05:16 2010 +++ /branches/lwc-gwt-migration/bikeshed/test/com/google/gwt/collections/CollectionsServerSideTestSuite.java Wed Jun 30 08:59:28 2010
@@ -30,6 +30,8 @@
     suite.addTestSuite(MutableArrayInternalTest.class);
     suite.addTestSuite(ImmutableArrayTest.class);
     suite.addTestSuite(ImmutableArrayInternalTest.class);
+    suite.addTestSuite(MutableSetTest.class);
+    suite.addTestSuite(MutableSetAdapterTest.class);

     return suite;
   }

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to