/** * Powerunit - A JDK1.8 test framework * Copyright (C) 2014 Mathieu Boretti. * * This file is part of Powerunit * * Powerunit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Powerunit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. */ package ch.powerunit.collector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collector; import java.util.stream.Collector.Characteristics; import java.util.stream.Stream; import org.hamcrest.Matcher; import ch.powerunit.TestInterface; import ch.powerunit.TestSuite; import ch.powerunit.collector.impl.CollectorTesterImpl; import ch.powerunit.collector.lang.CollectorTesterDSL0; import ch.powerunit.collector.lang.CollectorTesterDSL1; import ch.powerunit.collector.lang.CollectorTesterDSL2; import ch.powerunit.collector.lang.CollectorTesterDSL3; /** * This is a tester for {@link Collector}. * <p> * The goal of this tester is to validate a {@link Collector}. The following * tests are done : * <ol> * <li><code>{@link Collector#accumulator() accumulator()}</code> must return a * not null result.</li> * <li><code>{@link Collector#combiner() combiner()}</code> must return a not * null result.</li> * <li><code>{@link Collector#finisher() finisher()}</code> must return a not * null result.</li> * <li><code>{@link Collector#supplier() supplier()}</code> must return a not * null result.</li> * <li><code>{@link Collector#characteristics() characteristics()}</code> must * return a not null result and be the same list that is specified in this * tester.</li> * <li>For each received sample either use it - * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withInput(Stream) * withInput} - or create a stream - * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withStreamFromList(List) * withStreamFromList} or * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withParallelStreamFromList(List) * withParallelStreamFromList} - and then execute the method * {@link java.util.stream.Stream#collect(Collector) collect} with the * {@link Collector} under test and validate the returned result.</li> * </ol> * * @author borettim * @since 0.4.0 * @param <T> * the input type of the {@link java.util.stream.Collector Collector} * . * @param <A> * the accumulator type of the {@link java.util.stream.Collector * Collector}. * @param <R> * the return type of the {@link java.util.stream.Collector * Collector}. */ @TestInterface(CollectorTesterImpl.class) public final class CollectorTester<T, A, R> { private final Collector<T, A, R> collectorToTest; private final List<Stream<T>> inputs; private final List<Matcher<? super R>> results; private final Matcher<Iterable<? extends Characteristics>> expectedCharacteristics; private CollectorTester(Collector<T, A, R> collectorToTest, List<Stream<T>> inputs, List<Matcher<? super R>> results, Matcher<Iterable<? extends Characteristics>> expectedCharacteristics) { this.collectorToTest = collectorToTest; this.inputs = inputs; this.results = results; this.expectedCharacteristics = expectedCharacteristics; } /** * Return a builder to create a tester of {@link java.util.stream.Collector * Collector}. * * @param collectorToTest * the {@link java.util.stream.Collector Collector} to be tested. * @param <T> * the input type of the {@link java.util.stream.Collector * Collector} . * * @param <R> * the return type of the {@link java.util.stream.Collector * Collector}. * @return {@link CollectorTesterDSL0 the DSL to build the tester} */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static <T, R> CollectorTesterDSL0<T, ?, R> of( Collector<T, ?, R> collectorToTest) { return new CollectorTesterDSL(collectorToTest); } /** * Return a builder to create a tester of {@link java.util.stream.Collector * Collector}. * * @param inputClass * the class of the input of the * {@link java.util.stream.Collector Collector}. * @param outputClass * the class of the output of the * {@link java.util.stream.Collector Collector}. * @param collectorToTest * the {@link java.util.stream.Collector Collector} to be tested. * @param <T> * the input type of the {@link java.util.stream.Collector * Collector}. * * @param <R> * the return type of the {@link java.util.stream.Collector * Collector}. * @return {@link CollectorTesterDSL0 the DSL to build the tester} */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static <T, R> CollectorTesterDSL0<T, ?, R> of(Class<T> inputClass, Class<T> outputClass, Collector<T, ?, R> collectorToTest) { return new CollectorTesterDSL(collectorToTest); } private static class CollectorTesterDSL<T, A, R> implements CollectorTesterDSL0<T, A, R>, CollectorTesterDSL1<T, A, R>, CollectorTesterDSL2<T, A, R> { private final Collector<T, A, R> collectorToTest; private final List<Stream<T>> inputs = new ArrayList<>(); private final List<Matcher<? super R>> results = new ArrayList<>(); private Matcher<Iterable<? extends Characteristics>> expectedCharacteristics; public CollectorTesterDSL(Collector<T, A, R> collectorToTest) { this.collectorToTest = collectorToTest; } @Override public CollectorTesterDSL3<T, A, R> havingCharacteristics( Characteristics... expectedCharacteristics) { this.expectedCharacteristics = TestSuite.DSL .<Collector.Characteristics> containsInAnyOrder(expectedCharacteristics); return this; } @Override public CollectorTesterDSL2<T, A, R> withInput(Stream<T> input) { inputs.add(Objects.requireNonNull(input, "input can't be null")); return this; } @Override public CollectorTesterDSL2<T, A, R> withStreamFromList(List<T> input) { return withInput(Objects.requireNonNull(input, "input can't be null").stream()); } @Override public CollectorTesterDSL2<T, A, R> withParallelStreamFromList( List<T> input) { return withInput(Objects.requireNonNull(input, "input can't be null").parallelStream()); } @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray( @SuppressWarnings("unchecked") T... input) { return withInput(Arrays.stream(input)); } @SuppressWarnings("unchecked") @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first) { return withStreamFromArray((T[]) new Object[] { first }); } @SuppressWarnings("unchecked") @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, T second) { return withStreamFromArray((T[]) new Object[] { first, second }); } @SuppressWarnings("unchecked") @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, T second, T third) { return withStreamFromArray((T[]) new Object[] { first, second, third }); } @SuppressWarnings("unchecked") @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, T second, T third, T fourth) { return withStreamFromArray((T[]) new Object[] { first, second, third, fourth }); } @SuppressWarnings("unchecked") @Override public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, T second, T third, T fourth, T fifth) { return withStreamFromArray((T[]) new Object[] { first, second, third, fourth, fifth }); } @Override public CollectorTesterDSL1<T, A, R> expecting( Matcher<? super R> matching) { results.add(Objects.requireNonNull(matching, "matching can't be null")); return this; } @Override public CollectorTesterDSL1<T, A, R> expecting(R value) { return expecting(TestSuite.DSL.equalTo(value)); } @Override public CollectorTesterDSL1<T, A, R> expectingNull() { return expecting(TestSuite.DSL.nullValue()); } @Override public CollectorTester<T, A, R> build() { return new CollectorTester<T, A, R>(collectorToTest, inputs, results, expectedCharacteristics == null ? TestSuite.DSL .emptyIterable() : expectedCharacteristics); } } /** * Used by the framework. * * @return the collectorToTest */ public Collector<T, A, R> getCollectorToTest() { return collectorToTest; } /** * Used by the framework. * * @return the inputs */ public List<Stream<T>> getInputs() { return Collections.unmodifiableList(inputs); } /** * Used by the framework. * * @return the results */ public List<Matcher<? super R>> getResults() { return Collections.unmodifiableList(results); } /** * Used by the framework. * * @return the expectedCharacteristics */ public Matcher<Iterable<? extends Characteristics>> getExpectedCharacteristics() { return expectedCharacteristics; } }