• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import static com.google.common.collect.FluentIterableTest.Help.assertThat;
20 import static com.google.common.collect.Lists.newArrayList;
21 import static com.google.common.truth.Truth.assertThat;
22 import static java.util.Arrays.asList;
23 
24 import com.google.common.annotations.GwtCompatible;
25 import com.google.common.annotations.GwtIncompatible;
26 import com.google.common.base.Function;
27 import com.google.common.base.Functions;
28 import com.google.common.base.Joiner;
29 import com.google.common.base.Predicate;
30 import com.google.common.base.Predicates;
31 import com.google.common.collect.testing.IteratorFeature;
32 import com.google.common.collect.testing.IteratorTester;
33 import com.google.common.testing.NullPointerTester;
34 import com.google.common.truth.IterableSubject;
35 import com.google.common.truth.Truth;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Set;
42 import java.util.SortedSet;
43 import java.util.concurrent.TimeUnit;
44 import java.util.stream.Stream;
45 import junit.framework.AssertionFailedError;
46 import junit.framework.TestCase;
47 import org.checkerframework.checker.nullness.qual.Nullable;
48 
49 /**
50  * Unit test for {@link FluentIterable}.
51  *
52  * @author Marcin Mikosik
53  */
54 @GwtCompatible(emulated = true)
55 public class FluentIterableTest extends TestCase {
56 
57   @GwtIncompatible // NullPointerTester
testNullPointerExceptions()58   public void testNullPointerExceptions() {
59     NullPointerTester tester = new NullPointerTester();
60     tester.testAllPublicStaticMethods(FluentIterable.class);
61   }
62 
testFromArrayAndAppend()63   public void testFromArrayAndAppend() {
64     FluentIterable<TimeUnit> units =
65         FluentIterable.from(TimeUnit.values()).append(TimeUnit.SECONDS);
66   }
67 
testFromArrayAndIteratorRemove()68   public void testFromArrayAndIteratorRemove() {
69     FluentIterable<TimeUnit> units = FluentIterable.from(TimeUnit.values());
70     try {
71       Iterables.removeIf(units, Predicates.equalTo(TimeUnit.SECONDS));
72       fail("Expected an UnsupportedOperationException to be thrown but it wasn't.");
73     } catch (UnsupportedOperationException expected) {
74     }
75   }
76 
testFrom()77   public void testFrom() {
78     assertEquals(
79         ImmutableList.of(1, 2, 3, 4),
80         Lists.newArrayList(FluentIterable.from(ImmutableList.of(1, 2, 3, 4))));
81   }
82 
83   @SuppressWarnings("deprecation") // test of deprecated method
testFrom_alreadyFluentIterable()84   public void testFrom_alreadyFluentIterable() {
85     FluentIterable<Integer> iterable = FluentIterable.from(asList(1));
86     assertSame(iterable, FluentIterable.from(iterable));
87   }
88 
testOf()89   public void testOf() {
90     assertEquals(ImmutableList.of(1, 2, 3, 4), Lists.newArrayList(FluentIterable.of(1, 2, 3, 4)));
91   }
92 
testFromArray()93   public void testFromArray() {
94     assertEquals(
95         ImmutableList.of("1", "2", "3", "4"),
96         Lists.newArrayList(FluentIterable.from(new Object[] {"1", "2", "3", "4"})));
97   }
98 
testOf_empty()99   public void testOf_empty() {
100     assertEquals(ImmutableList.of(), Lists.newArrayList(FluentIterable.of()));
101   }
102 
103   // Exhaustive tests are in IteratorsTest. These are copied from IterablesTest.
testConcatIterable()104   public void testConcatIterable() {
105     List<Integer> list1 = newArrayList(1);
106     List<Integer> list2 = newArrayList(4);
107 
108     @SuppressWarnings("unchecked")
109     List<List<Integer>> input = newArrayList(list1, list2);
110 
111     FluentIterable<Integer> result = FluentIterable.concat(input);
112     assertEquals(asList(1, 4), newArrayList(result));
113 
114     // Now change the inputs and see result dynamically change as well
115 
116     list1.add(2);
117     List<Integer> list3 = newArrayList(3);
118     input.add(1, list3);
119 
120     assertEquals(asList(1, 2, 3, 4), newArrayList(result));
121     assertEquals("[1, 2, 3, 4]", result.toString());
122   }
123 
testConcatVarargs()124   public void testConcatVarargs() {
125     List<Integer> list1 = newArrayList(1);
126     List<Integer> list2 = newArrayList(4);
127     List<Integer> list3 = newArrayList(7, 8);
128     List<Integer> list4 = newArrayList(9);
129     List<Integer> list5 = newArrayList(10);
130     @SuppressWarnings("unchecked")
131     FluentIterable<Integer> result = FluentIterable.concat(list1, list2, list3, list4, list5);
132     assertEquals(asList(1, 4, 7, 8, 9, 10), newArrayList(result));
133     assertEquals("[1, 4, 7, 8, 9, 10]", result.toString());
134   }
135 
testConcatNullPointerException()136   public void testConcatNullPointerException() {
137     List<Integer> list1 = newArrayList(1);
138     List<Integer> list2 = newArrayList(4);
139 
140     try {
141       FluentIterable.concat(list1, null, list2);
142       fail();
143     } catch (NullPointerException expected) {
144     }
145   }
146 
testConcatPeformingFiniteCycle()147   public void testConcatPeformingFiniteCycle() {
148     Iterable<Integer> iterable = asList(1, 2, 3);
149     int n = 4;
150     FluentIterable<Integer> repeated = FluentIterable.concat(Collections.nCopies(n, iterable));
151     assertThat(repeated).containsExactly(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3).inOrder();
152   }
153 
154   interface X {}
155 
156   interface Y {}
157 
158   static class A implements X, Y {}
159 
160   static class B implements X, Y {}
161 
162   /**
163    * This test passes if the {@code concat(…).filter(…).filter(…)} statement at the end compiles.
164    * That statement compiles only if {@link FluentIterable#concat concat(aIterable, bIterable)}
165    * returns a {@link FluentIterable} of elements of an anonymous type whose supertypes are the <a
166    * href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.9">intersection</a> of
167    * the supertypes of {@code A} and the supertypes of {@code B}.
168    */
testConcatIntersectionType()169   public void testConcatIntersectionType() {
170     Iterable<A> aIterable = ImmutableList.of();
171     Iterable<B> bIterable = ImmutableList.of();
172 
173     Predicate<X> xPredicate = Predicates.alwaysTrue();
174     Predicate<Y> yPredicate = Predicates.alwaysTrue();
175 
176     FluentIterable<?> unused =
177         FluentIterable.concat(aIterable, bIterable).filter(xPredicate).filter(yPredicate);
178 
179     /* The following fails to compile:
180      *
181      * The method append(Iterable<? extends FluentIterableTest.A>) in the type
182      * FluentIterable<FluentIterableTest.A> is not applicable for the arguments
183      * (Iterable<FluentIterableTest.B>)
184      */
185     // FluentIterable.from(aIterable).append(bIterable);
186 
187     /* The following fails to compile:
188      *
189      * The method filter(Predicate<? super Object>) in the type FluentIterable<Object> is not
190      * applicable for the arguments (Predicate<FluentIterableTest.X>)
191      */
192     // FluentIterable.of().append(aIterable).append(bIterable).filter(xPredicate);
193   }
194 
testSize0()195   public void testSize0() {
196     assertEquals(0, FluentIterable.<String>of().size());
197   }
198 
testSize1Collection()199   public void testSize1Collection() {
200     assertEquals(1, FluentIterable.from(asList("a")).size());
201   }
202 
testSize2NonCollection()203   public void testSize2NonCollection() {
204     Iterable<Integer> iterable =
205         new Iterable<Integer>() {
206           @Override
207           public Iterator<Integer> iterator() {
208             return asList(0, 1).iterator();
209           }
210         };
211     assertEquals(2, FluentIterable.from(iterable).size());
212   }
213 
testSize_collectionDoesntIterate()214   public void testSize_collectionDoesntIterate() {
215     List<Integer> nums = asList(1, 2, 3, 4, 5);
216     List<Integer> collection =
217         new ArrayList<Integer>(nums) {
218           @Override
219           public Iterator<Integer> iterator() {
220             throw new AssertionFailedError("Don't iterate me!");
221           }
222         };
223     assertEquals(5, FluentIterable.from(collection).size());
224   }
225 
testContains_nullSetYes()226   public void testContains_nullSetYes() {
227     Iterable<String> set = Sets.newHashSet("a", null, "b");
228     assertTrue(FluentIterable.from(set).contains(null));
229   }
230 
testContains_nullSetNo()231   public void testContains_nullSetNo() {
232     Iterable<String> set = ImmutableSortedSet.of("a", "b");
233     assertFalse(FluentIterable.from(set).contains(null));
234   }
235 
testContains_nullIterableYes()236   public void testContains_nullIterableYes() {
237     Iterable<String> iterable = iterable("a", null, "b");
238     assertTrue(FluentIterable.from(iterable).contains(null));
239   }
240 
testContains_nullIterableNo()241   public void testContains_nullIterableNo() {
242     Iterable<String> iterable = iterable("a", "b");
243     assertFalse(FluentIterable.from(iterable).contains(null));
244   }
245 
testContains_nonNullSetYes()246   public void testContains_nonNullSetYes() {
247     Iterable<String> set = Sets.newHashSet("a", null, "b");
248     assertTrue(FluentIterable.from(set).contains("b"));
249   }
250 
testContains_nonNullSetNo()251   public void testContains_nonNullSetNo() {
252     Iterable<String> set = Sets.newHashSet("a", "b");
253     assertFalse(FluentIterable.from(set).contains("c"));
254   }
255 
testContains_nonNullIterableYes()256   public void testContains_nonNullIterableYes() {
257     Iterable<String> set = iterable("a", null, "b");
258     assertTrue(FluentIterable.from(set).contains("b"));
259   }
260 
testContains_nonNullIterableNo()261   public void testContains_nonNullIterableNo() {
262     Iterable<String> iterable = iterable("a", "b");
263     assertFalse(FluentIterable.from(iterable).contains("c"));
264   }
265 
testOfToString()266   public void testOfToString() {
267     assertEquals("[yam, bam, jam, ham]", FluentIterable.of("yam", "bam", "jam", "ham").toString());
268   }
269 
testToString()270   public void testToString() {
271     assertEquals("[]", FluentIterable.from(Collections.emptyList()).toString());
272     assertEquals("[]", FluentIterable.<String>of().toString());
273 
274     assertEquals(
275         "[yam, bam, jam, ham]", FluentIterable.from(asList("yam", "bam", "jam", "ham")).toString());
276   }
277 
testCycle()278   public void testCycle() {
279     FluentIterable<String> cycle = FluentIterable.from(asList("a", "b")).cycle();
280 
281     int howManyChecked = 0;
282     for (String string : cycle) {
283       String expected = (howManyChecked % 2 == 0) ? "a" : "b";
284       assertEquals(expected, string);
285       if (howManyChecked++ == 5) {
286         break;
287       }
288     }
289 
290     // We left the last iterator pointing to "b". But a new iterator should
291     // always point to "a".
292     assertEquals("a", cycle.iterator().next());
293   }
294 
testCycle_emptyIterable()295   public void testCycle_emptyIterable() {
296     FluentIterable<Integer> cycle = FluentIterable.<Integer>of().cycle();
297     assertFalse(cycle.iterator().hasNext());
298   }
299 
testCycle_removingAllElementsStopsCycle()300   public void testCycle_removingAllElementsStopsCycle() {
301     FluentIterable<Integer> cycle = fluent(1, 2).cycle();
302     Iterator<Integer> iterator = cycle.iterator();
303     iterator.next();
304     iterator.remove();
305     iterator.next();
306     iterator.remove();
307     assertFalse(iterator.hasNext());
308     assertFalse(cycle.iterator().hasNext());
309   }
310 
testAppend()311   public void testAppend() {
312     FluentIterable<Integer> result =
313         FluentIterable.<Integer>from(asList(1, 2, 3)).append(Lists.newArrayList(4, 5, 6));
314     assertEquals(asList(1, 2, 3, 4, 5, 6), Lists.newArrayList(result));
315     assertEquals("[1, 2, 3, 4, 5, 6]", result.toString());
316 
317     result = FluentIterable.<Integer>from(asList(1, 2, 3)).append(4, 5, 6);
318     assertEquals(asList(1, 2, 3, 4, 5, 6), Lists.newArrayList(result));
319     assertEquals("[1, 2, 3, 4, 5, 6]", result.toString());
320   }
321 
testAppend_toEmpty()322   public void testAppend_toEmpty() {
323     FluentIterable<Integer> result =
324         FluentIterable.<Integer>of().append(Lists.newArrayList(1, 2, 3));
325     assertEquals(asList(1, 2, 3), Lists.newArrayList(result));
326   }
327 
testAppend_emptyList()328   public void testAppend_emptyList() {
329     FluentIterable<Integer> result =
330         FluentIterable.<Integer>from(asList(1, 2, 3)).append(Lists.<Integer>newArrayList());
331     assertEquals(asList(1, 2, 3), Lists.newArrayList(result));
332   }
333 
testAppend_nullPointerException()334   public void testAppend_nullPointerException() {
335     try {
336       FluentIterable<Integer> unused =
337           FluentIterable.<Integer>from(asList(1, 2)).append((List<Integer>) null);
338       fail("Appending null iterable should throw NPE.");
339     } catch (NullPointerException expected) {
340     }
341   }
342 
343   /*
344    * Tests for partition(int size) method.
345    */
346 
347   /*
348    * Tests for partitionWithPadding(int size) method.
349    */
350 
testFilter()351   public void testFilter() {
352     FluentIterable<String> filtered =
353         FluentIterable.from(asList("foo", "bar")).filter(Predicates.equalTo("foo"));
354 
355     List<String> expected = Collections.singletonList("foo");
356     List<String> actual = Lists.newArrayList(filtered);
357     assertEquals(expected, actual);
358     assertCanIterateAgain(filtered);
359     assertEquals("[foo]", filtered.toString());
360   }
361 
362   private static class TypeA {}
363 
364   private interface TypeB {}
365 
366   private static class HasBoth extends TypeA implements TypeB {}
367 
368   @GwtIncompatible // Iterables.filter(Iterable, Class)
testFilterByType()369   public void testFilterByType() throws Exception {
370     HasBoth hasBoth = new HasBoth();
371     FluentIterable<TypeA> alist =
372         FluentIterable.from(asList(new TypeA(), new TypeA(), hasBoth, new TypeA()));
373     Iterable<TypeB> blist = alist.filter(TypeB.class);
374     assertThat(blist).containsExactly(hasBoth).inOrder();
375   }
376 
testAnyMatch()377   public void testAnyMatch() {
378     ArrayList<String> list = Lists.newArrayList();
379     FluentIterable<String> iterable = FluentIterable.<String>from(list);
380     Predicate<String> predicate = Predicates.equalTo("pants");
381 
382     assertFalse(iterable.anyMatch(predicate));
383     list.add("cool");
384     assertFalse(iterable.anyMatch(predicate));
385     list.add("pants");
386     assertTrue(iterable.anyMatch(predicate));
387   }
388 
testAllMatch()389   public void testAllMatch() {
390     List<String> list = Lists.newArrayList();
391     FluentIterable<String> iterable = FluentIterable.<String>from(list);
392     Predicate<String> predicate = Predicates.equalTo("cool");
393 
394     assertTrue(iterable.allMatch(predicate));
395     list.add("cool");
396     assertTrue(iterable.allMatch(predicate));
397     list.add("pants");
398     assertFalse(iterable.allMatch(predicate));
399   }
400 
testFirstMatch()401   public void testFirstMatch() {
402     FluentIterable<String> iterable = FluentIterable.from(Lists.newArrayList("cool", "pants"));
403     assertThat(iterable.firstMatch(Predicates.equalTo("cool"))).hasValue("cool");
404     assertThat(iterable.firstMatch(Predicates.equalTo("pants"))).hasValue("pants");
405     assertThat(iterable.firstMatch(Predicates.alwaysFalse())).isAbsent();
406     assertThat(iterable.firstMatch(Predicates.alwaysTrue())).hasValue("cool");
407   }
408 
409   private static final class IntegerValueOfFunction implements Function<String, Integer> {
410     @Override
apply(String from)411     public Integer apply(String from) {
412       return Integer.valueOf(from);
413     }
414   }
415 
testTransformWith()416   public void testTransformWith() {
417     List<String> input = asList("1", "2", "3");
418     Iterable<Integer> iterable = FluentIterable.from(input).transform(new IntegerValueOfFunction());
419 
420     assertEquals(asList(1, 2, 3), Lists.newArrayList(iterable));
421     assertCanIterateAgain(iterable);
422     assertEquals("[1, 2, 3]", iterable.toString());
423   }
424 
testTransformWith_poorlyBehavedTransform()425   public void testTransformWith_poorlyBehavedTransform() {
426     List<String> input = asList("1", null, "3");
427     Iterable<Integer> iterable = FluentIterable.from(input).transform(new IntegerValueOfFunction());
428 
429     Iterator<Integer> resultIterator = iterable.iterator();
430     resultIterator.next();
431 
432     try {
433       resultIterator.next();
434       fail("Transforming null to int should throw NumberFormatException");
435     } catch (NumberFormatException expected) {
436     }
437   }
438 
439   private static final class StringValueOfFunction implements Function<Integer, String> {
440     @Override
apply(Integer from)441     public String apply(Integer from) {
442       return String.valueOf(from);
443     }
444   }
445 
testTransformWith_nullFriendlyTransform()446   public void testTransformWith_nullFriendlyTransform() {
447     List<Integer> input = asList(1, 2, null, 3);
448     Iterable<String> result = FluentIterable.from(input).transform(new StringValueOfFunction());
449 
450     assertEquals(asList("1", "2", "null", "3"), Lists.newArrayList(result));
451   }
452 
453   private static final class RepeatedStringValueOfFunction
454       implements Function<Integer, List<String>> {
455     @Override
apply(Integer from)456     public List<String> apply(Integer from) {
457       String value = String.valueOf(from);
458       return ImmutableList.of(value, value);
459     }
460   }
461 
testTransformAndConcat()462   public void testTransformAndConcat() {
463     List<Integer> input = asList(1, 2, 3);
464     Iterable<String> result =
465         FluentIterable.from(input).transformAndConcat(new RepeatedStringValueOfFunction());
466     assertEquals(asList("1", "1", "2", "2", "3", "3"), Lists.newArrayList(result));
467   }
468 
469   private static final class RepeatedStringValueOfWildcardFunction
470       implements Function<Integer, List<? extends String>> {
471     @Override
apply(Integer from)472     public List<String> apply(Integer from) {
473       String value = String.valueOf(from);
474       return ImmutableList.of(value, value);
475     }
476   }
477 
testTransformAndConcat_wildcardFunctionGenerics()478   public void testTransformAndConcat_wildcardFunctionGenerics() {
479     List<Integer> input = asList(1, 2, 3);
480     FluentIterable<String> unused =
481         FluentIterable.from(input).transformAndConcat(new RepeatedStringValueOfWildcardFunction());
482   }
483 
testFirst_list()484   public void testFirst_list() {
485     List<String> list = Lists.newArrayList("a", "b", "c");
486     assertThat(FluentIterable.from(list).first()).hasValue("a");
487   }
488 
testFirst_null()489   public void testFirst_null() {
490     List<String> list = Lists.newArrayList(null, "a", "b");
491     try {
492       FluentIterable.from(list).first();
493       fail();
494     } catch (NullPointerException expected) {
495     }
496   }
497 
testFirst_emptyList()498   public void testFirst_emptyList() {
499     List<String> list = Collections.emptyList();
500     assertThat(FluentIterable.from(list).first()).isAbsent();
501   }
502 
testFirst_sortedSet()503   public void testFirst_sortedSet() {
504     SortedSet<String> sortedSet = ImmutableSortedSet.of("b", "c", "a");
505     assertThat(FluentIterable.from(sortedSet).first()).hasValue("a");
506   }
507 
testFirst_emptySortedSet()508   public void testFirst_emptySortedSet() {
509     SortedSet<String> sortedSet = ImmutableSortedSet.of();
510     assertThat(FluentIterable.from(sortedSet).first()).isAbsent();
511   }
512 
testFirst_iterable()513   public void testFirst_iterable() {
514     Set<String> set = ImmutableSet.of("a", "b", "c");
515     assertThat(FluentIterable.from(set).first()).hasValue("a");
516   }
517 
testFirst_emptyIterable()518   public void testFirst_emptyIterable() {
519     Set<String> set = Sets.newHashSet();
520     assertThat(FluentIterable.from(set).first()).isAbsent();
521   }
522 
testLast_list()523   public void testLast_list() {
524     List<String> list = Lists.newArrayList("a", "b", "c");
525     assertThat(FluentIterable.from(list).last()).hasValue("c");
526   }
527 
testLast_null()528   public void testLast_null() {
529     List<String> list = Lists.newArrayList("a", "b", null);
530     try {
531       FluentIterable.from(list).last();
532       fail();
533     } catch (NullPointerException expected) {
534     }
535   }
536 
testLast_emptyList()537   public void testLast_emptyList() {
538     List<String> list = Collections.emptyList();
539     assertThat(FluentIterable.from(list).last()).isAbsent();
540   }
541 
testLast_sortedSet()542   public void testLast_sortedSet() {
543     SortedSet<String> sortedSet = ImmutableSortedSet.of("b", "c", "a");
544     assertThat(FluentIterable.from(sortedSet).last()).hasValue("c");
545   }
546 
testLast_emptySortedSet()547   public void testLast_emptySortedSet() {
548     SortedSet<String> sortedSet = ImmutableSortedSet.of();
549     assertThat(FluentIterable.from(sortedSet).last()).isAbsent();
550   }
551 
testLast_iterable()552   public void testLast_iterable() {
553     Set<String> set = ImmutableSet.of("a", "b", "c");
554     assertThat(FluentIterable.from(set).last()).hasValue("c");
555   }
556 
testLast_emptyIterable()557   public void testLast_emptyIterable() {
558     Set<String> set = Sets.newHashSet();
559     assertThat(FluentIterable.from(set).last()).isAbsent();
560   }
561 
testSkip_simple()562   public void testSkip_simple() {
563     Collection<String> set = ImmutableSet.of("a", "b", "c", "d", "e");
564     assertEquals(
565         Lists.newArrayList("c", "d", "e"), Lists.newArrayList(FluentIterable.from(set).skip(2)));
566     assertEquals("[c, d, e]", FluentIterable.from(set).skip(2).toString());
567   }
568 
testSkip_simpleList()569   public void testSkip_simpleList() {
570     Collection<String> list = Lists.newArrayList("a", "b", "c", "d", "e");
571     assertEquals(
572         Lists.newArrayList("c", "d", "e"), Lists.newArrayList(FluentIterable.from(list).skip(2)));
573     assertEquals("[c, d, e]", FluentIterable.from(list).skip(2).toString());
574   }
575 
testSkip_pastEnd()576   public void testSkip_pastEnd() {
577     Collection<String> set = ImmutableSet.of("a", "b");
578     assertEquals(Collections.emptyList(), Lists.newArrayList(FluentIterable.from(set).skip(20)));
579   }
580 
testSkip_pastEndList()581   public void testSkip_pastEndList() {
582     Collection<String> list = Lists.newArrayList("a", "b");
583     assertEquals(Collections.emptyList(), Lists.newArrayList(FluentIterable.from(list).skip(20)));
584   }
585 
testSkip_skipNone()586   public void testSkip_skipNone() {
587     Collection<String> set = ImmutableSet.of("a", "b");
588     assertEquals(
589         Lists.newArrayList("a", "b"), Lists.newArrayList(FluentIterable.from(set).skip(0)));
590   }
591 
testSkip_skipNoneList()592   public void testSkip_skipNoneList() {
593     Collection<String> list = Lists.newArrayList("a", "b");
594     assertEquals(
595         Lists.newArrayList("a", "b"), Lists.newArrayList(FluentIterable.from(list).skip(0)));
596   }
597 
testSkip_iterator()598   public void testSkip_iterator() throws Exception {
599     new IteratorTester<Integer>(
600         5,
601         IteratorFeature.MODIFIABLE,
602         Lists.newArrayList(2, 3),
603         IteratorTester.KnownOrder.KNOWN_ORDER) {
604       @Override
605       protected Iterator<Integer> newTargetIterator() {
606         Collection<Integer> collection = Sets.newLinkedHashSet();
607         Collections.addAll(collection, 1, 2, 3);
608         return FluentIterable.from(collection).skip(1).iterator();
609       }
610     }.test();
611   }
612 
testSkip_iteratorList()613   public void testSkip_iteratorList() throws Exception {
614     new IteratorTester<Integer>(
615         5,
616         IteratorFeature.MODIFIABLE,
617         Lists.newArrayList(2, 3),
618         IteratorTester.KnownOrder.KNOWN_ORDER) {
619       @Override
620       protected Iterator<Integer> newTargetIterator() {
621         return FluentIterable.from(Lists.newArrayList(1, 2, 3)).skip(1).iterator();
622       }
623     }.test();
624   }
625 
testSkip_nonStructurallyModifiedList()626   public void testSkip_nonStructurallyModifiedList() throws Exception {
627     List<String> list = Lists.newArrayList("a", "b", "c");
628     FluentIterable<String> tail = FluentIterable.from(list).skip(1);
629     Iterator<String> tailIterator = tail.iterator();
630     list.set(2, "c2");
631     assertEquals("b", tailIterator.next());
632     assertEquals("c2", tailIterator.next());
633     assertFalse(tailIterator.hasNext());
634   }
635 
testSkip_structurallyModifiedSkipSome()636   public void testSkip_structurallyModifiedSkipSome() throws Exception {
637     Collection<String> set = Sets.newLinkedHashSet();
638     Collections.addAll(set, "a", "b", "c");
639     FluentIterable<String> tail = FluentIterable.from(set).skip(1);
640     set.remove("b");
641     set.addAll(Lists.newArrayList("X", "Y", "Z"));
642     assertThat(tail).containsExactly("c", "X", "Y", "Z").inOrder();
643   }
644 
testSkip_structurallyModifiedSkipSomeList()645   public void testSkip_structurallyModifiedSkipSomeList() throws Exception {
646     List<String> list = Lists.newArrayList("a", "b", "c");
647     FluentIterable<String> tail = FluentIterable.from(list).skip(1);
648     list.subList(1, 3).clear();
649     list.addAll(0, Lists.newArrayList("X", "Y", "Z"));
650     assertThat(tail).containsExactly("Y", "Z", "a").inOrder();
651   }
652 
testSkip_structurallyModifiedSkipAll()653   public void testSkip_structurallyModifiedSkipAll() throws Exception {
654     Collection<String> set = Sets.newLinkedHashSet();
655     Collections.addAll(set, "a", "b", "c");
656     FluentIterable<String> tail = FluentIterable.from(set).skip(2);
657     set.remove("a");
658     set.remove("b");
659     assertFalse(tail.iterator().hasNext());
660   }
661 
testSkip_structurallyModifiedSkipAllList()662   public void testSkip_structurallyModifiedSkipAllList() throws Exception {
663     List<String> list = Lists.newArrayList("a", "b", "c");
664     FluentIterable<String> tail = FluentIterable.from(list).skip(2);
665     list.subList(0, 2).clear();
666     assertThat(tail).isEmpty();
667   }
668 
testSkip_illegalArgument()669   public void testSkip_illegalArgument() {
670     try {
671       FluentIterable.from(asList("a", "b", "c")).skip(-1);
672       fail("Skipping negative number of elements should throw IllegalArgumentException.");
673     } catch (IllegalArgumentException expected) {
674     }
675   }
676 
testLimit()677   public void testLimit() {
678     Iterable<String> iterable = Lists.newArrayList("foo", "bar", "baz");
679     FluentIterable<String> limited = FluentIterable.from(iterable).limit(2);
680 
681     assertEquals(ImmutableList.of("foo", "bar"), Lists.newArrayList(limited));
682     assertCanIterateAgain(limited);
683     assertEquals("[foo, bar]", limited.toString());
684   }
685 
testLimit_illegalArgument()686   public void testLimit_illegalArgument() {
687     try {
688       FluentIterable<String> unused =
689           FluentIterable.from(Lists.newArrayList("a", "b", "c")).limit(-1);
690       fail("Passing negative number to limit(...) method should throw IllegalArgumentException");
691     } catch (IllegalArgumentException expected) {
692     }
693   }
694 
testIsEmpty()695   public void testIsEmpty() {
696     assertTrue(FluentIterable.<String>from(Collections.<String>emptyList()).isEmpty());
697     assertFalse(FluentIterable.<String>from(Lists.newArrayList("foo")).isEmpty());
698   }
699 
testToList()700   public void testToList() {
701     assertEquals(Lists.newArrayList(1, 2, 3, 4), fluent(1, 2, 3, 4).toList());
702   }
703 
testToList_empty()704   public void testToList_empty() {
705     assertTrue(fluent().toList().isEmpty());
706   }
707 
testToSortedList_withComparator()708   public void testToSortedList_withComparator() {
709     assertEquals(
710         Lists.newArrayList(4, 3, 2, 1),
711         fluent(4, 1, 3, 2).toSortedList(Ordering.<Integer>natural().reverse()));
712   }
713 
testToSortedList_withDuplicates()714   public void testToSortedList_withDuplicates() {
715     assertEquals(
716         Lists.newArrayList(4, 3, 1, 1),
717         fluent(1, 4, 1, 3).toSortedList(Ordering.<Integer>natural().reverse()));
718   }
719 
testToSet()720   public void testToSet() {
721     assertThat(fluent(1, 2, 3, 4).toSet()).containsExactly(1, 2, 3, 4).inOrder();
722   }
723 
testToSet_removeDuplicates()724   public void testToSet_removeDuplicates() {
725     assertThat(fluent(1, 2, 1, 2).toSet()).containsExactly(1, 2).inOrder();
726   }
727 
testToSet_empty()728   public void testToSet_empty() {
729     assertTrue(fluent().toSet().isEmpty());
730   }
731 
testToSortedSet()732   public void testToSortedSet() {
733     assertThat(fluent(1, 4, 2, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
734         .containsExactly(4, 3, 2, 1)
735         .inOrder();
736   }
737 
testToSortedSet_removeDuplicates()738   public void testToSortedSet_removeDuplicates() {
739     assertThat(fluent(1, 4, 1, 3).toSortedSet(Ordering.<Integer>natural().reverse()))
740         .containsExactly(4, 3, 1)
741         .inOrder();
742   }
743 
testToMultiset()744   public void testToMultiset() {
745     assertThat(fluent(1, 2, 1, 3, 2, 4).toMultiset()).containsExactly(1, 1, 2, 2, 3, 4).inOrder();
746   }
747 
testToMultiset_empty()748   public void testToMultiset_empty() {
749     assertThat(fluent().toMultiset()).isEmpty();
750   }
751 
testToMap()752   public void testToMap() {
753     assertThat(fluent(1, 2, 3).toMap(Functions.toStringFunction()).entrySet())
754         .containsExactly(
755             Maps.immutableEntry(1, "1"), Maps.immutableEntry(2, "2"), Maps.immutableEntry(3, "3"))
756         .inOrder();
757   }
758 
testToMap_nullKey()759   public void testToMap_nullKey() {
760     try {
761       fluent(1, null, 2).toMap(Functions.constant("foo"));
762       fail();
763     } catch (NullPointerException expected) {
764     }
765   }
766 
testToMap_nullValue()767   public void testToMap_nullValue() {
768     try {
769       fluent(1, 2, 3).toMap(Functions.constant(null));
770       fail();
771     } catch (NullPointerException expected) {
772     }
773   }
774 
testIndex()775   public void testIndex() {
776     ImmutableListMultimap<Integer, String> expected =
777         ImmutableListMultimap.<Integer, String>builder()
778             .putAll(3, "one", "two")
779             .put(5, "three")
780             .put(4, "four")
781             .build();
782     ImmutableListMultimap<Integer, String> index =
783         FluentIterable.from(asList("one", "two", "three", "four"))
784             .index(
785                 new Function<String, Integer>() {
786                   @Override
787                   public Integer apply(String input) {
788                     return input.length();
789                   }
790                 });
791     assertEquals(expected, index);
792   }
793 
testIndex_nullKey()794   public void testIndex_nullKey() {
795     try {
796       ImmutableListMultimap<Object, Integer> unused =
797           fluent(1, 2, 3).index(Functions.constant(null));
798       fail();
799     } catch (NullPointerException expected) {
800     }
801   }
802 
testIndex_nullValue()803   public void testIndex_nullValue() {
804     try {
805       ImmutableListMultimap<String, Integer> unused =
806           fluent(1, null, 2).index(Functions.constant("foo"));
807       fail();
808     } catch (NullPointerException expected) {
809     }
810   }
811 
testUniqueIndex()812   public void testUniqueIndex() {
813     ImmutableMap<Integer, String> expected = ImmutableMap.of(3, "two", 5, "three", 4, "four");
814     ImmutableMap<Integer, String> index =
815         FluentIterable.from(asList("two", "three", "four"))
816             .uniqueIndex(
817                 new Function<String, Integer>() {
818                   @Override
819                   public Integer apply(String input) {
820                     return input.length();
821                   }
822                 });
823     assertEquals(expected, index);
824   }
825 
testUniqueIndex_duplicateKey()826   public void testUniqueIndex_duplicateKey() {
827     try {
828       ImmutableMap<Integer, String> unused =
829           FluentIterable.from(asList("one", "two", "three", "four"))
830               .uniqueIndex(
831                   new Function<String, Integer>() {
832                     @Override
833                     public Integer apply(String input) {
834                       return input.length();
835                     }
836                   });
837       fail();
838     } catch (IllegalArgumentException expected) {
839     }
840   }
841 
testUniqueIndex_nullKey()842   public void testUniqueIndex_nullKey() {
843     try {
844       fluent(1, 2, 3).uniqueIndex(Functions.constant(null));
845       fail();
846     } catch (NullPointerException expected) {
847     }
848   }
849 
testUniqueIndex_nullValue()850   public void testUniqueIndex_nullValue() {
851     try {
852       ImmutableMap<Object, Integer> unused =
853           fluent(1, null, 2)
854               .uniqueIndex(
855                   new Function<Integer, Object>() {
856                     @Override
857                     public Object apply(@Nullable Integer input) {
858                       return String.valueOf(input);
859                     }
860                   });
861       fail();
862     } catch (NullPointerException expected) {
863     }
864   }
865 
testCopyInto_List()866   public void testCopyInto_List() {
867     assertThat(fluent(1, 3, 5).copyInto(Lists.newArrayList(1, 2)))
868         .containsExactly(1, 2, 1, 3, 5)
869         .inOrder();
870   }
871 
testCopyInto_Set()872   public void testCopyInto_Set() {
873     assertThat(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2))).containsExactly(1, 2, 3, 5);
874   }
875 
testCopyInto_SetAllDuplicates()876   public void testCopyInto_SetAllDuplicates() {
877     assertThat(fluent(1, 3, 5).copyInto(Sets.newHashSet(1, 2, 3, 5))).containsExactly(1, 2, 3, 5);
878   }
879 
testCopyInto_NonCollection()880   public void testCopyInto_NonCollection() {
881     final ArrayList<Integer> list = Lists.newArrayList(1, 2, 3);
882 
883     final ArrayList<Integer> iterList = Lists.newArrayList(9, 8, 7);
884     Iterable<Integer> iterable =
885         new Iterable<Integer>() {
886           @Override
887           public Iterator<Integer> iterator() {
888             return iterList.iterator();
889           }
890         };
891 
892     assertThat(FluentIterable.from(iterable).copyInto(list))
893         .containsExactly(1, 2, 3, 9, 8, 7)
894         .inOrder();
895   }
896 
testJoin()897   public void testJoin() {
898     assertEquals("2,1,3,4", fluent(2, 1, 3, 4).join(Joiner.on(",")));
899   }
900 
testJoin_empty()901   public void testJoin_empty() {
902     assertEquals("", fluent().join(Joiner.on(",")));
903   }
904 
testGet()905   public void testGet() {
906     assertEquals("a", FluentIterable.from(Lists.newArrayList("a", "b", "c")).get(0));
907     assertEquals("b", FluentIterable.from(Lists.newArrayList("a", "b", "c")).get(1));
908     assertEquals("c", FluentIterable.from(Lists.newArrayList("a", "b", "c")).get(2));
909   }
910 
testGet_outOfBounds()911   public void testGet_outOfBounds() {
912     try {
913       FluentIterable.from(Lists.newArrayList("a", "b", "c")).get(-1);
914       fail();
915     } catch (IndexOutOfBoundsException expected) {
916     }
917 
918     try {
919       FluentIterable.from(Lists.newArrayList("a", "b", "c")).get(3);
920       fail();
921     } catch (IndexOutOfBoundsException expected) {
922     }
923   }
924 
925   /*
926    * Full and proper black-box testing of a Stream-returning method is extremely involved, and is
927    * overkill when nearly all Streams are produced using well-tested JDK calls. So, we cheat and
928    * just test that the toArray() contents are as expected.
929    */
testStream()930   public void testStream() {
931     assertThat(FluentIterable.of().stream()).isEmpty();
932     assertThat(FluentIterable.of("a").stream()).containsExactly("a");
933     assertThat(FluentIterable.of(1, 2, 3).stream().filter(n -> n > 1)).containsExactly(2, 3);
934   }
935 
936   // TODO(kevinb): add assertThat(Stream) to Truth?
937   static class Help {
assertThat(Stream<?> stream)938     static IterableSubject assertThat(Stream<?> stream) {
939       return Truth.assertThat(stream.toArray()).asList();
940     }
941   }
942 
assertCanIterateAgain(Iterable<?> iterable)943   private static void assertCanIterateAgain(Iterable<?> iterable) {
944     for (Object unused : iterable) {
945       // do nothing
946     }
947   }
948 
fluent(Integer... elements)949   private static FluentIterable<Integer> fluent(Integer... elements) {
950     return FluentIterable.from(Lists.newArrayList(elements));
951   }
952 
iterable(String... elements)953   private static Iterable<String> iterable(String... elements) {
954     final List<String> list = asList(elements);
955     return new Iterable<String>() {
956       @Override
957       public Iterator<String> iterator() {
958         return list.iterator();
959       }
960     };
961   }
962 }
963