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 static java.lang.System.arraycopy;
020import static java.util.Arrays.asList;
021
022import com.google.common.annotations.GwtCompatible;
023import java.util.AbstractCollection;
024import java.util.Collection;
025import java.util.Iterator;
026import org.checkerframework.checker.nullness.qual.NonNull;
027import org.jspecify.annotations.NullMarked;
028import org.checkerframework.checker.nullness.qual.Nullable;
029
030/**
031 * A simplistic collection which implements only the bare minimum allowed by the spec, and throws
032 * exceptions whenever it can.
033 *
034 * @author Kevin Bourrillion
035 */
036@GwtCompatible
037@NullMarked
038public class MinimalCollection<E extends @Nullable Object> extends AbstractCollection<E> {
039  // TODO: expose allow nulls parameter?
040
041  public static <E extends @Nullable Object> MinimalCollection<E> of(E... contents) {
042    return new MinimalCollection<>(Object.class, true, contents);
043  }
044
045  // TODO: use this
046  public static <E extends @Nullable Object> MinimalCollection<E> ofClassAndContents(
047      Class<? super @NonNull E> type, E... contents) {
048    return new MinimalCollection<>(type, true, contents);
049  }
050
051  private final E[] contents;
052  private final Class<? super @NonNull E> type;
053  private final boolean allowNulls;
054
055  // Package-private so that it can be extended.
056  MinimalCollection(Class<? super @NonNull E> type, boolean allowNulls, E... contents) {
057    // TODO: consider making it shuffle the contents to test iteration order.
058    this.contents = Platform.clone(contents);
059    this.type = type;
060    this.allowNulls = allowNulls;
061
062    if (!allowNulls) {
063      for (Object element : contents) {
064        if (element == null) {
065          throw new NullPointerException();
066        }
067      }
068    }
069  }
070
071  @Override
072  public int size() {
073    return contents.length;
074  }
075
076  @Override
077  public boolean contains(@Nullable Object object) {
078    if (!allowNulls) {
079      // behave badly
080      if (object == null) {
081        throw new NullPointerException();
082      }
083    }
084    Platform.checkCast(type, object); // behave badly
085    return asList(contents).contains(object);
086  }
087
088  @Override
089  public boolean containsAll(Collection<?> collection) {
090    if (!allowNulls) {
091      for (Object object : collection) {
092        // behave badly
093        if (object == null) {
094          throw new NullPointerException();
095        }
096      }
097    }
098    return super.containsAll(collection);
099  }
100
101  @Override
102  public Iterator<E> iterator() {
103    return asList(contents).iterator();
104  }
105
106  @Override
107  public @Nullable Object[] toArray() {
108    @Nullable Object[] result = new @Nullable Object[contents.length];
109    arraycopy(contents, 0, result, 0, contents.length);
110    return result;
111  }
112
113  /*
114   * a "type A" unmodifiable collection freaks out proactively, even if there
115   * wasn't going to be any actual work to do anyway
116   */
117
118  @Override
119  public boolean addAll(Collection<? extends E> elementsToAdd) {
120    throw up();
121  }
122
123  @Override
124  public boolean removeAll(Collection<?> elementsToRemove) {
125    throw up();
126  }
127
128  @Override
129  public boolean retainAll(Collection<?> elementsToRetain) {
130    throw up();
131  }
132
133  @Override
134  public void clear() {
135    throw up();
136  }
137
138  private static UnsupportedOperationException up() {
139    throw new UnsupportedOperationException();
140  }
141}