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

com.tngtech.jgiven.junit5.ArgumentReflectionUtil Maven / Gradle / Ivy

package com.tngtech.jgiven.junit5;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tngtech.jgiven.impl.util.ParameterNameUtil;
import com.tngtech.jgiven.impl.util.ReflectionUtil;
import com.tngtech.jgiven.report.model.NamedArgument;

class ArgumentReflectionUtil {
    private static final Logger log = LoggerFactory.getLogger(ArgumentReflectionUtil.class);

    static final String METHOD_EXTENSION_CONTEXT = "org.junit.jupiter.engine.descriptor.MethodExtensionContext";
    static final String TEST_TEMPLATE_INVOCATION_TEST_DESCRIPTOR = "org.junit.jupiter.engine.descriptor.TestTemplateInvocationTestDescriptor";
    static final String PARAMETERIZED_TEST_INVOCATION_CONTEXT = "org.junit.jupiter.params.ParameterizedTestInvocationContext";

    static final String ERROR = "Not able to access field containing test method arguments. " +
            "Probably the internal representation has changed. Consider writing a bug report.";

    /**
     * This is a very ugly workaround to get the method arguments from the JUnit 5 context via reflection.
     */
    static List getNamedArgs(ExtensionContext context) {
        List namedArgs = new ArrayList<>();

        if (context.getTestMethod().get().getParameterCount() > 0) {
            try {
                if (context.getClass().getCanonicalName().equals(METHOD_EXTENSION_CONTEXT)) {
                    Field field = context.getClass().getSuperclass().getDeclaredField("testDescriptor");
                    Object testDescriptor = ReflectionUtil.getFieldValueOrNull(field, context, ERROR);
                    if (testDescriptor != null
                            && testDescriptor.getClass().getCanonicalName().equals(TEST_TEMPLATE_INVOCATION_TEST_DESCRIPTOR)) {
                        Object invocationContext = ReflectionUtil.getFieldValueOrNull("invocationContext", testDescriptor, ERROR);
                        if (invocationContext != null
                                && invocationContext.getClass().getCanonicalName().equals(PARAMETERIZED_TEST_INVOCATION_CONTEXT)) {
                            Object arguments = ReflectionUtil.getFieldValueOrNull("arguments", invocationContext, ERROR);
                            if (arguments instanceof Arguments) {
                                List args = Arrays.asList(((Arguments) arguments).get());
                                namedArgs = ParameterNameUtil.mapArgumentsWithParameterNames(context.getTestMethod().get(), args);
                            } else {
                                log.warn(ERROR + " The type of arguments in the invocation context has changed. Please write a bug report.");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.warn(ERROR, e);
            }
        }

        return namedArgs;
    }
}