FunctionTester.java

/**
 * 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.function;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;

import org.hamcrest.Matcher;

import ch.powerunit.TestInterface;
import ch.powerunit.function.impl.FunctionTesterImpl;
import ch.powerunit.function.impl.SupplierEqualsToMatcher;
import ch.powerunit.function.lang.FunctionTesterDefineDSL;
import ch.powerunit.function.lang.FunctionTesterEndDSL;
import ch.powerunit.function.lang.FunctionTesterNextDSL;
import ch.powerunit.function.lang.FunctionTesterStartDSL;

/**
 * Tester for function.
 * 
 * @author borettim
 * @since 0.3.0
 */
@TestInterface(FunctionTesterImpl.class)
public final class FunctionTester<T, R> {
	private final Function<T, R> underTest;
	private final List<Supplier<T>> input;
	private final List<Supplier<Matcher<? super R>>> result;
	private final List<Supplier<String>> name;

	private static class FunctionTesterDSL<T, R> implements
			FunctionTesterDefineDSL<T, R>, FunctionTesterEndDSL<T, R>,
			FunctionTesterNextDSL<T, R>, FunctionTesterStartDSL<T, R> {

		private final Function<T, R> underTest;

		private List<Supplier<T>> tmpInput = new ArrayList<>();

		private List<Supplier<Matcher<? super R>>> tmpResult = new ArrayList<>();

		private List<Supplier<String>> tmpName = new ArrayList<>();

		private void finalizeCase() {
			if (tmpName.size() < tmpInput.size()) {
				tmpName.add(() -> "");
			}
		}

		public FunctionTesterDSL(Function<T, R> underTest) {
			this.underTest = underTest;
		}

		@Override
		public FunctionTesterDefineDSL<T, R> passingAsParameter(T input) {
			return passingAsParameter(() -> input);
		}

		@Override
		public FunctionTesterDefineDSL<T, R> passingAsParameter(
				Supplier<T> input) {
			Objects.requireNonNull(input, "input can't be null");
			finalizeCase();
			tmpInput.add(input);
			return this;
		}

		@Override
		public FunctionTesterNextDSL<T, R> thenExpectingResult(R result) {
			return thenExpectingResult(() -> result);
		}

		@Override
		public FunctionTesterNextDSL<T, R> thenExpectingResult(
				Supplier<R> result) {
			Objects.requireNonNull(result, "matching can't be null");
			return thenExpectingResultThat(new SupplierEqualsToMatcher<R>(
					result));
		}

		@Override
		public FunctionTesterNextDSL<T, R> thenExpectingResultThat(
				Matcher<? super R> matching) {
			Objects.requireNonNull(matching, "matching can't be null");
			return thenExpectingResultThat(() -> matching);
		}

		@Override
		public FunctionTesterNextDSL<T, R> thenExpectingResultThat(
				Supplier<Matcher<? super R>> matching) {
			Objects.requireNonNull(matching, "matching can't be null");
			tmpResult.add(matching);
			return this;
		}

		@Override
		public FunctionTesterEndDSL<T, R> testNamed(String name) {
			return testNamed(() -> name);
		}

		@Override
		public FunctionTesterEndDSL<T, R> testNamed(Supplier<String> name) {
			Objects.requireNonNull(name, "name can't be null");
			tmpName.add(name);
			return this;
		}

		@Override
		public FunctionTester<T, R> build() {
			finalizeCase();
			return new FunctionTester<T, R>(underTest, tmpInput, tmpResult,
					tmpName);
		}

	}

	private FunctionTester(Function<T, R> underTest,
			List<Supplier<T>> tmpInput,
			List<Supplier<Matcher<? super R>>> tmpResult,
			List<Supplier<String>> tmpName) {
		this.underTest = underTest;
		this.input = tmpInput;
		this.result = tmpResult;
		this.name = tmpName;
	}

	/**
	 * Start the creation of a tester of function.
	 * 
	 * @param functionUnderTest
	 *            the function to be tested
	 * @return {@link FunctionTesterStartDSL the DSL}
	 * @throws NullPointerException
	 *             when functionUnderTest is null
	 * @param <T>
	 *            the input argument type
	 * @param <R>
	 *            the result type
	 * @see ch.powerunit.TestDelegate
	 */
	public static <T, R> FunctionTesterStartDSL<T, R> of(
			Function<T, R> functionUnderTest) {
		Objects.requireNonNull(functionUnderTest,
				"functionUnderTest can't be null");
		return new FunctionTesterDSL<T, R>(functionUnderTest);
	}

	/**
	 * Used by the framework.
	 * 
	 * @return the underTest
	 */
	public Function<T, R> getUnderTest() {
		return underTest;
	}

	/**
	 * Used by the framework.
	 * 
	 * @return the input
	 */
	public List<Supplier<T>> getInput() {
		return Collections.unmodifiableList(input);
	}

	/**
	 * Used by the framework.
	 * 
	 * @return the result
	 */
	public List<Supplier<Matcher<? super R>>> getResult() {
		return Collections.unmodifiableList(result);
	}

	/**
	 * Used by the framework.
	 * 
	 * @return the name
	 */
	public List<Supplier<String>> getName() {
		return Collections.unmodifiableList(name);
	}

}