Commit 27da08f0 authored by Stein Eldar Johnsen's avatar Stein Eldar Johnsen 💬

Add utility to build DataProvider dimensions for junit-dataprovider.

parent 4099adce
Pipeline #32931520 failed with stages
in 1 minute and 59 seconds
...@@ -233,6 +233,7 @@ ...@@ -233,6 +233,7 @@
<nodeprecatedlist>true</nodeprecatedlist> <nodeprecatedlist>true</nodeprecatedlist>
<notimestamp>true</notimestamp> <notimestamp>true</notimestamp>
<quiet>true</quiet> <quiet>true</quiet>
<additionalOptions>-html5</additionalOptions>
<groups> <groups>
<group> <group>
<title>Testing Utils</title> <title>Testing Utils</title>
...@@ -347,9 +348,9 @@ ...@@ -347,9 +348,9 @@
<profiles> <profiles>
<profile> <profile>
<id>jdk9</id> <id>jdk8</id>
<activation> <activation>
<jdk>[9,100)</jdk> <jdk>1.8</jdk>
</activation> </activation>
<build> <build>
<plugins> <plugins>
...@@ -358,7 +359,8 @@ ...@@ -358,7 +359,8 @@
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<configuration> <configuration>
<additionalOptions> <additionalOptions>
<additionalOption>-html5</additionalOption> <!-- JDK8 javadoc does not support the -html5 option -->
<additionalOption>-quiet</additionalOption>
</additionalOptions> </additionalOptions>
</configuration> </configuration>
</plugin> </plugin>
......
package net.morimekta.testing;
import java.util.ArrayList;
import java.util.List;
public class DataProviderUtil {
/**
* This is a utility to be used with <code>junit-dataprovider</code>. It will
* instead of taking in an array of argument arrays, will get an array of
* available dimensions, each with possible values. It will then multiply all
* the possible dimension possibilities with each other and result the
* array of parameter array that <code>junit-dataprovider</code> wants.
* <p>
* E.g. providing two dimensions, content type and locale, e.g. like this:
*
* <pre>{@code
* return buildDataDimensions(
* Arrays.asList(ContentType.WALLPAPER, ContentType.AUDIO),
* Arrays.asList(Locale.US, Locale.DE, Locale.SIMPLIFIED_CHINESE));
* }</pre>
*
* Will create 6 argument arrays, one for each combination of content type and
* locale as if the input was this:
*
* <pre>{@code
* return new Object[][]{
* {ContentType.WALLPAPER, Locale.US},
* {ContentType.WALLPAPER, Locale.DE},
* {ContentType.WALLPAPER, Locale.SIMPLIFIED_CHINESE},
* {ContentType.AUDIO, Locale.US},
* {ContentType.AUDIO, Locale.DE},
* {ContentType.AUDIO, Locale.SIMPLIFIED_CHINESE},
* });
* }</pre>
*
* This can significantly shorten the argument list especially with larger set
* of dimensions and longer lists of options for each. It accepts null values
* and does not accept empty dimensions. Each dimension is called a 'layer' in
* the input.
*
* @param dimensions The available dimensions.
* @return The argument arrays.
*/
public static Object[][] buildDataDimensions(List<?>... dimensions) {
if (dimensions.length == 0) {
throw new IllegalArgumentException("No dimensions provided");
}
if (dimensions[0].size() == 0) {
throw new IllegalArgumentException("Empty dimension in layer 1");
}
List<List<Object>> result = new ArrayList<>();
for (Object o : dimensions[0]) {
List<Object> base = new ArrayList<>();
base.add(o);
result.add(base);
}
for (int layer = 1; layer < dimensions.length; ++layer) {
if (dimensions[layer].size() == 0) {
throw new IllegalArgumentException("Empty dimension in layer " + (layer + 1));
}
// The layer below is the one that will be multiplied with the
// arguments from this layer.
List<List<Object>> layerBelow = deepCopy(result);
Object first = dimensions[layer].get(0);
for (List<Object> l : result) {
l.add(first);
}
for (int pos = 1; pos < dimensions[layer].size(); ++pos) {
List<List<Object>> extraResults = deepCopy(layerBelow);
for (List<Object> l : extraResults) {
l.add(dimensions[layer].get(pos));
}
result.addAll(extraResults);
}
}
return fromLists(result);
}
private static List<List<Object>> deepCopy(List<List<Object>> base) {
List<List<Object>> copy = new ArrayList<>(base.size());
for (List<Object> list : base) {
copy.add(new ArrayList<>(list));
}
return copy;
}
private static Object[][] fromLists(List<List<Object>> lists) {
// assumes all inner lists are the same size.
Object[][] out = new Object[lists.size()][];
for (int i = 0; i < lists.size(); ++i) {
out[i] = lists.get(i).toArray(EMPTY);
}
return out;
}
private static final Object[] EMPTY = new Object[0];
private DataProviderUtil() {}
}
package net.morimekta.testing;
import org.junit.Test;
import java.util.ArrayList;
import static java.util.Arrays.asList;
import static net.morimekta.testing.DataProviderUtil.buildDataDimensions;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class DataProviderUtilTest {
@Test
public void testBuildDataDimension() {
Object[][] out = buildDataDimensions(
asList(1, 2, 3),
asList("a", "b"),
asList('y', 'n', '?'));
assertThat(out.length, is(3 * 2 * 3));
for (Object[] a : out) {
assertThat(a.length, is(3));
assertThat(a[0], is(instanceOf(Integer.TYPE)));
assertThat(a[1], is(instanceOf(String.class)));
assertThat(a[2], is(instanceOf(Character.TYPE)));
}
// the first is the first of all
assertThat(out[0], is(new Object[]{1, "a", 'y'}));
// the last is the last of all
assertThat(out[17], is(new Object[]{3, "b", '?'}));
try {
buildDataDimensions();
fail("no exception");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), is("No dimensions provided"));
}
try {
buildDataDimensions(new ArrayList<>());
fail("no exception");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), is("Empty dimension in layer 1"));
}
try {
buildDataDimensions(asList(1, 2), new ArrayList<>());
fail("no exception");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), is("Empty dimension in layer 2"));
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment