1 /*
2  * Copyright (C) 2008 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect.testing;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_KEYS;
21 import static com.google.common.collect.testing.features.MapFeature.ALLOWS_NULL_VALUES;
22 
23 import com.google.common.collect.Lists;
24 import com.google.common.collect.Maps;
25 import com.google.common.collect.testing.features.CollectionFeature;
26 import com.google.common.collect.testing.features.CollectionSize;
27 import com.google.common.collect.testing.features.Feature;
28 import com.google.common.collect.testing.features.MapFeature;
29 import java.util.AbstractMap;
30 import java.util.AbstractSet;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.Set;
39 import java.util.function.Predicate;
40 import junit.framework.Test;
41 import junit.framework.TestCase;
42 import junit.framework.TestSuite;
43 
44 /**
45  * Tests {@link MapTestSuiteBuilder} by using it against maps that have various negative behaviors.
46  *
47  * @author George van den Driessche
48  */
49 public final class MapTestSuiteBuilderTests extends TestCase {
MapTestSuiteBuilderTests()50   private MapTestSuiteBuilderTests() {}
51 
suite()52   public static Test suite() {
53     TestSuite suite = new TestSuite(MapTestSuiteBuilderTests.class.getSimpleName());
54     suite.addTest(testsForHashMapNullKeysForbidden());
55     suite.addTest(testsForHashMapNullValuesForbidden());
56     return suite;
57   }
58 
59   private abstract static class WrappedHashMapGenerator extends TestStringMapGenerator {
60     @Override
create(Entry<String, String>[] entries)61     protected final Map<String, String> create(Entry<String, String>[] entries) {
62       HashMap<String, String> map = Maps.newHashMap();
63       for (Entry<String, String> entry : entries) {
64         map.put(entry.getKey(), entry.getValue());
65       }
66       return wrap(map);
67     }
68 
wrap(HashMap<String, String> map)69     abstract Map<String, String> wrap(HashMap<String, String> map);
70   }
71 
wrappedHashMapTests( WrappedHashMapGenerator generator, String name, Feature<?>... features)72   private static TestSuite wrappedHashMapTests(
73       WrappedHashMapGenerator generator, String name, Feature<?>... features) {
74     List<Feature<?>> featuresList = Lists.newArrayList(features);
75     Collections.addAll(
76         featuresList,
77         MapFeature.GENERAL_PURPOSE,
78         CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
79         CollectionSize.ANY);
80     return MapTestSuiteBuilder.using(generator)
81         .named(name)
82         .withFeatures(featuresList)
83         .createTestSuite();
84   }
85 
86   // TODO: consider being null-hostile in these tests
87 
testsForHashMapNullKeysForbidden()88   private static Test testsForHashMapNullKeysForbidden() {
89     return wrappedHashMapTests(
90         new WrappedHashMapGenerator() {
91           @Override
92           Map<String, String> wrap(final HashMap<String, String> map) {
93             if (map.containsKey(null)) {
94               throw new NullPointerException();
95             }
96             return new AbstractMap<String, String>() {
97               @Override
98               public Set<Entry<String, String>> entrySet() {
99                 return map.entrySet();
100               }
101 
102               @Override
103               public String put(String key, String value) {
104                 checkNotNull(key);
105                 return map.put(key, value);
106               }
107             };
108           }
109         },
110         "HashMap w/out null keys",
111         ALLOWS_NULL_VALUES);
112   }
113 
114   private static Test testsForHashMapNullValuesForbidden() {
115     return wrappedHashMapTests(
116         new WrappedHashMapGenerator() {
117           @Override
118           Map<String, String> wrap(final HashMap<String, String> map) {
119             if (map.containsValue(null)) {
120               throw new NullPointerException();
121             }
122 
123             return new AbstractMap<String, String>() {
124               @Override
125               public Set<Entry<String, String>> entrySet() {
126                 return new EntrySet();
127               }
128 
129               @Override
130               public int hashCode() {
131                 return map.hashCode();
132               }
133 
134               @Override
135               public boolean equals(Object o) {
136                 return map.equals(o);
137               }
138 
139               @Override
140               public String toString() {
141                 return map.toString();
142               }
143 
144               @Override
145               public String remove(Object key) {
146                 return map.remove(key);
147               }
148 
149               @Override
150               public boolean remove(Object key, Object value) {
151                 return map.remove(key, value);
152               }
153 
154               class EntrySet extends AbstractSet<Map.Entry<String, String>> {
155                 @Override
156                 public Iterator<Entry<String, String>> iterator() {
157                   return new Iterator<Entry<String, String>>() {
158 
159                     final Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
160 
161                     @Override
162                     public void remove() {
163                       iterator.remove();
164                     }
165 
166                     @Override
167                     public boolean hasNext() {
168                       return iterator.hasNext();
169                     }
170 
171                     @Override
172                     public Entry<String, String> next() {
173                       return transform(iterator.next());
174                     }
175 
176                     private Entry<String, String> transform(final Entry<String, String> next) {
177                       return new Entry<String, String>() {
178 
179                         @Override
180                         public String setValue(String value) {
181                           checkNotNull(value);
182                           return next.setValue(value);
183                         }
184 
185                         @Override
186                         public String getValue() {
187                           return next.getValue();
188                         }
189 
190                         @Override
191                         public String getKey() {
192                           return next.getKey();
193                         }
194 
195                         @Override
196                         public boolean equals(Object obj) {
197                           return next.equals(obj);
198                         }
199 
200                         @Override
201                         public int hashCode() {
202                           return next.hashCode();
203                         }
204                       };
205                     }
206                   };
207                 }
208 
209                 @Override
210                 public int size() {
211                   return map.size();
212                 }
213 
214                 @Override
215                 public boolean remove(Object o) {
216                   return map.entrySet().remove(o);
217                 }
218 
219                 @Override
220                 public boolean removeIf(Predicate<? super Entry<String, String>> filter) {
221                   return map.entrySet().removeIf(filter);
222                 }
223 
224                 @Override
225                 public boolean containsAll(Collection<?> c) {
226                   return map.entrySet().containsAll(c);
227                 }
228 
229                 @Override
230                 public boolean removeAll(Collection<?> c) {
231                   return map.entrySet().removeAll(c);
232                 }
233 
234                 @Override
235                 public boolean retainAll(Collection<?> c) {
236                   return map.entrySet().retainAll(c);
237                 }
238 
239                 @Override
240                 public int hashCode() {
241                   return map.entrySet().hashCode();
242                 }
243 
244                 @Override
245                 public boolean equals(Object o) {
246                   return map.entrySet().equals(o);
247                 }
248 
249                 @Override
250                 public String toString() {
251                   return map.entrySet().toString();
252                 }
253               }
254 
255               @Override
256               public String put(String key, String value) {
257                 checkNotNull(value);
258                 return map.put(key, value);
259               }
260             };
261           }
262         },
263         "HashMap w/out null values",
264         ALLOWS_NULL_KEYS);
265   }
266 }
267