/*
 * Copyright (c) 2006, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation
//
package org.eclipse.persistence.jpa.tests.jpql;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.persistence.jpa.jpql.tools.model.AbstractActualJPQLQueryFormatter;
import org.eclipse.persistence.jpa.jpql.tools.model.BaseJPQLQueryFormatter;
import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryBuilder;
import org.eclipse.persistence.jpa.tests.jpql.parser.JPQLGrammarTestHelper;
import org.eclipse.persistence.jpa.tests.jpql.tools.model.IJPQLQueryBuilderTestHelper;
import org.eclipse.persistence.jpa.tests.jpql.tools.model.IJPQLQueryFormatterTestHelper;
import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
import org.junit.internal.runners.ErrorReportingRunner;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.ParentRunner;
import org.junit.runners.Suite.SuiteClasses;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;

/**
 * This JUnit runner is the sole runner of Hermes unit-tests because it modifies the default
 * behavior by adding the following support:
 * <ul>
 * <li>Adds the ability to inject objects that are instantiated by a test suite into the unit-test
 * before they are run.
 * <li>Because one unit-test can be run more than once with different state of any given object,
 * this cause issues in Eclipse because the IDE uses {@link Object#toString()} and cannot
 * discriminate between those identical tests. This runner changes the test's description by adding
 * enough information in order to make each test's description unique.
 * </ul>
 *
 * @version 2.4
 * @since 2.4
 * @author Pascal Filion
 */
@SuppressWarnings({ "nls", "restriction" })
public class JPQLTestRunner extends ParentRunner<Runner> {

    /**
     * The cached {@link Description} so it's not recreated every time.
     */
    private Description description;

    /**
     * This contains the helpers that will be injected into each test.
     */
    private DescriptionHelper descriptionHelper;

    /**
     * The display string of this test suite.
     */
    private String name;

    /**
     * The {@link Runner runners} for the test classes defined in {@link org.junit.runners.Suite.SuiteClasses
     * &#64;SuiteClasses}.
     */
    private List<Runner> runners;

    /**
     * The parent {@link SuiteHelper} or <code>null</code> if none was defined yet.
     */
    private SuiteHelper suiteHelper;

    /**
     * The list of registered helpers that inject values from the test suite into the unit-tests
     * before they are running.
     */
    private static final Map<Class<? extends Annotation>, DescriptionBuilder> testRunnerHelpers;

    /**
     * Registers the supported test runner helpers.
     */
    static {

        testRunnerHelpers = new HashMap<Class<? extends Annotation>, DescriptionBuilder>();

        testRunnerHelpers.put(IJPQLQueryBuilderTestHelper.class,   buildJPQLQueryBuilderTestHelperDescriptionBuilder());
        testRunnerHelpers.put(IJPQLQueryFormatterTestHelper.class, buildJPQLQueryFormatterTestHelperDescriptionBuilder());
        testRunnerHelpers.put(JPQLGrammarTestHelper.class,         buildJPQLGrammarTestHelperDescriptionBuilder());
        testRunnerHelpers.put(JPQLQueryHelperTestHelper.class,     buildJPQLQueryHelperTestHelperDescriptionBuilder());
        testRunnerHelpers.put(JPQLQueryTestHelperTestHelper.class, buildJPQLQueryTestHelperTestHelperDescriptionBuilder());
    }

