diff --git a/test-utils/build.gradle b/test-utils/build.gradle index 7118b630..b9b47a4d 100644 --- a/test-utils/build.gradle +++ b/test-utils/build.gradle @@ -10,6 +10,8 @@ configurations { apply from: '../publish.gradle' dependencies { + compile project(':iterators') + compile 'junit:junit:' + JUNIT compile 'org.hamcrest:hamcrest-all:' + HAMCREST compile 'org.mockito:mockito-core:' + MOCKITO diff --git a/test-utils/src/main/java/org/dmfs/testutils/mocks/MockFunction.java b/test-utils/src/main/java/org/dmfs/testutils/mocks/MockFunction.java new file mode 100644 index 00000000..3686c5f9 --- /dev/null +++ b/test-utils/src/main/java/org/dmfs/testutils/mocks/MockFunction.java @@ -0,0 +1,95 @@ +/* + * Copyright 2017 dmfs GmbH + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.testutils.mocks; + +import org.dmfs.iterators.Function; +import org.dmfs.iterators.SingletonIterator; +import org.dmfs.jems.single.Single; +import org.mockito.Mockito; + +import java.util.Iterator; + +import static org.dmfs.testutils.TestDoubles.failingMock; + + +/** + * {@link Single} for a mock {@link Function} that expects on the provided arguments (fails on anything else) and returns the provided, corresponding results. + * + * @author Gabor Keszthelyi + */ +public final class MockFunction implements Single> +{ + private final Iterator mExpectedArguments; + private final Iterator mMockResults; + + + public MockFunction(Iterator expectedArguments, Iterator mockResults) + { + mExpectedArguments = expectedArguments; + mMockResults = mockResults; + } + + + public MockFunction(Iterable expectedArguments, Iterable mockResults) + { + this(expectedArguments.iterator(), mockResults.iterator()); + } + + + public MockFunction(Iterator expectedArguments, Iterable mockResults) + { + this(expectedArguments, mockResults.iterator()); + } + + + public MockFunction(Iterable expectedArguments, Iterator mockResults) + { + this(expectedArguments.iterator(), mockResults); + } + + + public MockFunction(Argument argument, Result result) + { + this(new SingletonIterator<>(argument), new SingletonIterator<>(result)); + } + + + @Override + public Function value() + { + Function mockFunction = failingMock(Function.class); + + while (mExpectedArguments.hasNext()) + { + + if (!mMockResults.hasNext()) + { + throw new IllegalArgumentException("Less results than arguments provided"); + } + + Mockito.doReturn(mMockResults.next()).when(mockFunction).apply(mExpectedArguments.next()); + } + + if (mMockResults.hasNext()) + { + throw new IllegalArgumentException("Less arguments than results provided"); + } + + return mockFunction; + } +} diff --git a/test-utils/src/test/java/org/dmfs/testutils/mocks/MockFunctionTest.java b/test-utils/src/test/java/org/dmfs/testutils/mocks/MockFunctionTest.java new file mode 100644 index 00000000..bb0ab30b --- /dev/null +++ b/test-utils/src/test/java/org/dmfs/testutils/mocks/MockFunctionTest.java @@ -0,0 +1,180 @@ +/* + * Copyright 2017 dmfs GmbH + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.testutils.mocks; + +import org.dmfs.iterables.ArrayIterable; +import org.dmfs.iterators.ArrayIterator; +import org.dmfs.iterators.Function; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + + +/** + * Unit test for {@link MockFunction}. + * + * @author Gabor Keszthelyi + */ +public final class MockFunctionTest +{ + + private static final Object RES = new Object(); + private static final Object RES_1 = new Object(); + private static final Object RES_2 = new Object(); + private static final Object RES_3 = new Object(); + + + private static ValueObject arg(int value) + { + return new ValueObject(value); + } + + @Test + public void test_singles_sameArg_pass() + { + assertThat(new MockFunction<>(arg(1), RES).value().apply(arg(1)), sameInstance(RES)); + } + + + @Test(expected = AssertionError.class) + public void test_singles_differentArg_fail() + { + new MockFunction<>(arg(1), RES_1).value().apply(arg(2)); + } + + + @Test + public void test_iterators_single_sameArg_pass() + { + assertThat(new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(1)), sameInstance(RES)); + } + + + @Test(expected = AssertionError.class) + public void test_iterators_single_differentArg_fail() + { + new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(555)); + } + + + @Test + public void test_iterators_multi_sameArg_pass() + { + Function mockFunction = new MockFunction<>( + new ArrayIterator<>(arg(1), arg(2), arg(3)), + new ArrayIterator<>(RES_1, RES_2, RES_3)).value(); + assertThat(mockFunction.apply(arg(1)), sameInstance(RES_1)); + assertThat(mockFunction.apply(arg(2)), sameInstance(RES_2)); + assertThat(mockFunction.apply(arg(3)), sameInstance(RES_3)); + } + + + @Test(expected = AssertionError.class) + public void test_iterators_multi_differentArg_fail() + { + Function mockFunction = new MockFunction<>( + new ArrayIterator<>(arg(1), arg(2), arg(3)), + new ArrayIterator<>(RES_1, RES_2, RES_3)).value(); + + assertThat(mockFunction.apply(arg(1)), sameInstance(RES_1)); + mockFunction.apply(arg(555)); + } + + + @Test(expected = IllegalArgumentException.class) + public void test_lessArgumentThanResult_throwsException() + { + new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterator<>(RES_1, RES_2)).value(); + } + + + @Test(expected = IllegalArgumentException.class) + public void test_lessResultThanArgument_throwsException() + { + new MockFunction<>(new ArrayIterator<>(arg(1), arg(2)), new ArrayIterator<>(RES_1)).value(); + } + + + @Test + public void test_iterable_iterable_pass() + { + assertThat(new MockFunction<>(new ArrayIterable<>(arg(1)), new ArrayIterable<>(RES)).value().apply(arg(1)), sameInstance(RES)); + } + + + @Test + public void test_iterator_iterable_pass() + { + assertThat(new MockFunction<>(new ArrayIterator<>(arg(1)), new ArrayIterable<>(RES)).value().apply(arg(1)), sameInstance(RES)); + } + + + @Test + public void test_iterable_iterator_pass() + { + assertThat(new MockFunction<>(new ArrayIterable<>(arg(1)), new ArrayIterator<>(RES)).value().apply(arg(1)), sameInstance(RES)); + } + + + // TODO Use the top level class when/if available + public static final class ValueObject + { + private final int mValue; + + + public ValueObject(int value) + { + mValue = value; + } + + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + + ValueObject that = (ValueObject) o; + + return mValue == that.mValue; + } + + + @Override + public int hashCode() + { + return mValue; + } + + + @Override + public String toString() + { + return "ValueObject{" + mValue + '}'; + } + + } + +} \ No newline at end of file