DataProviderUtil.java
- package net.morimekta.testing.junit4;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Utility for using <code>junit-dataprovider</code>.
- */
- 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
- * {@literal@}RunWith(DataProviderRunner.class)
- * public class MyTest {
- * {@literal@}DataProvider
- * public static Object[][] testParams() {
- * return buildDataDimensions(
- * List.of(ContentType.WALLPAPER, ContentType.AUDIO),
- * List.of(Locale.US, Locale.DE, Locale.SIMPLIFIED_CHINESE));
- * }
- * {@literal@}Test
- * {@literal@}UseDataProvider("testParams")
- * public void testMyParams(ContentType contentType, Locale locale) {
- * // The test.
- * }
- * }
- * }</pre>
- * <p>
- * 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>
- * <p>
- * 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 makeDataParams(result);
- }
- /**
- * Convenience method to be able to use lists instead of arrays to build the dimensions. This must be a a list of
- * lists of equal sizes, with compatible argument objects in each list.
- *
- * @param lists List of list of arguments.
- * @return Array of array of arguments.
- */
- public static Object[][] makeDataParams(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 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 final Object[] EMPTY = new Object[0];
- private DataProviderUtil() {
- }
- }