    /**
     * Creates a new <code>JPQLTestRunner</code>.
     *
     * @param testClass The class that is either a test suite or a unit-tests
     * @throws InitializationError If the given test class is malformed
     */
    public JPQLTestRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
    }

    /**
     * Creates a new <code>JPQLTestRunner</code>.
     *
     * @param testClass The class that is either a test suite or a unit-tests
     * @param suiteHelper The parent {@link SuiteHelper} or {@link null} if none was defined yet
     * @throws InitializationError If the given test class is malformed
     */
    public JPQLTestRunner(Class<?> testClass, SuiteHelper suiteHelper) throws InitializationError {
        this(testClass);
        this.suiteHelper = suiteHelper;
    }

    private static DescriptionBuilder buildJPQLGrammarTestHelperDescriptionBuilder() {
        return new DescriptionBuilder() {
            @Override
            public String toString(Object object) {
                return object.toString();
            }
        };
    }

    private static DescriptionBuilder buildJPQLQueryBuilderTestHelperDescriptionBuilder() {
        return new DescriptionBuilder() {
            @Override
            public String toString(Object object) {
                IJPQLQueryBuilder builder = (IJPQLQueryBuilder) object;
                StringBuilder sb = new StringBuilder();
                sb.append(builder.getClass().getSimpleName());
                sb.append("[");
                sb.append(builder.getGrammar().toString());
                sb.append("]");
                return sb.toString();
            }
        };
    }

    private static DescriptionBuilder buildJPQLQueryFormatterTestHelperDescriptionBuilder() {
        return new DescriptionBuilder() {
            @Override
            public String toString(Object object) {
                BaseJPQLQueryFormatter formatter = (BaseJPQLQueryFormatter) object;
                StringBuilder sb = new StringBuilder();
                sb.append(formatter.getClass().getSimpleName());
                sb.append("[");
                sb.append(formatter.getIdentifierStyle().name());
                if (object instanceof AbstractActualJPQLQueryFormatter) {
                    AbstractActualJPQLQueryFormatter actualFormatter = (AbstractActualJPQLQueryFormatter) object;
                    sb.append("|");
                    sb.append(actualFormatter.isUsingExactMatch());
                }
                sb.append("]");
                return sb.toString();
            }
        };
    }

    private static DescriptionBuilder buildJPQLQueryHelperTestHelperDescriptionBuilder() {
        return new DescriptionBuilder() {
            @Override
            public String toString(Object object) {
                return object.getClass().getSimpleName();
            }
        };
    }

    private static DescriptionBuilder buildJPQLQueryTestHelperTestHelperDescriptionBuilder() {
        return new DescriptionBuilder() {
            @Override
            public String toString(Object object) {
                return object.getClass().getSimpleName();
            }
        };
    }

    private List<Runner> buildChildren() {

        SuiteClasses suiteClasses = findSuiteClasses(getTestClass().getJavaClass());

        if (suiteClasses == null) {
            return Collections.emptyList();
        }

        List<Runner> runners = new ArrayList<Runner>();

        for (Class<?> test : suiteClasses.value()) {
            if (descriptionHelper.helpers.isEmpty()) {
                Runner runner = buildRunner(test, suiteHelper);
                runners.add(runner);
            }
            else {
                for (SuiteHelper suiteHelper : buildSuiteHelpers()) {
                    Runner runner = buildRunner(test, suiteHelper);
                    runners.add(runner);
                }
            }
        }

        Collections.sort(runners, buildRunnerComparator());
        return runners;
    }

    private String buildDisplayString() {

        String displayString = super.getName();

        if (suiteHelper != null) {
            StringBuilder writer = new StringBuilder();
            writer.append(displayString);
            suiteHelper.addAdditionalInfo(writer);
            displayString = writer.toString();
        }

        return displayString;
    }

    private Runner buildRunner(Class<?> testClass, SuiteHelper suiteHelper) {

        try {

            // Create a runner for multiple unit-tests
            SuiteClasses suiteClasses = findSuiteClasses(testClass);

            if (suiteClasses != null) {
                return new JPQLTestRunner(testClass, suiteHelper);
            }

            // Create a runner for a single unit-test
            if (JPQLBasicTest.class.isAssignableFrom(testClass)) {
                return new JPQLBasicTestRunner(testClass, suiteHelper);
            }

            // Create the default runner
            return new AllDefaultPossibilitiesBuilder(true).runnerForClass(testClass);
        }
        catch (Throwable e) {
            return new ErrorReportingRunner(testClass, e);
        }
    }

    private Comparator<Runner> buildRunnerComparator() {
        return new Comparator<Runner>() {
            @Override
            public int compare(Runner runner1, Runner runner2) {
                String displayName1 = runner1.getDescription().getDisplayName();
                String displayName2 = runner1.getDescription().getDisplayName();
                return displayName1.compareTo(displayName2);
            }
        };
    }

    private List<SuiteHelper> buildSuiteHelpers() {

        List<SuiteHelper> suiteHelpers = new ArrayList<SuiteHelper>();
        Map<Class<? extends Annotation>, Object> singleHelpers = new HashMap<Class<? extends Annotation>, Object>();
        Collection<Class<? extends Annotation>> multipleHelpers = retrieveMultipleHelpers();

        for (Map.Entry<Class<? extends Annotation>, Object[]> helper : descriptionHelper.helpers.entrySet()) {
            if (!multipleHelpers.contains(helper.getKey())) {
                singleHelpers.put(helper.getKey(), helper.getValue()[0]);
            }
        }

        if (multipleHelpers.size() > 1) {
            for (Class<? extends Annotation> firstHelperKey : multipleHelpers) {
                for (Class<? extends Annotation> secondHelperKey : multipleHelpers) {
                    if (firstHelperKey != secondHelperKey) {
                        for (Object firstHelper : descriptionHelper.helpers.get(firstHelperKey)) {
                            for (Object secondHelper : descriptionHelper.helpers.get(secondHelperKey)) {
                                Map<Class<? extends Annotation>, Object> copy = new HashMap<Class<? extends Annotation>, Object>();
                                copy.putAll(singleHelpers);
                                copy.put(firstHelperKey,  firstHelper);
                                copy.put(secondHelperKey, secondHelper);

                                List<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>();
                                keys.add(firstHelperKey);
                                keys.add(secondHelperKey);

                                suiteHelpers.add(new SuiteHelper(suiteHelper, copy, keys));
                            }
                        }
                    }
                }
            }
        }
        else if (multipleHelpers.size() == 1) {
            for (Class<? extends Annotation> firstHelperKey : multipleHelpers) {
                for (Object firstHelper : descriptionHelper.helpers.get(firstHelperKey)) {
                    Map<Class<? extends Annotation>, Object> copy = new HashMap<Class<? extends Annotation>, Object>();
                    copy.putAll(singleHelpers);
                    copy.put(firstHelperKey, firstHelper);

                    List<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>();
                    keys.add(firstHelperKey);

                    suiteHelpers.add(new SuiteHelper(suiteHelper, copy, keys));
                }
            }
        }
        else {
            suiteHelpers.add(new SuiteHelper(suiteHelper, singleHelpers));
        }

        return suiteHelpers;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void collectInitializationErrors(List<Throwable> errors) {
        super.collectInitializationErrors(errors);
        initializeDescriptionHelper(errors);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Description describeChild(Runner child) {
        return child.getDescription();
    }

    private SuiteClasses findSuiteClasses(Class<?> testClass) {

        if (testClass == Object.class) {
            return null;
        }

        SuiteClasses suiteClasses = testClass.getAnnotation(SuiteClasses.class);

        if (suiteClasses != null) {
            return suiteClasses;
        }

        return findSuiteClasses(testClass.getSuperclass());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<Runner> getChildren() {
        // Cache the Description since JUnit always recreate it, this will increase performance
        if (runners == null) {
            runners = buildChildren();
        }
        return runners;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Description getDescription() {
        // Cache the Description since JUnit always recreate it, this will increase performance
        if (description == null) {
            description = super.getDescription();
        }
        return description;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getName() {
        // Cache the Description since JUnit always recreate it, this will increase performance and
        // also, add the extra information otherwise Eclipse will not be able to update the status of
        // the tests, it uses the display string to retrieve the node from the JUnit view, if two
        // nodes have the same display string, then only the last one is updated
        if (name == null) {
            name = buildDisplayString();
        }
        return name;
    }

    private void initializeDescriptionHelper(List<Throwable> errors) {

        descriptionHelper = new DescriptionHelper();
        Class<?> unitTest = getTestClass().getJavaClass();

        for (Method method : unitTest.getDeclaredMethods()) {

            if (isHelperMethod(method)) {

                for (Class<? extends Annotation> annotation : testRunnerHelpers.keySet()) {

                    if (method.isAnnotationPresent(annotation)) {

                        try {
                            method.setAccessible(true);
                            Object value = method.invoke(null);

                            descriptionHelper.helpers.put(
                                annotation,
                                value.getClass().isArray() ? (Object[]) value : new Object[] { value }
                            );
                        }
                        catch (Exception e) {
                            errors.add(e);
                        }
                    }
                }
            }
        }
    }

    private boolean isHelperMethod(Method method) {
        return Modifier.isStatic(method.getModifiers());
    }

    private Collection<Class<? extends Annotation>> retrieveMultipleHelpers() {

        Collection<Class<? extends Annotation>> keys = new ArrayList<Class<? extends Annotation>>();

        for (Map.Entry<Class<? extends Annotation>, Object[]> helper : descriptionHelper.helpers.entrySet()) {
            if (helper.getValue().length > 1) {
                keys.add(helper.getKey());
            }
        }

        return keys;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void runChild(Runner child, RunNotifier notifier) {
        child.run(notifier);
    }

    /**
     * This interface is used to create the description of a unit-tests.
     */
    private static interface DescriptionBuilder {

        /**
         * Creates a string representation of the given object.
         *
         * @param object The object to convert into a human readable string
         * @return A unique description for the given object
         */
        String toString(Object object);
    }

    private static class DescriptionHelper {

        private Map<Class<? extends Annotation>, Object[]> helpers;

        DescriptionHelper() {
            super();
            helpers = new HashMap<Class<? extends Annotation>, Object[]>();
        }
    }

    private static class JPQLBasicTestRunner extends BlockJUnit4ClassRunner {

        private Description description;
        private SuiteHelper suiteHelper;
        private JPQLBasicTest test;
        private boolean uniquenessRequired;

        JPQLBasicTestRunner(Class<?> testClass, SuiteHelper suiteHelper) throws InitializationError {
            super(testClass);
            this.suiteHelper = suiteHelper;
            // Check to see if the signature of the test methods needs to be unique,
            // this is required when the same test is run more than once and the
            // generated signature remains identical
            uniquenessRequired = testClass.isAnnotationPresent(UniqueSignature.class);
        }

        private Description buildDescription() {

            Description description = Description.createSuiteDescription(
                buildDisplayString(),
                getTestClass().getAnnotations()
            );

            Description superDescription = super.getDescription();
            description.getChildren().addAll(superDescription.getChildren());

            return description;
        }

        private String buildDisplayString() {
            if (suiteHelper != null) {
                StringBuilder writer = new StringBuilder();
                writer.append(getName());
                suiteHelper.addAdditionalInfo(writer);
                return writer.toString();
            }
            return getName();
        }

        private Comparator<FrameworkMethod> buildMethodComparator() {
            return new Comparator<FrameworkMethod>() {
                @Override
                public int compare(FrameworkMethod method1, FrameworkMethod method2) {
                    return method1.getName().compareTo(method2.getName());
                }
            };
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Statement classBlock(RunNotifier notifier) {
            Statement statement = new CreateTestStatement();
            statement = new SetUpClassStatement(statement);
            statement = new CompositeStatement(statement, childrenInvoker(notifier));
            statement = new TearDownClassStatement(statement);
            return statement;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Object createTest() throws Exception {
            return test;
        }

        @Override
        protected List<FrameworkMethod> getChildren() {
            List<FrameworkMethod> methods = new ArrayList<>(super.getChildren());
            Collections.sort(methods, buildMethodComparator());
            return methods;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Description getDescription() {
            if (description == null) {
                description = buildDescription();
            }
            return description;
        }

        private void instantiateTest() throws Throwable {

            Class<?> testClass = getTestClass().getJavaClass();
            Constructor<?> constructor = testClass.getConstructor();
            constructor.setAccessible(true);
            test = (JPQLBasicTest) constructor.newInstance();

            // Inject the SuiteHelper' values into the test
            if (suiteHelper != null) {
                suiteHelper.injectValues(test);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Statement methodBlock(FrameworkMethod method) {
            Statement statement = new SetUpStatement();
            statement = new CompositeStatement(statement, super.methodBlock(method));
            statement = new TearDownStatement(statement);
            return statement;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Statement methodInvoker(FrameworkMethod method, Object test) {
            this.test = (JPQLBasicTest) test;
            return super.methodInvoker(method, test);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected String testName(FrameworkMethod method) {

            // Create the signature of the method, which will have the helpers' additional information
            StringBuilder writer = new StringBuilder();
            writer.append(method.getName());

            if (suiteHelper != null) {
                suiteHelper.addAdditionalInfo(writer);
            }

            // It is possible two signatures maybe be identical, add something unique
            if (uniquenessRequired) {
                writer.append(" (");
                writer.append(hashCode());
                writer.append(")");
            }

            return writer.toString();
        }

        private class CompositeStatement extends Statement {

            private Statement statement1;
            private Statement statement2;

            CompositeStatement(Statement statement1, Statement statement2) {
                super();
                this.statement1 = statement1;
                this.statement2 = statement2;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void evaluate() throws Throwable {
                statement1.evaluate();
                statement2.evaluate();
            }
        }

        /**
         * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link
         * JPQLBasicTest#setUpClass()}.
         */
        private class CreateTestStatement extends Statement {
            @Override
            public void evaluate() throws Throwable {
                instantiateTest();
            }
        }

        /**
         * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link
         * JPQLBasicTest#setUpClass()}.
         */
        private class SetUpClassStatement extends Statement {

            private Statement statement;

            SetUpClassStatement(Statement statement) {
                super();
                this.statement = statement;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void evaluate() throws Throwable {
                statement.evaluate();
                test.setUpClass();
            }
        }

        /**
         * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link
         * JPQLBasicTest#setUp()}.
         */
        private class SetUpStatement extends Statement {
            @Override
            public void evaluate() throws Throwable {
                test.setUp();
            }
        }

        /**
         * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link
         * JPQLBasicTest#tearDownClass()}.
         */
        private class TearDownClassStatement extends Statement {

            private Statement statement;

            TearDownClassStatement(Statement statement) {
                super();
                this.statement = statement;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void evaluate() throws Throwable {
                try {
                    statement.evaluate();
                }
                finally {
                    if (test != null) {
                        test.tearDownClass();
                    }
                }
            }
        }

        /**
         * This {@link Statement} evaluates the wrapped {@link Statement} and then invoke {@link
         * JPQLBasicTest#tearDown()}.
         */
        private class TearDownStatement extends Statement {

            private Statement statement;

            TearDownStatement(Statement statement) {
                super();
                this.statement = statement;
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public void evaluate() throws Throwable {
                try {
                    statement.evaluate();
                }
                finally {
                    if (test != null) {
                        test.tearDown();
                    }
                }
            }
        }
    }

    private static class SuiteHelper {

        private Map<Class<? extends Annotation>, Object> helpers;
        private SuiteHelper parent;
        private List<Class<? extends Annotation>> primaryKeys;

        SuiteHelper(SuiteHelper parent,
                    Map<Class<? extends Annotation>, Object> helpers) {

            this(parent, helpers, Collections.<Class<? extends Annotation>>emptyList());
        }

        SuiteHelper(SuiteHelper parent,
                    Map<Class<? extends Annotation>, Object> helpers,
                    List<Class<? extends Annotation>> primaryKeys) {

            super();
            this.parent      = parent;
            this.helpers     = helpers;
            this.primaryKeys = primaryKeys;
        }

        void addAdditionalInfo(StringBuilder writer) {

            for (Class<? extends Annotation> primaryKey : primaryKeys) {
                writer.append(" - ");
                Object helper = helpers.get(primaryKey);
                DescriptionBuilder descriptionBuilder = testRunnerHelpers.get(primaryKey);
                writer.append(descriptionBuilder.toString(helper));
            }

            if (parent != null) {
                parent.addAdditionalInfo(writer);
            }
        }

        private void injectValues(Class<?> testClass, JPQLBasicTest test) throws Exception {

            if (testClass == Object.class) {
                return;
            }

            Field[] fields = testClass.getDeclaredFields();

            for (Field field : fields) {
                for (Map.Entry<Class<? extends Annotation>, Object> helper : helpers.entrySet()) {
                    if (field.isAnnotationPresent(helper.getKey())) {
                        field.setAccessible(true);
                        field.set(test, helper.getValue());
                    }
                }
            }

            injectValues(testClass.getSuperclass(), test);
        }

        void injectValues(JPQLBasicTest test) throws Exception {

            injectValues(test.getClass(), test);

            if (parent != null) {
                parent.injectValues(test);
            }
        }
    }
}
