// Path: mug/src/main/java/com/google/mu/util/Funnel.java
// public final class Funnel<T> {
// 
//   private int size = 0;
//   private final List<Batch<?, T>> batches = new ArrayList<>();
//   private final Batch<T, T> passthrough = through(Function.identity());
// 
//   /**
//    * Holds the elements to be converted through a single batch conversion.
//    *
//    * @param <F> batch input element type
//    * @param <T> batch output element type
//    */
//   public static final class Batch<F, T> implements Consumer<F> {
//     private final Funnel<T> funnel;
//     private final Function<? super List<F>, ? extends Collection<? extends T>> converter;
//     private final List<Indexed<F, T>> indexedSources = new ArrayList<>();
// 
//     Batch(Funnel<T> funnel, Function<? super List<F>, ? extends Collection<? extends T>> converter) {
//       this.funnel = funnel;
//       this.converter = requireNonNull(converter);
//     }
// 
//     /** Adds {@code source} to be converted. */
//     @Override public void accept(F source) {
//       accept(source, Function.identity());
//     }
// 
//     /**
//      * Adds {@code source} to be converted.
//      * {@code postConversion} will be applied after the batch conversion completes,
//      * to compute the final result for this input.
//      */
//     public void accept(F source, Function<? super T, ? extends T> postConversion) {
//       indexedSources.add(new Indexed<>(funnel.size++, source, postConversion));
//     }
// 
//     /**
//      * Adds {@code source} to be converted.
//      * {@code aftereffect} will be applied against the conversion result after the batch completes.
//      */
//     public void accept(F source, Consumer<? super T> aftereffect) {
//       requireNonNull(aftereffect);
//       accept(source, v -> {
//         aftereffect.accept(v);
//         return v;
//       });
//     }
// 
//     void convertInto(ArrayList<T> output) {
//       if (indexedSources.isEmpty()) {
//         return;
//       }
//       List<F> params = indexedSources.stream().map(i -> i.value).collect(toList());
//       List<T> results = new ArrayList<>(converter.apply(params));
//       if (params.size() != results.size()) {
//         throw new IllegalStateException(
//             converter + " expected to return " + params.size() + " elements for input "
//                 + params + ", but got " + results + " of size " + results.size() + ".");
//       }
//       for (int i = 0; i < indexedSources.size(); i++) {
//         indexedSources.get(i).setAtIndex(results.get(i), output);
//       }
//     }
//   }
// 
//   /**
//    * Returns a {@link Batch} accepting elements that, when {@link #run} is called,
//    * will be converted together in a batch through {@code converter}.
//    */
//   public <F> Batch<F, T> through(
//       Function<? super List<F>, ? extends Collection<? extends T>> converter) {
//     Batch<F, T> batch = new Batch<>(this, converter);
//     batches.add(batch);
//     return batch;
//   }
// 
//   /** Adds {@code element} to the funnel. */
//   public void add(T element) {
//     passthrough.accept(element);
//   }
// 
//   /**
//    * Runs all batch conversions and returns conversion results together with elements {@link #add
//    * added} as is, in encounter order.
//    */
//   public List<T> run() {
//     ArrayList<T> output = new ArrayList<>(Collections.nCopies(size, null));
//     for (Batch<?, T> batch : batches) {
//       batch.convertInto(output);
//     }
//     return output;
//   }
// 
//   private static final class Indexed<F, T> {
//     private final int index;
//     final F value;
//     private final Function<? super T, ? extends T> converter;
// 
//     Indexed(int index, F value, Function<? super T, ? extends T> converter) {
//       this.index = index;
//       this.value = requireNonNull(value);
//       this.converter = requireNonNull(converter);
//     }
// 
//     void setAtIndex(T from, List<? super T> to) {
//       to.set(index, converter.apply(from));
//     }
//   }
// }


import org.mockito.MockitoAnnotations;
import com.google.common.testing.ClassSanityTester;
import com.google.common.testing.NullPointerTester;
import com.google.mu.util.Funnel;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.Mockito;
/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.util;





