package eu.dnetlib.miscutils.functional;

import static org.junit.Assert.*; // NOPMD

import org.junit.Test;

public class CompositeUnaryFunctionTest  {

	@Test
	public void testOf() {
		final UnaryFunction<String, Integer> toStringBase = new UnaryFunction<String, Integer>() { // NOPMD
			@Override
			public String evaluate(final Integer arg) {
				return arg.toString();
			}
		};

		final UnaryFunction<Integer, String> fromStringBase = new UnaryFunction<Integer, String>() {
			@Override
			public Integer evaluate(final String arg) {
				return Integer.decode(arg);
			}
		};

		final CompositeUnaryFunction<String, Integer> toString = new CompositeUnaryFunction<String, Integer>(toStringBase);
		final CompositeUnaryFunction<Integer, String> fromString = new CompositeUnaryFunction<Integer, String>(fromStringBase);

		assertEquals("evaluation", toString.evaluate(10), "10");
		assertEquals("evaluation", fromString.evaluate("10"), (Integer) 10);

		final UnaryFunction<String, String> stringIdentity = toString.of(fromString);
		final UnaryFunction<Integer, Integer> integerIdentity = fromString.of(toString);
		final UnaryFunction<Integer, Integer> integerIdentity2 = fromString.of(stringIdentity).of(toString).of(integerIdentity);

		assertEquals("string evaluation", stringIdentity.evaluate("10"), "10");
		assertEquals("integer evaluation", integerIdentity.evaluate(10), (Integer) 10);
		assertEquals("integer identity", integerIdentity2.evaluate(10), (Integer) 10);
	}

	private transient int calls;
	private transient final static int TIMES = 100;

	@Test
	public void testRecursive() {
		calls = 0;
		final UnaryFunction<Integer, Integer> incrementBase = new UnaryFunction<Integer, Integer>() { // NOPMD
			@Override
			public Integer evaluate(final Integer arg) {
				calls++;
				return arg + 1;
			}
		};

		final CompositeUnaryFunction<Integer, Integer> increment = new CompositeUnaryFunction<Integer, Integer>(incrementBase);

		CompositeUnaryFunction<Integer, Integer> comp = increment;
		for (int i = 1; i <= 100; i++) {
			assertEquals("compare", comp.evaluate(0), (Integer) i);
			comp = comp.of(increment);
		}

		assertEquals("number of calls", calls, (TIMES * (TIMES + 1) / 2));
	}

	@Test
	public void testCurry() {
		final UnaryFunction<UnaryFunction<Integer, Integer>, Integer> add = new UnaryFunction<UnaryFunction<Integer, Integer>, Integer>() { // NOPMD
			@Override
			public UnaryFunction<Integer, Integer> evaluate(final Integer arg) {
				return new UnaryFunction<Integer, Integer>() {
					@Override
					public Integer evaluate(final Integer brg) {
						return arg + brg;
					}
				};

			}
		};

		final UnaryFunction<Integer, Integer> increment = add.evaluate(1);

		assertEquals("check add", add.evaluate(1).evaluate(2), (Integer) 3);
		assertEquals("check increment", increment.evaluate(1), (Integer) 2);
	}

}
