001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing;
018
019import com.google.common.annotations.GwtCompatible;
020import java.util.AbstractCollection;
021import java.util.Arrays;
022import java.util.Collection;
023import java.util.Iterator;
024import org.checkerframework.checker.nullness.qual.NonNull;
025import org.checkerframework.checker.nullness.qual.Nullable;
026
027/**
028 * A simplistic collection which implements only the bare minimum allowed by the spec, and throws
029 * exceptions whenever it can.
030 *
031 * @author Kevin Bourrillion
032 */
033@GwtCompatible
034@ElementTypesAreNonnullByDefault
035public class MinimalCollection<E extends @Nullable Object> extends AbstractCollection<E> {
036  // TODO: expose allow nulls parameter?
037
038  public static <E extends @Nullable Object> MinimalCollection<E> of(E... contents) {
039    return new MinimalCollection<>(Object.class, true, contents);
040  }
041
042  // TODO: use this
043  public static <E extends @Nullable Object> MinimalCollection<E> ofClassAndContents(
044      Class<? super @NonNull E> type, E... contents) {
045    return new MinimalCollection<>(type, true, contents);
046  }
047
048  private final E[] contents;
049  private final Class<? super @NonNull E> type;
050  private final boolean allowNulls;
051
052  // Package-private so that it can be extended.
053  MinimalCollection(Class<? super @NonNull E> type, boolean allowNulls, E... contents) {
054    // TODO: consider making it shuffle the contents to test iteration order.
055    this.contents = Platform.clone(contents);
056    this.type = type;
057    this.allowNulls = allowNulls;
058
059    if (!allowNulls) {
060      for (Object element : contents) {
061        if (element == null) {
062          throw new NullPointerException();
063        }
064      }
065    }
066  }
067
068  @Override
069  public int size() {
070    return contents.length;
071  }
072
073  @Override
074  public boolean contains(@Nullable Object object) {
075    if (!allowNulls) {
076      // behave badly
077      if (object == null) {
078        throw new NullPointerException();
079      }
080    }
081    Platform.checkCast(type, object); // behave badly
082    return Arrays.asList(contents).contains(object);
083  }
084
085  @Override
086  public boolean containsAll(Collection<?> collection) {
087    if (!allowNulls) {
088      for (Object object : collection) {
089        // behave badly
090        if (object == null) {
091          throw new NullPointerException();
092        }
093      }
094    }
095    return super.containsAll(collection);
096  }
097
098  @Override
099  public Iterator<E> iterator() {
100    return Arrays.asList(contents).iterator();
101  }
102
103  @Override
104  public @Nullable Object[] toArray() {
105    @Nullable Object[] result = new @Nullable Object[contents.length];
106    System.arraycopy(contents, 0, result, 0, contents.length);
107    return result;
108  }
109
110  /*
111   * a "type A" unmodifiable collection freaks out proactively, even if there
112   * wasn't going to be any actual work to do anyway
113   */
114
115  @Override
116  public boolean addAll(Collection<? extends E> elementsToAdd) {
117    throw up();
118  }
119
120  @Override
121  public boolean removeAll(Collection<?> elementsToRemove) {
122    throw up();
123  }
124
125  @Override
126  public boolean retainAll(Collection<?> elementsToRetain) {
127    throw up();
128  }
129
130  @Override
131  public void clear() {
132    throw up();
133  }
134
135  private static UnsupportedOperationException up() {
136    throw new UnsupportedOperationException();
137  }
138}