// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T, R> Stream<R> groupConsecutive(
//     Stream<T> stream,
//     BiPredicate<? super T, ? super T> sameGroup,
//     Collector<? super T, ?, R> groupCollector) {
//   return biStream(stream).groupConsecutiveIf(sameGroup, groupCollector);
// }
// 
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static Stream<Integer> indexesFrom(int firstIndex) {
//   return IntStream.iterate(firstIndex, i -> i + 1).boxed();
// }
// 
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T> Stream<T> whileNotNull(Supplier<? extends T> supplier) {
//   requireNonNull(supplier);
//   return StreamSupport.stream(
//       new Spliterator<T>() {
//         @Override public boolean tryAdvance(Consumer<? super T> action) {
//           T generated = supplier.get();
//           if (generated == null) {
//             return false;
//           }
//           action.accept(generated);
//           return true;
//         }
//         @Override public int characteristics() {
//           return Spliterator.NONNULL | Spliterator.ORDERED;
//         }
//         @Override public long estimateSize() {
//           return Long.MAX_VALUE;
//         }
//         @Override public Spliterator<T> trySplit() {
//           return null;
//         }
//       },
//       false);
// }


import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.mu.util.stream.MoreStreams.groupConsecutive;
import static com.google.mu.util.stream.MoreStreams.indexesFrom;
import static com.google.mu.util.stream.MoreStreams.whileNotNull;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.junit.Assume.assumeTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.Spliterator;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.testing.ClassSanityTester;
import com.google.common.testing.NullPointerTester;

  @Test public void flattenMultipleElements() throws Exception {
    Stream<Integer> flattened = MoreStreams.flatten(Stream.of(Stream.of(1, 2), Stream.of(3, 4)));
    assertThat(flattened.collect(toList())).containsExactly(1, 2, 3, 4).inOrder();
  }

  @Test public void flattenWithTrailingInfiniteStream() throws Exception {
    Stream<Integer> flattened =
        MoreStreams.flatten(Stream.of(Stream.of(1), Stream.iterate(2, i -> i + 1)));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenWithLeadingInfiniteStream() throws Exception {
    Stream<Integer> flattened =
        MoreStreams.flatten(Stream.of(Stream.iterate(1, i -> i + 1), Stream.of(100)));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenWithInfiniteOuterStream() throws Exception {
    Stream<List<Integer>> infinite = Stream.iterate(
        ImmutableList.of(1), l -> l.stream().map(i -> i + 1).collect(toImmutableList()));
    Stream<Integer> flattened = MoreStreams.flatten(infinite.map(l -> l.stream()));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenReturnsSequentialStream() throws Exception {
    Stream<Integer> flattened = MoreStreams.flatten(Stream.of(Stream.of(1, 2), Stream.of(3)).parallel());
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T, R> Stream<R> groupConsecutive(
//     Stream<T> stream,
//     BiPredicate<? super T, ? super T> sameGroup,
//     Collector<? super T, ?, R> groupCollector) {
//   return biStream(stream).groupConsecutiveIf(sameGroup, groupCollector);
// }
// 
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static Stream<Integer> indexesFrom(int firstIndex) {
//   return IntStream.iterate(firstIndex, i -> i + 1).boxed();
// }
// 
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T> Stream<T> whileNotNull(Supplier<? extends T> supplier) {
//   requireNonNull(supplier);
//   return StreamSupport.stream(
//       new Spliterator<T>() {
//         @Override public boolean tryAdvance(Consumer<? super T> action) {
//           T generated = supplier.get();
//           if (generated == null) {
//             return false;
//           }
//           action.accept(generated);
//           return true;
//         }
//         @Override public int characteristics() {
//           return Spliterator.NONNULL | Spliterator.ORDERED;
//         }
//         @Override public long estimateSize() {
//           return Long.MAX_VALUE;
//         }
//         @Override public Spliterator<T> trySplit() {
//           return null;
//         }
//       },
//       false);
// }


// Path: mug/src/test/java/com/google/mu/util/stream/MoreStreamsTest.java
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.google.mu.util.stream.MoreStreams.groupConsecutive;
import static com.google.mu.util.stream.MoreStreams.indexesFrom;
import static com.google.mu.util.stream.MoreStreams.whileNotNull;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.junit.Assume.assumeTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.Spliterator;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.testing.ClassSanityTester;
import com.google.common.testing.NullPointerTester;


  @Test public void flattenMultipleElements() throws Exception {
    Stream<Integer> flattened = MoreStreams.flatten(Stream.of(Stream.of(1, 2), Stream.of(3, 4)));
    assertThat(flattened.collect(toList())).containsExactly(1, 2, 3, 4).inOrder();
  }

  @Test public void flattenWithTrailingInfiniteStream() throws Exception {
    Stream<Integer> flattened =
        MoreStreams.flatten(Stream.of(Stream.of(1), Stream.iterate(2, i -> i + 1)));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenWithLeadingInfiniteStream() throws Exception {
    Stream<Integer> flattened =
        MoreStreams.flatten(Stream.of(Stream.iterate(1, i -> i + 1), Stream.of(100)));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenWithInfiniteOuterStream() throws Exception {
    Stream<List<Integer>> infinite = Stream.iterate(
        ImmutableList.of(1), l -> l.stream().map(i -> i + 1).collect(toImmutableList()));
    Stream<Integer> flattened = MoreStreams.flatten(infinite.map(l -> l.stream()));
    assertThat(flattened.limit(5).collect(toList()))
        .containsExactly(1, 2, 3, 4, 5).inOrder();
  }

  @Test public void flattenReturnsSequentialStream() throws Exception {
    Stream<Integer> flattened = MoreStreams.flatten(Stream.of(Stream.of(1, 2), Stream.of(3)).parallel());
    assertThat(flattened.isParallel()).isFalse();