Coverage Summary for Class: CollectorTester (com.google.common.testing)

Class Method, % Line, %
CollectorTester 66.7% (4/6) 31.8% (7/22)
CollectorTester$CollectStrategy 0% (0/1) 0% (0/4)
CollectorTester$CollectStrategy$1 0% (0/2) 0% (0/6)
CollectorTester$CollectStrategy$2 0% (0/2) 0% (0/8)
CollectorTester$CollectStrategy$3 0% (0/4) 0% (0/16)
Total 26.7% (4/15) 12.5% (7/56)


1 /* 2  * Copyright (C) 2015 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.testing; 18  19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static junit.framework.Assert.assertTrue; 21  22 import com.google.common.annotations.Beta; 23 import com.google.common.annotations.GwtCompatible; 24 import java.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.Collections; 27 import java.util.EnumSet; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.function.BiPredicate; 31 import java.util.stream.Collector; 32 import org.checkerframework.checker.nullness.qual.Nullable; 33  34 /** 35  * Tester for {@code Collector} implementations. 36  * 37  * <p>Example usage: 38  * 39  * <pre> 40  * CollectorTester.of(Collectors.summingInt(Integer::parseInt)) 41  * .expectCollects(3, "1", "2") 42  * .expectCollects(10, "1", "4", "3", "2") 43  * .expectCollects(5, "-3", "0", "8"); 44  * </pre> 45  * 46  * @author Louis Wasserman 47  * @since 21.0 48  */ 49 @Beta 50 @GwtCompatible 51 public final class CollectorTester<T, A, R> { 52  /** 53  * Creates a {@code CollectorTester} for the specified {@code Collector}. The result of the {@code 54  * Collector} will be compared to the expected value using {@link Object.equals}. 55  */ 56  public static <T, A, R> CollectorTester<T, A, R> of(Collector<T, A, R> collector) { 57  return of(collector, Objects::equals); 58  } 59  60  /** 61  * Creates a {@code CollectorTester} for the specified {@code Collector}. The result of the {@code 62  * Collector} will be compared to the expected value using the specified {@code equivalence}. 63  */ 64  public static <T, A, R> CollectorTester<T, A, R> of( 65  Collector<T, A, R> collector, BiPredicate<? super R, ? super R> equivalence) { 66  return new CollectorTester<>(collector, equivalence); 67  } 68  69  private final Collector<T, A, R> collector; 70  private final BiPredicate<? super R, ? super R> equivalence; 71  72  private CollectorTester( 73  Collector<T, A, R> collector, BiPredicate<? super R, ? super R> equivalence) { 74  this.collector = checkNotNull(collector); 75  this.equivalence = checkNotNull(equivalence); 76  } 77  78  /** 79  * Different orderings for combining the elements of an input array, which must all produce the 80  * same result. 81  */ 82  enum CollectStrategy { 83  /** Get one accumulator and accumulate the elements into it sequentially. */ 84  SEQUENTIAL { 85  @Override 86  final <T, A, R> A result(Collector<T, A, R> collector, Iterable<T> inputs) { 87  A accum = collector.supplier().get(); 88  for (T input : inputs) { 89  collector.accumulator().accept(accum, input); 90  } 91  return accum; 92  } 93  }, 94  /** Get one accumulator for each element and merge the accumulators left-to-right. */ 95  MERGE_LEFT_ASSOCIATIVE { 96  @Override 97  final <T, A, R> A result(Collector<T, A, R> collector, Iterable<T> inputs) { 98  A accum = collector.supplier().get(); 99  for (T input : inputs) { 100  A newAccum = collector.supplier().get(); 101  collector.accumulator().accept(newAccum, input); 102  accum = collector.combiner().apply(accum, newAccum); 103  } 104  return accum; 105  } 106  }, 107  /** Get one accumulator for each element and merge the accumulators right-to-left. */ 108  MERGE_RIGHT_ASSOCIATIVE { 109  @Override 110  final <T, A, R> A result(Collector<T, A, R> collector, Iterable<T> inputs) { 111  List<A> stack = new ArrayList<>(); 112  for (T input : inputs) { 113  A newAccum = collector.supplier().get(); 114  collector.accumulator().accept(newAccum, input); 115  push(stack, newAccum); 116  } 117  push(stack, collector.supplier().get()); 118  while (stack.size() > 1) { 119  A right = pop(stack); 120  A left = pop(stack); 121  push(stack, collector.combiner().apply(left, right)); 122  } 123  return pop(stack); 124  } 125  126  <E> void push(List<E> stack, E value) { 127  stack.add(value); 128  } 129  130  <E> E pop(List<E> stack) { 131  return stack.remove(stack.size() - 1); 132  } 133  }; 134  135  abstract <T, A, R> A result(Collector<T, A, R> collector, Iterable<T> inputs); 136  } 137  138  /** 139  * Verifies that the specified expected result is always produced by collecting the specified 140  * inputs, regardless of how the elements are divided. 141  */ 142  @SafeVarargs 143  public final CollectorTester<T, A, R> expectCollects(@Nullable R expectedResult, T... inputs) { 144  List<T> list = Arrays.asList(inputs); 145  doExpectCollects(expectedResult, list); 146  if (collector.characteristics().contains(Collector.Characteristics.UNORDERED)) { 147  Collections.reverse(list); 148  doExpectCollects(expectedResult, list); 149  } 150  return this; 151  } 152  153  private void doExpectCollects(@Nullable R expectedResult, List<T> inputs) { 154  for (CollectStrategy scheme : EnumSet.allOf(CollectStrategy.class)) { 155  A finalAccum = scheme.result(collector, inputs); 156  if (collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { 157  assertEquivalent(expectedResult, (R) finalAccum); 158  } 159  assertEquivalent(expectedResult, collector.finisher().apply(finalAccum)); 160  } 161  } 162  163  private void assertEquivalent(@Nullable R expected, @Nullable R actual) { 164  assertTrue( 165  "Expected " + expected + " got " + actual + " modulo equivalence " + equivalence, 166  equivalence.test(expected, actual)); 167  } 168 }