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.bifunction;
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Objects;
026import java.util.function.BiFunction;
027import java.util.function.Supplier;
028
029import org.hamcrest.Matcher;
030
031import ch.powerunit.TestInterface;
032import ch.powerunit.bifunction.impl.BiFunctionTesterImpl;
033import ch.powerunit.bifunction.lang.BiFunctionTesterDefineDSL;
034import ch.powerunit.bifunction.lang.BiFunctionTesterEndDSL;
035import ch.powerunit.bifunction.lang.BiFunctionTesterNextDSL;
036import ch.powerunit.bifunction.lang.BiFunctionTesterStartDSL;
037import ch.powerunit.function.impl.SupplierEqualsToMatcher;
038
039/**
040 * Tester for bifunction.
041 * 
042 * @author borettim
043 * @since 0.3.0
044 */
045@TestInterface(BiFunctionTesterImpl.class)
046public final class BiFunctionTester<T, U, R> {
047        private final BiFunction<T, U, R> underTest;
048        private final List<Supplier<T>> input1;
049        private final List<Supplier<U>> input2;
050        private final List<Supplier<Matcher<? super R>>> result;
051        private final List<Supplier<String>> name;
052
053        private static class BiFunctionTesterDSL<T, U, R> implements
054                        BiFunctionTesterDefineDSL<T, U, R>,
055                        BiFunctionTesterEndDSL<T, U, R>, BiFunctionTesterNextDSL<T, U, R>,
056                        BiFunctionTesterStartDSL<T, U, R> {
057
058                private final BiFunction<T, U, R> underTest;
059
060                private List<Supplier<T>> tmpInput1 = new ArrayList<>();
061
062                private List<Supplier<U>> tmpInput2 = new ArrayList<>();
063
064                private List<Supplier<Matcher<? super R>>> tmpResult = new ArrayList<>();
065
066                private List<Supplier<String>> tmpName = new ArrayList<>();
067
068                private void finalizeCase() {
069                        if (tmpName.size() < tmpInput1.size()) {
070                                tmpName.add(() -> "");
071                        }
072                }
073
074                public BiFunctionTesterDSL(BiFunction<T, U, R> underTest) {
075                        this.underTest = underTest;
076                }
077
078                @Override
079                public BiFunctionTesterDefineDSL<T, U, R> passingAsParameter(T input1,
080                                U input2) {
081                        return passingAsParameter(() -> input1, () -> input2);
082                }
083
084                @Override
085                public BiFunctionTesterDefineDSL<T, U, R> passingAsParameter(
086                                Supplier<T> input1, Supplier<U> input2) {
087                        Objects.requireNonNull(input1, "input1 can't be null");
088                        Objects.requireNonNull(input2, "input2 can't be null");
089                        finalizeCase();
090                        tmpInput1.add(input1);
091                        tmpInput2.add(input2);
092                        return this;
093                }
094
095                @Override
096                public BiFunctionTesterNextDSL<T, U, R> thenExpectingResult(R result) {
097                        return thenExpectingResult(() -> result);
098                }
099
100                @Override
101                public BiFunctionTesterNextDSL<T, U, R> thenExpectingResult(
102                                Supplier<R> result) {
103                        Objects.requireNonNull(result, "matching can't be null");
104                        return thenExpectingResultThat(new SupplierEqualsToMatcher<R>(
105                                        result));
106                }
107
108                @Override
109                public BiFunctionTesterNextDSL<T, U, R> thenExpectingResultThat(
110                                Matcher<? super R> matching) {
111                        Objects.requireNonNull(matching, "matching can't be null");
112                        return thenExpectingResultThat(() -> matching);
113                }
114
115                @Override
116                public BiFunctionTesterNextDSL<T, U, R> thenExpectingResultThat(
117                                Supplier<Matcher<? super R>> matching) {
118                        Objects.requireNonNull(matching, "matching can't be null");
119                        tmpResult.add(matching);
120                        return this;
121                }
122
123                @Override
124                public BiFunctionTesterEndDSL<T, U, R> testNamed(String name) {
125                        return testNamed(() -> name);
126                }
127
128                @Override
129                public BiFunctionTesterEndDSL<T, U, R> testNamed(Supplier<String> name) {
130                        Objects.requireNonNull(name, "name can't be null");
131                        tmpName.add(name);
132                        return this;
133                }
134
135                @Override
136                public BiFunctionTester<T, U, R> build() {
137                        finalizeCase();
138                        return new BiFunctionTester<T, U, R>(underTest, tmpInput1,
139                                        tmpInput2, tmpResult, tmpName);
140                }
141        }
142
143        private BiFunctionTester(BiFunction<T, U, R> underTest,
144                        List<Supplier<T>> tmpInput1, List<Supplier<U>> tmpInput2,
145                        List<Supplier<Matcher<? super R>>> tmpResult,
146                        List<Supplier<String>> tmpName) {
147                this.underTest = underTest;
148                this.input1 = tmpInput1;
149                this.input2 = tmpInput2;
150                this.result = tmpResult;
151                this.name = tmpName;
152        }
153
154        /**
155         * Start the creation of a tester of function.
156         * <p>
157         * For example :
158         * 
159         * <pre>
160         * &#064;TestDelegate
161         * public final BiFunctionTester&lt;Short, Integer, Long&gt; tester1 = BiFunctionTester
162         *              .of(this::bifunctionToBeTested).passingAsParameter((short) 1, 2)
163         *              .thenExpectingResult(3l).testNamed(&quot;tested&quot;)
164         *              .passingAsParameter((short) 2, 4).thenExpectingResult(6l).build();
165         * </pre>
166         * 
167         * @param bifunctionUnderTest
168         *            the function to be tested
169         * @return {@link BiFunctionTesterStartDSL the DSL}
170         * @throws NullPointerException
171         *             when bifunctionUnderTest is null
172         * @param <T>
173         *            the first input argument type
174         * @param <U>
175         *            the second input argument type
176         * @param <R>
177         *            the result type
178         * @see ch.powerunit.TestDelegate
179         */
180        public static <T, U, R> BiFunctionTesterStartDSL<T, U, R> of(
181                        BiFunction<T, U, R> bifunctionUnderTest) {
182                Objects.requireNonNull(bifunctionUnderTest,
183                                "bifunctionUnderTest can't be null");
184                return new BiFunctionTesterDSL<T, U, R>(bifunctionUnderTest);
185        }
186
187        /**
188         * Used by the framework.
189         * 
190         * @return the underTest
191         */
192        public BiFunction<T, U, R> getUnderTest() {
193                return underTest;
194        }
195
196        /**
197         * Used by the framework.
198         * 
199         * @return the first input
200         */
201        public List<Supplier<T>> getInput1() {
202                return Collections.unmodifiableList(input1);
203        }
204
205        /**
206         * Used by the framework.
207         * 
208         * @return the first input
209         */
210        public List<Supplier<U>> getInput2() {
211                return Collections.unmodifiableList(input2);
212        }
213
214        /**
215         * Used by the framework.
216         * 
217         * @return the result
218         */
219        public List<Supplier<Matcher<? super R>>> getResult() {
220                return Collections.unmodifiableList(result);
221        }
222
223        /**
224         * Used by the framework.
225         * 
226         * @return the name
227         */
228        public List<Supplier<String>> getName() {
229                return Collections.unmodifiableList(name);
230        }
231
232}