@RunWith(JUnit4.class)
public final class FunnelTest {
// Path: mug/src/main/java/com/google/mu/util/Funnel.java
// public final class Funnel<T> {
// 
//   private int size = 0;
//   private final List<Batch<?, T>> batches = new ArrayList<>();
//   private final Batch<T, T> passthrough = through(Function.identity());
// 
//   /**
//    * Holds the elements to be converted through a single batch conversion.
//    *
//    * @param <F> batch input element type
//    * @param <T> batch output element type
//    */
//   public static final class Batch<F, T> implements Consumer<F> {
//     private final Funnel<T> funnel;
//     private final Function<? super List<F>, ? extends Collection<? extends T>> converter;
//     private final List<Indexed<F, T>> indexedSources = new ArrayList<>();
// 
//     Batch(Funnel<T> funnel, Function<? super List<F>, ? extends Collection<? extends T>> converter) {
//       this.funnel = funnel;
//       this.converter = requireNonNull(converter);
//     }
// 
//     /** Adds {@code source} to be converted. */
//     @Override public void accept(F source) {
//       accept(source, Function.identity());
//     }
// 
//     /**
//      * Adds {@code source} to be converted.
//      * {@code postConversion} will be applied after the batch conversion completes,
//      * to compute the final result for this input.
//      */
//     public void accept(F source, Function<? super T, ? extends T> postConversion) {
//       indexedSources.add(new Indexed<>(funnel.size++, source, postConversion));
//     }
// 
//     /**
//      * Adds {@code source} to be converted.
//      * {@code aftereffect} will be applied against the conversion result after the batch completes.
//      */
//     public void accept(F source, Consumer<? super T> aftereffect) {
//       requireNonNull(aftereffect);
//       accept(source, v -> {
//         aftereffect.accept(v);
//         return v;
//       });
//     }
// 
//     void convertInto(ArrayList<T> output) {
//       if (indexedSources.isEmpty()) {
//         return;
//       }
//       List<F> params = indexedSources.stream().map(i -> i.value).collect(toList());
//       List<T> results = new ArrayList<>(converter.apply(params));
//       if (params.size() != results.size()) {
//         throw new IllegalStateException(
//             converter + " expected to return " + params.size() + " elements for input "
//                 + params + ", but got " + results + " of size " + results.size() + ".");
//       }
//       for (int i = 0; i < indexedSources.size(); i++) {
//         indexedSources.get(i).setAtIndex(results.get(i), output);
//       }
//     }
//   }
// 
//   /**
//    * Returns a {@link Batch} accepting elements that, when {@link #run} is called,
//    * will be converted together in a batch through {@code converter}.
//    */
//   public <F> Batch<F, T> through(
//       Function<? super List<F>, ? extends Collection<? extends T>> converter) {
//     Batch<F, T> batch = new Batch<>(this, converter);
//     batches.add(batch);
//     return batch;
//   }
// 
//   /** Adds {@code element} to the funnel. */
//   public void add(T element) {
//     passthrough.accept(element);
//   }
// 
//   /**
//    * Runs all batch conversions and returns conversion results together with elements {@link #add
//    * added} as is, in encounter order.
//    */
//   public List<T> run() {
//     ArrayList<T> output = new ArrayList<>(Collections.nCopies(size, null));
//     for (Batch<?, T> batch : batches) {
//       batch.convertInto(output);
//     }
//     return output;
//   }
// 
//   private static final class Indexed<F, T> {
//     private final int index;
//     final F value;
//     private final Function<? super T, ? extends T> converter;
// 
//     Indexed(int index, F value, Function<? super T, ? extends T> converter) {
//       this.index = index;
//       this.value = requireNonNull(value);
//       this.converter = requireNonNull(converter);
//     }
// 
//     void setAtIndex(T from, List<? super T> to) {
//       to.set(index, converter.apply(from));
//     }
//   }
// }


// Path: mug/src/test/java/com/google/mu/util/FunnelTest.java
import org.mockito.MockitoAnnotations;
import com.google.common.testing.ClassSanityTester;
import com.google.common.testing.NullPointerTester;
import com.google.mu.util.Funnel;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.Mockito;

/*****************************************************************************
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package com.google.mu.util;





@RunWith(JUnit4.class)
public final class FunnelTest {
  private final Funnel<String> funnel = new Funnel<>();