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
17package com.google.common.collect;
18
19import static com.google.common.collect.Lists.newArrayList;
20import static com.google.common.collect.Lists.newLinkedList;
21import static com.google.common.collect.testing.testers.CollectionIteratorTester.getIteratorKnownOrderRemoveSupportedMethod;
22import static java.util.Arrays.asList;
23import static org.junit.contrib.truth.Truth.ASSERT;
24
25import com.google.common.annotations.GwtCompatible;
26import com.google.common.annotations.GwtIncompatible;
27import com.google.common.base.Function;
28import com.google.common.base.Predicate;
29import com.google.common.collect.testing.CollectionTestSuiteBuilder;
30import com.google.common.collect.testing.TestStringCollectionGenerator;
31import com.google.common.collect.testing.features.CollectionFeature;
32import com.google.common.collect.testing.features.CollectionSize;
33import com.google.common.testing.NullPointerTester;
34
35import junit.framework.Test;
36import junit.framework.TestCase;
37import junit.framework.TestSuite;
38
39import java.util.Collection;
40import java.util.Collections;
41import java.util.List;
42
43/**
44 * Tests for {@link Collections2}.
45 *
46 * @author Chris Povirk
47 * @author Jared Levy
48 */
49@GwtCompatible(emulated = true)
50public class Collections2Test extends TestCase {
51  @GwtIncompatible("suite")
52  public static Test suite() {
53    TestSuite suite = new TestSuite(Collections2Test.class.getSimpleName());
54    suite.addTest(testsForFilter());
55    suite.addTest(testsForFilterAll());
56    suite.addTest(testsForFilterLinkedList());
57    suite.addTest(testsForFilterNoNulls());
58    suite.addTest(testsForFilterFiltered());
59    suite.addTest(testsForTransform());
60    suite.addTestSuite(Collections2Test.class);
61    return suite;
62  }
63
64  static final Predicate<String> NOT_YYY_ZZZ = new Predicate<String>() {
65      @Override
66      public boolean apply(String input) {
67        return !"yyy".equals(input) && !"zzz".equals(input);
68      }
69  };
70
71  static final Predicate<String> LENGTH_1 = new Predicate<String>() {
72    @Override
73    public boolean apply(String input) {
74      return input.length() == 1;
75    }
76  };
77
78  static final Predicate<String> STARTS_WITH_VOWEL = new Predicate<String>() {
79    @Override
80    public boolean apply(String input) {
81      return asList('a', 'e', 'i', 'o', 'u').contains(input.charAt(0));
82    }
83  };
84
85  @GwtIncompatible("suite")
86  private static Test testsForFilter() {
87    return CollectionTestSuiteBuilder.using(
88        new TestStringCollectionGenerator() {
89          @Override public Collection<String> create(String[] elements) {
90            List<String> unfiltered = newArrayList();
91            unfiltered.add("yyy");
92            unfiltered.addAll(asList(elements));
93            unfiltered.add("zzz");
94            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
95          }
96        })
97        .named("Collections2.filter")
98        .withFeatures(
99            CollectionFeature.GENERAL_PURPOSE,
100            CollectionFeature.ALLOWS_NULL_VALUES,
101            CollectionFeature.KNOWN_ORDER,
102            CollectionSize.ANY)
103        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
104        .createTestSuite();
105  }
106
107  @GwtIncompatible("suite")
108  private static Test testsForFilterAll() {
109    return CollectionTestSuiteBuilder.using(
110        new TestStringCollectionGenerator() {
111          @Override public Collection<String> create(String[] elements) {
112            List<String> unfiltered = newArrayList();
113            unfiltered.addAll(asList(elements));
114            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
115          }
116        })
117        .named("Collections2.filter")
118        .withFeatures(
119            CollectionFeature.GENERAL_PURPOSE,
120            CollectionFeature.ALLOWS_NULL_VALUES,
121            CollectionFeature.KNOWN_ORDER,
122            CollectionSize.ANY)
123        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
124        .createTestSuite();
125  }
126
127  @GwtIncompatible("suite")
128  private static Test testsForFilterLinkedList() {
129    return CollectionTestSuiteBuilder.using(
130        new TestStringCollectionGenerator() {
131          @Override public Collection<String> create(String[] elements) {
132            List<String> unfiltered = newLinkedList();
133            unfiltered.add("yyy");
134            unfiltered.addAll(asList(elements));
135            unfiltered.add("zzz");
136            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
137          }
138        })
139        .named("Collections2.filter")
140        .withFeatures(
141            CollectionFeature.GENERAL_PURPOSE,
142            CollectionFeature.ALLOWS_NULL_VALUES,
143            CollectionFeature.KNOWN_ORDER,
144            CollectionSize.ANY)
145        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
146        .createTestSuite();
147  }
148
149  @GwtIncompatible("suite")
150  private static Test testsForFilterNoNulls() {
151    return CollectionTestSuiteBuilder.using(
152        new TestStringCollectionGenerator() {
153          @Override public Collection<String> create(String[] elements) {
154            List<String> unfiltered = newArrayList();
155            unfiltered.add("yyy");
156            unfiltered.addAll(ImmutableList.copyOf(elements));
157            unfiltered.add("zzz");
158            return Collections2.filter(unfiltered, LENGTH_1);
159          }
160        })
161        .named("Collections2.filter, no nulls")
162        .withFeatures(
163            CollectionFeature.GENERAL_PURPOSE,
164            CollectionFeature.ALLOWS_NULL_QUERIES,
165            CollectionFeature.KNOWN_ORDER,
166            CollectionSize.ANY)
167        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
168        .createTestSuite();
169  }
170
171  @GwtIncompatible("suite")
172  private static Test testsForFilterFiltered() {
173    return CollectionTestSuiteBuilder.using(
174        new TestStringCollectionGenerator() {
175          @Override public Collection<String> create(String[] elements) {
176            List<String> unfiltered = newArrayList();
177            unfiltered.add("yyy");
178            unfiltered.addAll(ImmutableList.copyOf(elements));
179            unfiltered.add("zzz");
180            unfiltered.add("abc");
181            return Collections2.filter(
182                Collections2.filter(unfiltered, LENGTH_1), NOT_YYY_ZZZ);
183          }
184        })
185        .named("Collections2.filter, filtered input")
186        .withFeatures(
187            CollectionFeature.GENERAL_PURPOSE,
188            CollectionFeature.KNOWN_ORDER,
189            CollectionFeature.ALLOWS_NULL_QUERIES,
190            CollectionSize.ANY)
191        .suppressing(getIteratorKnownOrderRemoveSupportedMethod())
192        .createTestSuite();
193  }
194
195  public abstract static class FilterChangeTest extends TestCase {
196    protected abstract <E> List<E> newList();
197
198    public void testFilterIllegalAdd() {
199      List<String> unfiltered = newList();
200      Collection<String> filtered
201          = Collections2.filter(unfiltered, NOT_YYY_ZZZ);
202      filtered.add("a");
203      filtered.add("b");
204      ASSERT.that(filtered).hasContentsInOrder("a", "b");
205
206      try {
207        filtered.add("yyy");
208        fail();
209      } catch (IllegalArgumentException expected) {}
210
211      try {
212        filtered.addAll(asList("c", "zzz", "d"));
213        fail();
214      } catch (IllegalArgumentException expected) {}
215
216      ASSERT.that(filtered).hasContentsInOrder("a", "b");
217    }
218
219    public void testFilterChangeUnfiltered() {
220      List<String> unfiltered = newList();
221      Collection<String> filtered
222          = Collections2.filter(unfiltered, NOT_YYY_ZZZ);
223
224      unfiltered.add("a");
225      unfiltered.add("yyy");
226      unfiltered.add("b");
227      ASSERT.that(unfiltered).hasContentsInOrder("a", "yyy", "b");
228      ASSERT.that(filtered).hasContentsInOrder("a", "b");
229
230      unfiltered.remove("a");
231      ASSERT.that(unfiltered).hasContentsInOrder("yyy", "b");
232      ASSERT.that(filtered).hasContentsInOrder("b");
233
234      unfiltered.clear();
235      ASSERT.that(unfiltered).isEmpty();
236      ASSERT.that(filtered).isEmpty();
237
238      unfiltered.add("yyy");
239      ASSERT.that(unfiltered).hasContentsInOrder("yyy");
240      ASSERT.that(filtered).isEmpty();
241      filtered.clear();
242      ASSERT.that(unfiltered).hasContentsInOrder("yyy");
243      ASSERT.that(filtered).isEmpty();
244
245      unfiltered.clear();
246      filtered.clear();
247      ASSERT.that(unfiltered).isEmpty();
248      ASSERT.that(filtered).isEmpty();
249
250      unfiltered.add("a");
251      ASSERT.that(unfiltered).hasContentsInOrder("a");
252      ASSERT.that(filtered).hasContentsInOrder("a");
253      filtered.clear();
254      ASSERT.that(unfiltered).isEmpty();
255      ASSERT.that(filtered).isEmpty();
256
257      unfiltered.clear();
258      Collections.addAll(unfiltered,
259          "a", "b", "yyy", "zzz", "c", "d", "yyy", "zzz");
260      ASSERT.that(unfiltered).hasContentsInOrder(
261          "a", "b", "yyy", "zzz", "c", "d", "yyy", "zzz");
262      ASSERT.that(filtered).hasContentsInOrder("a", "b", "c", "d");
263      filtered.clear();
264      ASSERT.that(unfiltered).hasContentsInOrder("yyy", "zzz", "yyy", "zzz");
265      ASSERT.that(filtered).isEmpty();
266    }
267
268    public void testFilterChangeFiltered() {
269      List<String> unfiltered = newList();
270      Collection<String> filtered
271          = Collections2.filter(unfiltered, NOT_YYY_ZZZ);
272
273      unfiltered.add("a");
274      unfiltered.add("yyy");
275      filtered.add("b");
276      ASSERT.that(unfiltered).hasContentsInOrder("a", "yyy", "b");
277      ASSERT.that(filtered).hasContentsInOrder("a", "b");
278
279      filtered.remove("a");
280      ASSERT.that(unfiltered).hasContentsInOrder("yyy", "b");
281      ASSERT.that(filtered).hasContentsInOrder("b");
282
283      filtered.clear();
284      ASSERT.that(unfiltered).hasContentsInOrder("yyy");
285      ASSERT.that(filtered);
286    }
287
288    public void testFilterFiltered() {
289      List<String> unfiltered = newList();
290      Collection<String> filtered = Collections2.filter(
291          Collections2.filter(unfiltered, LENGTH_1), STARTS_WITH_VOWEL);
292      unfiltered.add("a");
293      unfiltered.add("b");
294      unfiltered.add("apple");
295      unfiltered.add("banana");
296      unfiltered.add("e");
297      ASSERT.that(filtered).hasContentsInOrder("a", "e");
298      ASSERT.that(unfiltered).hasContentsInOrder("a", "b", "apple", "banana", "e");
299
300      try {
301        filtered.add("d");
302        fail();
303      } catch (IllegalArgumentException expected) {}
304      try {
305        filtered.add("egg");
306        fail();
307      } catch (IllegalArgumentException expected) {}
308      ASSERT.that(filtered).hasContentsInOrder("a", "e");
309      ASSERT.that(unfiltered).hasContentsInOrder("a", "b", "apple", "banana", "e");
310
311      filtered.clear();
312      ASSERT.that(filtered).isEmpty();
313      ASSERT.that(unfiltered).hasContentsInOrder("b", "apple", "banana");
314    }
315  }
316
317  public static class ArrayListFilterChangeTest extends FilterChangeTest {
318    @Override protected <E> List<E> newList() {
319      return Lists.newArrayList();
320    }
321  }
322
323  public static class LinkedListFilterChangeTest extends FilterChangeTest {
324    @Override protected <E> List<E> newList() {
325      return Lists.newLinkedList();
326    }
327  }
328
329  private static final Function<String, String> REMOVE_FIRST_CHAR
330      = new Function<String, String>() {
331        @Override
332        public String apply(String from) {
333          return ((from == null) || "".equals(from))
334              ? null : from.substring(1);
335        }
336      };
337
338  @GwtIncompatible("suite")
339  private static Test testsForTransform() {
340    return CollectionTestSuiteBuilder.using(
341        new TestStringCollectionGenerator() {
342          @Override public Collection<String> create(String[] elements) {
343            List<String> list = newArrayList();
344            for (String element : elements) {
345              list.add((element == null) ? null : "q" + element);
346            }
347            return Collections2.transform(list, REMOVE_FIRST_CHAR);
348          }
349        })
350        .named("Collections2.transform")
351        .withFeatures(
352            CollectionFeature.REMOVE_OPERATIONS,
353            CollectionFeature.ALLOWS_NULL_VALUES,
354            CollectionFeature.KNOWN_ORDER,
355            CollectionSize.ANY)
356        .createTestSuite();
357  }
358
359  @GwtIncompatible("NullPointerTester")
360  public void testNullPointerExceptions() throws Exception {
361    NullPointerTester tester = new NullPointerTester();
362    tester.testAllPublicStaticMethods(Collections2.class);
363  }
364}
365