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