Java

Форк
0
/
MapTestSuiteBuilderTests.java 
359 строк · 11.9 Кб
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 com.google.common.reflect.Reflection;
30
import java.io.Serializable;
31
import java.lang.reflect.InvocationHandler;
32
import java.lang.reflect.InvocationTargetException;
33
import java.lang.reflect.Method;
34
import java.util.AbstractMap;
35
import java.util.AbstractSet;
36
import java.util.Collection;
37
import java.util.Collections;
38
import java.util.HashMap;
39
import java.util.Iterator;
40
import java.util.List;
41
import java.util.Map;
42
import java.util.Map.Entry;
43
import java.util.Set;
44
import java.util.concurrent.atomic.AtomicBoolean;
45
import java.util.function.Predicate;
46
import junit.framework.Test;
47
import junit.framework.TestCase;
48
import junit.framework.TestSuite;
49
import org.checkerframework.checker.nullness.qual.Nullable;
50

51
/**
52
 * Tests {@link MapTestSuiteBuilder} by using it against maps that have various negative behaviors.
53
 *
54
 * @author George van den Driessche
55
 */
56
public final class MapTestSuiteBuilderTests extends TestCase {
57
  private MapTestSuiteBuilderTests() {}
58

59
  public static Test suite() {
60
    TestSuite suite = new TestSuite(MapTestSuiteBuilderTests.class.getSimpleName());
61
    suite.addTest(testsForHashMapNullKeysForbidden());
62
    suite.addTest(testsForHashMapNullValuesForbidden());
63
    suite.addTest(testsForSetUpTearDown());
64
    return suite;
65
  }
66

67
  private abstract static class WrappedHashMapGenerator extends TestStringMapGenerator {
68
    @Override
69
    protected final Map<String, String> create(Entry<String, String>[] entries) {
70
      HashMap<String, String> map = Maps.newHashMap();
71
      for (Entry<String, String> entry : entries) {
72
        map.put(entry.getKey(), entry.getValue());
73
      }
74
      return wrap(map);
75
    }
76

77
    abstract Map<String, String> wrap(HashMap<String, String> map);
78
  }
79

80
  private static TestSuite wrappedHashMapTests(
81
      WrappedHashMapGenerator generator, String name, Feature<?>... features) {
82
    List<Feature<?>> featuresList = Lists.newArrayList(features);
83
    Collections.addAll(
84
        featuresList,
85
        MapFeature.GENERAL_PURPOSE,
86
        CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
87
        CollectionSize.ANY);
88
    return MapTestSuiteBuilder.using(generator)
89
        .named(name)
90
        .withFeatures(featuresList)
91
        .createTestSuite();
92
  }
93

94
  // TODO: consider being null-hostile in these tests
95

96
  private static Test testsForHashMapNullKeysForbidden() {
97
    return wrappedHashMapTests(
98
        new WrappedHashMapGenerator() {
99
          @Override
100
          Map<String, String> wrap(final HashMap<String, String> map) {
101
            if (map.containsKey(null)) {
102
              throw new NullPointerException();
103
            }
104
            return new AbstractMap<String, String>() {
105
              @Override
106
              public Set<Entry<String, String>> entrySet() {
107
                return map.entrySet();
108
              }
109

110
              @Override
111
              public @Nullable String put(String key, String value) {
112
                checkNotNull(key);
113
                return map.put(key, value);
114
              }
115
            };
116
          }
117
        },
118
        "HashMap w/out null keys",
119
        ALLOWS_NULL_VALUES);
120
  }
121

122
  private static Test testsForHashMapNullValuesForbidden() {
123
    return wrappedHashMapTests(
124
        new WrappedHashMapGenerator() {
125
          @Override
126
          Map<String, String> wrap(final HashMap<String, String> map) {
127
            if (map.containsValue(null)) {
128
              throw new NullPointerException();
129
            }
130

131
            return new AbstractMap<String, String>() {
132
              @Override
133
              public Set<Entry<String, String>> entrySet() {
134
                return new EntrySet();
135
              }
136

137
              @Override
138
              public int hashCode() {
139
                return map.hashCode();
140
              }
141

142
              @Override
143
              public boolean equals(@Nullable Object o) {
144
                return map.equals(o);
145
              }
146

147
              @Override
148
              public String toString() {
149
                return map.toString();
150
              }
151

152
              @Override
153
              public @Nullable String remove(Object key) {
154
                return map.remove(key);
155
              }
156

157
              @Override
158
              public boolean remove(Object key, Object value) {
159
                return map.remove(key, value);
160
              }
161

162
              class EntrySet extends AbstractSet<Map.Entry<String, String>> {
163
                @Override
164
                public Iterator<Entry<String, String>> iterator() {
165
                  return new Iterator<Entry<String, String>>() {
166

167
                    final Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
168

169
                    @Override
170
                    public void remove() {
171
                      iterator.remove();
172
                    }
173

174
                    @Override
175
                    public boolean hasNext() {
176
                      return iterator.hasNext();
177
                    }
178

179
                    @Override
180
                    public Entry<String, String> next() {
181
                      return transform(iterator.next());
182
                    }
183

184
                    private Entry<String, String> transform(final Entry<String, String> next) {
185
                      return new Entry<String, String>() {
186

187
                        @Override
188
                        public String setValue(String value) {
189
                          checkNotNull(value);
190
                          return next.setValue(value);
191
                        }
192

193
                        @Override
194
                        public String getValue() {
195
                          return next.getValue();
196
                        }
197

198
                        @Override
199
                        public String getKey() {
200
                          return next.getKey();
201
                        }
202

203
                        @Override
204
                        public boolean equals(@Nullable Object obj) {
205
                          return next.equals(obj);
206
                        }
207

208
                        @Override
209
                        public int hashCode() {
210
                          return next.hashCode();
211
                        }
212
                      };
213
                    }
214
                  };
215
                }
216

217
                @Override
218
                public int size() {
219
                  return map.size();
220
                }
221

222
                @Override
223
                public boolean remove(Object o) {
224
                  return map.entrySet().remove(o);
225
                }
226

227
                @Override
228
                public boolean removeIf(Predicate<? super Entry<String, String>> filter) {
229
                  return map.entrySet().removeIf(filter);
230
                }
231

232
                @Override
233
                public boolean containsAll(Collection<?> c) {
234
                  return map.entrySet().containsAll(c);
235
                }
236

237
                @Override
238
                public boolean removeAll(Collection<?> c) {
239
                  return map.entrySet().removeAll(c);
240
                }
241

242
                @Override
243
                public boolean retainAll(Collection<?> c) {
244
                  return map.entrySet().retainAll(c);
245
                }
246

247
                @Override
248
                public int hashCode() {
249
                  return map.entrySet().hashCode();
250
                }
251

252
                @Override
253
                public boolean equals(@Nullable Object o) {
254
                  return map.entrySet().equals(o);
255
                }
256

257
                @Override
258
                public String toString() {
259
                  return map.entrySet().toString();
260
                }
261
              }
262

263
              @Override
264
              public @Nullable String put(String key, String value) {
265
                checkNotNull(value);
266
                return map.put(key, value);
267
              }
268
            };
269
          }
270
        },
271
        "HashMap w/out null values",
272
        ALLOWS_NULL_KEYS);
273
  }
274

275
  /**
276
   * Map generator that verifies that {@code setUp()} methods are called in all the test cases. The
277
   * {@code setUpRan} parameter is set true by the {@code setUp} that every test case is supposed to
278
   * have registered, and set false by the {@code tearDown}. We use a dynamic proxy to intercept all
279
   * of the {@code Map} method calls and check that {@code setUpRan} is true.
280
   */
281
  private static class CheckSetUpHashMapGenerator extends WrappedHashMapGenerator {
282
    private final AtomicBoolean setUpRan;
283

284
    CheckSetUpHashMapGenerator(AtomicBoolean setUpRan) {
285
      this.setUpRan = setUpRan;
286
    }
287

288
    @Override
289
    Map<String, String> wrap(HashMap<String, String> map) {
290
      @SuppressWarnings("unchecked")
291
      Map<String, String> proxy =
292
          Reflection.newProxy(Map.class, new CheckSetUpInvocationHandler(map, setUpRan));
293
      return proxy;
294
    }
295
  }
296

297
  /**
298
   * Intercepts calls to a {@code Map} to check that {@code setUpRan} is true when they happen. Then
299
   * forwards the calls to the underlying {@code Map}.
300
   */
301
  private static class CheckSetUpInvocationHandler implements InvocationHandler, Serializable {
302
    private final Map<String, String> map;
303
    private final AtomicBoolean setUpRan;
304

305
    CheckSetUpInvocationHandler(Map<String, String> map, AtomicBoolean setUpRan) {
306
      this.map = map;
307
      this.setUpRan = setUpRan;
308
    }
309

310
    @Override
311
    public Object invoke(Object target, Method method, Object[] args) throws Throwable {
312
      assertTrue("setUp should have run", setUpRan.get());
313
      try {
314
        return method.invoke(map, args);
315
      } catch (InvocationTargetException e) {
316
        throw e.getCause();
317
      } catch (IllegalAccessException e) {
318
        throw newLinkageError(e);
319
      }
320
    }
321
  }
322

323
  /** Verifies that {@code setUp} and {@code tearDown} are called in all map test cases. */
324
  private static Test testsForSetUpTearDown() {
325
    final AtomicBoolean setUpRan = new AtomicBoolean();
326
    Runnable setUp =
327
        new Runnable() {
328
          @Override
329
          public void run() {
330
            assertFalse("previous tearDown should have run before setUp", setUpRan.getAndSet(true));
331
          }
332
        };
333
    Runnable tearDown =
334
        new Runnable() {
335
          @Override
336
          public void run() {
337
            assertTrue("setUp should have run", setUpRan.getAndSet(false));
338
          }
339
        };
340
    return MapTestSuiteBuilder.using(new CheckSetUpHashMapGenerator(setUpRan))
341
        .named("setUpTearDown")
342
        .withFeatures(
343
            MapFeature.GENERAL_PURPOSE,
344
            MapFeature.ALLOWS_NULL_KEYS,
345
            MapFeature.ALLOWS_NULL_VALUES,
346
            CollectionFeature.SERIALIZABLE,
347
            CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
348
            CollectionSize.ANY)
349
        .withSetUp(setUp)
350
        .withTearDown(tearDown)
351
        .createTestSuite();
352
  }
353

354
  private static LinkageError newLinkageError(Throwable cause) {
355
    LinkageError error = new LinkageError(cause.toString());
356
    error.initCause(cause);
357
    return error;
358
  }
359
}
360

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.