001/** 002 * Powerunit - A JDK1.8 test framework 003 * Copyright (C) 2014 Mathieu Boretti. 004 * 005 * This file is part of Powerunit 006 * 007 * Powerunit is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * Powerunit is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package ch.powerunit.collector; 021 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.List; 026import java.util.Objects; 027import java.util.stream.Collector; 028import java.util.stream.Collector.Characteristics; 029import java.util.stream.Stream; 030 031import org.hamcrest.Matcher; 032 033import ch.powerunit.TestInterface; 034import ch.powerunit.TestSuite; 035import ch.powerunit.collector.impl.CollectorTesterImpl; 036import ch.powerunit.collector.lang.CollectorTesterDSL0; 037import ch.powerunit.collector.lang.CollectorTesterDSL1; 038import ch.powerunit.collector.lang.CollectorTesterDSL2; 039import ch.powerunit.collector.lang.CollectorTesterDSL3; 040 041/** 042 * This is a tester for {@link Collector}. 043 * <p> 044 * The goal of this tester is to validate a {@link Collector}. The following 045 * tests are done : 046 * <ol> 047 * <li><code>{@link Collector#accumulator() accumulator()}</code> must return a 048 * not null result.</li> 049 * <li><code>{@link Collector#combiner() combiner()}</code> must return a not 050 * null result.</li> 051 * <li><code>{@link Collector#finisher() finisher()}</code> must return a not 052 * null result.</li> 053 * <li><code>{@link Collector#supplier() supplier()}</code> must return a not 054 * null result.</li> 055 * <li><code>{@link Collector#characteristics() characteristics()}</code> must 056 * return a not null result and be the same list that is specified in this 057 * tester.</li> 058 * <li>For each received sample either use it - 059 * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withInput(Stream) 060 * withInput} - or create a stream - 061 * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withStreamFromList(List) 062 * withStreamFromList} or 063 * {@link ch.powerunit.collector.lang.CollectorTesterDSL0#withParallelStreamFromList(List) 064 * withParallelStreamFromList} - and then execute the method 065 * {@link java.util.stream.Stream#collect(Collector) collect} with the 066 * {@link Collector} under test and validate the returned result.</li> 067 * </ol> 068 * 069 * @author borettim 070 * @since 0.4.0 071 * @param <T> 072 * the input type of the {@link java.util.stream.Collector Collector} 073 * . 074 * @param <A> 075 * the accumulator type of the {@link java.util.stream.Collector 076 * Collector}. 077 * @param <R> 078 * the return type of the {@link java.util.stream.Collector 079 * Collector}. 080 */ 081@TestInterface(CollectorTesterImpl.class) 082public final class CollectorTester<T, A, R> { 083 private final Collector<T, A, R> collectorToTest; 084 085 private final List<Stream<T>> inputs; 086 087 private final List<Matcher<? super R>> results; 088 089 private final Matcher<Iterable<? extends Characteristics>> expectedCharacteristics; 090 091 private CollectorTester(Collector<T, A, R> collectorToTest, 092 List<Stream<T>> inputs, List<Matcher<? super R>> results, 093 Matcher<Iterable<? extends Characteristics>> expectedCharacteristics) { 094 this.collectorToTest = collectorToTest; 095 this.inputs = inputs; 096 this.results = results; 097 this.expectedCharacteristics = expectedCharacteristics; 098 } 099 100 /** 101 * Return a builder to create a tester of {@link java.util.stream.Collector 102 * Collector}. 103 * 104 * @param collectorToTest 105 * the {@link java.util.stream.Collector Collector} to be tested. 106 * @param <T> 107 * the input type of the {@link java.util.stream.Collector 108 * Collector} . 109 * 110 * @param <R> 111 * the return type of the {@link java.util.stream.Collector 112 * Collector}. 113 * @return {@link CollectorTesterDSL0 the DSL to build the tester} 114 */ 115 @SuppressWarnings({ "rawtypes", "unchecked" }) 116 public static <T, R> CollectorTesterDSL0<T, ?, R> of( 117 Collector<T, ?, R> collectorToTest) { 118 return new CollectorTesterDSL(collectorToTest); 119 } 120 121 /** 122 * Return a builder to create a tester of {@link java.util.stream.Collector 123 * Collector}. 124 * 125 * @param inputClass 126 * the class of the input of the 127 * {@link java.util.stream.Collector Collector}. 128 * @param outputClass 129 * the class of the output of the 130 * {@link java.util.stream.Collector Collector}. 131 * @param collectorToTest 132 * the {@link java.util.stream.Collector Collector} to be tested. 133 * @param <T> 134 * the input type of the {@link java.util.stream.Collector 135 * Collector}. 136 * 137 * @param <R> 138 * the return type of the {@link java.util.stream.Collector 139 * Collector}. 140 * @return {@link CollectorTesterDSL0 the DSL to build the tester} 141 */ 142 @SuppressWarnings({ "rawtypes", "unchecked" }) 143 public static <T, R> CollectorTesterDSL0<T, ?, R> of(Class<T> inputClass, 144 Class<T> outputClass, Collector<T, ?, R> collectorToTest) { 145 return new CollectorTesterDSL(collectorToTest); 146 } 147 148 private static class CollectorTesterDSL<T, A, R> implements 149 CollectorTesterDSL0<T, A, R>, CollectorTesterDSL1<T, A, R>, 150 CollectorTesterDSL2<T, A, R> { 151 private final Collector<T, A, R> collectorToTest; 152 153 private final List<Stream<T>> inputs = new ArrayList<>(); 154 155 private final List<Matcher<? super R>> results = new ArrayList<>(); 156 157 private Matcher<Iterable<? extends Characteristics>> expectedCharacteristics; 158 159 public CollectorTesterDSL(Collector<T, A, R> collectorToTest) { 160 this.collectorToTest = collectorToTest; 161 } 162 163 @Override 164 public CollectorTesterDSL3<T, A, R> havingCharacteristics( 165 Characteristics... expectedCharacteristics) { 166 this.expectedCharacteristics = TestSuite.DSL 167 .<Collector.Characteristics> containsInAnyOrder(expectedCharacteristics); 168 return this; 169 } 170 171 @Override 172 public CollectorTesterDSL2<T, A, R> withInput(Stream<T> input) { 173 inputs.add(Objects.requireNonNull(input, "input can't be null")); 174 return this; 175 } 176 177 @Override 178 public CollectorTesterDSL2<T, A, R> withStreamFromList(List<T> input) { 179 return withInput(Objects.requireNonNull(input, 180 "input can't be null").stream()); 181 } 182 183 @Override 184 public CollectorTesterDSL2<T, A, R> withParallelStreamFromList( 185 List<T> input) { 186 return withInput(Objects.requireNonNull(input, 187 "input can't be null").parallelStream()); 188 } 189 190 @Override 191 public CollectorTesterDSL2<T, A, R> withStreamFromArray( 192 @SuppressWarnings("unchecked") T... input) { 193 return withInput(Arrays.stream(input)); 194 } 195 196 @SuppressWarnings("unchecked") 197 @Override 198 public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first) { 199 return withStreamFromArray((T[]) new Object[] { first }); 200 } 201 202 @SuppressWarnings("unchecked") 203 @Override 204 public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, 205 T second) { 206 return withStreamFromArray((T[]) new Object[] { first, second }); 207 } 208 209 @SuppressWarnings("unchecked") 210 @Override 211 public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, 212 T second, T third) { 213 return withStreamFromArray((T[]) new Object[] { first, second, 214 third }); 215 } 216 217 @SuppressWarnings("unchecked") 218 @Override 219 public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, 220 T second, T third, T fourth) { 221 return withStreamFromArray((T[]) new Object[] { first, second, 222 third, fourth }); 223 } 224 225 @SuppressWarnings("unchecked") 226 @Override 227 public CollectorTesterDSL2<T, A, R> withStreamFromArray(T first, 228 T second, T third, T fourth, T fifth) { 229 return withStreamFromArray((T[]) new Object[] { first, second, 230 third, fourth, fifth }); 231 } 232 233 @Override 234 public CollectorTesterDSL1<T, A, R> expecting( 235 Matcher<? super R> matching) { 236 results.add(Objects.requireNonNull(matching, 237 "matching can't be null")); 238 return this; 239 } 240 241 @Override 242 public CollectorTesterDSL1<T, A, R> expecting(R value) { 243 return expecting(TestSuite.DSL.equalTo(value)); 244 } 245 246 @Override 247 public CollectorTesterDSL1<T, A, R> expectingNull() { 248 return expecting(TestSuite.DSL.nullValue()); 249 } 250 251 @Override 252 public CollectorTester<T, A, R> build() { 253 return new CollectorTester<T, A, R>(collectorToTest, inputs, 254 results, 255 expectedCharacteristics == null ? TestSuite.DSL 256 .emptyIterable() : expectedCharacteristics); 257 } 258 259 } 260 261 /** 262 * Used by the framework. 263 * 264 * @return the collectorToTest 265 */ 266 public Collector<T, A, R> getCollectorToTest() { 267 return collectorToTest; 268 } 269 270 /** 271 * Used by the framework. 272 * 273 * @return the inputs 274 */ 275 public List<Stream<T>> getInputs() { 276 return Collections.unmodifiableList(inputs); 277 } 278 279 /** 280 * Used by the framework. 281 * 282 * @return the results 283 */ 284 public List<Matcher<? super R>> getResults() { 285 return Collections.unmodifiableList(results); 286 } 287 288 /** 289 * Used by the framework. 290 * 291 * @return the expectedCharacteristics 292 */ 293 public Matcher<Iterable<? extends Characteristics>> getExpectedCharacteristics() { 294 return expectedCharacteristics; 295 } 296 297}