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