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