All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.junitpioneer.internal.PioneerUtils Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/*
 * Copyright 2016-2022 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * http://www.eclipse.org/legal/epl-v20.html
 */

package org.junitpioneer.internal;

import static org.junit.platform.commons.support.ReflectionSupport.findMethod;

import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.junit.jupiter.api.extension.ExtensionContext;

/**
 * Pioneer-internal utility class.
 * DO NOT USE THIS CLASS - IT MAY CHANGE SIGNIFICANTLY IN ANY MINOR UPDATE.
 *
 * @see PioneerAnnotationUtils
 */
public class PioneerUtils {

	private PioneerUtils() {
		// private constructor to prevent instantiation of utility class
	}

	/**
	 * A {@link Collectors#toSet() toSet} collector that throws an {@link IllegalStateException}
	 * on duplicate elements (according to {@link Object#equals(Object) equals}).
	 */
	public static  Collector, Set> distinctToSet() {
		return Collector.of(HashSet::new, PioneerUtils::addButThrowIfDuplicate, (left, right) -> {
			right.forEach(element -> addButThrowIfDuplicate(left, element));
			return left;
		});
	}

	private static  void addButThrowIfDuplicate(Set set, T element) {
		boolean newElement = set.add(element);
		if (!newElement) {
			throw new IllegalStateException("Duplicate element '" + element + "'.");
		}
	}

	/**
	 * Find the first {@link Method} of the supplied class or interface that
	 * meets the specified criteria, beginning with the specified class or
	 * interface and traversing its enclosing classes until such a method is
	 * found or the top level class is reached.
	 *
	 * 

The algorithm does not search for methods in {@link java.lang.Object}. * * @param clazz the class or interface in which to find the method; never {@code null} * @param methodName the name of the method to find; never {@code null} or empty * @param parameterTypes the types of parameters accepted by the method, if any; * never {@code null} * @return an {@code Optional} containing the method found; never {@code null} * but potentially empty if no such method could be found * @see org.junit.platform.commons.support.ReflectionSupport#findMethod(Class, String, Class...) */ public static Optional findMethodCurrentOrEnclosing(Class clazz, String methodName, Class... parameterTypes) { Class current = clazz; Optional method; do { // null checking done by ReflectionSupport.findMethod method = findMethod(current, methodName, parameterTypes); current = current.getEnclosingClass(); } while (!method.isPresent() && current != null); return method; } /** * Find all (parent) {@code ExtensionContext}s via {@link ExtensionContext#getParent()}. * * @param context the context for which to find all (parent) contexts; never {@code null} * @return a list of all contexts, "outwards" in the {@link ExtensionContext#getParent() getParent}-order, * beginning with the given context; never {@code null} or empty */ public static List findAllContexts(ExtensionContext context) { List allContexts = new ArrayList<>(); allContexts.add(context); List parentContexts = context .getParent() .map(PioneerUtils::findAllContexts) .orElse(Collections.emptyList()); allContexts.addAll(parentContexts); return allContexts; } public static String nullSafeToString(Object object) { if (object == null) { return "null"; } if (object.getClass().isArray()) { switch (object.getClass().getComponentType().getSimpleName()) { case "boolean": return Arrays.toString((boolean[]) object); case "byte": return Arrays.toString((byte[]) object); case "char": return Arrays.toString((char[]) object); case "int": return Arrays.toString((int[]) object); case "short": return Arrays.toString((short[]) object); case "long": return Arrays.toString((long[]) object); case "float": return Arrays.toString((float[]) object); case "double": return Arrays.toString((double[]) object); default: return Arrays.deepToString((Object[]) object); } } return object.toString(); } /** * Replaces all primitive types with the appropriate wrapper types. * Returns the passed argument if it's not a primitive according to {@link Class#isPrimitive()}. * * @return the wrapped class of the primitive type, or the passed class * @see MethodType#wrap() */ @SuppressWarnings("unchecked") public static Class wrap(Class clazz) { return (Class) MethodType.methodType(clazz).wrap().returnType(); } public static List> cartesianProduct(List> lists) { List> resultLists = new ArrayList<>(); if (lists.isEmpty()) { resultLists.add(Collections.emptyList()); return resultLists; } List firstList = lists.get(0); // Note the recursion here List> remainingLists = cartesianProduct(lists.subList(1, lists.size())); for (Object item : firstList) { for (List remainingList : remainingLists) { ArrayList resultList = new ArrayList<>(); resultList.add(item); resultList.addAll(remainingList); resultLists.add(resultList); } } return resultLists; } }